bench_test.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. package core
  2. import (
  3. "crypto/ecdsa"
  4. "io/ioutil"
  5. "math/big"
  6. "os"
  7. "testing"
  8. "github.com/ethereum/go-ethereum/common"
  9. "github.com/ethereum/go-ethereum/core/types"
  10. "github.com/ethereum/go-ethereum/crypto"
  11. "github.com/ethereum/go-ethereum/ethdb"
  12. "github.com/ethereum/go-ethereum/event"
  13. "github.com/ethereum/go-ethereum/params"
  14. )
  15. func BenchmarkInsertChain_empty_memdb(b *testing.B) {
  16. benchInsertChain(b, false, nil)
  17. }
  18. func BenchmarkInsertChain_empty_diskdb(b *testing.B) {
  19. benchInsertChain(b, true, nil)
  20. }
  21. func BenchmarkInsertChain_valueTx_memdb(b *testing.B) {
  22. benchInsertChain(b, false, genValueTx(0))
  23. }
  24. func BenchmarkInsertChain_valueTx_diskdb(b *testing.B) {
  25. benchInsertChain(b, true, genValueTx(0))
  26. }
  27. func BenchmarkInsertChain_valueTx_100kB_memdb(b *testing.B) {
  28. benchInsertChain(b, false, genValueTx(100*1024))
  29. }
  30. func BenchmarkInsertChain_valueTx_100kB_diskdb(b *testing.B) {
  31. benchInsertChain(b, true, genValueTx(100*1024))
  32. }
  33. func BenchmarkInsertChain_uncles_memdb(b *testing.B) {
  34. benchInsertChain(b, false, genUncles)
  35. }
  36. func BenchmarkInsertChain_uncles_diskdb(b *testing.B) {
  37. benchInsertChain(b, true, genUncles)
  38. }
  39. func BenchmarkInsertChain_ring200_memdb(b *testing.B) {
  40. benchInsertChain(b, false, genTxRing(200))
  41. }
  42. func BenchmarkInsertChain_ring200_diskdb(b *testing.B) {
  43. benchInsertChain(b, true, genTxRing(200))
  44. }
  45. func BenchmarkInsertChain_ring1000_memdb(b *testing.B) {
  46. benchInsertChain(b, false, genTxRing(1000))
  47. }
  48. func BenchmarkInsertChain_ring1000_diskdb(b *testing.B) {
  49. benchInsertChain(b, true, genTxRing(1000))
  50. }
  51. var (
  52. // This is the content of the genesis block used by the benchmarks.
  53. benchRootKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
  54. benchRootAddr = crypto.PubkeyToAddress(benchRootKey.PublicKey)
  55. benchRootFunds = common.BigPow(2, 100)
  56. )
  57. // genValueTx returns a block generator that includes a single
  58. // value-transfer transaction with n bytes of extra data in each
  59. // block.
  60. func genValueTx(nbytes int) func(int, *BlockGen) {
  61. return func(i int, gen *BlockGen) {
  62. toaddr := common.Address{}
  63. data := make([]byte, nbytes)
  64. gas := IntrinsicGas(data)
  65. tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(benchRootKey)
  66. gen.AddTx(tx)
  67. }
  68. }
  69. var (
  70. ringKeys = make([]*ecdsa.PrivateKey, 1000)
  71. ringAddrs = make([]common.Address, len(ringKeys))
  72. )
  73. func init() {
  74. ringKeys[0] = benchRootKey
  75. ringAddrs[0] = benchRootAddr
  76. for i := 1; i < len(ringKeys); i++ {
  77. ringKeys[i], _ = crypto.GenerateKey()
  78. ringAddrs[i] = crypto.PubkeyToAddress(ringKeys[i].PublicKey)
  79. }
  80. }
  81. // genTxRing returns a block generator that sends ether in a ring
  82. // among n accounts. This is creates n entries in the state database
  83. // and fills the blocks with many small transactions.
  84. func genTxRing(naccounts int) func(int, *BlockGen) {
  85. from := 0
  86. return func(i int, gen *BlockGen) {
  87. gas := CalcGasLimit(gen.PrevBlock(i - 1))
  88. for {
  89. gas.Sub(gas, params.TxGas)
  90. if gas.Cmp(params.TxGas) < 0 {
  91. break
  92. }
  93. to := (from + 1) % naccounts
  94. tx := types.NewTransaction(
  95. gen.TxNonce(ringAddrs[from]),
  96. ringAddrs[to],
  97. benchRootFunds,
  98. params.TxGas,
  99. nil,
  100. nil,
  101. )
  102. tx, _ = tx.SignECDSA(ringKeys[from])
  103. gen.AddTx(tx)
  104. from = to
  105. }
  106. }
  107. }
  108. // genUncles generates blocks with two uncle headers.
  109. func genUncles(i int, gen *BlockGen) {
  110. if i >= 6 {
  111. b2 := gen.PrevBlock(i - 6).Header()
  112. b2.Extra = []byte("foo")
  113. gen.AddUncle(b2)
  114. b3 := gen.PrevBlock(i - 6).Header()
  115. b3.Extra = []byte("bar")
  116. gen.AddUncle(b3)
  117. }
  118. }
  119. func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
  120. // Create the database in memory or in a temporary directory.
  121. var db common.Database
  122. if !disk {
  123. db, _ = ethdb.NewMemDatabase()
  124. } else {
  125. dir, err := ioutil.TempDir("", "eth-core-bench")
  126. if err != nil {
  127. b.Fatalf("cannot create temporary directory: %v", err)
  128. }
  129. defer os.RemoveAll(dir)
  130. db, err = ethdb.NewLDBDatabase(dir)
  131. if err != nil {
  132. b.Fatalf("cannot create temporary database: %v", err)
  133. }
  134. defer db.Close()
  135. }
  136. // Generate a chain of b.N blocks using the supplied block
  137. // generator function.
  138. genesis := GenesisBlockForTesting(db, benchRootAddr, benchRootFunds)
  139. chain := GenerateChain(genesis, db, b.N, gen)
  140. // Time the insertion of the new chain.
  141. // State and blocks are stored in the same DB.
  142. evmux := new(event.TypeMux)
  143. chainman, _ := NewChainManager(genesis, db, db, FakePow{}, evmux)
  144. chainman.SetProcessor(NewBlockProcessor(db, db, FakePow{}, chainman, evmux))
  145. defer chainman.Stop()
  146. b.ReportAllocs()
  147. b.ResetTimer()
  148. if i, err := chainman.InsertChain(chain); err != nil {
  149. b.Fatalf("insert error (block %d): %v\n", i, err)
  150. }
  151. }