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() + } +}