diff --git a/tm-bench/main.go b/tm-bench/main.go index c63832e2b..32ac548ad 100644 --- a/tm-bench/main.go +++ b/tm-bench/main.go @@ -1,16 +1,18 @@ package main import ( + "encoding/json" "flag" "fmt" "os" "strings" - "text/tabwriter" "time" "github.com/go-kit/kit/log/term" metrics "github.com/rcrowley/go-metrics" + "text/tabwriter" + tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/log" "github.com/tendermint/tools/tm-monitor/monitor" @@ -29,17 +31,19 @@ type statistics struct { func main() { var duration, txsRate, connections int var verbose bool + var outputFormat string flag.IntVar(&connections, "c", 1, "Connections to keep open per endpoint") flag.IntVar(&duration, "T", 10, "Exit after the specified amount of time in seconds") flag.IntVar(&txsRate, "r", 1000, "Txs per second to send in a connection") + flag.StringVar(&outputFormat, "output-format", "plain", "Output format: plain or json") flag.BoolVar(&verbose, "v", false, "Verbose output") flag.Usage = func() { fmt.Println(`Tendermint blockchain benchmarking tool. Usage: - tm-bench [-c 1] [-T 10] [-r 1000] [endpoints] + tm-bench [-c 1] [-T 10] [-r 1000] [endpoints] [-output-format ] Examples: tm-bench localhost:46657`) @@ -55,6 +59,10 @@ Examples: } if verbose { + if outputFormat == "json" { + fmt.Println("Verbose mode not supported with json output.") + os.Exit(1) + } // Color errors red colorFn := func(keyvals ...interface{}) term.FgBgColor { for i := 1; i < len(keyvals); i += 2 { @@ -65,9 +73,9 @@ Examples: return term.FgBgColor{} } logger = log.NewTMLoggerWithColorFn(log.NewSyncWriter(os.Stdout), colorFn) - } - fmt.Printf("Running %ds test @ %s\n", duration, flag.Arg(0)) + fmt.Printf("Running %ds test @ %s\n", duration, flag.Arg(0)) + } endpoints := strings.Split(flag.Arg(0), ",") @@ -110,7 +118,7 @@ Examples: t.Stop() } - printStatistics(stats) + printStatistics(stats, outputFormat) for _, n := range nodes { n.Stop() @@ -154,20 +162,47 @@ func startTransacters(endpoints []string, connections int, txsRate int) []*trans return transacters } -func printStatistics(stats *statistics) { - w := tabwriter.NewWriter(os.Stdout, 0, 0, 5, ' ', 0) - fmt.Fprintln(w, "Stats\tAvg\tStdev\tMax\t") - fmt.Fprintln(w, fmt.Sprintf("Block latency\t%.2fms\t%.2fms\t%dms\t", - stats.BlockLatency.Mean()/1000000.0, - stats.BlockLatency.StdDev()/1000000.0, - stats.BlockLatency.Max()/1000000)) - fmt.Fprintln(w, fmt.Sprintf("Blocks/sec\t%.3f\t%.3f\t%d\t", - stats.BlockTimeSample.Mean(), - stats.BlockTimeSample.StdDev(), - stats.BlockTimeSample.Max())) - fmt.Fprintln(w, fmt.Sprintf("Txs/sec\t%.0f\t%.0f\t%d\t", - stats.TxThroughputSample.Mean(), - stats.TxThroughputSample.StdDev(), - stats.TxThroughputSample.Max())) - w.Flush() +type Results struct { + BlockLatencyMean float64 + BlockLatencyMax int64 + BlockLatencyStdDev float64 + BlockTimeMean float64 + BlockTimeMax int64 + BlockTimeStdDev float64 + TxThroughputMean float64 + TxThroughputMax int64 + TxThroughputStdDev float64 +} + +func printStatistics(stats *statistics, outputFormat string) { + if outputFormat == "json" { + result, _ := json.Marshal(Results{ + stats.BlockLatency.Mean() / 1000000.0, + stats.BlockLatency.Max() / 1000000.0, + stats.BlockLatency.StdDev() / 1000000.0, + stats.BlockTimeSample.Mean(), + stats.BlockTimeSample.Max(), + stats.BlockTimeSample.StdDev(), + stats.TxThroughputSample.Mean(), + stats.TxThroughputSample.Max(), + stats.TxThroughputSample.StdDev(), + }) + fmt.Println(string(result)) + } else { + w := tabwriter.NewWriter(os.Stdout, 0, 0, 5, ' ', 0) + fmt.Fprintln(w, "Stats\tAvg\tStdev\tMax\t") + fmt.Fprintln(w, fmt.Sprintf("Block latency\t%.2fms\t%.2fms\t%dms\t", + stats.BlockLatency.Mean()/1000000.0, + stats.BlockLatency.StdDev()/1000000.0, + stats.BlockLatency.Max()/1000000)) + fmt.Fprintln(w, fmt.Sprintf("Blocks/sec\t%.3f\t%.3f\t%d\t", + stats.BlockTimeSample.Mean(), + stats.BlockTimeSample.StdDev(), + stats.BlockTimeSample.Max())) + fmt.Fprintln(w, fmt.Sprintf("Txs/sec\t%.0f\t%.0f\t%d\t", + stats.TxThroughputSample.Mean(), + stats.TxThroughputSample.StdDev(), + stats.TxThroughputSample.Max())) + w.Flush() + } }