Skip to content

Commit

Permalink
report: HDR Histogram plot output format
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomás Senart committed Jun 17, 2019
1 parent 0f5577e commit 96a3bd9
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 16 deletions.
131 changes: 131 additions & 0 deletions lib/reporters.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,134 @@ func NewJSONReporter(m *Metrics) Reporter {
return json.NewEncoder(w).Encode(m)
}
}

var hdrHeader = []byte("Value Percentile TotalCount 1/(1-Percentile)\n\n")

var logarithmic = []float64{
0.00,
0.100,
0.200,
0.300,
0.400,
0.500,
0.550,
0.600,
0.650,
0.700,
0.750,
0.775,
0.800,
0.825,
0.850,
0.875,
0.8875,
0.900,
0.9125,
0.925,
0.9375,
0.94375,
0.950,
0.95625,
0.9625,
0.96875,
0.971875,
0.975,
0.978125,
0.98125,
0.984375,
0.985938,
0.9875,
0.989062,
0.990625,
0.992188,
0.992969,
0.99375,
0.994531,
0.995313,
0.996094,
0.996484,
0.996875,
0.997266,
0.997656,
0.998047,
0.998242,
0.998437,
0.998633,
0.998828,
0.999023,
0.999121,
0.999219,
0.999316,
0.999414,
0.999512,
0.999561,
0.999609,
0.999658,
0.999707,
0.999756,
0.99978,
0.999805,
0.999829,
0.999854,
0.999878,
0.99989,
0.999902,
0.999915,
0.999927,
0.999939,
0.999945,
0.999951,
0.999957,
0.999963,
0.999969,
0.999973,
0.999976,
0.999979,
0.999982,
0.999985,
0.999986,
0.999988,
0.999989,
0.999991,
0.999992,
0.999993,
0.999994,
0.999995,
0.999996,
0.999997,
0.999998,
0.999999,
1.0,
}

// NewHDRHistogramPlotReporter returns a Reporter that writes out latency metrics
// in a format plottable by http://hdrhistogram.github.io/HdrHistogram/plotFiles.html.
func NewHDRHistogramPlotReporter(m *Metrics) Reporter {
return func(w io.Writer) error {
if _, err := w.Write(hdrHeader); err != nil {
return err
}

const fmtstr = "%f %f %d %f\n"
total := m.Requests

for _, q := range logarithmic {
value := m.Latencies.Quantile(q).Seconds() * 1000 // milliseconds
oneBy := oneByQuantile(q)
count := int64((q * float64(total)) + 0.5) // Count at quantile
_, err := fmt.Fprintf(w, fmtstr, value, q, count, oneBy)
if err != nil {
return err
}
}

return nil
}
}

func oneByQuantile(q float64) float64 {
if q < 1.0 {
return 1 / (1 - q)
}
return float64(10000000)
}
34 changes: 18 additions & 16 deletions report.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"io"
"os"
"os/signal"
"strings"
"time"

vegeta "github.com/tsenart/vegeta/lib"
Expand All @@ -20,7 +21,7 @@ Arguments:
the supported encodings (gob | json | csv) [default: stdin]
Options:
--type Which report type to generate (text | json | hist[buckets]).
--type Which report type to generate (text | json | hist[buckets] | hdrplot).
[default: text]
--every Write the report to --output at every given interval (e.g 100ms)
Expand All @@ -37,7 +38,7 @@ Examples:

func reportCmd() command {
fs := flag.NewFlagSet("vegeta report", flag.ExitOnError)
typ := fs.String("type", "text", "Report type to generate [text, json, hist[buckets]]")
typ := fs.String("type", "text", "Report type to generate [text, json, hist[buckets], hdrplot]")
every := fs.Duration("every", 0, "Report interval")
output := fs.String("output", "stdout", "Output file")

Expand All @@ -56,10 +57,6 @@ func reportCmd() command {
}

func report(files []string, typ, output string, every time.Duration) error {
if len(typ) < 4 {
return fmt.Errorf("invalid report type: %s", typ)
}

dec, mc, err := decoder(files)
defer mc.Close()
if err != nil {
Expand All @@ -77,7 +74,7 @@ func report(files []string, typ, output string, every time.Duration) error {
report vegeta.Report
)

switch typ[:4] {
switch typ {
case "plot":
return fmt.Errorf("The plot reporter has been deprecated and succeeded by the vegeta plot command")
case "text":
Expand All @@ -86,16 +83,21 @@ func report(files []string, typ, output string, every time.Duration) error {
case "json":
var m vegeta.Metrics
rep, report = vegeta.NewJSONReporter(&m), &m
case "hist":
if len(typ) < 6 {
return fmt.Errorf("bad buckets: '%s'", typ[4:])
}
var hist vegeta.Histogram
if err := hist.Buckets.UnmarshalText([]byte(typ[4:])); err != nil {
return err
}
rep, report = vegeta.NewHistogramReporter(&hist), &hist
case "hdrplot":
var m vegeta.Metrics
rep, report = vegeta.NewHDRHistogramPlotReporter(&m), &m
default:
switch {
case strings.HasPrefix(typ, "hist"):
if len(typ) < 6 {
return fmt.Errorf("bad buckets: '%s'", typ[4:])
}
var hist vegeta.Histogram
if err := hist.Buckets.UnmarshalText([]byte(typ[4:])); err != nil {
return err
}
rep, report = vegeta.NewHistogramReporter(&hist), &hist
}
return fmt.Errorf("unknown report type: %q", typ)
}

Expand Down

0 comments on commit 96a3bd9

Please sign in to comment.