From aff063b79bc4698539b719b8a92e32e7724e39c1 Mon Sep 17 00:00:00 2001 From: ValarDragon Date: Fri, 13 Jul 2018 18:00:49 -0700 Subject: [PATCH] tools/tmbench: Move statistics to a seperate file This PR moves statistics to its own file, seperates getBlockMetas into its own function, and removes the timeEnd parameter from calculate statistics. The ending time is now computed directly from the start time and the duration, to enforce that we only collect data for the provided duration. --- tools/tm-bench/main.go | 132 ------------------------------ tools/tm-bench/statistics.go | 150 +++++++++++++++++++++++++++++++++++ 2 files changed, 150 insertions(+), 132 deletions(-) create mode 100644 tools/tm-bench/statistics.go diff --git a/tools/tm-bench/main.go b/tools/tm-bench/main.go index 5f597cec..a8ede4a0 100644 --- a/tools/tm-bench/main.go +++ b/tools/tm-bench/main.go @@ -1,18 +1,14 @@ package main import ( - "encoding/json" "flag" "fmt" - "math" "os" "strings" "sync" - "text/tabwriter" "time" "github.com/go-kit/kit/log/term" - metrics "github.com/rcrowley/go-metrics" "github.com/tendermint/tendermint/libs/log" tmrpc "github.com/tendermint/tendermint/rpc/client" @@ -20,11 +16,6 @@ import ( var logger = log.NewNopLogger() -type statistics struct { - TxsThroughput metrics.Histogram `json:"txs_per_sec"` - BlocksThroughput metrics.Histogram `json:"blocks_per_sec"` -} - func main() { var durationInt, txsRate, connections, txSize int var verbose bool @@ -126,7 +117,6 @@ Examples: client, initialHeight, timeStart, - timeEnd, durationInt, ) if err != nil { @@ -156,91 +146,6 @@ func countCrashes(crashes []bool) int { return count } -// calculateStatistics calculates the tx / second, and blocks / second based -// off of the number the transactions and number of blocks that occurred from -// the start block, and the end time. -func calculateStatistics( - client tmrpc.Client, - minHeight int64, - timeStart, timeStop time.Time, - duration int, -) (*statistics, error) { - stats := &statistics{ - BlocksThroughput: metrics.NewHistogram(metrics.NewUniformSample(1000)), - TxsThroughput: metrics.NewHistogram(metrics.NewUniformSample(1000)), - } - - // get blocks between minHeight and last height - // This returns max(minHeight,(last_height - 20)) to last_height - info, err := client.BlockchainInfo(minHeight, 0) - if err != nil { - return nil, err - } - - var ( - blockMetas = info.BlockMetas - lastHeight = info.LastHeight - diff = lastHeight - minHeight - offset = len(blockMetas) - ) - - for offset < int(diff) { - // get blocks between minHeight and last height - info, err := client.BlockchainInfo(minHeight, lastHeight-int64(offset)) - if err != nil { - return nil, err - } - blockMetas = append(blockMetas, info.BlockMetas...) - offset = len(blockMetas) - } - - var ( - numBlocksPerSec = make(map[int64]int64) - numTxsPerSec = make(map[int64]int64) - ) - - // because during some seconds blocks won't be created... - for i := int64(0); i < int64(duration); i++ { - numBlocksPerSec[i] = 0 - numTxsPerSec[i] = 0 - } - - // iterates from max height to min height - for i, blockMeta := range blockMetas { - // check if block was created after timeStart - if blockMeta.Header.Time.Before(timeStart) { - break - } - - // check if block was created before timeStop - if blockMeta.Header.Time.After(timeStop) { - continue - } - sec := secondsSinceTimeStart(timeStart, blockMeta.Header.Time) - - // increase number of blocks for that second - numBlocksPerSec[sec]++ - - // increase number of txs for that second - numTxsPerSec[sec] += blockMeta.Header.NumTxs - logger.Debug(fmt.Sprintf("%d txs in block %d, height %d", blockMeta.Header.NumTxs, i, blockMeta.Header.Height)) - } - - for _, n := range numBlocksPerSec { - stats.BlocksThroughput.Update(n) - } - - for _, n := range numTxsPerSec { - stats.TxsThroughput.Update(n) - } - - return stats, nil -} - -func secondsSinceTimeStart(timeStart, timePassed time.Time) int64 { - return int64(math.Round(timePassed.Sub(timeStart).Seconds())) -} - func startTransacters( endpoints []string, connections, @@ -268,40 +173,3 @@ func startTransacters( return transacters } - -func printStatistics(stats *statistics, outputFormat string) { - if outputFormat == "json" { - result, err := json.Marshal(struct { - TxsThroughput float64 `json:"txs_per_sec_avg"` - BlocksThroughput float64 `json:"blocks_per_sec_avg"` - }{stats.TxsThroughput.Mean(), stats.BlocksThroughput.Mean()}) - if err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) - } - fmt.Println(string(result)) - } else { - w := tabwriter.NewWriter(os.Stdout, 0, 0, 5, ' ', 0) - fmt.Fprintln(w, "Stats\tAvg\tStdDev\tMax\tTotal\t") - fmt.Fprintln( - w, - fmt.Sprintf( - "Txs/sec\t%.0f\t%.0f\t%d\t%d\t", - stats.TxsThroughput.Mean(), - stats.TxsThroughput.StdDev(), - stats.TxsThroughput.Max(), - stats.TxsThroughput.Sum(), - ), - ) - fmt.Fprintln( - w, - fmt.Sprintf("Blocks/sec\t%.3f\t%.3f\t%d\t%d\t", - stats.BlocksThroughput.Mean(), - stats.BlocksThroughput.StdDev(), - stats.BlocksThroughput.Max(), - stats.BlocksThroughput.Sum(), - ), - ) - w.Flush() - } -} diff --git a/tools/tm-bench/statistics.go b/tools/tm-bench/statistics.go new file mode 100644 index 00000000..5a8f6057 --- /dev/null +++ b/tools/tm-bench/statistics.go @@ -0,0 +1,150 @@ +package main + +import ( + "encoding/json" + "fmt" + "math" + "os" + "text/tabwriter" + "time" + + metrics "github.com/rcrowley/go-metrics" + tmrpc "github.com/tendermint/tendermint/rpc/client" + "github.com/tendermint/tendermint/types" +) + +type statistics struct { + TxsThroughput metrics.Histogram `json:"txs_per_sec"` + BlocksThroughput metrics.Histogram `json:"blocks_per_sec"` +} + +// calculateStatistics calculates the tx / second, and blocks / second based +// off of the number the transactions and number of blocks that occurred from +// the start block, and the end time. +func calculateStatistics( + client tmrpc.Client, + minHeight int64, + timeStart time.Time, + duration int, +) (*statistics, error) { + timeEnd := timeStart.Add(time.Duration(duration) * time.Second) + + stats := &statistics{ + BlocksThroughput: metrics.NewHistogram(metrics.NewUniformSample(1000)), + TxsThroughput: metrics.NewHistogram(metrics.NewUniformSample(1000)), + } + + var ( + numBlocksPerSec = make(map[int64]int64) + numTxsPerSec = make(map[int64]int64) + ) + + // because during some seconds blocks won't be created... + for i := int64(0); i < int64(duration); i++ { + numBlocksPerSec[i] = 0 + numTxsPerSec[i] = 0 + } + + blockMetas, err := getBlockMetas(client, minHeight, timeStart, timeEnd) + if err != nil { + return nil, err + } + + // iterates from max height to min height + for _, blockMeta := range blockMetas { + // check if block was created after timeStart + if blockMeta.Header.Time.Before(timeStart) { + break + } + + // check if block was created before timeEnd + if blockMeta.Header.Time.After(timeEnd) { + continue + } + sec := secondsSinceTimeStart(timeStart, blockMeta.Header.Time) + + // increase number of blocks for that second + numBlocksPerSec[sec]++ + + // increase number of txs for that second + numTxsPerSec[sec] += blockMeta.Header.NumTxs + logger.Debug(fmt.Sprintf("%d txs at block height %d", blockMeta.Header.NumTxs, blockMeta.Header.Height)) + } + + for i := int64(0); i < int64(duration); i++ { + stats.BlocksThroughput.Update(numBlocksPerSec[i]) + stats.TxsThroughput.Update(numTxsPerSec[i]) + } + + return stats, nil +} + +func getBlockMetas(client tmrpc.Client, minHeight int64, timeStart, timeEnd time.Time) ([]*types.BlockMeta, error) { + // get blocks between minHeight and last height + // This returns max(minHeight,(last_height - 20)) to last_height + info, err := client.BlockchainInfo(minHeight, 0) + if err != nil { + return nil, err + } + + var ( + blockMetas = info.BlockMetas + lastHeight = info.LastHeight + diff = lastHeight - minHeight + offset = len(blockMetas) + ) + + for offset < int(diff) { + // get blocks between minHeight and last height + info, err := client.BlockchainInfo(minHeight, lastHeight-int64(offset)) + if err != nil { + return nil, err + } + blockMetas = append(blockMetas, info.BlockMetas...) + offset = len(blockMetas) + } + + return blockMetas, nil +} + +func secondsSinceTimeStart(timeStart, timePassed time.Time) int64 { + return int64(math.Round(timePassed.Sub(timeStart).Seconds())) +} + +func printStatistics(stats *statistics, outputFormat string) { + if outputFormat == "json" { + result, err := json.Marshal(struct { + TxsThroughput float64 `json:"txs_per_sec_avg"` + BlocksThroughput float64 `json:"blocks_per_sec_avg"` + }{stats.TxsThroughput.Mean(), stats.BlocksThroughput.Mean()}) + + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + fmt.Println(string(result)) + } else { + w := tabwriter.NewWriter(os.Stdout, 0, 0, 5, ' ', 0) + fmt.Fprintln(w, "Stats\tAvg\tStdDev\tMax\tTotal\t") + fmt.Fprintln( + w, + fmt.Sprintf( + "Txs/sec\t%.0f\t%.0f\t%d\t%d\t", + stats.TxsThroughput.Mean(), + stats.TxsThroughput.StdDev(), + stats.TxsThroughput.Max(), + stats.TxsThroughput.Sum(), + ), + ) + fmt.Fprintln( + w, + fmt.Sprintf("Blocks/sec\t%.3f\t%.3f\t%d\t%d\t", + stats.BlocksThroughput.Mean(), + stats.BlocksThroughput.StdDev(), + stats.BlocksThroughput.Max(), + stats.BlocksThroughput.Sum(), + ), + ) + w.Flush() + } +}