From bcc785fc7891adeea235d669cfc70d90871fad49 Mon Sep 17 00:00:00 2001 From: Etienne Perot Date: Mon, 1 Jul 2024 16:04:25 -0700 Subject: [PATCH] Metrics visualization: Show extrapolated rate for short-duration profiles. All rate metrics currently show per-second rates, which cannot be computed before we have at least 1 second's worth of profile data. However, it's reasonable to want to run very short workloads (less than 1 second) and still want to see how those rates evolved over this duration. So this change computes an extrapolated per-second rate for the first second of execution. PiperOrigin-RevId: 648513094 --- test/metricsviz/metricsviz.go | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/test/metricsviz/metricsviz.go b/test/metricsviz/metricsviz.go index ba9b872c2..2c049e798 100644 --- a/test/metricsviz/metricsviz.go +++ b/test/metricsviz/metricsviz.go @@ -221,9 +221,13 @@ func (c *chart) getXAxis() ([]string, error) { // series returns a single line series of the chart. func (c *chart) series(ts *TimeSeries, isCumulative bool) ([]opts.LineData, error) { - const windowDuration = time.Second + const ( + windowDuration = time.Second + minTimeToReport = 10 * time.Millisecond + ) seriesData := make([]opts.LineData, len(ts.Data)) if isCumulative { + timeSeriesIsLongEnough := false lastValidXIndex := 0 for i, p := range ts.Data { baselineWhen := p.When.Add(-windowDuration) @@ -263,12 +267,30 @@ func (c *chart) series(ts *TimeSeries, isCumulative bool) ([]opts.LineData, erro baselineWhenFraction := float64(baselineWhen.Sub(whenBefore)) / float64(whenDelta) baseline := baselineBefore + uint64(float64(baselineDelta)*baselineWhenFraction) seriesData[i] = opts.LineData{Value: p.Value - baseline, YAxisIndex: 0, Symbol: "none"} + timeSeriesIsLongEnough = true + case p.When.Sub(ts.Data[0].When) >= minTimeToReport: + // We don't yet have enough points to get a full `windowDuration`'s + // worth of data, but we do have enough data to report something if + // we assume that the rate can be extrapolated from the first point + // until now. + baselineBefore := ts.Data[0].Value + baselineAfter := p.Value + baselineDelta := baselineAfter - baselineBefore + whenBefore := ts.Data[0].When + whenAfter := p.When + whenDelta := whenAfter.Sub(whenBefore) + interpolationMultiplier := float64(windowDuration.Nanoseconds()) / float64(whenDelta.Nanoseconds()) + seriesData[i] = opts.LineData{Value: uint64(float64(baselineDelta) * interpolationMultiplier), YAxisIndex: 0, Symbol: "none"} + timeSeriesIsLongEnough = true default: // Happens naturally for points too early in the timeseries, // set the point to nil. seriesData[i] = opts.LineData{Value: nil, YAxisIndex: 0, Symbol: "none"} } } + if !timeSeriesIsLongEnough { + return nil, fmt.Errorf("metric %v is cumulative but timeseries data for it is smaller than minimum chartable duration (%v), please run the workload for longer for cumulative timeseries to become meaningful", ts.Metric.Name, minTimeToReport) + } } else { // Non-cumulative time series are more straightforward. for i, p := range ts.Data {