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