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  }