Merge pull request #199 from alanbernstein/benchmarks-readable

Use Duration's string representation in JSON output
This commit is contained in:
Matthew Jaffee 2016-12-19 14:50:53 -06:00 committed by GitHub
commit e211dbd54a
4 changed files with 141 additions and 4 deletions

View file

@ -118,7 +118,7 @@ func (sb *serialBenchmark) Init(hosts []string, agentNum int) error {
// and the values are the results of each benchmark's Run method.
func (sb *serialBenchmark) Run(ctx context.Context, agentNum int) map[string]interface{} {
results := make(map[string]interface{}, len(sb.benchmarkers))
runtimes := make(map[string]time.Duration)
runtimes := make(map[string]interface{})
total_start := time.Now()
for i, b := range sb.benchmarkers {
start := time.Now()

34
bench/prettify.go Normal file
View file

@ -0,0 +1,34 @@
package bench
import "time"
// wrapper type to force human-readable JSON output
type PrettyDuration time.Duration
func (d PrettyDuration) MarshalJSON() ([]byte, error) {
s := time.Duration(d).String()
return []byte("\"" + s + "\""), nil
}
// Recursively replaces elements of ugly types with their pretty wrappers
func Prettify(m map[string]interface{}) map[string]interface{} {
newmap := make(map[string]interface{})
for k, v := range m {
switch v.(type) {
case map[string]interface{}:
newmap[k] = Prettify(v.(map[string]interface{}))
case []time.Duration:
newslice := make([]PrettyDuration, len(v.([]time.Duration)))
slice := v.([]time.Duration)
for n, e := range slice {
newslice[n] = PrettyDuration(e)
}
newmap[k] = newslice
case time.Duration:
newmap[k] = PrettyDuration(v.(time.Duration))
default:
newmap[k] = v
}
}
return newmap
}

93
bench/prettify_test.go Normal file
View file

@ -0,0 +1,93 @@
package bench_test
import (
"bytes"
"encoding/json"
"fmt"
"os"
"testing"
"time"
"github.com/pilosa/pilosa/bench"
)
func prettyEncode(data map[string]interface{}) string {
pretty := bench.Prettify(data)
jsonString := new(bytes.Buffer)
enc := json.NewEncoder(jsonString)
enc.SetIndent("", " ")
err := enc.Encode(pretty)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
return jsonString.String()
}
func TestPrettifyString(t *testing.T) {
res := make(map[string]interface{}, 1)
res["0"] = "foobar"
pretty := prettyEncode(res)
expected := `
{
"0": "foobar"
}
`[1:]
if pretty != expected {
t.Fatalf("Pretty string doesn't match")
}
}
func TestPrettifyInt(t *testing.T) {
res := make(map[string]interface{}, 1)
res["0"] = 234567
pretty := prettyEncode(res)
expected := `
{
"0": 234567
}
`[1:]
if pretty != expected {
t.Fatalf("Pretty int doesn't match")
}
}
func TestPrettifyDuration(t *testing.T) {
res := make(map[string]interface{}, 1)
res["0"] = time.Duration(234567)
pretty := prettyEncode(res)
expected := `
{
"0": "234.567µs"
}
`[1:]
if pretty != expected {
t.Fatalf("Pretty duration doesn't match")
}
}
func TestPrettifyDurationSlice(t *testing.T) {
res := make(map[string]interface{}, 1)
res["0"] = []time.Duration{123, 234567, 34567890}
pretty := prettyEncode(res)
expected := `
{
"0": [
"123ns",
"234.567µs",
"34.56789ms"
]
}
`[1:]
if pretty != expected {
t.Fatalf("Pretty duration slice doesn't match")
}
}

View file

@ -1156,6 +1156,8 @@ type BagentCommand struct {
AgentNum int
// Slice of pilosa hosts to run the Benchmarks against.
Hosts []string
// Enable pretty printing of results, for human consumption.
HumanReadable bool
Stdin io.Reader
Stdout io.Writer
@ -1165,9 +1167,10 @@ type BagentCommand struct {
// NewBagentCommand returns a new instance of BagentCommand.
func NewBagentCommand(stdin io.Reader, stdout, stderr io.Writer) *BagentCommand {
return &BagentCommand{
Benchmarks: []bench.Benchmark{},
Hosts: []string{},
AgentNum: 0,
Benchmarks: []bench.Benchmark{},
Hosts: []string{},
AgentNum: 0,
HumanReadable: false,
Stdin: stdin,
Stdout: stdout,
@ -1188,6 +1191,7 @@ func (cmd *BagentCommand) ParseFlags(args []string) error {
var pilosaHosts string
fs.StringVar(&pilosaHosts, "hosts", "localhost:15000", "Comma separated list of host:port")
fs.IntVar(&cmd.AgentNum, "agentNum", 0, "An integer differentiating this agent from other in the fleet.")
fs.BoolVar(&cmd.HumanReadable, "human", false, "Boolean to enable human-readable format.")
if err := fs.Parse(args); err != nil {
return err
@ -1251,6 +1255,9 @@ The following arguments are available:
-agentNum N
An integer differentiating this agent from others in the fleet.
-human
Boolean to enable human-readable format.
subcommands:
diagonal-set-bits
random-set-bits
@ -1273,6 +1280,9 @@ func (cmd *BagentCommand) Run(ctx context.Context) error {
res := sbm.Run(ctx, cmd.AgentNum)
enc := json.NewEncoder(cmd.Stdout)
enc.SetIndent("", " ")
if cmd.HumanReadable {
res = bench.Prettify(res)
}
err = enc.Encode(res)
if err != nil {
fmt.Fprintln(cmd.Stderr, err)