mirror of
https://github.com/fluencelabs/tendermint
synced 2025-04-25 14:52:17 +00:00
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.
151 lines
3.9 KiB
Go
151 lines
3.9 KiB
Go
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()
|
|
}
|
|
}
|