mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-12 01:41:36 +00:00
trie/bintrie: keep StemNode.Hash's data array on stack
The pooled hash.Hash interface forced the local [StemNodeWidth]common.Hash data array to escape to the heap: h.Sum(data[i][:0]) passes a subslice of data into an interface method, so escape analysis conservatively moves the whole array. pprof (post-rollback) showed this single allocation as 52% of total bytes (5 GB over BenchmarkCollectNodesSparseWrite). Switch to sha256.Sum256 (takes []byte, returns [32]byte by value) — no slice into data ever leaves the frame, so data stays on stack. Also drops per-Hash h.Sum(nil) allocs and the sync.Pool Get/Put round-trip for stems. Benchmark delta (M4 Pro, go1.24.0, --count=5 --benchtime=5s): before: 9095 ns/op 15008 B/op 106 allocs/op after: 9133 ns/op 6526 B/op 95 allocs/op vs upstream/master@53ff723cc: bytes/op -82.7% (was -60%), allocs/op -29.1% (was -20.9%).
This commit is contained in:
parent
50d815313e
commit
ef3217c249
1 changed files with 16 additions and 14 deletions
|
|
@ -17,6 +17,8 @@
|
|||
package bintrie
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
|
|
@ -58,36 +60,36 @@ func (sn *StemNode) Hash() common.Hash {
|
|||
return sn.hash
|
||||
}
|
||||
|
||||
// Use sha256.Sum256 (returns [32]byte by value) instead of a pooled
|
||||
// hash.Hash: feeding data[i][:0] into the interface method Sum forces
|
||||
// data to heap (escape analysis is conservative through interfaces).
|
||||
// Sum256 takes []byte and returns by value, so data stays on stack.
|
||||
var data [StemNodeWidth]common.Hash
|
||||
h := newSha256()
|
||||
defer returnSha256(h)
|
||||
|
||||
for i, v := range sn.values {
|
||||
if v != nil {
|
||||
h.Reset()
|
||||
h.Write(v)
|
||||
h.Sum(data[i][:0])
|
||||
data[i] = sha256.Sum256(v)
|
||||
}
|
||||
}
|
||||
|
||||
var pair [2 * HashSize]byte
|
||||
for level := 1; level <= 8; level++ {
|
||||
for i := range StemNodeWidth / (1 << level) {
|
||||
if data[i*2] == (common.Hash{}) && data[i*2+1] == (common.Hash{}) {
|
||||
data[i] = common.Hash{}
|
||||
continue
|
||||
}
|
||||
h.Reset()
|
||||
h.Write(data[i*2][:])
|
||||
h.Write(data[i*2+1][:])
|
||||
data[i] = common.Hash(h.Sum(nil))
|
||||
copy(pair[:HashSize], data[i*2][:])
|
||||
copy(pair[HashSize:], data[i*2+1][:])
|
||||
data[i] = sha256.Sum256(pair[:])
|
||||
}
|
||||
}
|
||||
|
||||
h.Reset()
|
||||
h.Write(sn.Stem[:])
|
||||
h.Write([]byte{0})
|
||||
h.Write(data[0][:])
|
||||
sn.hash = common.BytesToHash(h.Sum(nil))
|
||||
var final [StemSize + 1 + HashSize]byte
|
||||
copy(final[:StemSize], sn.Stem[:])
|
||||
final[StemSize] = 0
|
||||
copy(final[StemSize+1:], data[0][:])
|
||||
sn.hash = sha256.Sum256(final[:])
|
||||
sn.mustRecompute = false
|
||||
return sn.hash
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue