core/vm: less allocations for various call variants (#21222)
* core/vm/runtime/tests: add more benchmarks * core/vm: initial work on improving alloc count for calls to precompiles name old time/op new time/op delta SimpleLoop/identity-precompile-10M-6 117ms ±75% 43ms ± 1% -63.09% (p=0.008 n=5+5) SimpleLoop/loop-10M-6 79.6ms ± 4% 70.5ms ± 1% -11.42% (p=0.008 n=5+5) name old alloc/op new alloc/op delta SimpleLoop/identity-precompile-10M-6 24.4MB ± 0% 4.9MB ± 0% -79.94% (p=0.008 n=5+5) SimpleLoop/loop-10M-6 13.2kB ± 0% 13.2kB ± 0% ~ (p=0.357 n=5+5) name old allocs/op new allocs/op delta SimpleLoop/identity-precompile-10M-6 382k ± 0% 153k ± 0% -59.99% (p=0.000 n=5+4) SimpleLoop/loop-10M-6 40.0 ± 0% 40.0 ± 0% ~ (all equal) * core/vm: don't allocate big.int for touch name old time/op new time/op delta SimpleLoop/identity-precompile-10M-6 43.3ms ± 1% 42.4ms ± 7% ~ (p=0.151 n=5+5) SimpleLoop/loop-10M-6 70.5ms ± 1% 76.7ms ± 1% +8.67% (p=0.008 n=5+5) name old alloc/op new alloc/op delta SimpleLoop/identity-precompile-10M-6 4.90MB ± 0% 2.46MB ± 0% -49.83% (p=0.008 n=5+5) SimpleLoop/loop-10M-6 13.2kB ± 0% 13.2kB ± 1% ~ (p=0.571 n=5+5) name old allocs/op new allocs/op delta SimpleLoop/identity-precompile-10M-6 153k ± 0% 76k ± 0% -49.98% (p=0.029 n=4+4) SimpleLoop/loop-10M-6 40.0 ± 0% 40.0 ± 0% ~ (all equal) * core/vm: reduce allocs in staticcall name old time/op new time/op delta SimpleLoop/identity-precompile-10M-6 42.4ms ± 7% 37.5ms ± 6% -11.68% (p=0.008 n=5+5) SimpleLoop/loop-10M-6 76.7ms ± 1% 69.1ms ± 1% -9.82% (p=0.008 n=5+5) name old alloc/op new alloc/op delta SimpleLoop/identity-precompile-10M-6 2.46MB ± 0% 0.02MB ± 0% -99.35% (p=0.008 n=5+5) SimpleLoop/loop-10M-6 13.2kB ± 1% 13.2kB ± 0% ~ (p=0.143 n=5+5) name old allocs/op new allocs/op delta SimpleLoop/identity-precompile-10M-6 76.4k ± 0% 0.1k ± 0% ~ (p=0.079 n=4+5) SimpleLoop/loop-10M-6 40.0 ± 0% 40.0 ± 0% ~ (all equal) * trie: better use of hasher keccakState * core/state/statedb: reduce allocations in getDeletedStateObject * core/vm: reduce allocations in all call derivates * core/vm: reduce allocations in call variants - Make returnstack `uint32` - Use a `sync.Pool` of `stack`s * core/vm: fix tests * core/vm: goimports * core/vm: tracer fix + staticcall gas fix * core/vm: add back snapshot to staticcall * core/vm: review concerns + make returnstack pooled + enable returndata in traces * core/vm: fix some test tracer method signatures * core/vm: run gencodec, minor comment polish Co-authored-by: Péter Szilágyi <peterke@gmail.com>
This commit is contained in:
committed by
GitHub
parent
240d1851db
commit
295693759e
@ -47,11 +47,12 @@ func (s Storage) Copy() Storage {
|
||||
|
||||
// LogConfig are the configuration options for structured logger the EVM
|
||||
type LogConfig struct {
|
||||
DisableMemory bool // disable memory capture
|
||||
DisableStack bool // disable stack capture
|
||||
DisableStorage bool // disable storage capture
|
||||
Debug bool // print output during capture end
|
||||
Limit int // maximum length of output, but zero means unlimited
|
||||
DisableMemory bool // disable memory capture
|
||||
DisableStack bool // disable stack capture
|
||||
DisableStorage bool // disable storage capture
|
||||
DisableReturnData bool // disable return data capture
|
||||
Debug bool // print output during capture end
|
||||
Limit int // maximum length of output, but zero means unlimited
|
||||
}
|
||||
|
||||
//go:generate gencodec -type StructLog -field-override structLogMarshaling -out gen_structlog.go
|
||||
@ -66,7 +67,8 @@ type StructLog struct {
|
||||
Memory []byte `json:"memory"`
|
||||
MemorySize int `json:"memSize"`
|
||||
Stack []*big.Int `json:"stack"`
|
||||
ReturnStack []uint64 `json:"returnStack"`
|
||||
ReturnStack []uint32 `json:"returnStack"`
|
||||
ReturnData []byte `json:"returnData"`
|
||||
Storage map[common.Hash]common.Hash `json:"-"`
|
||||
Depth int `json:"depth"`
|
||||
RefundCounter uint64 `json:"refund"`
|
||||
@ -104,7 +106,7 @@ func (s *StructLog) ErrorString() string {
|
||||
// if you need to retain them beyond the current call.
|
||||
type Tracer interface {
|
||||
CaptureStart(from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) error
|
||||
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rStack *ReturnStack, contract *Contract, depth int, err error) error
|
||||
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rStack *ReturnStack, rData []byte, contract *Contract, depth int, err error) error
|
||||
CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rStack *ReturnStack, contract *Contract, depth int, err error) error
|
||||
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error
|
||||
}
|
||||
@ -142,7 +144,7 @@ func (l *StructLogger) CaptureStart(from common.Address, to common.Address, crea
|
||||
// CaptureState logs a new structured log message and pushes it out to the environment
|
||||
//
|
||||
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
|
||||
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rStack *ReturnStack, contract *Contract, depth int, err error) error {
|
||||
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rStack *ReturnStack, rData []byte, contract *Contract, depth int, err error) error {
|
||||
// check if already accumulated the specified number of logs
|
||||
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
|
||||
return errTraceLimitReached
|
||||
@ -161,9 +163,9 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
|
||||
stck[i] = new(big.Int).Set(item.ToBig())
|
||||
}
|
||||
}
|
||||
var rstack []uint64
|
||||
var rstack []uint32
|
||||
if !l.cfg.DisableStack && rStack != nil {
|
||||
rstck := make([]uint64, len(rStack.data))
|
||||
rstck := make([]uint32, len(rStack.data))
|
||||
copy(rstck, rStack.data)
|
||||
}
|
||||
// Copy a snapshot of the current storage to a new container
|
||||
@ -192,8 +194,13 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
|
||||
}
|
||||
storage = l.storage[contract.Address()].Copy()
|
||||
}
|
||||
var rdata []byte
|
||||
if !l.cfg.DisableReturnData {
|
||||
rdata = make([]byte, len(rData))
|
||||
copy(rdata, rData)
|
||||
}
|
||||
// create a new snapshot of the EVM.
|
||||
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rstack, storage, depth, env.StateDB.GetRefund(), err}
|
||||
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rstack, rdata, storage, depth, env.StateDB.GetRefund(), err}
|
||||
l.logs = append(l.logs, log)
|
||||
return nil
|
||||
}
|
||||
@ -257,6 +264,10 @@ func WriteTrace(writer io.Writer, logs []StructLog) {
|
||||
fmt.Fprintf(writer, "%x: %x\n", h, item)
|
||||
}
|
||||
}
|
||||
if len(log.ReturnData) > 0 {
|
||||
fmt.Fprintln(writer, "ReturnData:")
|
||||
fmt.Fprint(writer, hex.Dump(log.ReturnData))
|
||||
}
|
||||
fmt.Fprintln(writer)
|
||||
}
|
||||
}
|
||||
@ -308,7 +319,7 @@ func (t *mdLogger) CaptureStart(from common.Address, to common.Address, create b
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rStack *ReturnStack, contract *Contract, depth int, err error) error {
|
||||
func (t *mdLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, rStack *ReturnStack, rData []byte, contract *Contract, depth int, err error) error {
|
||||
fmt.Fprintf(t.out, "| %4d | %10v | %3d |", pc, op, cost)
|
||||
|
||||
if !t.cfg.DisableStack { // format stack
|
||||
|
Reference in New Issue
Block a user