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.
This commit is contained in:
parent
66c4f7aeae
commit
aff063b79b
|
@ -1,18 +1,14 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"text/tabwriter"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/go-kit/kit/log/term"
|
"github.com/go-kit/kit/log/term"
|
||||||
metrics "github.com/rcrowley/go-metrics"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
tmrpc "github.com/tendermint/tendermint/rpc/client"
|
tmrpc "github.com/tendermint/tendermint/rpc/client"
|
||||||
|
@ -20,11 +16,6 @@ import (
|
||||||
|
|
||||||
var logger = log.NewNopLogger()
|
var logger = log.NewNopLogger()
|
||||||
|
|
||||||
type statistics struct {
|
|
||||||
TxsThroughput metrics.Histogram `json:"txs_per_sec"`
|
|
||||||
BlocksThroughput metrics.Histogram `json:"blocks_per_sec"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
var durationInt, txsRate, connections, txSize int
|
var durationInt, txsRate, connections, txSize int
|
||||||
var verbose bool
|
var verbose bool
|
||||||
|
@ -126,7 +117,6 @@ Examples:
|
||||||
client,
|
client,
|
||||||
initialHeight,
|
initialHeight,
|
||||||
timeStart,
|
timeStart,
|
||||||
timeEnd,
|
|
||||||
durationInt,
|
durationInt,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -156,91 +146,6 @@ func countCrashes(crashes []bool) int {
|
||||||
return count
|
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(
|
func startTransacters(
|
||||||
endpoints []string,
|
endpoints []string,
|
||||||
connections,
|
connections,
|
||||||
|
@ -268,40 +173,3 @@ func startTransacters(
|
||||||
|
|
||||||
return transacters
|
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue