github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/core/bench_test.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package core 13 14 import ( 15 "crypto/ecdsa" 16 "io/ioutil" 17 "math/big" 18 "os" 19 "testing" 20 21 "github.com/Sberex/go-sberex/common" 22 "github.com/Sberex/go-sberex/common/math" 23 "github.com/Sberex/go-sberex/consensus/ethash" 24 "github.com/Sberex/go-sberex/core/types" 25 "github.com/Sberex/go-sberex/core/vm" 26 "github.com/Sberex/go-sberex/crypto" 27 "github.com/Sberex/go-sberex/ethdb" 28 "github.com/Sberex/go-sberex/params" 29 ) 30 31 func BenchmarkInsertChain_empty_memdb(b *testing.B) { 32 benchInsertChain(b, false, nil) 33 } 34 func BenchmarkInsertChain_empty_diskdb(b *testing.B) { 35 benchInsertChain(b, true, nil) 36 } 37 func BenchmarkInsertChain_valueTx_memdb(b *testing.B) { 38 benchInsertChain(b, false, genValueTx(0)) 39 } 40 func BenchmarkInsertChain_valueTx_diskdb(b *testing.B) { 41 benchInsertChain(b, true, genValueTx(0)) 42 } 43 func BenchmarkInsertChain_valueTx_100kB_memdb(b *testing.B) { 44 benchInsertChain(b, false, genValueTx(100*1024)) 45 } 46 func BenchmarkInsertChain_valueTx_100kB_diskdb(b *testing.B) { 47 benchInsertChain(b, true, genValueTx(100*1024)) 48 } 49 func BenchmarkInsertChain_uncles_memdb(b *testing.B) { 50 benchInsertChain(b, false, genUncles) 51 } 52 func BenchmarkInsertChain_uncles_diskdb(b *testing.B) { 53 benchInsertChain(b, true, genUncles) 54 } 55 func BenchmarkInsertChain_ring200_memdb(b *testing.B) { 56 benchInsertChain(b, false, genTxRing(200)) 57 } 58 func BenchmarkInsertChain_ring200_diskdb(b *testing.B) { 59 benchInsertChain(b, true, genTxRing(200)) 60 } 61 func BenchmarkInsertChain_ring1000_memdb(b *testing.B) { 62 benchInsertChain(b, false, genTxRing(1000)) 63 } 64 func BenchmarkInsertChain_ring1000_diskdb(b *testing.B) { 65 benchInsertChain(b, true, genTxRing(1000)) 66 } 67 68 var ( 69 // This is the content of the genesis block used by the benchmarks. 70 benchRootKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 71 benchRootAddr = crypto.PubkeyToAddress(benchRootKey.PublicKey) 72 benchRootFunds = math.BigPow(2, 100) 73 ) 74 75 // genValueTx returns a block generator that includes a single 76 // value-transfer transaction with n bytes of extra data in each 77 // block. 78 func genValueTx(nbytes int) func(int, *BlockGen) { 79 return func(i int, gen *BlockGen) { 80 toaddr := common.Address{} 81 data := make([]byte, nbytes) 82 gas, _ := IntrinsicGas(data, false, false) 83 tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey) 84 gen.AddTx(tx) 85 } 86 } 87 88 var ( 89 ringKeys = make([]*ecdsa.PrivateKey, 1000) 90 ringAddrs = make([]common.Address, len(ringKeys)) 91 ) 92 93 func init() { 94 ringKeys[0] = benchRootKey 95 ringAddrs[0] = benchRootAddr 96 for i := 1; i < len(ringKeys); i++ { 97 ringKeys[i], _ = crypto.GenerateKey() 98 ringAddrs[i] = crypto.PubkeyToAddress(ringKeys[i].PublicKey) 99 } 100 } 101 102 // genTxRing returns a block generator that sends sbr in a ring 103 // among n accounts. This is creates n entries in the state database 104 // and fills the blocks with many small transactions. 105 func genTxRing(naccounts int) func(int, *BlockGen) { 106 from := 0 107 return func(i int, gen *BlockGen) { 108 gas := CalcGasLimit(gen.PrevBlock(i - 1)) 109 for { 110 gas -= params.TxGas 111 if gas < params.TxGas { 112 break 113 } 114 to := (from + 1) % naccounts 115 tx := types.NewTransaction( 116 gen.TxNonce(ringAddrs[from]), 117 ringAddrs[to], 118 benchRootFunds, 119 params.TxGas, 120 nil, 121 nil, 122 ) 123 tx, _ = types.SignTx(tx, types.HomesteadSigner{}, ringKeys[from]) 124 gen.AddTx(tx) 125 from = to 126 } 127 } 128 } 129 130 // genUncles generates blocks with two uncle headers. 131 func genUncles(i int, gen *BlockGen) { 132 if i >= 6 { 133 b2 := gen.PrevBlock(i - 6).Header() 134 b2.Extra = []byte("foo") 135 gen.AddUncle(b2) 136 b3 := gen.PrevBlock(i - 6).Header() 137 b3.Extra = []byte("bar") 138 gen.AddUncle(b3) 139 } 140 } 141 142 func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { 143 // Create the database in memory or in a temporary directory. 144 var db ethdb.Database 145 if !disk { 146 db, _ = ethdb.NewMemDatabase() 147 } else { 148 dir, err := ioutil.TempDir("", "eth-core-bench") 149 if err != nil { 150 b.Fatalf("cannot create temporary directory: %v", err) 151 } 152 defer os.RemoveAll(dir) 153 db, err = ethdb.NewLDBDatabase(dir, 128, 128) 154 if err != nil { 155 b.Fatalf("cannot create temporary database: %v", err) 156 } 157 defer db.Close() 158 } 159 160 // Generate a chain of b.N blocks using the supplied block 161 // generator function. 162 gspec := Genesis{ 163 Config: params.TestChainConfig, 164 Alloc: GenesisAlloc{benchRootAddr: {Balance: benchRootFunds}}, 165 } 166 genesis := gspec.MustCommit(db) 167 chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, b.N, gen) 168 169 // Time the insertion of the new chain. 170 // State and blocks are stored in the same DB. 171 chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) 172 defer chainman.Stop() 173 b.ReportAllocs() 174 b.ResetTimer() 175 if i, err := chainman.InsertChain(chain); err != nil { 176 b.Fatalf("insert error (block %d): %v\n", i, err) 177 } 178 } 179 180 func BenchmarkChainRead_header_10k(b *testing.B) { 181 benchReadChain(b, false, 10000) 182 } 183 func BenchmarkChainRead_full_10k(b *testing.B) { 184 benchReadChain(b, true, 10000) 185 } 186 func BenchmarkChainRead_header_100k(b *testing.B) { 187 benchReadChain(b, false, 100000) 188 } 189 func BenchmarkChainRead_full_100k(b *testing.B) { 190 benchReadChain(b, true, 100000) 191 } 192 func BenchmarkChainRead_header_500k(b *testing.B) { 193 benchReadChain(b, false, 500000) 194 } 195 func BenchmarkChainRead_full_500k(b *testing.B) { 196 benchReadChain(b, true, 500000) 197 } 198 func BenchmarkChainWrite_header_10k(b *testing.B) { 199 benchWriteChain(b, false, 10000) 200 } 201 func BenchmarkChainWrite_full_10k(b *testing.B) { 202 benchWriteChain(b, true, 10000) 203 } 204 func BenchmarkChainWrite_header_100k(b *testing.B) { 205 benchWriteChain(b, false, 100000) 206 } 207 func BenchmarkChainWrite_full_100k(b *testing.B) { 208 benchWriteChain(b, true, 100000) 209 } 210 func BenchmarkChainWrite_header_500k(b *testing.B) { 211 benchWriteChain(b, false, 500000) 212 } 213 func BenchmarkChainWrite_full_500k(b *testing.B) { 214 benchWriteChain(b, true, 500000) 215 } 216 217 // makeChainForBench writes a given number of headers or empty blocks/receipts 218 // into a database. 219 func makeChainForBench(db ethdb.Database, full bool, count uint64) { 220 var hash common.Hash 221 for n := uint64(0); n < count; n++ { 222 header := &types.Header{ 223 Coinbase: common.Address{}, 224 Number: big.NewInt(int64(n)), 225 ParentHash: hash, 226 Difficulty: big.NewInt(1), 227 UncleHash: types.EmptyUncleHash, 228 TxHash: types.EmptyRootHash, 229 ReceiptHash: types.EmptyRootHash, 230 } 231 hash = header.Hash() 232 WriteHeader(db, header) 233 WriteCanonicalHash(db, hash, n) 234 WriteTd(db, hash, n, big.NewInt(int64(n+1))) 235 if full || n == 0 { 236 block := types.NewBlockWithHeader(header) 237 WriteBody(db, hash, n, block.Body()) 238 WriteBlockReceipts(db, hash, n, nil) 239 } 240 } 241 } 242 243 func benchWriteChain(b *testing.B, full bool, count uint64) { 244 for i := 0; i < b.N; i++ { 245 dir, err := ioutil.TempDir("", "eth-chain-bench") 246 if err != nil { 247 b.Fatalf("cannot create temporary directory: %v", err) 248 } 249 db, err := ethdb.NewLDBDatabase(dir, 128, 1024) 250 if err != nil { 251 b.Fatalf("error opening database at %v: %v", dir, err) 252 } 253 makeChainForBench(db, full, count) 254 db.Close() 255 os.RemoveAll(dir) 256 } 257 } 258 259 func benchReadChain(b *testing.B, full bool, count uint64) { 260 dir, err := ioutil.TempDir("", "eth-chain-bench") 261 if err != nil { 262 b.Fatalf("cannot create temporary directory: %v", err) 263 } 264 defer os.RemoveAll(dir) 265 266 db, err := ethdb.NewLDBDatabase(dir, 128, 1024) 267 if err != nil { 268 b.Fatalf("error opening database at %v: %v", dir, err) 269 } 270 makeChainForBench(db, full, count) 271 db.Close() 272 273 b.ReportAllocs() 274 b.ResetTimer() 275 276 for i := 0; i < b.N; i++ { 277 db, err := ethdb.NewLDBDatabase(dir, 128, 1024) 278 if err != nil { 279 b.Fatalf("error opening database at %v: %v", dir, err) 280 } 281 chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}) 282 if err != nil { 283 b.Fatalf("error creating chain: %v", err) 284 } 285 286 for n := uint64(0); n < count; n++ { 287 header := chain.GetHeaderByNumber(n) 288 if full { 289 hash := header.Hash() 290 GetBody(db, hash, n) 291 GetBlockReceipts(db, hash, n) 292 } 293 } 294 295 chain.Stop() 296 db.Close() 297 } 298 }