Skip to content

Commit da17f2d

Browse files
holimans1na
andauthored
all: fix issues with benchmarks (#30667)
This PR fixes some issues with benchmarks - [x] Removes log output from a log-test - [x] Avoids a `nil`-defer in `triedb/pathdb` - [x] Fixes some crashes re tracers - [x] Refactors a very resource-expensive benchmark for blobpol. **NOTE**: this rewrite touches live production code (a little bit), as it makes the validator-function used by the blobpool configurable. - [x] Switch some benches over to use pebble over leveldb - [x] reduce mem overhead in the setup-phase of some tests - [x] Marks some tests with a long setup-phase to be skipped if `-short` is specified (where long is on the order of tens of seconds). Ideally, in my opinion, one should be able to run with `-benchtime 10ms -short` and sanity-check all tests very quickly. - [x] Drops some metrics-bechmark which times the speed of `copy`. --------- Co-authored-by: Sina Mahmoodi <[email protected]>
1 parent 06cbc80 commit da17f2d

File tree

11 files changed

+105
-62
lines changed

11 files changed

+105
-62
lines changed

core/bench_test.go

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,15 @@ var (
8181
// value-transfer transaction with n bytes of extra data in each
8282
// block.
8383
func genValueTx(nbytes int) func(int, *BlockGen) {
84+
// We can reuse the data for all transactions.
85+
// During signing, the method tx.WithSignature(s, sig)
86+
// performs:
87+
// cpy := tx.inner.copy()
88+
// cpy.setSignatureValues(signer.ChainID(), v, r, s)
89+
// After this operation, the data can be reused by the caller.
90+
data := make([]byte, nbytes)
8491
return func(i int, gen *BlockGen) {
8592
toaddr := common.Address{}
86-
data := make([]byte, nbytes)
8793
gas, _ := IntrinsicGas(data, nil, false, false, false, false)
8894
signer := gen.Signer()
8995
gasPrice := big.NewInt(0)
@@ -210,15 +216,27 @@ func BenchmarkChainRead_full_10k(b *testing.B) {
210216
benchReadChain(b, true, 10000)
211217
}
212218
func BenchmarkChainRead_header_100k(b *testing.B) {
219+
if testing.Short() {
220+
b.Skip("Skipping in short-mode")
221+
}
213222
benchReadChain(b, false, 100000)
214223
}
215224
func BenchmarkChainRead_full_100k(b *testing.B) {
225+
if testing.Short() {
226+
b.Skip("Skipping in short-mode")
227+
}
216228
benchReadChain(b, true, 100000)
217229
}
218230
func BenchmarkChainRead_header_500k(b *testing.B) {
231+
if testing.Short() {
232+
b.Skip("Skipping in short-mode")
233+
}
219234
benchReadChain(b, false, 500000)
220235
}
221236
func BenchmarkChainRead_full_500k(b *testing.B) {
237+
if testing.Short() {
238+
b.Skip("Skipping in short-mode")
239+
}
222240
benchReadChain(b, true, 500000)
223241
}
224242
func BenchmarkChainWrite_header_10k(b *testing.B) {
@@ -234,9 +252,15 @@ func BenchmarkChainWrite_full_100k(b *testing.B) {
234252
benchWriteChain(b, true, 100000)
235253
}
236254
func BenchmarkChainWrite_header_500k(b *testing.B) {
255+
if testing.Short() {
256+
b.Skip("Skipping in short-mode")
257+
}
237258
benchWriteChain(b, false, 500000)
238259
}
239260
func BenchmarkChainWrite_full_500k(b *testing.B) {
261+
if testing.Short() {
262+
b.Skip("Skipping in short-mode")
263+
}
240264
benchWriteChain(b, true, 500000)
241265
}
242266

core/rawdb/accessors_chain_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -649,11 +649,15 @@ func makeTestBlocks(nblock int, txsPerBlock int) []*types.Block {
649649
// makeTestReceipts creates fake receipts for the ancient write benchmark.
650650
func makeTestReceipts(n int, nPerBlock int) []types.Receipts {
651651
receipts := make([]*types.Receipt, nPerBlock)
652+
var logs []*types.Log
653+
for i := 0; i < 5; i++ {
654+
logs = append(logs, new(types.Log))
655+
}
652656
for i := 0; i < len(receipts); i++ {
653657
receipts[i] = &types.Receipt{
654658
Status: types.ReceiptStatusSuccessful,
655659
CumulativeGasUsed: 0x888888888,
656-
Logs: make([]*types.Log, 5),
660+
Logs: logs,
657661
}
658662
}
659663
allReceipts := make([]types.Receipts, n)

core/txpool/blobpool/blobpool.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,10 @@ type BlobPool struct {
318318
discoverFeed event.Feed // Event feed to send out new tx events on pool discovery (reorg excluded)
319319
insertFeed event.Feed // Event feed to send out new tx events on pool inclusion (reorg included)
320320

321+
// txValidationFn defaults to txpool.ValidateTransaction, but can be
322+
// overridden for testing purposes.
323+
txValidationFn txpool.ValidationFunction
324+
321325
lock sync.RWMutex // Mutex protecting the pool during reorg handling
322326
}
323327

@@ -329,12 +333,13 @@ func New(config Config, chain BlockChain) *BlobPool {
329333

330334
// Create the transaction pool with its initial settings
331335
return &BlobPool{
332-
config: config,
333-
signer: types.LatestSigner(chain.Config()),
334-
chain: chain,
335-
lookup: newLookup(),
336-
index: make(map[common.Address][]*blobTxMeta),
337-
spent: make(map[common.Address]*uint256.Int),
336+
config: config,
337+
signer: types.LatestSigner(chain.Config()),
338+
chain: chain,
339+
lookup: newLookup(),
340+
index: make(map[common.Address][]*blobTxMeta),
341+
spent: make(map[common.Address]*uint256.Int),
342+
txValidationFn: txpool.ValidateTransaction,
338343
}
339344
}
340345

@@ -1090,7 +1095,8 @@ func (p *BlobPool) validateTx(tx *types.Transaction) error {
10901095
MaxSize: txMaxSize,
10911096
MinTip: p.gasTip.ToBig(),
10921097
}
1093-
if err := txpool.ValidateTransaction(tx, p.head, p.signer, baseOpts); err != nil {
1098+
1099+
if err := p.txValidationFn(tx, p.head, p.signer, baseOpts); err != nil {
10941100
return err
10951101
}
10961102
// Ensure the transaction adheres to the stateful pool filters (nonce, balance)

core/txpool/blobpool/blobpool_test.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1449,11 +1449,29 @@ func TestAdd(t *testing.T) {
14491449
}
14501450
}
14511451

1452+
// fakeBilly is a billy.Database implementation which just drops data on the floor.
1453+
type fakeBilly struct {
1454+
billy.Database
1455+
count uint64
1456+
}
1457+
1458+
func (f *fakeBilly) Put(data []byte) (uint64, error) {
1459+
f.count++
1460+
return f.count, nil
1461+
}
1462+
1463+
var _ billy.Database = (*fakeBilly)(nil)
1464+
14521465
// Benchmarks the time it takes to assemble the lazy pending transaction list
14531466
// from the pool contents.
14541467
func BenchmarkPoolPending100Mb(b *testing.B) { benchmarkPoolPending(b, 100_000_000) }
14551468
func BenchmarkPoolPending1GB(b *testing.B) { benchmarkPoolPending(b, 1_000_000_000) }
1456-
func BenchmarkPoolPending10GB(b *testing.B) { benchmarkPoolPending(b, 10_000_000_000) }
1469+
func BenchmarkPoolPending10GB(b *testing.B) {
1470+
if testing.Short() {
1471+
b.Skip("Skipping in short-mode")
1472+
}
1473+
benchmarkPoolPending(b, 10_000_000_000)
1474+
}
14571475

14581476
func benchmarkPoolPending(b *testing.B, datacap uint64) {
14591477
// Calculate the maximum number of transaction that would fit into the pool
@@ -1477,6 +1495,15 @@ func benchmarkPoolPending(b *testing.B, datacap uint64) {
14771495
if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil {
14781496
b.Fatalf("failed to create blob pool: %v", err)
14791497
}
1498+
// Make the pool not use disk (just drop everything). This test never reads
1499+
// back the data, it just iterates over the pool in-memory items
1500+
pool.store = &fakeBilly{pool.store, 0}
1501+
// Avoid validation - verifying all blob proofs take significant time
1502+
// when the capacity is large. The purpose of this bench is to measure assembling
1503+
// the lazies, not the kzg verifications.
1504+
pool.txValidationFn = func(tx *types.Transaction, head *types.Header, signer types.Signer, opts *txpool.ValidationOptions) error {
1505+
return nil // accept all
1506+
}
14801507
// Fill the pool up with one random transaction from each account with the
14811508
// same price and everything to maximize the worst case scenario
14821509
for i := 0; i < int(capacity); i++ {

core/txpool/blobpool/evictheap_test.go

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,25 @@ func BenchmarkPriceHeapOverflow10MB(b *testing.B) { benchmarkPriceHeapOverflow(
239239
func BenchmarkPriceHeapOverflow100MB(b *testing.B) { benchmarkPriceHeapOverflow(b, 100*1024*1024) }
240240
func BenchmarkPriceHeapOverflow1GB(b *testing.B) { benchmarkPriceHeapOverflow(b, 1024*1024*1024) }
241241
func BenchmarkPriceHeapOverflow10GB(b *testing.B) { benchmarkPriceHeapOverflow(b, 10*1024*1024*1024) }
242-
func BenchmarkPriceHeapOverflow25GB(b *testing.B) { benchmarkPriceHeapOverflow(b, 25*1024*1024*1024) }
243-
func BenchmarkPriceHeapOverflow50GB(b *testing.B) { benchmarkPriceHeapOverflow(b, 50*1024*1024*1024) }
244-
func BenchmarkPriceHeapOverflow100GB(b *testing.B) { benchmarkPriceHeapOverflow(b, 100*1024*1024*1024) }
242+
243+
func BenchmarkPriceHeapOverflow25GB(b *testing.B) {
244+
if testing.Short() {
245+
b.Skip("Skipping in short-mode")
246+
}
247+
benchmarkPriceHeapOverflow(b, 25*1024*1024*1024)
248+
}
249+
func BenchmarkPriceHeapOverflow50GB(b *testing.B) {
250+
if testing.Short() {
251+
b.Skip("Skipping in short-mode")
252+
}
253+
benchmarkPriceHeapOverflow(b, 50*1024*1024*1024)
254+
}
255+
func BenchmarkPriceHeapOverflow100GB(b *testing.B) {
256+
if testing.Short() {
257+
b.Skip("Skipping in short-mode")
258+
}
259+
benchmarkPriceHeapOverflow(b, 100*1024*1024*1024)
260+
}
245261

246262
func benchmarkPriceHeapOverflow(b *testing.B, datacap uint64) {
247263
// Calculate how many unique transactions we can fit into the provided disk

core/txpool/validation.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ type ValidationOptions struct {
4747
MinTip *big.Int // Minimum gas tip needed to allow a transaction into the caller pool
4848
}
4949

50+
// ValidationFunction is an method type which the pools use to perform the tx-validations which do not
51+
// require state access. Production code typically uses ValidateTransaction, whereas testing-code
52+
// might choose to instead use something else, e.g. to always fail or avoid heavy cpu usage.
53+
type ValidationFunction func(tx *types.Transaction, head *types.Header, signer types.Signer, opts *ValidationOptions) error
54+
5055
// ValidateTransaction is a helper method to check whether a transaction is valid
5156
// according to the consensus rules, but does not check state-dependent validation
5257
// (balance, nonce, etc).

eth/tracers/internal/tracetest/calltrace_test.go

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ import (
3535
"github.com/ethereum/go-ethereum/crypto"
3636
"github.com/ethereum/go-ethereum/eth/tracers"
3737
"github.com/ethereum/go-ethereum/params"
38-
"github.com/ethereum/go-ethereum/rlp"
3938
"github.com/ethereum/go-ethereum/tests"
4039
)
4140

@@ -202,7 +201,7 @@ func BenchmarkTracers(b *testing.B) {
202201
func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
203202
// Configure a blockchain with the given prestate
204203
tx := new(types.Transaction)
205-
if err := rlp.DecodeBytes(common.FromHex(test.Input), tx); err != nil {
204+
if err := tx.UnmarshalBinary(common.FromHex(test.Input)); err != nil {
206205
b.Fatalf("failed to parse testcase input: %v", err)
207206
}
208207
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
@@ -211,15 +210,7 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
211210
Origin: origin,
212211
GasPrice: tx.GasPrice(),
213212
}
214-
context := vm.BlockContext{
215-
CanTransfer: core.CanTransfer,
216-
Transfer: core.Transfer,
217-
Coinbase: test.Context.Miner,
218-
BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)),
219-
Time: uint64(test.Context.Time),
220-
Difficulty: (*big.Int)(test.Context.Difficulty),
221-
GasLimit: uint64(test.Context.GasLimit),
222-
}
213+
context := test.Context.toBlockContext(test.Genesis)
223214
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
224215
if err != nil {
225216
b.Fatalf("failed to prepare transaction for tracing: %v", err)

eth/tracers/tracers_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,13 @@ func BenchmarkTransactionTrace(b *testing.B) {
9999

100100
for i := 0; i < b.N; i++ {
101101
snap := state.StateDB.Snapshot()
102+
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
102103
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
103-
_, err = st.TransitionDb()
104+
res, err := st.TransitionDb()
104105
if err != nil {
105106
b.Fatal(err)
106107
}
108+
tracer.OnTxEnd(&types.Receipt{GasUsed: res.UsedGas}, nil)
107109
state.StateDB.RevertToSnapshot(snap)
108110
if have, want := len(tracer.StructLogs()), 244752; have != want {
109111
b.Fatalf("trace wrong, want %d steps, have %d", want, have)

log/logger_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"io"
88
"log/slog"
99
"math/big"
10-
"os"
1110
"strings"
1211
"testing"
1312
"time"
@@ -70,7 +69,7 @@ func TestJSONHandler(t *testing.T) {
7069
}
7170

7271
func BenchmarkTraceLogging(b *testing.B) {
73-
SetDefault(NewLogger(NewTerminalHandler(os.Stderr, true)))
72+
SetDefault(NewLogger(NewTerminalHandler(io.Discard, true)))
7473
b.ResetTimer()
7574
for i := 0; i < b.N; i++ {
7675
Trace("a message", "v", i)

metrics/sample_test.go

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package metrics
33
import (
44
"math"
55
"math/rand"
6-
"runtime"
76
"testing"
87
"time"
98
)
@@ -27,6 +26,7 @@ func BenchmarkCompute1000(b *testing.B) {
2726
SampleVariance(mean, s)
2827
}
2928
}
29+
3030
func BenchmarkCompute1000000(b *testing.B) {
3131
s := make([]int64, 1000000)
3232
var sum int64
@@ -40,28 +40,6 @@ func BenchmarkCompute1000000(b *testing.B) {
4040
SampleVariance(mean, s)
4141
}
4242
}
43-
func BenchmarkCopy1000(b *testing.B) {
44-
s := make([]int64, 1000)
45-
for i := 0; i < len(s); i++ {
46-
s[i] = int64(i)
47-
}
48-
b.ResetTimer()
49-
for i := 0; i < b.N; i++ {
50-
sCopy := make([]int64, len(s))
51-
copy(sCopy, s)
52-
}
53-
}
54-
func BenchmarkCopy1000000(b *testing.B) {
55-
s := make([]int64, 1000000)
56-
for i := 0; i < len(s); i++ {
57-
s[i] = int64(i)
58-
}
59-
b.ResetTimer()
60-
for i := 0; i < b.N; i++ {
61-
sCopy := make([]int64, len(s))
62-
copy(sCopy, s)
63-
}
64-
}
6543

6644
func BenchmarkExpDecaySample257(b *testing.B) {
6745
benchmarkSample(b, NewExpDecaySample(257, 0.015))
@@ -237,17 +215,9 @@ func TestUniformSampleStatistics(t *testing.T) {
237215
}
238216

239217
func benchmarkSample(b *testing.B, s Sample) {
240-
var memStats runtime.MemStats
241-
runtime.ReadMemStats(&memStats)
242-
pauseTotalNs := memStats.PauseTotalNs
243-
b.ResetTimer()
244218
for i := 0; i < b.N; i++ {
245219
s.Update(1)
246220
}
247-
b.StopTimer()
248-
runtime.GC()
249-
runtime.ReadMemStats(&memStats)
250-
b.Logf("GC cost: %d ns/op", int(memStats.PauseTotalNs-pauseTotalNs)/b.N)
251221
}
252222

253223
func testExpDecaySampleStatistics(t *testing.T, s SampleSnapshot) {

0 commit comments

Comments
 (0)