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.

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