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