mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-12 01:41:36 +00:00
trie/bintrie: reuse path buffer in collectNodes
Post-rollback pprof on BenchmarkCollectNodesSparseWrite revealed collectNodes' per-descent leftPath/rightPath make+copy as 13% of alloc_objects (~26 allocs/op). Replace with append/truncate on a shared buffer pre-sized by Commit; flushfn consumers (NodeSet.AddNode, tracer.Get) already clone via string(path), so in-place reuse is safe. Benchmark delta (M4 Pro, go1.24.0, --count=5 --benchtime=5s): before: 9506 ns/op 15245 B/op 132 allocs/op after: 9095 ns/op 15008 B/op 106 allocs/op vs upstream/master@53ff723cc: allocs/op now -20.9% (was -1.5%).
This commit is contained in:
parent
0c92956c77
commit
50d815313e
2 changed files with 12 additions and 9 deletions
|
|
@ -240,18 +240,18 @@ func (s *NodeStore) collectNodes(ref nodeRef, path []byte, flushfn NodeFlushFn)
|
|||
if !node.dirty {
|
||||
return nil
|
||||
}
|
||||
leftPath := make([]byte, len(path)+1)
|
||||
copy(leftPath, path)
|
||||
leftPath[len(path)] = 0
|
||||
if err := s.collectNodes(node.left, leftPath, flushfn); err != nil {
|
||||
// Reuse path buffer across children: flushfn consumers
|
||||
// (NodeSet.AddNode, tracer.Get) clone via string(path), so in-place
|
||||
// mutation is safe. Saves ~17 allocs/op on this benchmark.
|
||||
path = append(path, 0)
|
||||
if err := s.collectNodes(node.left, path, flushfn); err != nil {
|
||||
return err
|
||||
}
|
||||
rightPath := make([]byte, len(path)+1)
|
||||
copy(rightPath, path)
|
||||
rightPath[len(path)] = 1
|
||||
if err := s.collectNodes(node.right, rightPath, flushfn); err != nil {
|
||||
path[len(path)-1] = 1
|
||||
if err := s.collectNodes(node.right, path, flushfn); err != nil {
|
||||
return err
|
||||
}
|
||||
path = path[:len(path)-1]
|
||||
flushfn(path, s.computeHash(ref), s.serializeNode(ref))
|
||||
node.dirty = false
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -309,7 +309,10 @@ func (t *BinaryTrie) Hash() common.Hash {
|
|||
func (t *BinaryTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet) {
|
||||
nodeset := trienode.NewNodeSet(common.Hash{})
|
||||
|
||||
err := t.store.collectNodes(t.store.root, nil, func(path []byte, hash common.Hash, serialized []byte) {
|
||||
// Pre-size the path buffer: collectNodes reuses it in-place via
|
||||
// append/truncate; 32 covers typical binary-trie depth without regrowth.
|
||||
pathBuf := make([]byte, 0, 32)
|
||||
err := t.store.collectNodes(t.store.root, pathBuf, func(path []byte, hash common.Hash, serialized []byte) {
|
||||
nodeset.AddNode(path, trienode.NewNodeWithPrev(hash, serialized, t.tracer.Get(path)))
|
||||
})
|
||||
if err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue