github.com/evdatsion/aphelion-dpos-bft@v0.32.1/tools/tm-bench/statistics.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "math" 7 "os" 8 "text/tabwriter" 9 "time" 10 11 metrics "github.com/rcrowley/go-metrics" 12 tmrpc "github.com/evdatsion/aphelion-dpos-bft/rpc/client" 13 "github.com/evdatsion/aphelion-dpos-bft/types" 14 ) 15 16 type statistics struct { 17 TxsThroughput metrics.Histogram `json:"txs_per_sec"` 18 BlocksThroughput metrics.Histogram `json:"blocks_per_sec"` 19 } 20 21 // calculateStatistics calculates the tx / second, and blocks / second based 22 // off of the number the transactions and number of blocks that occurred from 23 // the start block, and the end time. 24 func calculateStatistics( 25 client tmrpc.Client, 26 minHeight int64, 27 timeStart time.Time, 28 duration int, 29 ) (*statistics, error) { 30 timeEnd := timeStart.Add(time.Duration(duration) * time.Second) 31 32 stats := &statistics{ 33 BlocksThroughput: metrics.NewHistogram(metrics.NewUniformSample(1000)), 34 TxsThroughput: metrics.NewHistogram(metrics.NewUniformSample(1000)), 35 } 36 37 var ( 38 numBlocksPerSec = make(map[int64]int64) 39 numTxsPerSec = make(map[int64]int64) 40 ) 41 42 // because during some seconds blocks won't be created... 43 for i := int64(0); i < int64(duration); i++ { 44 numBlocksPerSec[i] = 0 45 numTxsPerSec[i] = 0 46 } 47 48 blockMetas, err := getBlockMetas(client, minHeight, timeStart, timeEnd) 49 if err != nil { 50 return nil, err 51 } 52 53 // iterates from max height to min height 54 for _, blockMeta := range blockMetas { 55 // check if block was created after timeStart 56 if blockMeta.Header.Time.Before(timeStart) { 57 break 58 } 59 60 // check if block was created before timeEnd 61 if blockMeta.Header.Time.After(timeEnd) { 62 continue 63 } 64 sec := secondsSinceTimeStart(timeStart, blockMeta.Header.Time) 65 66 // increase number of blocks for that second 67 numBlocksPerSec[sec]++ 68 69 // increase number of txs for that second 70 numTxsPerSec[sec] += blockMeta.Header.NumTxs 71 logger.Debug(fmt.Sprintf("%d txs at block height %d", blockMeta.Header.NumTxs, blockMeta.Header.Height)) 72 } 73 74 for i := int64(0); i < int64(duration); i++ { 75 stats.BlocksThroughput.Update(numBlocksPerSec[i]) 76 stats.TxsThroughput.Update(numTxsPerSec[i]) 77 } 78 79 return stats, nil 80 } 81 82 func getBlockMetas(client tmrpc.Client, minHeight int64, timeStart, timeEnd time.Time) ([]*types.BlockMeta, error) { 83 // get blocks between minHeight and last height 84 // This returns max(minHeight,(last_height - 20)) to last_height 85 info, err := client.BlockchainInfo(minHeight, 0) 86 if err != nil { 87 return nil, err 88 } 89 90 var ( 91 blockMetas = info.BlockMetas 92 lastHeight = info.LastHeight 93 diff = lastHeight - minHeight 94 offset = len(blockMetas) 95 ) 96 97 for offset < int(diff) { 98 // get blocks between minHeight and last height 99 info, err := client.BlockchainInfo(minHeight, lastHeight-int64(offset)) 100 if err != nil { 101 return nil, err 102 } 103 blockMetas = append(blockMetas, info.BlockMetas...) 104 offset = len(blockMetas) 105 } 106 107 return blockMetas, nil 108 } 109 110 func secondsSinceTimeStart(timeStart, timePassed time.Time) int64 { 111 return int64(math.Round(timePassed.Sub(timeStart).Seconds())) 112 } 113 114 func printStatistics(stats *statistics, outputFormat string) { 115 if outputFormat == "json" { 116 result, err := json.Marshal(struct { 117 TxsThroughput float64 `json:"txs_per_sec_avg"` 118 BlocksThroughput float64 `json:"blocks_per_sec_avg"` 119 }{stats.TxsThroughput.Mean(), stats.BlocksThroughput.Mean()}) 120 121 if err != nil { 122 fmt.Fprintln(os.Stderr, err) 123 os.Exit(1) 124 } 125 fmt.Println(string(result)) 126 } else { 127 w := tabwriter.NewWriter(os.Stdout, 0, 0, 5, ' ', 0) 128 fmt.Fprintln(w, "Stats\tAvg\tStdDev\tMax\tTotal\t") 129 fmt.Fprintln( 130 w, 131 fmt.Sprintf( 132 "Txs/sec\t%.0f\t%.0f\t%d\t%d\t", 133 stats.TxsThroughput.Mean(), 134 stats.TxsThroughput.StdDev(), 135 stats.TxsThroughput.Max(), 136 stats.TxsThroughput.Sum(), 137 ), 138 ) 139 fmt.Fprintln( 140 w, 141 fmt.Sprintf("Blocks/sec\t%.3f\t%.3f\t%d\t%d\t", 142 stats.BlocksThroughput.Mean(), 143 stats.BlocksThroughput.StdDev(), 144 stats.BlocksThroughput.Max(), 145 stats.BlocksThroughput.Sum(), 146 ), 147 ) 148 w.Flush() 149 } 150 }