From 7dfb53d08e8a1a7f0d048b18baf5135ff993dd5a Mon Sep 17 00:00:00 2001 From: Alan Bernstein Date: Thu, 8 Dec 2016 15:06:02 -0600 Subject: [PATCH 1/7] Use Duration's string representation in JSON output --- bench/bench.go | 22 +++++++++++++++++++++- cmd/pilosactl/main.go | 1 + 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/bench/bench.go b/bench/bench.go index 5363d29b2..c264b8e58 100644 --- a/bench/bench.go +++ b/bench/bench.go @@ -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() @@ -139,3 +139,23 @@ func Serial(bs ...Benchmark) Benchmark { benchmarkers: bs, } } + +type PrettyDuration time.Duration + +func (d PrettyDuration) MarshalJSON() ([]byte, error) { + s := time.Duration(d).String() + return []byte("\"" + s + "\""), nil +} + +func Prettify(m map[string]interface{}) map[string]interface{} { + newmap := make(map[string]interface{}) + for k, v := range m { + switch v.(type) { + case time.Duration: + newmap[k] = PrettyDuration(v.(time.Duration)) + default: + newmap[k] = Prettify(v.(map[string]interface{})) + } + } + return newmap +} diff --git a/cmd/pilosactl/main.go b/cmd/pilosactl/main.go index 6408794df..7d367cf40 100644 --- a/cmd/pilosactl/main.go +++ b/cmd/pilosactl/main.go @@ -1226,6 +1226,7 @@ func (cmd *BagentCommand) Run(ctx context.Context) error { res := sbm.Run(ctx, cmd.AgentNum) enc := json.NewEncoder(cmd.Stdout) enc.SetIndent("", " ") + res = bench.Prettify(res) err = enc.Encode(res) if err != nil { fmt.Fprintln(cmd.Stderr, err) From a6cda398664e81186d1dd297b47eaec5c6e6bf50 Mon Sep 17 00:00:00 2001 From: Alan Bernstein Date: Thu, 8 Dec 2016 15:29:05 -0600 Subject: [PATCH 2/7] Add comments --- bench/bench.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bench/bench.go b/bench/bench.go index c264b8e58..e75f30f80 100644 --- a/bench/bench.go +++ b/bench/bench.go @@ -140,6 +140,7 @@ func Serial(bs ...Benchmark) Benchmark { } } +// wrapper type to force human-readable JSON output type PrettyDuration time.Duration func (d PrettyDuration) MarshalJSON() ([]byte, error) { @@ -147,6 +148,7 @@ func (d PrettyDuration) MarshalJSON() ([]byte, error) { 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 { From d08ffd20e2e44ce4c044e815c38df219268b613f Mon Sep 17 00:00:00 2001 From: Alan Bernstein Date: Mon, 12 Dec 2016 16:57:21 -0600 Subject: [PATCH 3/7] Move prettify to own file --- bench/bench.go | 22 ---------------------- bench/prettify.go | 27 +++++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 bench/prettify.go diff --git a/bench/bench.go b/bench/bench.go index e75f30f80..28a85c111 100644 --- a/bench/bench.go +++ b/bench/bench.go @@ -139,25 +139,3 @@ func Serial(bs ...Benchmark) Benchmark { benchmarkers: bs, } } - -// 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 time.Duration: - newmap[k] = PrettyDuration(v.(time.Duration)) - default: - newmap[k] = Prettify(v.(map[string]interface{})) - } - } - return newmap -} diff --git a/bench/prettify.go b/bench/prettify.go new file mode 100644 index 000000000..f9fdb04bf --- /dev/null +++ b/bench/prettify.go @@ -0,0 +1,27 @@ +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 time.Duration: + newmap[k] = PrettyDuration(v.(time.Duration)) + default: + newmap[k] = Prettify(v.(map[string]interface{})) + } + } + return newmap +} From da3bb99f0a324820564e6a9f6b264aeb61a7e0c2 Mon Sep 17 00:00:00 2001 From: Alan Bernstein Date: Mon, 12 Dec 2016 22:10:07 -0600 Subject: [PATCH 4/7] Generalize Prettify function --- bench/prettify.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/bench/prettify.go b/bench/prettify.go index f9fdb04bf..e0636bec3 100644 --- a/bench/prettify.go +++ b/bench/prettify.go @@ -1,8 +1,6 @@ package bench -import ( - "time" -) +import "time" // wrapper type to force human-readable JSON output type PrettyDuration time.Duration @@ -17,10 +15,19 @@ 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] = Prettify(v.(map[string]interface{})) + newmap[k] = v } } return newmap From 356f1cfd1777f1537f1dc0705836e68cfd309af5 Mon Sep 17 00:00:00 2001 From: Alan Bernstein Date: Mon, 12 Dec 2016 22:17:56 -0600 Subject: [PATCH 5/7] Add test for prettify --- bench/prettify_test.go | 58 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 bench/prettify_test.go diff --git a/bench/prettify_test.go b/bench/prettify_test.go new file mode 100644 index 000000000..4da62895b --- /dev/null +++ b/bench/prettify_test.go @@ -0,0 +1,58 @@ +package bench_test + +import ( + "bytes" + "encoding/json" + "fmt" + "os" + "testing" + "time" + + "github.com/pilosa/pilosa/bench" +) + +func TestPrettify(t *testing.T) { + res := make(map[string]interface{}, 1) + res["0"] = map[string]interface{}{ + "avg": time.Duration(12345), + "max": time.Duration(23456), + "int": 3456, + "slice": []time.Duration{123, 234}, + } + res["runtimes"] = map[string]interface{}{ + "0": time.Duration(10e9), + "total": time.Duration(10e9), + } + resPretty := bench.Prettify(res) + + jsonString := new(bytes.Buffer) + enc := json.NewEncoder(jsonString) + enc.SetIndent("", " ") + + err := enc.Encode(resPretty) + if err != nil { + fmt.Fprintln(os.Stderr, err) + } + + expected := ` +{ + "0": { + "avg": "12.345µs", + "max": "23.456µs", + "slice": [ + "123ns", + "234ns" + ], + "int": 3456 + }, + "runtimes": { + "0": "10s", + "total": "10s" + } +} +`[1:] + + if jsonString.String() != expected { + t.Fatalf("failure") + } +} From 44a738afde3967f33c3a1356761a3d3745d3b7f0 Mon Sep 17 00:00:00 2001 From: Alan Bernstein Date: Tue, 13 Dec 2016 14:21:49 -0600 Subject: [PATCH 6/7] Add more prettify tests --- bench/prettify_test.go | 97 ++++++++++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 31 deletions(-) diff --git a/bench/prettify_test.go b/bench/prettify_test.go index 4da62895b..20269d73e 100644 --- a/bench/prettify_test.go +++ b/bench/prettify_test.go @@ -11,48 +11,83 @@ import ( "github.com/pilosa/pilosa/bench" ) -func TestPrettify(t *testing.T) { - res := make(map[string]interface{}, 1) - res["0"] = map[string]interface{}{ - "avg": time.Duration(12345), - "max": time.Duration(23456), - "int": 3456, - "slice": []time.Duration{123, 234}, - } - res["runtimes"] = map[string]interface{}{ - "0": time.Duration(10e9), - "total": time.Duration(10e9), - } - resPretty := bench.Prettify(res) - +func prettyEncode(data map[string]interface{}) string { + pretty := bench.Prettify(data) jsonString := new(bytes.Buffer) enc := json.NewEncoder(jsonString) enc.SetIndent("", " ") - - err := enc.Encode(resPretty) + 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": { - "avg": "12.345µs", - "max": "23.456µs", - "slice": [ - "123ns", - "234ns" - ], - "int": 3456 - }, - "runtimes": { - "0": "10s", - "total": "10s" - } + "0": "foobar" } `[1:] - if jsonString.String() != expected { - t.Fatalf("failure") + 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") } } From 8690157d3fd9e698b9bab575431b44cd7530b0b9 Mon Sep 17 00:00:00 2001 From: Alan Bernstein Date: Mon, 19 Dec 2016 14:49:09 -0600 Subject: [PATCH 7/7] Add -human flag to bagent --- cmd/pilosactl/main.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/cmd/pilosactl/main.go b/cmd/pilosactl/main.go index 7d367cf40..5edfacd97 100644 --- a/cmd/pilosactl/main.go +++ b/cmd/pilosactl/main.go @@ -1112,6 +1112,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 @@ -1121,9 +1123,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, @@ -1144,6 +1147,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 @@ -1205,6 +1209,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 @@ -1226,7 +1233,9 @@ func (cmd *BagentCommand) Run(ctx context.Context) error { res := sbm.Run(ctx, cmd.AgentNum) enc := json.NewEncoder(cmd.Stdout) enc.SetIndent("", " ") - res = bench.Prettify(res) + if cmd.HumanReadable { + res = bench.Prettify(res) + } err = enc.Encode(res) if err != nil { fmt.Fprintln(cmd.Stderr, err)