go.etcd.io/etcd@v3.3.27+incompatible/pkg/report/weighted.go (about) 1 // Copyright 2017 The etcd Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // the file is borrowed from github.com/rakyll/boom/boomer/print.go 16 17 package report 18 19 import ( 20 "time" 21 ) 22 23 type weightedReport struct { 24 baseReport Report 25 26 report *report 27 results chan Result 28 weightTotal float64 29 } 30 31 // NewWeightedReport returns a report that includes 32 // both weighted and unweighted statistics. 33 func NewWeightedReport(r Report, precision string) Report { 34 return &weightedReport{ 35 baseReport: r, 36 report: newReport(precision), 37 results: make(chan Result, 16), 38 } 39 } 40 41 func (wr *weightedReport) Results() chan<- Result { return wr.results } 42 43 func (wr *weightedReport) Run() <-chan string { 44 donec := make(chan string, 2) 45 go func() { 46 defer close(donec) 47 basec, rc := make(chan string, 1), make(chan Stats, 1) 48 go func() { basec <- (<-wr.baseReport.Run()) }() 49 go func() { rc <- (<-wr.report.Stats()) }() 50 go wr.processResults() 51 wr.report.stats = wr.reweighStat(<-rc) 52 donec <- wr.report.String() 53 donec <- (<-basec) 54 }() 55 return donec 56 } 57 58 func (wr *weightedReport) Stats() <-chan Stats { 59 donec := make(chan Stats, 2) 60 go func() { 61 defer close(donec) 62 basec, rc := make(chan Stats, 1), make(chan Stats, 1) 63 go func() { basec <- (<-wr.baseReport.Stats()) }() 64 go func() { rc <- (<-wr.report.Stats()) }() 65 go wr.processResults() 66 donec <- wr.reweighStat(<-rc) 67 donec <- (<-basec) 68 }() 69 return donec 70 } 71 72 func (wr *weightedReport) processResults() { 73 defer close(wr.report.results) 74 defer close(wr.baseReport.Results()) 75 for res := range wr.results { 76 wr.processResult(res) 77 wr.baseReport.Results() <- res 78 } 79 } 80 81 func (wr *weightedReport) processResult(res Result) { 82 if res.Err != nil { 83 wr.report.results <- res 84 return 85 } 86 if res.Weight == 0 { 87 res.Weight = 1.0 88 } 89 wr.weightTotal += res.Weight 90 res.End = res.Start.Add(time.Duration(float64(res.End.Sub(res.Start)) / res.Weight)) 91 res.Weight = 1.0 92 wr.report.results <- res 93 } 94 95 func (wr *weightedReport) reweighStat(s Stats) Stats { 96 weightCoef := wr.weightTotal / float64(len(s.Lats)) 97 // weight > 1 => processing more than one request 98 s.RPS *= weightCoef 99 s.AvgTotal *= weightCoef * weightCoef 100 return s 101 }