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