You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
3.5 KiB

  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "os"
  6. "strings"
  7. "text/tabwriter"
  8. "time"
  9. metrics "github.com/rcrowley/go-metrics"
  10. tmtypes "github.com/tendermint/tendermint/types"
  11. "github.com/tendermint/tools/tm-monitor/monitor"
  12. )
  13. var version = "0.1.0.pre"
  14. type statistics struct {
  15. BlockTimeSample metrics.Histogram
  16. TxThroughputSample metrics.Histogram
  17. BlockLatency metrics.Histogram
  18. }
  19. func main() {
  20. var duration, txsRate, connections int
  21. flag.IntVar(&connections, "c", 1, "Connections to keep open per endpoint")
  22. flag.IntVar(&duration, "T", 10, "Exit after the specified amount of time in seconds")
  23. flag.IntVar(&txsRate, "r", 1000, "Txs per second to send in a connection")
  24. flag.Usage = func() {
  25. fmt.Println(`Tendermint blockchain benchmarking tool.
  26. Usage:
  27. tm-bench [-c 1] [-T 10] [-r 1000] [endpoints]
  28. Examples:
  29. tm-bench localhost:46657`)
  30. fmt.Println("Flags:")
  31. flag.PrintDefaults()
  32. }
  33. flag.Parse()
  34. if flag.NArg() == 0 {
  35. flag.Usage()
  36. os.Exit(1)
  37. }
  38. fmt.Printf("Running %ds test @ %s\n", duration, flag.Arg(0))
  39. endpoints := strings.Split(flag.Arg(0), ",")
  40. blockCh := make(chan tmtypes.Header, 100)
  41. blockLatencyCh := make(chan float64, 100)
  42. nodes := startNodes(endpoints, blockCh, blockLatencyCh)
  43. transacters := startTransacters(endpoints, connections, txsRate)
  44. stats := &statistics{
  45. BlockTimeSample: metrics.NewHistogram(metrics.NewUniformSample(1000)),
  46. TxThroughputSample: metrics.NewHistogram(metrics.NewUniformSample(1000)),
  47. BlockLatency: metrics.NewHistogram(metrics.NewUniformSample(1000)),
  48. }
  49. lastBlockHeight := -1
  50. durationTimer := time.After(time.Duration(duration) * time.Second)
  51. ticker := time.NewTicker(1 * time.Second)
  52. var blocks, txs int
  53. for {
  54. select {
  55. case b := <-blockCh:
  56. if lastBlockHeight < b.Height {
  57. blocks++
  58. txs += b.NumTxs
  59. lastBlockHeight = b.Height
  60. }
  61. case l := <-blockLatencyCh:
  62. stats.BlockLatency.Update(int64(l))
  63. case <-ticker.C:
  64. stats.BlockTimeSample.Update(int64(blocks))
  65. stats.TxThroughputSample.Update(int64(txs))
  66. blocks = 0
  67. txs = 0
  68. case <-durationTimer:
  69. for _, t := range transacters {
  70. t.Stop()
  71. }
  72. printStatistics(stats)
  73. for _, n := range nodes {
  74. n.Stop()
  75. }
  76. return
  77. }
  78. }
  79. }
  80. func startNodes(endpoints []string, blockCh chan<- tmtypes.Header, blockLatencyCh chan<- float64) []*monitor.Node {
  81. nodes := make([]*monitor.Node, len(endpoints))
  82. for i, e := range endpoints {
  83. n := monitor.NewNode(e)
  84. n.SendBlocksTo(blockCh)
  85. n.SendBlockLatenciesTo(blockLatencyCh)
  86. if err := n.Start(); err != nil {
  87. panic(err)
  88. }
  89. nodes[i] = n
  90. }
  91. return nodes
  92. }
  93. func startTransacters(endpoints []string, connections int, txsRate int) []*transacter {
  94. transacters := make([]*transacter, len(endpoints))
  95. for i, e := range endpoints {
  96. t := newTransacter(e, connections, txsRate)
  97. if err := t.Start(); err != nil {
  98. panic(err)
  99. }
  100. transacters[i] = t
  101. }
  102. return transacters
  103. }
  104. func printStatistics(stats *statistics) {
  105. w := tabwriter.NewWriter(os.Stdout, 0, 0, 5, ' ', 0)
  106. fmt.Fprintln(w, "Stats\tAvg\tStdev\tMax\t")
  107. fmt.Fprintln(w, fmt.Sprintf("Block latency\t%.2fms\t%.2fms\t%dms\t",
  108. stats.BlockLatency.Mean()/1000000.0,
  109. stats.BlockLatency.StdDev()/1000000.0,
  110. stats.BlockLatency.Max()/1000000))
  111. fmt.Fprintln(w, fmt.Sprintf("Blocks/sec\t%.3f\t%.3f\t%d\t",
  112. stats.BlockTimeSample.Mean(),
  113. stats.BlockTimeSample.StdDev(),
  114. stats.BlockTimeSample.Max()))
  115. fmt.Fprintln(w, fmt.Sprintf("Txs/sec\t%.0f\t%.0f\t%d\t",
  116. stats.TxThroughputSample.Mean(),
  117. stats.TxThroughputSample.StdDev(),
  118. stats.TxThroughputSample.Max()))
  119. w.Flush()
  120. }