Skip to content

Commit

Permalink
pkg/metrics: add "RequestsSummaryCompare"
Browse files Browse the repository at this point in the history
Signed-off-by: Gyuho Lee <leegyuho@amazon.com>
  • Loading branch information
gyuho committed Jun 22, 2020
1 parent 8d0174d commit 00b7c5c
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 11 deletions.
83 changes: 83 additions & 0 deletions pkg/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,89 @@ import (
dto "github.com/prometheus/client_model/go"
)

// RequestsSummaryCompare compares two "RequestsSummary".
// Delta is computed with "A" as "before" and with "B" as "after".
type RequestsSummaryCompare struct {
A RequestsSummary `json:"a" read-only:"true"`
B RequestsSummary `json:"b" read-only:"true"`

LantencyP50DeltaPercent float64 `json:"latency-p50-delta-percent" read-only:"true"`
LantencyP90DeltaPercent float64 `json:"latency-p90-delta-percent" read-only:"true"`
LantencyP99DeltaPercent float64 `json:"latency-p99-delta-percent" read-only:"true"`
LantencyP999DeltaPercent float64 `json:"latency-p99.9-delta-percent" read-only:"true"`
LantencyP9999DeltaPercent float64 `json:"latency-p99.99-delta-percent" read-only:"true"`
}

func (c RequestsSummaryCompare) Table() string {
buf := bytes.NewBuffer(nil)
tb := tablewriter.NewWriter(buf)
tb.SetAutoWrapText(false)
tb.SetColWidth(1500)
tb.SetCenterSeparator("*")
tb.SetAlignment(tablewriter.ALIGN_CENTER)
tb.SetCaption(true, "(% delta from 'A' to 'B')")
tb.SetHeader([]string{"Percentile", fmt.Sprintf("A %q", c.A.TestID), fmt.Sprintf("B %q", c.B.TestID), "Delta"})

tb.Append([]string{"50-pct Latency", c.A.LantencyP50.String(), c.B.LantencyP50.String(), toPercent(c.LantencyP50DeltaPercent)})
tb.Append([]string{"90-pct Latency", c.A.LantencyP90.String(), c.B.LantencyP90.String(), toPercent(c.LantencyP90DeltaPercent)})
tb.Append([]string{"99-pct Latency", c.A.LantencyP99.String(), c.B.LantencyP99.String(), toPercent(c.LantencyP99DeltaPercent)})
tb.Append([]string{"99.9-pct Latency", c.A.LantencyP999.String(), c.B.LantencyP999.String(), toPercent(c.LantencyP999DeltaPercent)})
tb.Append([]string{"99.99-pct Latency", c.A.LantencyP9999.String(), c.B.LantencyP9999.String(), toPercent(c.LantencyP9999DeltaPercent)})

tb.Render()
return buf.String()
}

func toPercent(f float64) string {
sign := "+"
if f < 0.0 {
sign = ""
}
return fmt.Sprintf("%s%.3f %%", sign, f)
}

// CompareRequestsSummary compares two "RequestsSummary".
func CompareRequestsSummary(a RequestsSummary, b RequestsSummary) (c RequestsSummaryCompare, err error) {
if len(a.LatencyHistogram) != len(b.LatencyHistogram) {
return RequestsSummaryCompare{}, fmt.Errorf("len(a.LatencyHistogram) %d != len(b.LatencyHistogram) %d", len(a.LatencyHistogram), len(b.LatencyHistogram))
}

c = RequestsSummaryCompare{
A: a,
B: b,
}

// e.g. "A" 100, "B" 50 == -50%
// e.g. "A" 50, "B" 100 == 100%
deltaP50 := float64(b.LantencyP50) - float64(a.LantencyP50)
deltaP50 /= float64(a.LantencyP50)
deltaP50 *= 100.0

deltaP90 := float64(b.LantencyP90) - float64(a.LantencyP90)
deltaP90 /= float64(a.LantencyP90)
deltaP90 *= 100.0

deltaP99 := float64(b.LantencyP99) - float64(a.LantencyP99)
deltaP99 /= float64(a.LantencyP99)
deltaP99 *= 100.0

deltaP999 := float64(b.LantencyP999) - float64(a.LantencyP999)
deltaP999 /= float64(a.LantencyP999)
deltaP999 *= 100.0

deltaP9999 := float64(b.LantencyP9999) - float64(a.LantencyP9999)
deltaP9999 /= float64(a.LantencyP9999)
deltaP9999 *= 100.0

c.LantencyP50DeltaPercent = deltaP50
c.LantencyP90DeltaPercent = deltaP90
c.LantencyP99DeltaPercent = deltaP99
c.LantencyP999DeltaPercent = deltaP999
c.LantencyP9999DeltaPercent = deltaP9999

return c, nil
}

// RequestsSummary represents request results.
type RequestsSummary struct {
// TestID is the test ID.
Expand Down
75 changes: 64 additions & 11 deletions pkg/metrics/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package metrics
import (
"fmt"
"math"
"math/rand"
"reflect"
"sort"
"testing"
Expand All @@ -12,21 +13,66 @@ import (
)

func TestRequestsSummary(t *testing.T) {
ds := make(Durations, 20000)
ds1 := make(Durations, 20000)
for i := 0; i < 20000; i++ {
sign := 1
if i%2 == 0 {
sign = -1
}
delta := time.Duration(rand.Int63n(500)) * time.Millisecond
dur := time.Second + time.Duration(sign*i)*time.Millisecond
if dur < 0 {
dur = 2 * time.Second
}
ds[20000-1-i] = dur
ds1[20000-1-i] = dur + delta
}
sort.Sort(ds)
sort.Sort(ds1)
rs1 := RequestsSummary{
TestID: time.Now().UTC().Format(time.RFC3339Nano),
SuccessTotal: 10,
FailureTotal: 10,
LatencyHistogram: HistogramBuckets([]HistogramBucket{
{Scale: "milliseconds", LowerBound: 0, UpperBound: 0.5, Count: 0},
{Scale: "milliseconds", LowerBound: 0.5, UpperBound: 1, Count: 2},
{Scale: "milliseconds", LowerBound: 1, UpperBound: 2, Count: 0},
{Scale: "milliseconds", LowerBound: 2, UpperBound: 4, Count: 0},
{Scale: "milliseconds", LowerBound: 4, UpperBound: 8, Count: 0},
{Scale: "milliseconds", LowerBound: 8, UpperBound: 16, Count: 8},
{Scale: "milliseconds", LowerBound: 16, UpperBound: 32, Count: 0},
{Scale: "milliseconds", LowerBound: 32, UpperBound: 64, Count: 100},
{Scale: "milliseconds", LowerBound: 64, UpperBound: 128, Count: 0},
{Scale: "milliseconds", LowerBound: 128, UpperBound: 256, Count: 0},
{Scale: "milliseconds", LowerBound: 256, UpperBound: 512, Count: 20},
{Scale: "milliseconds", LowerBound: 512, UpperBound: 1024, Count: 0},
{Scale: "milliseconds", LowerBound: 1024, UpperBound: 2048, Count: 0},
{Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0},
{Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 4},
}),
LantencyP50: ds1.PickLantencyP50(),
LantencyP90: ds1.PickLantencyP90(),
LantencyP99: ds1.PickLantencyP99(),
LantencyP999: ds1.PickLantencyP999(),
LantencyP9999: ds1.PickLantencyP9999(),
}
fmt.Println(rs1.JSON())
fmt.Println(rs1.Table())

rs := RequestsSummary{
println()
ds2 := make(Durations, 20000)
for i := 0; i < 20000; i++ {
sign := 1
if i%2 == 0 {
sign = -1
}
delta := time.Duration(rand.Int63n(500)) * time.Millisecond
dur := time.Second + time.Duration(sign*i)*time.Millisecond
if dur < 0 {
dur = 2 * time.Second
}
ds2[20000-1-i] = dur + delta
}
sort.Sort(ds2)
rs2 := RequestsSummary{
TestID: time.Now().UTC().Format(time.RFC3339Nano),
SuccessTotal: 10,
FailureTotal: 10,
Expand All @@ -47,14 +93,21 @@ func TestRequestsSummary(t *testing.T) {
{Scale: "milliseconds", LowerBound: 2048, UpperBound: 4096, Count: 0},
{Scale: "milliseconds", LowerBound: 4096, UpperBound: math.MaxFloat64, Count: 4},
}),
LantencyP50: ds.PickLantencyP50(),
LantencyP90: ds.PickLantencyP90(),
LantencyP99: ds.PickLantencyP99(),
LantencyP999: ds.PickLantencyP999(),
LantencyP9999: ds.PickLantencyP9999(),
LantencyP50: ds2.PickLantencyP50(),
LantencyP90: ds2.PickLantencyP90(),
LantencyP99: ds2.PickLantencyP99(),
LantencyP999: ds2.PickLantencyP999(),
LantencyP9999: ds2.PickLantencyP9999(),
}
fmt.Println(rs2.JSON())
fmt.Println(rs2.Table())

println()
c, err := CompareRequestsSummary(rs1, rs2)
if err != nil {
t.Fatal(err)
}
fmt.Println(rs.JSON())
fmt.Println(rs.Table())
fmt.Println(c.Table())
}

func TestMetricsHistogram(t *testing.T) {
Expand Down

0 comments on commit 00b7c5c

Please sign in to comment.