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