diff --git a/pkg/report/timeseries.go b/pkg/report/timeseries.go index ba4a5f86f..fcd976063 100644 --- a/pkg/report/timeseries.go +++ b/pkg/report/timeseries.go @@ -27,7 +27,9 @@ import ( type DataPoint struct { Timestamp int64 + MinLatency time.Duration AvgLatency time.Duration + MaxLatency time.Duration ThroughPut int64 } @@ -38,6 +40,8 @@ func (t TimeSeries) Len() int { return len(t) } func (t TimeSeries) Less(i, j int) bool { return t[i].Timestamp < t[j].Timestamp } type secondPoint struct { + minLatency time.Duration + maxLatency time.Duration totalLatency time.Duration count int64 } @@ -57,10 +61,14 @@ func (sp *secondPoints) Add(ts time.Time, lat time.Duration) { tk := ts.Unix() if v, ok := sp.tm[tk]; !ok { - sp.tm[tk] = secondPoint{totalLatency: lat, count: 1} + sp.tm[tk] = secondPoint{minLatency: lat, maxLatency: lat, totalLatency: lat, count: 1} } else { + if lat != time.Duration(0) { + v.minLatency = minDuration(v.minLatency, lat) + } + v.maxLatency = maxDuration(v.maxLatency, lat) v.totalLatency += lat - v.count += 1 + v.count++ sp.tm[tk] = v } } @@ -98,7 +106,9 @@ func (sp *secondPoints) getTimeSeries() TimeSeries { } tslice[i] = DataPoint{ Timestamp: k, + MinLatency: v.minLatency, AvgLatency: lat, + MaxLatency: v.maxLatency, ThroughPut: v.count, } i++ @@ -111,14 +121,16 @@ func (sp *secondPoints) getTimeSeries() TimeSeries { func (ts TimeSeries) String() string { buf := new(bytes.Buffer) wr := csv.NewWriter(buf) - if err := wr.Write([]string{"UNIX-TS", "AVG-LATENCY-MS", "AVG-THROUGHPUT"}); err != nil { + if err := wr.Write([]string{"UNIX-SECOND", "MIN-LATENCY-MS", "AVG-LATENCY-MS", "MAX-LATENCY-MS", "AVG-THROUGHPUT"}); err != nil { log.Fatal(err) } rows := [][]string{} for i := range ts { row := []string{ fmt.Sprintf("%d", ts[i].Timestamp), + fmt.Sprintf("%s", ts[i].MinLatency), fmt.Sprintf("%s", ts[i].AvgLatency), + fmt.Sprintf("%s", ts[i].MaxLatency), fmt.Sprintf("%d", ts[i].ThroughPut), } rows = append(rows, row) @@ -132,3 +144,17 @@ func (ts TimeSeries) String() string { } return fmt.Sprintf("\nSample in one second (unix latency throughput):\n%s", buf.String()) } + +func minDuration(a, b time.Duration) time.Duration { + if a < b { + return a + } + return b +} + +func maxDuration(a, b time.Duration) time.Duration { + if a > b { + return a + } + return b +} diff --git a/pkg/report/timeseries_test.go b/pkg/report/timeseries_test.go index 99874cd44..13fcbfa39 100644 --- a/pkg/report/timeseries_test.go +++ b/pkg/report/timeseries_test.go @@ -28,4 +28,17 @@ func TestGetTimeseries(t *testing.T) { if n < 3 { t.Fatalf("expected at 6 points of time series, got %s", sp.getTimeSeries()) } + + // add a point with duplicate timestamp + sp.Add(now, 3*time.Second) + ts := sp.getTimeSeries() + if ts[0].MinLatency != time.Second { + t.Fatalf("ts[0] min latency expected %v, got %s", time.Second, ts[0].MinLatency) + } + if ts[0].AvgLatency != 2*time.Second { + t.Fatalf("ts[0] average latency expected %v, got %s", 2*time.Second, ts[0].AvgLatency) + } + if ts[0].MaxLatency != 3*time.Second { + t.Fatalf("ts[0] max latency expected %v, got %s", 3*time.Second, ts[0].MaxLatency) + } }