github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/core/bench_test.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "crypto/ecdsa" 21 "io/ioutil" 22 "math/big" 23 "os" 24 "testing" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/core/types" 28 "github.com/ethereum/go-ethereum/crypto" 29 "github.com/ethereum/go-ethereum/ethdb" 30 "github.com/ethereum/go-ethereum/event" 31 "github.com/ethereum/go-ethereum/params" 32 ) 33 34 func BenchmarkInsertChain_empty_memdb(b *testing.B) { 35 benchInsertChain(b, false, nil) 36 } 37 func BenchmarkInsertChain_empty_diskdb(b *testing.B) { 38 benchInsertChain(b, true, nil) 39 } 40 func BenchmarkInsertChain_valueTx_memdb(b *testing.B) { 41 benchInsertChain(b, false, genValueTx(0)) 42 } 43 func BenchmarkInsertChain_valueTx_diskdb(b *testing.B) { 44 benchInsertChain(b, true, genValueTx(0)) 45 } 46 func BenchmarkInsertChain_valueTx_100kB_memdb(b *testing.B) { 47 benchInsertChain(b, false, genValueTx(100*1024)) 48 } 49 func BenchmarkInsertChain_valueTx_100kB_diskdb(b *testing.B) { 50 benchInsertChain(b, true, genValueTx(100*1024)) 51 } 52 func BenchmarkInsertChain_uncles_memdb(b *testing.B) { 53 benchInsertChain(b, false, genUncles) 54 } 55 func BenchmarkInsertChain_uncles_diskdb(b *testing.B) { 56 benchInsertChain(b, true, genUncles) 57 } 58 func BenchmarkInsertChain_ring200_memdb(b *testing.B) { 59 benchInsertChain(b, false, genTxRing(200)) 60 } 61 func BenchmarkInsertChain_ring200_diskdb(b *testing.B) { 62 benchInsertChain(b, true, genTxRing(200)) 63 } 64 func BenchmarkInsertChain_ring1000_memdb(b *testing.B) { 65 benchInsertChain(b, false, genTxRing(1000)) 66 } 67 func BenchmarkInsertChain_ring1000_diskdb(b *testing.B) { 68 benchInsertChain(b, true, genTxRing(1000)) 69 } 70 71 var ( 72 // This is the content of the genesis block used by the benchmarks. 73 benchRootKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 74 benchRootAddr = crypto.PubkeyToAddress(benchRootKey.PublicKey) 75 benchRootFunds = common.BigPow(2, 100) 76 ) 77 78 // genValueTx returns a block generator that includes a single 79 // value-transfer transaction with n bytes of extra data in each 80 // block. 81 func genValueTx(nbytes int) func(int, *BlockGen) { 82 return func(i int, gen *BlockGen) { 83 toaddr := common.Address{} 84 data := make([]byte, nbytes) 85 gas := IntrinsicGas(data) 86 tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(benchRootKey) 87 gen.AddTx(tx) 88 } 89 } 90 91 var ( 92 ringKeys = make([]*ecdsa.PrivateKey, 1000) 93 ringAddrs = make([]common.Address, len(ringKeys)) 94 ) 95 96 func init() { 97 ringKeys[0] = benchRootKey 98 ringAddrs[0] = benchRootAddr 99 for i := 1; i < len(ringKeys); i++ { 100 ringKeys[i], _ = crypto.GenerateKey() 101 ringAddrs[i] = crypto.PubkeyToAddress(ringKeys[i].PublicKey) 102 } 103 } 104 105 // genTxRing returns a block generator that sends ether in a ring 106 // among n accounts. This is creates n entries in the state database 107 // and fills the blocks with many small transactions. 108 func genTxRing(naccounts int) func(int, *BlockGen) { 109 from := 0 110 return func(i int, gen *BlockGen) { 111 gas := CalcGasLimit(gen.PrevBlock(i - 1)) 112 for { 113 gas.Sub(gas, params.TxGas) 114 if gas.Cmp(params.TxGas) < 0 { 115 break 116 } 117 to := (from + 1) % naccounts 118 tx := types.NewTransaction( 119 gen.TxNonce(ringAddrs[from]), 120 ringAddrs[to], 121 benchRootFunds, 122 params.TxGas, 123 nil, 124 nil, 125 ) 126 tx, _ = tx.SignECDSA(ringKeys[from]) 127 gen.AddTx(tx) 128 from = to 129 } 130 } 131 } 132 133 // genUncles generates blocks with two uncle headers. 134 func genUncles(i int, gen *BlockGen) { 135 if i >= 6 { 136 b2 := gen.PrevBlock(i - 6).Header() 137 b2.Extra = []byte("foo") 138 gen.AddUncle(b2) 139 b3 := gen.PrevBlock(i - 6).Header() 140 b3.Extra = []byte("bar") 141 gen.AddUncle(b3) 142 } 143 } 144 145 func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { 146 // Create the database in memory or in a temporary directory. 147 var db common.Database 148 if !disk { 149 db, _ = ethdb.NewMemDatabase() 150 } else { 151 dir, err := ioutil.TempDir("", "eth-core-bench") 152 if err != nil { 153 b.Fatalf("cannot create temporary directory: %v", err) 154 } 155 defer os.RemoveAll(dir) 156 db, err = ethdb.NewLDBDatabase(dir, 0) 157 if err != nil { 158 b.Fatalf("cannot create temporary database: %v", err) 159 } 160 defer db.Close() 161 } 162 163 // Generate a chain of b.N blocks using the supplied block 164 // generator function. 165 genesis := WriteGenesisBlockForTesting(db, benchRootAddr, benchRootFunds) 166 chain := GenerateChain(genesis, db, b.N, gen) 167 168 // Time the insertion of the new chain. 169 // State and blocks are stored in the same DB. 170 evmux := new(event.TypeMux) 171 chainman, _ := NewChainManager(db, FakePow{}, evmux) 172 chainman.SetProcessor(NewBlockProcessor(db, FakePow{}, chainman, evmux)) 173 defer chainman.Stop() 174 b.ReportAllocs() 175 b.ResetTimer() 176 if i, err := chainman.InsertChain(chain); err != nil { 177 b.Fatalf("insert error (block %d): %v\n", i, err) 178 } 179 }