github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/core/bench_test.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 19:16:34</date> 10 //</624450077443756032> 11 12 13 package core 14 15 import ( 16 "crypto/ecdsa" 17 "io/ioutil" 18 "math/big" 19 "os" 20 "testing" 21 22 "github.com/ethereum/go-ethereum/common" 23 "github.com/ethereum/go-ethereum/common/math" 24 "github.com/ethereum/go-ethereum/consensus/ethash" 25 "github.com/ethereum/go-ethereum/core/rawdb" 26 "github.com/ethereum/go-ethereum/core/types" 27 "github.com/ethereum/go-ethereum/core/vm" 28 "github.com/ethereum/go-ethereum/crypto" 29 "github.com/ethereum/go-ethereum/ethdb" 30 "github.com/ethereum/go-ethereum/params" 31 ) 32 33 func BenchmarkInsertChain_empty_memdb(b *testing.B) { 34 benchInsertChain(b, false, nil) 35 } 36 func BenchmarkInsertChain_empty_diskdb(b *testing.B) { 37 benchInsertChain(b, true, nil) 38 } 39 func BenchmarkInsertChain_valueTx_memdb(b *testing.B) { 40 benchInsertChain(b, false, genValueTx(0)) 41 } 42 func BenchmarkInsertChain_valueTx_diskdb(b *testing.B) { 43 benchInsertChain(b, true, genValueTx(0)) 44 } 45 func BenchmarkInsertChain_valueTx_100kB_memdb(b *testing.B) { 46 benchInsertChain(b, false, genValueTx(100*1024)) 47 } 48 func BenchmarkInsertChain_valueTx_100kB_diskdb(b *testing.B) { 49 benchInsertChain(b, true, genValueTx(100*1024)) 50 } 51 func BenchmarkInsertChain_uncles_memdb(b *testing.B) { 52 benchInsertChain(b, false, genUncles) 53 } 54 func BenchmarkInsertChain_uncles_diskdb(b *testing.B) { 55 benchInsertChain(b, true, genUncles) 56 } 57 func BenchmarkInsertChain_ring200_memdb(b *testing.B) { 58 benchInsertChain(b, false, genTxRing(200)) 59 } 60 func BenchmarkInsertChain_ring200_diskdb(b *testing.B) { 61 benchInsertChain(b, true, genTxRing(200)) 62 } 63 func BenchmarkInsertChain_ring1000_memdb(b *testing.B) { 64 benchInsertChain(b, false, genTxRing(1000)) 65 } 66 func BenchmarkInsertChain_ring1000_diskdb(b *testing.B) { 67 benchInsertChain(b, true, genTxRing(1000)) 68 } 69 70 var ( 71 //这是基准使用的Genesis块的内容。 72 benchRootKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 73 benchRootAddr = crypto.PubkeyToAddress(benchRootKey.PublicKey) 74 benchRootFunds = math.BigPow(2, 100) 75 ) 76 77 //genvaluetx返回包含单个 78 //值传输事务,每个事务中有n个字节的额外数据 79 //块。 80 func genValueTx(nbytes int) func(int, *BlockGen) { 81 return func(i int, gen *BlockGen) { 82 toaddr := common.Address{} 83 data := make([]byte, nbytes) 84 gas, _ := IntrinsicGas(data, false, false) 85 tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, 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返回一个以环形方式发送乙醚的块生成器 105 //在N个帐户中。这是在状态数据库中创建n个条目 106 //并用许多小事务填充块。 107 func genTxRing(naccounts int) func(int, *BlockGen) { 108 from := 0 109 return func(i int, gen *BlockGen) { 110 block := gen.PrevBlock(i - 1) 111 gas := CalcGasLimit(block, block.GasLimit(), block.GasLimit()) 112 for { 113 gas -= params.TxGas 114 if gas < params.TxGas { 115 break 116 } 117 to := (from + 1) % naccounts 118 tx := types.NewTransaction( 119 gen.TxNonce(ringAddrs[from]), 120 ringAddrs[to], 121 benchRootFunds, 122 params.TxGas, 123 nil, 124 nil, 125 ) 126 tx, _ = types.SignTx(tx, types.HomesteadSigner{}, ringKeys[from]) 127 gen.AddTx(tx) 128 from = to 129 } 130 } 131 } 132 133 //Genincles生成带有两个叔叔头的块。 134 func genUncles(i int, gen *BlockGen) { 135 if i >= 6 { 136 b2 := gen.PrevBlock(i - 6).Header() 137 b2.Extra = []byte("foo") 138 gen.AddUncle(b2) 139 b3 := gen.PrevBlock(i - 6).Header() 140 b3.Extra = []byte("bar") 141 gen.AddUncle(b3) 142 } 143 } 144 145 func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { 146 //在内存或临时目录中创建数据库。 147 var db ethdb.Database 148 if !disk { 149 db = ethdb.NewMemDatabase() 150 } else { 151 dir, err := ioutil.TempDir("", "eth-core-bench") 152 if err != nil { 153 b.Fatalf("cannot create temporary directory: %v", err) 154 } 155 defer os.RemoveAll(dir) 156 db, err = ethdb.NewLDBDatabase(dir, 128, 128) 157 if err != nil { 158 b.Fatalf("cannot create temporary database: %v", err) 159 } 160 defer db.Close() 161 } 162 163 //使用提供的块生成B.N块链 164 //发电机功能。 165 gspec := Genesis{ 166 Config: params.TestChainConfig, 167 Alloc: GenesisAlloc{benchRootAddr: {Balance: benchRootFunds}}, 168 } 169 genesis := gspec.MustCommit(db) 170 chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, b.N, gen) 171 172 //给插入新链条计时。 173 //状态和块存储在同一个数据库中。 174 chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil) 175 defer chainman.Stop() 176 b.ReportAllocs() 177 b.ResetTimer() 178 if i, err := chainman.InsertChain(chain); err != nil { 179 b.Fatalf("insert error (block %d): %v\n", i, err) 180 } 181 } 182 183 func BenchmarkChainRead_header_10k(b *testing.B) { 184 benchReadChain(b, false, 10000) 185 } 186 func BenchmarkChainRead_full_10k(b *testing.B) { 187 benchReadChain(b, true, 10000) 188 } 189 func BenchmarkChainRead_header_100k(b *testing.B) { 190 benchReadChain(b, false, 100000) 191 } 192 func BenchmarkChainRead_full_100k(b *testing.B) { 193 benchReadChain(b, true, 100000) 194 } 195 func BenchmarkChainRead_header_500k(b *testing.B) { 196 benchReadChain(b, false, 500000) 197 } 198 func BenchmarkChainRead_full_500k(b *testing.B) { 199 benchReadChain(b, true, 500000) 200 } 201 func BenchmarkChainWrite_header_10k(b *testing.B) { 202 benchWriteChain(b, false, 10000) 203 } 204 func BenchmarkChainWrite_full_10k(b *testing.B) { 205 benchWriteChain(b, true, 10000) 206 } 207 func BenchmarkChainWrite_header_100k(b *testing.B) { 208 benchWriteChain(b, false, 100000) 209 } 210 func BenchmarkChainWrite_full_100k(b *testing.B) { 211 benchWriteChain(b, true, 100000) 212 } 213 func BenchmarkChainWrite_header_500k(b *testing.B) { 214 benchWriteChain(b, false, 500000) 215 } 216 func BenchmarkChainWrite_full_500k(b *testing.B) { 217 benchWriteChain(b, true, 500000) 218 } 219 220 //makechainforbench写入给定数量的头或空块/收据 221 //进入数据库。 222 func makeChainForBench(db ethdb.Database, full bool, count uint64) { 223 var hash common.Hash 224 for n := uint64(0); n < count; n++ { 225 header := &types.Header{ 226 Coinbase: common.Address{}, 227 Number: big.NewInt(int64(n)), 228 ParentHash: hash, 229 Difficulty: big.NewInt(1), 230 UncleHash: types.EmptyUncleHash, 231 TxHash: types.EmptyRootHash, 232 ReceiptHash: types.EmptyRootHash, 233 } 234 hash = header.Hash() 235 236 rawdb.WriteHeader(db, header) 237 rawdb.WriteCanonicalHash(db, hash, n) 238 rawdb.WriteTd(db, hash, n, big.NewInt(int64(n+1))) 239 240 if full || n == 0 { 241 block := types.NewBlockWithHeader(header) 242 rawdb.WriteBody(db, hash, n, block.Body()) 243 rawdb.WriteReceipts(db, 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, err := ethdb.NewLDBDatabase(dir, 128, 1024) 255 if 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, err := ethdb.NewLDBDatabase(dir, 128, 1024) 272 if 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, err := ethdb.NewLDBDatabase(dir, 128, 1024) 283 if err != nil { 284 b.Fatalf("error opening database at %v: %v", dir, err) 285 } 286 chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}, nil) 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, hash, n) 296 rawdb.ReadReceipts(db, hash, n) 297 } 298 } 299 chain.Stop() 300 db.Close() 301 } 302 } 303