From 3bbf5f5b6a9cd5ba998f6580586ddf208217e915 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Wed, 26 Nov 2025 16:50:16 +0100 Subject: [PATCH] core/vm: improve memory resize (#33056) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looks like (in some very EVM specific tests) we spent a lot of time resizing memory. If the underlying array is big enough, we can speed it up a bit by simply slicing the memory. goos: linux goarch: amd64 pkg: github.com/ethereum/go-ethereum/core/vm cpu: Intel(R) Core(TM) Ultra 7 155U │ /tmp/old.txt │ /tmp/new.txt │ │ sec/op │ sec/op vs base │ Resize-14 6.145n ± 9% 1.854n ± 14% -69.83% (p=0.000 n=10) │ /tmp/old.txt │ /tmp/new.txt │ │ B/op │ B/op vs base │ Resize-14 5.000 ± 0% 5.000 ± 0% ~ (p=1.000 n=10) │ /tmp/old.txt │ /tmp/new.txt │ │ allocs/op │ allocs/op vs base │ Resize-14 0.000 ± 0% 0.000 ± 0% ~ (p=1.000 n=10) ¹ From the blocktest benchmark: 620ms 10.93s (flat, cum) 9.92% of Total . . 80:func (m *Memory) Resize(size uint64) { 30ms 60ms 81: if uint64(m.Len()) < size { 590ms 10.87s 82: m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) . . 83: } . . 84:} --------- Co-authored-by: Felix Lange --- core/vm/memory.go | 11 ++++++++--- core/vm/memory_test.go | 7 +++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/core/vm/memory.go b/core/vm/memory.go index 5e11e83748..54bc2b2849 100644 --- a/core/vm/memory.go +++ b/core/vm/memory.go @@ -44,6 +44,7 @@ func (m *Memory) Free() { // To reduce peak allocation, return only smaller memory instances to the pool. const maxBufferSize = 16 << 10 if cap(m.store) <= maxBufferSize { + clear(m.store) m.store = m.store[:0] m.lastGasCost = 0 memoryPool.Put(m) @@ -76,10 +77,14 @@ func (m *Memory) Set32(offset uint64, val *uint256.Int) { val.PutUint256(m.store[offset:]) } -// Resize resizes the memory to size +// Resize grows the memory to the requested size. func (m *Memory) Resize(size uint64) { - if uint64(m.Len()) < size { - m.store = append(m.store, make([]byte, size-uint64(m.Len()))...) + if uint64(len(m.store)) < size { + if uint64(cap(m.store)) >= size { + m.store = m.store[:size] + } else { + m.store = append(m.store, make([]byte, size-uint64(len(m.store)))...) + } } } diff --git a/core/vm/memory_test.go b/core/vm/memory_test.go index 41389b729a..3890d18cb5 100644 --- a/core/vm/memory_test.go +++ b/core/vm/memory_test.go @@ -83,3 +83,10 @@ func TestMemoryCopy(t *testing.T) { } } } + +func BenchmarkResize(b *testing.B) { + memory := NewMemory() + for i := range b.N { + memory.Resize(uint64(i)) + } +}