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