github.com/core-coin/go-core/v2@v2.1.9/core/bench_test.go (about) 1 // Copyright 2015 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 crand "crypto/rand" 21 "io/ioutil" 22 "math/big" 23 "os" 24 "testing" 25 26 "github.com/core-coin/go-core/v2/xcbdb" 27 28 "github.com/core-coin/go-core/v2/consensus/cryptore" 29 30 "github.com/core-coin/go-core/v2/common" 31 "github.com/core-coin/go-core/v2/common/math" 32 "github.com/core-coin/go-core/v2/core/rawdb" 33 "github.com/core-coin/go-core/v2/core/types" 34 "github.com/core-coin/go-core/v2/core/vm" 35 "github.com/core-coin/go-core/v2/crypto" 36 "github.com/core-coin/go-core/v2/params" 37 ) 38 39 func BenchmarkInsertChain_empty_memdb(b *testing.B) { 40 benchInsertChain(b, false, nil) 41 } 42 func BenchmarkInsertChain_empty_diskdb(b *testing.B) { 43 benchInsertChain(b, true, nil) 44 } 45 func BenchmarkInsertChain_valueTx_memdb(b *testing.B) { 46 benchInsertChain(b, false, genValueTx(0)) 47 } 48 func BenchmarkInsertChain_valueTx_diskdb(b *testing.B) { 49 benchInsertChain(b, true, genValueTx(0)) 50 } 51 func BenchmarkInsertChain_valueTx_100kB_memdb(b *testing.B) { 52 benchInsertChain(b, false, genValueTx(100*1024)) 53 } 54 func BenchmarkInsertChain_valueTx_100kB_diskdb(b *testing.B) { 55 benchInsertChain(b, true, genValueTx(100*1024)) 56 } 57 func BenchmarkInsertChain_uncles_memdb(b *testing.B) { 58 benchInsertChain(b, false, genUncles) 59 } 60 func BenchmarkInsertChain_uncles_diskdb(b *testing.B) { 61 benchInsertChain(b, true, genUncles) 62 } 63 func BenchmarkInsertChain_ring200_memdb(b *testing.B) { 64 benchInsertChain(b, false, genTxRing(200)) 65 } 66 func BenchmarkInsertChain_ring200_diskdb(b *testing.B) { 67 benchInsertChain(b, true, genTxRing(200)) 68 } 69 func BenchmarkInsertChain_ring1000_memdb(b *testing.B) { 70 benchInsertChain(b, false, genTxRing(1000)) 71 } 72 func BenchmarkInsertChain_ring1000_diskdb(b *testing.B) { 73 benchInsertChain(b, true, genTxRing(1000)) 74 } 75 76 var ( 77 // This is the content of the genesis block used by the benchmarks. 78 benchRootKey, _ = crypto.UnmarshalPrivateKeyHex("ab856a9af6b0b651dd2f43b5e12193652ec1701c4da6f1c0d2a366ac4b9dabc9433ef09e41ca129552bd2c029086d9b03604de872a3b343204") 79 benchRootFunds = math.BigPow(2, 100) 80 ) 81 82 // genValueTx returns a block generator that includes a single 83 // value-transfer transaction with n bytes of extra data in each 84 // block. 85 func genValueTx(nbytes int) func(int, *BlockGen) { 86 return func(i int, gen *BlockGen) { 87 toaddr := common.Address{} 88 data := make([]byte, nbytes) 89 energy, _ := IntrinsicEnergy(data, false) 90 tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootKey.Address()), toaddr, big.NewInt(1), energy, nil, data), types.NewNucleusSigner(big.NewInt(1)), benchRootKey) 91 gen.AddTx(tx) 92 } 93 } 94 95 var ( 96 ringKeys = make([]*crypto.PrivateKey, 1000) 97 ringAddrs = make([]common.Address, len(ringKeys)) 98 ) 99 100 func init() { 101 ringKeys[0] = benchRootKey 102 ringAddrs[0] = benchRootKey.Address() 103 for i := 1; i < len(ringKeys); i++ { 104 ringKeys[i], _ = crypto.GenerateKey(crand.Reader) 105 ringAddrs[i] = ringKeys[i].Address() 106 } 107 } 108 109 // genTxRing returns a block generator that sends core in a ring 110 // among n accounts. This is creates n entries in the state database 111 // and fills the blocks with many small transactions. 112 func genTxRing(naccounts int) func(int, *BlockGen) { 113 from := 0 114 return func(i int, gen *BlockGen) { 115 block := gen.PrevBlock(i - 1) 116 energy := CalcEnergyLimit(block, block.EnergyLimit(), block.EnergyLimit()) 117 for { 118 energy -= params.TxEnergy 119 if energy < params.TxEnergy { 120 break 121 } 122 to := (from + 1) % naccounts 123 tx := types.NewTransaction( 124 gen.TxNonce(ringAddrs[from]), 125 ringAddrs[to], 126 benchRootFunds, 127 params.TxEnergy, 128 nil, 129 nil, 130 ) 131 tx, _ = types.SignTx(tx, types.NewNucleusSigner(big.NewInt(1)), 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.Extra = []byte("foo") 143 gen.AddUncle(b2) 144 b3 := gen.PrevBlock(i - 6).Header() 145 b3.Extra = []byte("bar") 146 gen.AddUncle(b3) 147 } 148 } 149 150 func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { 151 // Create the database in memory or in a temporary directory. 152 var db xcbdb.Database 153 if !disk { 154 db = rawdb.NewMemoryDatabase() 155 } else { 156 dir, err := ioutil.TempDir("", "xcb-core-bench") 157 if err != nil { 158 b.Fatalf("cannot create temporary directory: %v", err) 159 } 160 defer os.RemoveAll(dir) 161 db, err = rawdb.NewLevelDBDatabase(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.MainnetChainConfig, 172 Alloc: GenesisAlloc{benchRootKey.Address(): {Balance: benchRootFunds}}, 173 } 174 genesis := gspec.MustCommit(db) 175 chain, _ := GenerateChain(gspec.Config, genesis, cryptore.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, cryptore.NewFaker(), vm.Config{}, nil, nil) 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) 190 } 191 func BenchmarkChainRead_full_10k(b *testing.B) { 192 benchReadChain(b, true, 10000) 193 } 194 func BenchmarkChainRead_header_100k(b *testing.B) { 195 benchReadChain(b, false, 100000) 196 } 197 func BenchmarkChainRead_full_100k(b *testing.B) { 198 benchReadChain(b, true, 100000) 199 } 200 func BenchmarkChainRead_header_500k(b *testing.B) { 201 benchReadChain(b, false, 500000) 202 } 203 func BenchmarkChainRead_full_500k(b *testing.B) { 204 benchReadChain(b, true, 500000) 205 } 206 func BenchmarkChainWrite_header_10k(b *testing.B) { 207 benchWriteChain(b, false, 10000) 208 } 209 func BenchmarkChainWrite_full_10k(b *testing.B) { 210 benchWriteChain(b, true, 10000) 211 } 212 func BenchmarkChainWrite_header_100k(b *testing.B) { 213 benchWriteChain(b, false, 100000) 214 } 215 func BenchmarkChainWrite_full_100k(b *testing.B) { 216 benchWriteChain(b, true, 100000) 217 } 218 func BenchmarkChainWrite_header_500k(b *testing.B) { 219 benchWriteChain(b, false, 500000) 220 } 221 func BenchmarkChainWrite_full_500k(b *testing.B) { 222 benchWriteChain(b, true, 500000) 223 } 224 225 // makeChainForBench writes a given number of headers or empty blocks/receipts 226 // into a database. 227 func makeChainForBench(db xcbdb.Database, full bool, count uint64) { 228 var hash common.Hash 229 for n := uint64(0); n < count; n++ { 230 header := &types.Header{ 231 Coinbase: common.Address{}, 232 Number: big.NewInt(int64(n)), 233 ParentHash: hash, 234 Difficulty: big.NewInt(1), 235 UncleHash: types.EmptyUncleHash, 236 TxHash: types.EmptyRootHash, 237 ReceiptHash: types.EmptyRootHash, 238 } 239 hash = header.Hash() 240 241 rawdb.WriteHeader(db, header) 242 rawdb.WriteCanonicalHash(db, hash, n) 243 rawdb.WriteTd(db, hash, n, big.NewInt(int64(n+1))) 244 245 if full || n == 0 { 246 block := types.NewBlockWithHeader(header) 247 rawdb.WriteBody(db, hash, n, block.Body()) 248 rawdb.WriteReceipts(db, hash, n, nil) 249 } 250 } 251 } 252 253 func benchWriteChain(b *testing.B, full bool, count uint64) { 254 for i := 0; i < b.N; i++ { 255 dir, err := ioutil.TempDir("", "xcb-chain-bench") 256 if err != nil { 257 b.Fatalf("cannot create temporary directory: %v", err) 258 } 259 db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "") 260 if err != nil { 261 b.Fatalf("error opening database at %v: %v", dir, err) 262 } 263 makeChainForBench(db, full, count) 264 db.Close() 265 os.RemoveAll(dir) 266 } 267 } 268 269 func benchReadChain(b *testing.B, full bool, count uint64) { 270 dir, err := ioutil.TempDir("", "xcb-chain-bench") 271 if err != nil { 272 b.Fatalf("cannot create temporary directory: %v", err) 273 } 274 defer os.RemoveAll(dir) 275 276 db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "") 277 if err != nil { 278 b.Fatalf("error opening database at %v: %v", dir, err) 279 } 280 makeChainForBench(db, full, count) 281 db.Close() 282 283 b.ReportAllocs() 284 b.ResetTimer() 285 286 for i := 0; i < b.N; i++ { 287 db, err := rawdb.NewLevelDBDatabase(dir, 128, 1024, "") 288 if err != nil { 289 b.Fatalf("error opening database at %v: %v", dir, err) 290 } 291 chain, err := NewBlockChain(db, nil, params.MainnetChainConfig, cryptore.NewFaker(), vm.Config{}, nil, nil) 292 if err != nil { 293 b.Fatalf("error creating chain: %v", err) 294 } 295 296 for n := uint64(0); n < count; n++ { 297 header := chain.GetHeaderByNumber(n) 298 if full { 299 hash := header.Hash() 300 rawdb.ReadBody(db, hash, n) 301 rawdb.ReadReceipts(db, hash, n, chain.Config()) 302 } 303 } 304 chain.Stop() 305 db.Close() 306 } 307 }