diff --git a/src/cmd/trace/mmu.go b/src/cmd/trace/mmu.go index 3fae3d6645..062e5ad2ca 100644 --- a/src/cmd/trace/mmu.go +++ b/src/cmd/trace/mmu.go @@ -88,6 +88,14 @@ func httpMMUPlot(w http.ResponseWriter, r *http.Request) { return } + var quantiles []float64 + for _, flagStr := range strings.Split(r.FormValue("flags"), "|") { + if flagStr == "mut" { + quantiles = []float64{0, 1 - .999, 1 - .99, 1 - .95} + break + } + } + // Find a nice starting point for the plot. xMin := time.Second for xMin > 1 { @@ -114,15 +122,21 @@ func httpMMUPlot(w http.ResponseWriter, r *http.Request) { // Compute MMU curve. logMin, logMax := math.Log(float64(xMin)), math.Log(float64(xMax)) const samples = 100 - plot := make([][2]float64, samples) + plot := make([][]float64, samples) for i := 0; i < samples; i++ { window := time.Duration(math.Exp(float64(i)/(samples-1)*(logMax-logMin) + logMin)) - y := mmuCurve.MMU(window) - plot[i] = [2]float64{float64(window), y} + if quantiles == nil { + plot[i] = make([]float64, 2) + plot[i][1] = mmuCurve.MMU(window) + } else { + plot[i] = make([]float64, 1+len(quantiles)) + copy(plot[i][1:], mmuCurve.MUD(window, quantiles)) + } + plot[i][0] = float64(window) } // Create JSON response. - err = json.NewEncoder(w).Encode(map[string]interface{}{"xMin": int64(xMin), "xMax": int64(xMax), "curve": plot}) + err = json.NewEncoder(w).Encode(map[string]interface{}{"xMin": int64(xMin), "xMax": int64(xMax), "quantiles": quantiles, "curve": plot}) if err != nil { log.Printf("failed to serialize response: %v", err) return @@ -150,6 +164,10 @@ var templMMU = ` else { return ns / 1e9 + 's'; } } + function niceQuantile(q) { + return 'p' + q*100; + } + function mmuFlags() { var flags = ""; $("#options input").each(function(i, elt) { @@ -181,6 +199,11 @@ var templMMU = ` var data = new google.visualization.DataTable(); data.addColumn('number', 'Window duration'); data.addColumn('number', 'Minimum mutator utilization'); + if (plotData.quantiles) { + for (var i = 1; i < plotData.quantiles.length; i++) { + data.addColumn('number', niceQuantile(1 - plotData.quantiles[i]) + ' MU'); + } + } data.addRows(curve); for (var i = 0; i < curve.length; i++) { data.setFormattedValue(i, 0, niceDuration(curve[i][0])); @@ -201,6 +224,7 @@ var templMMU = ` maxValue: 1.0, }, legend: { position: 'none' }, + focusTarget: 'category', width: 900, height: 500, chartArea: { width: '80%', height: '80%' }, @@ -208,6 +232,10 @@ var templMMU = ` for (var v = plotData.xMin; v <= plotData.xMax; v *= 10) { options.hAxis.ticks.push({v:v, f:niceDuration(v)}); } + if (plotData.quantiles) { + options.vAxis.title = 'Mutator utilization'; + options.legend.position = 'in'; + } var container = $('#mmu_chart'); container.empty(); @@ -298,6 +326,11 @@ var templMMU = ` ?Sweep reclaims unused memory between GCs. (Enabling this may be very slow.).

+

+ Display
+ + ?Display percentile mutator utilization in addition to minimum. E.g., p99 MU drops the worst 1% of windows.
+

Select a point for details.