// Copyright 2017 The etcd Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // the file is borrowed from github.com/rakyll/boom/boomer/print.go package report import ( "time" ) type weightedReport struct { baseReport Report report *report results chan Result weightTotal float64 } // NewWeightedReport returns a report that includes // both weighted and unweighted statistics. func NewWeightedReport(r Report, precision string) Report { return &weightedReport{ baseReport: r, report: newReport(precision), results: make(chan Result, 16), } } func (wr *weightedReport) Results() chan<- Result { return wr.results } func (wr *weightedReport) Run() <-chan string { donec := make(chan string, 2) go func() { defer close(donec) basec, rc := make(chan string, 1), make(chan Stats, 1) go func() { basec <- (<-wr.baseReport.Run()) }() go func() { rc <- (<-wr.report.Stats()) }() go wr.processResults() wr.report.stats = wr.reweighStat(<-rc) donec <- wr.report.String() donec <- (<-basec) }() return donec } func (wr *weightedReport) Stats() <-chan Stats { donec := make(chan Stats, 2) go func() { defer close(donec) basec, rc := make(chan Stats, 1), make(chan Stats, 1) go func() { basec <- (<-wr.baseReport.Stats()) }() go func() { rc <- (<-wr.report.Stats()) }() go wr.processResults() donec <- wr.reweighStat(<-rc) donec <- (<-basec) }() return donec } func (wr *weightedReport) processResults() { defer close(wr.report.results) defer close(wr.baseReport.Results()) for res := range wr.results { wr.processResult(res) wr.baseReport.Results() <- res } } func (wr *weightedReport) processResult(res Result) { if res.Err != nil { wr.report.results <- res return } if res.Weight == 0 { res.Weight = 1.0 } wr.weightTotal += res.Weight res.End = res.Start.Add(time.Duration(float64(res.End.Sub(res.Start)) / res.Weight)) res.Weight = 1.0 wr.report.results <- res } func (wr *weightedReport) reweighStat(s Stats) Stats { weightCoef := wr.weightTotal / float64(len(s.Lats)) // weight > 1 => processing more than one request s.RPS *= weightCoef s.AvgTotal *= weightCoef * weightCoef return s }