forked from bnb-chain/tendermint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
statistics.go
150 lines (129 loc) · 3.89 KB
/
statistics.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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()
}
}