# HG changeset patch # User Sascha L. Teichmann # Date 1558696148 -7200 # Node ID ae6c09fbc5905fdc3b4ae2ef04a26da85b7327d9 # Parent 8634d2bd0aac598a1eac6e2891ef030dafdd96c9 fairway depth/availability: bring unified CVS to streches and sections, too. diff -r 8634d2bd0aac -r ae6c09fbc590 pkg/controllers/stretches.go --- a/pkg/controllers/stretches.go Fri May 24 13:07:02 2019 +0200 +++ b/pkg/controllers/stretches.go Fri May 24 13:09:08 2019 +0200 @@ -60,8 +60,33 @@ breaks []float64 access func(*availMeasurement) float64 } + + availResult struct { + label string + from, to time.Time + ldc, breaks []time.Duration + } + + availCalculation struct { + result *availResult + ldc, breaks []time.Duration + } + + availJob struct { + result *availResult + bn *fullStretchBottleneck + } ) +func (r *availResult) add(c availCalculation) { + for i, v := range c.ldc { + r.ldc[i] += v + } + for i, v := range c.breaks { + r.breaks[i] += v + } +} + func (bns stretchBottlenecks) contains(limiting string) bool { for i := range bns { if bns[i].limiting == limiting { @@ -159,7 +184,6 @@ vars := mux.Vars(req) stretch := vars["kind"] == "stretch" name := vars["name"] - mode := intervalMode(req.FormValue("mode")) depthbreaks, widthbreaks := afdRefs, afdRefs @@ -250,31 +274,13 @@ return } - type ( - result struct { - label string - from, to time.Time - ldc, breaks []time.Duration - } - - calculation struct { - result *result - ldc, breaks []time.Duration - } - - job struct { - result *result - bn *fullStretchBottleneck - } - ) - n := runtime.NumCPU() / 2 if n == 0 { n = 1 } - jobCh := make(chan job) - calcCh := make(chan calculation, n) + jobCh := make(chan availJob) + calcCh := make(chan availCalculation, n) done := make(chan struct{}) var wg sync.WaitGroup @@ -282,14 +288,7 @@ go func() { defer close(done) for calc := range calcCh { - ldc := calc.result.ldc - for i, v := range calc.ldc { - ldc[i] += v - } - breaks := calc.result.breaks - for i, v := range calc.breaks { - breaks[i] += v - } + calc.result.add(calc) } }() @@ -310,7 +309,7 @@ bn.breaks, bn.access, ) - calcCh <- calculation{ + calcCh <- availCalculation{ result: res, breaks: breaks, ldc: ldc, @@ -319,7 +318,7 @@ }() } - var results []*result + var results []*availResult interval := intervals[mode](from, to) @@ -333,7 +332,7 @@ for pfrom, pto, label := interval(); label != ""; pfrom, pto, label = interval() { - res := &result{ + res := &availResult{ label: label, from: pfrom, to: pto, @@ -343,9 +342,10 @@ results = append(results, res) for _, bn := range loaded { - jobCh <- job{bn: bn, result: res} + jobCh <- availJob{bn: bn, result: res} } } + close(jobCh) wg.Wait() close(calcCh) @@ -355,21 +355,22 @@ out := csv.NewWriter(rw) - // label, classes, lnwl - record := make([]string, 1+1+len(breaks)+1) - record[0] = "#label" - record[1] = "# >= LDC [h]" + // label, lnwl, classes + record := make([]string, 1+2+len(breaks)+1) + record[0] = "# time" + record[1] = "# < LDC [h]" + record[2] = "# >= LDC [h]" for i, v := range breaks { if useDepth && useWidth { if i == 0 { - record[2] = "# < break_1 [h]" + record[3] = "# < break_1 [h]" } - record[i+3] = fmt.Sprintf("# >= break_%d", i+1) + record[i+4] = fmt.Sprintf("# >= break_%d", i+1) } else { if i == 0 { - record[2] = fmt.Sprintf("# < %.2f [h]", v) + record[3] = fmt.Sprintf("# < %.2f [h]", v) } - record[i+3] = fmt.Sprintf("# >= %.2f [h]", v) + record[i+4] = fmt.Sprintf("# >= %.2f [h]", v) } } @@ -384,10 +385,12 @@ for _, r := range results { record[0] = r.label - record[1] = fmt.Sprintf("%.3f", r.ldc[1].Hours()*scale) + for i, v := range r.ldc { + record[1+i] = fmt.Sprintf("%.3f", v.Hours()*scale) + } for i, d := range r.breaks { - record[2+i] = fmt.Sprintf("%.3f", d.Hours()*scale) + record[3+i] = fmt.Sprintf("%.3f", d.Hours()*scale) } if err := out.Write(record); err != nil { @@ -420,6 +423,7 @@ vars := mux.Vars(req) stretch := vars["kind"] == "stretch" name := vars["name"] + mode := intervalMode(req.FormValue("mode")) if name == "" { http.Error( @@ -522,40 +526,21 @@ return } - type calculation struct { - ldc, afd []time.Duration - } - n := runtime.NumCPU() / 2 if n == 0 { n = 1 } - var breaks []float64 - if useDepth { - breaks = depthbreaks - } else { - breaks = widthbreaks - } - - jobCh := make(chan *fullStretchBottleneck) - calcCh := make(chan calculation, n) + jobCh := make(chan availJob) + calcCh := make(chan availCalculation, n) done := make(chan struct{}) - ldc := make([]time.Duration, 2) - afd := make([]time.Duration, len(breaks)+1) - var wg sync.WaitGroup go func() { defer close(done) for calc := range calcCh { - for i, v := range calc.ldc { - ldc[i] += v - } - for i, v := range calc.afd { - afd[i] += v - } + calc.result.add(calc) } }() @@ -563,25 +548,55 @@ wg.Add(1) go func() { defer wg.Done() - for bn := range jobCh { + for job := range jobCh { + bn := job.bn + res := job.result ldc := bn.measurements.classify( from, to, bn.ldc, (*availMeasurement).getValue, ) - afd := bn.measurements.classify( + breaks := bn.measurements.classify( from, to, bn.breaks, bn.access, ) - calcCh <- calculation{ldc: ldc, afd: afd} + calcCh <- availCalculation{ + result: res, + breaks: breaks, + ldc: ldc, + } } }() } - for _, bn := range loaded { - jobCh <- bn + var results []*availResult + + interval := intervals[mode](from, to) + + var breaks []float64 + + if useDepth { + breaks = depthbreaks + } else { + breaks = widthbreaks + } + + for pfrom, pto, label := interval(); label != ""; pfrom, pto, label = interval() { + + res := &availResult{ + label: label, + from: pfrom, + to: pto, + ldc: make([]time.Duration, 2), + breaks: make([]time.Duration, len(breaks)+1), + } + results = append(results, res) + + for _, bn := range loaded { + jobCh <- availJob{bn: bn, result: res} + } } close(jobCh) @@ -589,61 +604,61 @@ close(calcCh) <-done - duration := to.Sub(from) * time.Duration(len(loaded)) + rw.Header().Add("Content-Type", "text/csv") - lnwlPercents := durationsToPercentage(duration, ldc) - afdPercents := durationsToPercentage(duration, afd) + out := csv.NewWriter(rw) - _ = lnwlPercents - _ = afdPercents - - /* // TODO: Rewrite this - - type ldcOutput struct { - Value float64 `json:"value"` - Below float64 `json:"below"` - Above float64 `json:"above"` + // label, lnwl, classes + record := make([]string, 1+2+len(breaks)+1) + record[0] = "# time" + record[1] = "# < LDC [%%]" + record[2] = "# >= LDC [%%]" + for i, v := range breaks { + if useDepth && useWidth { + if i == 0 { + record[3] = "# < break_1 [%%]" + } + record[i+4] = fmt.Sprintf("# >= break_%d [%%]", i+1) + } else { + if i == 0 { + record[3] = fmt.Sprintf("# < %.3f [%%]", v) + } + record[i+4] = fmt.Sprintf("# >= %.3f [%%]", v) + } } - type intervalOutput struct { - From *float64 `json:"from,omitempty"` - To *float64 `json:"to,omitempty"` - Percent float64 `json:"percent"` - } - - type output struct { - LDC []intervalOutput `json:"ldc"` - AFD []intervalOutput `json:"afd"` + if err := out.Write(record); err != nil { + // Too late for HTTP status message. + log.Printf("error: %v\n", err) + return } - out := output{ - LDC: []intervalOutput{ - {To: new(float64), Percent: lnwlPercents[0]}, - {From: new(float64), Percent: lnwlPercents[1]}, - }, + for _, r := range results { + duration := r.to.Sub(r.from) * time.Duration(len(loaded)) + + ldcPercents := durationsToPercentage(duration, r.ldc) + breaksPercents := durationsToPercentage(duration, r.breaks) + + record[0] = r.label + + for i, v := range ldcPercents { + record[2+i] = fmt.Sprintf("%.3f", v) + } + + for i, v := range breaksPercents { + record[3+i] = fmt.Sprintf("%.3f", v) + } + + if err := out.Write(record); err != nil { + // Too late for HTTP status message. + log.Printf("error: %v\n", err) + return + } } - // XXX: In mixed mode the breaks are not correct! - - for i, percent := range afdPercents { - var from, to *float64 - switch { - case i == 0: - to = &breaks[i] - case i == len(afdPercents)-1: - from = &breaks[len(breaks)-1] - default: - from = &breaks[i-1] - to = &breaks[i] - } - out.AFD = append(out.AFD, intervalOutput{ - From: from, - To: to, - Percent: percent, - }) + out.Flush() + if err := out.Error(); err != nil { + // Too late for HTTP status message. + log.Printf("error: %v\n", err) } - - jr = JSONResult{Result: &out} - return - */ }