From 7c25f135efa07f78fe3b9d4cbc080803385b2308 Mon Sep 17 00:00:00 2001 From: stevemilk Date: Wed, 18 Sep 2024 23:47:12 +0800 Subject: [PATCH 1/5] trie: parallize committer --- core/state/statedb.go | 4 +- trie/committer.go | 128 +++++++++++++++++++++++++++++-------- trie/trie.go | 33 ++++++---- trie/trienode/node.go | 4 +- trie/trienode/node_test.go | 2 +- trie/verkle.go | 2 +- 6 files changed, 128 insertions(+), 45 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index 1a12f519a46c..31e48be1dbf8 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -945,7 +945,7 @@ func (s *StateDB) fastDeleteStorage(snaps *snapshot.Tree, addrHash common.Hash, slots = make(map[common.Hash][]byte) ) stack := trie.NewStackTrie(func(path []byte, hash common.Hash, blob []byte) { - nodes.AddNode(path, trienode.NewDeleted()) + nodes.AddNode(string(path), trienode.NewDeleted()) }) for iter.Next() { slot := common.CopyBytes(iter.Slot()) @@ -991,7 +991,7 @@ func (s *StateDB) slowDeleteStorage(addr common.Address, addrHash common.Hash, r if it.Hash() == (common.Hash{}) { continue } - nodes.AddNode(it.Path(), trienode.NewDeleted()) + nodes.AddNode(string(it.Path()), trienode.NewDeleted()) } if err := it.Error(); err != nil { return nil, nil, err diff --git a/trie/committer.go b/trie/committer.go index 863e7bafdc4b..a2ad2c2b42ea 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -18,6 +18,8 @@ package trie import ( "fmt" + "runtime" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/trie/trienode" @@ -30,28 +32,44 @@ type committer struct { nodes *trienode.NodeSet tracer *tracer collectLeaf bool + parallel bool } // newCommitter creates a new committer or picks one from the pool. -func newCommitter(nodeset *trienode.NodeSet, tracer *tracer, collectLeaf bool) *committer { +func newCommitter(nodes *trienode.NodeSet, tracer *tracer, collectLeaf bool, parallel bool) *committer { return &committer{ - nodes: nodeset, + nodes: nodes, tracer: tracer, collectLeaf: collectLeaf, + parallel: parallel, } } +type wrapNode struct { + node *trienode.Node + path string + leafHash common.Hash // optional, the parent hash of the relative leaf + leafBlob []byte // optional, the blob of the relative leaf +} + // Commit collapses a node down into a hash node. func (c *committer) Commit(n node) hashNode { - return c.commit(nil, n).(hashNode) + hn, wnodes := c.commit(nil, n, true) + for _, wn := range wnodes { + c.nodes.AddNode(wn.path, wn.node) + if wn.leafHash != (common.Hash{}) { + c.nodes.AddLeaf(wn.leafHash, wn.leafBlob) + } + } + return hn.(hashNode) } // commit collapses a node down into a hash node and returns it. -func (c *committer) commit(path []byte, n node) node { +func (c *committer) commit(path []byte, n node, topmost bool) (node, []*wrapNode) { // if this path is clean, use available cached data hash, dirty := n.cache() if hash != nil && !dirty { - return hash + return hash, nil } // Commit children, then parent, and remove the dirty flag. switch cn := n.(type) { @@ -61,38 +79,72 @@ func (c *committer) commit(path []byte, n node) node { // If the child is fullNode, recursively commit, // otherwise it can only be hashNode or valueNode. + var nodes []*wrapNode if _, ok := cn.Val.(*fullNode); ok { - collapsed.Val = c.commit(append(path, cn.Key...), cn.Val) + collapsed.Val, nodes = c.commit(append(path, cn.Key...), cn.Val, false) } // The key needs to be copied, since we're adding it to the // modified nodeset. collapsed.Key = hexToCompact(cn.Key) - hashedNode := c.store(path, collapsed) + hashedNode, wNode := c.store(path, collapsed) + if wNode != nil { + nodes = append(nodes, wNode) + } if hn, ok := hashedNode.(hashNode); ok { - return hn + return hn, nodes } - return collapsed + return collapsed, nodes case *fullNode: - hashedKids := c.commitChildren(path, cn) + hashedKids, nodes := c.commitChildren(path, cn, topmost && c.parallel) collapsed := cn.copy() collapsed.Children = hashedKids - hashedNode := c.store(path, collapsed) + hashedNode, wNode := c.store(path, collapsed) + if wNode != nil { + nodes = append(nodes, wNode) + } if hn, ok := hashedNode.(hashNode); ok { - return hn + return hn, nodes } - return collapsed + return collapsed, nodes case hashNode: - return cn + return cn, nil default: // nil, valuenode shouldn't be committed panic(fmt.Sprintf("%T: invalid node: %v", n, n)) } } +type task struct { + node node + index int + path []byte +} + // commitChildren commits the children of the given fullnode -func (c *committer) commitChildren(path []byte, n *fullNode) [17]node { - var children [17]node +func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) ([17]node, []*wrapNode) { + var ( + wg sync.WaitGroup + children [17]node + results [16][]*wrapNode + tasks = make(chan task) + ) + if parallel { + worker := func() { + defer wg.Done() + for t := range tasks { + children[t.index], results[t.index] = c.commit(t.path, t.node, false) + } + } + threads := runtime.NumCPU() + if threads > 16 { + threads = 16 + } + for i := 0; i < threads; i++ { + wg.Add(1) + go worker() + } + } for i := 0; i < 16; i++ { child := n.Children[i] if child == nil { @@ -108,18 +160,36 @@ func (c *committer) commitChildren(path []byte, n *fullNode) [17]node { // Commit the child recursively and store the "hashed" value. // Note the returned node can be some embedded nodes, so it's // possible the type is not hashNode. - children[i] = c.commit(append(path, byte(i)), child) + if !parallel { + children[i], results[i] = c.commit(append(path, byte(i)), child, false) + } else { + tasks <- task{ + index: i, + node: child, + path: append(path, byte(i)), + } + } + } + if parallel { + close(tasks) + wg.Wait() } // For the 17th child, it's possible the type is valuenode. if n.Children[16] != nil { children[16] = n.Children[16] } - return children + var wnodes []*wrapNode + for i := 0; i < 16; i++ { + if results[i] != nil { + wnodes = append(wnodes, results[i]...) + } + } + return children, wnodes } // store hashes the node n and adds it to the modified nodeset. If leaf collection // is enabled, leaf nodes will be tracked in the modified nodeset as well. -func (c *committer) store(path []byte, n node) node { +func (c *committer) store(path []byte, n node) (node, *wrapNode) { // Larger nodes are replaced by their hash and stored in the database. var hash, _ = n.cache() @@ -133,25 +203,33 @@ func (c *committer) store(path []byte, n node) node { // deleted only if the node was existent in database before. _, ok := c.tracer.accessList[string(path)] if ok { - c.nodes.AddNode(path, trienode.NewDeleted()) + return n, &wrapNode{ + path: string(path), + node: trienode.NewDeleted(), + } } - return n + return n, nil } - // Collect the dirty node to nodeset for return. nhash := common.BytesToHash(hash) - c.nodes.AddNode(path, trienode.New(nhash, nodeToBytes(n))) + wNode := &wrapNode{ + path: string(path), + node: trienode.New(nhash, nodeToBytes(n)), + } // Collect the corresponding leaf node if it's required. We don't check // full node since it's impossible to store value in fullNode. The key - // length of leaves should be exactly same. + // length of leaves should be exactly same.. if c.collectLeaf { if sn, ok := n.(*shortNode); ok { if val, ok := sn.Val.(valueNode); ok { c.nodes.AddLeaf(nhash, val) + wNode.leafHash = nhash + wNode.leafBlob = val } } } - return hash + + return hash, wNode } // ForGatherChildren decodes the provided node and traverses the children inside. diff --git a/trie/trie.go b/trie/trie.go index f44e10b918d4..1c7e6bcf5338 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -44,16 +44,17 @@ type Trie struct { // trie is not usable(latest states is invisible). committed bool - // Keep track of the number leaves which have been inserted since the last - // hashing operation. This number will not directly map to the number of - // actually unhashed nodes. - unhashed int - // reader is the handler trie can retrieve nodes from. reader *trieReader // tracer is the tool to track the trie changes. tracer *tracer + + // The number of trie mutations that have been performed + mutate int + + // The number of mutations that have been hashed + hashed int } // newFlag returns the cache flag value for a newly created node. @@ -67,9 +68,10 @@ func (t *Trie) Copy() *Trie { root: t.root, owner: t.owner, committed: t.committed, - unhashed: t.unhashed, reader: t.reader, tracer: t.tracer.copy(), + mutate: t.mutate, + hashed: t.hashed, } } @@ -304,11 +306,12 @@ func (t *Trie) Update(key, value []byte) error { if t.committed { return ErrCommitted } + t.mutate++ return t.update(key, value) } func (t *Trie) update(key, value []byte) error { - t.unhashed++ + t.mutate++ k := keybytesToHex(key) if len(value) != 0 { _, n, err := t.insert(t.root, nil, k, valueNode(value)) @@ -422,7 +425,7 @@ func (t *Trie) Delete(key []byte) error { if t.committed { return ErrCommitted } - t.unhashed++ + t.mutate++ k := keybytesToHex(key) _, n, err := t.delete(t.root, nil, k) if err != nil { @@ -622,7 +625,7 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { } nodes := trienode.NewNodeSet(t.owner) for _, path := range paths { - nodes.AddNode([]byte(path), trienode.NewDeleted()) + nodes.AddNode(path, trienode.NewDeleted()) } return types.EmptyRootHash, nodes // case (b) } @@ -640,9 +643,10 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { } nodes := trienode.NewNodeSet(t.owner) for _, path := range t.tracer.deletedNodes() { - nodes.AddNode([]byte(path), trienode.NewDeleted()) + nodes.AddNode(path, trienode.NewDeleted()) } - t.root = newCommitter(nodes, t.tracer, collectLeaf).Commit(t.root) + t.root = newCommitter(nodes, t.tracer, collectLeaf, t.mutate > 100).Commit(t.root) + t.mutate = 0 return rootHash, nodes } @@ -652,10 +656,10 @@ func (t *Trie) hashRoot() (node, node) { return hashNode(types.EmptyRootHash.Bytes()), nil } // If the number of changes is below 100, we let one thread handle it - h := newHasher(t.unhashed >= 100) + h := newHasher(t.mutate-t.hashed >= 100) defer func() { returnHasherToPool(h) - t.unhashed = 0 + t.hashed = t.mutate }() hashed, cached := h.hash(t.root, true) return hashed, cached @@ -677,7 +681,8 @@ func (t *Trie) Witness() map[string]struct{} { func (t *Trie) Reset() { t.root = nil t.owner = common.Hash{} - t.unhashed = 0 t.tracer.reset() t.committed = false + t.hashed = 0 + t.mutate = 0 } diff --git a/trie/trienode/node.go b/trie/trienode/node.go index 09f355f3b590..cb123df2c508 100644 --- a/trie/trienode/node.go +++ b/trie/trienode/node.go @@ -90,13 +90,13 @@ func (set *NodeSet) ForEachWithOrder(callback func(path string, n *Node)) { } // AddNode adds the provided node into set. -func (set *NodeSet) AddNode(path []byte, n *Node) { +func (set *NodeSet) AddNode(path string, n *Node) { if n.IsDeleted() { set.deletes += 1 } else { set.updates += 1 } - set.Nodes[string(path)] = n + set.Nodes[path] = n } // Merge adds a set of nodes into the set. diff --git a/trie/trienode/node_test.go b/trie/trienode/node_test.go index bcb3a2202b53..7829d59c08b8 100644 --- a/trie/trienode/node_test.go +++ b/trie/trienode/node_test.go @@ -42,7 +42,7 @@ func benchmarkMerge(b *testing.B, count int) { blob := make([]byte, 32) rand.Read(blob) hash := crypto.Keccak256Hash(blob) - s.AddNode(path, New(hash, blob)) + s.AddNode(string(path), New(hash, blob)) } for i := 0; i < count; i++ { // Random path of 4 nibbles diff --git a/trie/verkle.go b/trie/verkle.go index 6bd9d3d1af5a..29d69cde3462 100644 --- a/trie/verkle.go +++ b/trie/verkle.go @@ -258,7 +258,7 @@ func (t *VerkleTrie) Commit(_ bool) (common.Hash, *trienode.NodeSet) { nodeset := trienode.NewNodeSet(common.Hash{}) for _, node := range nodes { // Hash parameter is not used in pathdb - nodeset.AddNode(node.Path, trienode.New(common.Hash{}, node.SerializedBytes)) + nodeset.AddNode(string(node.Path), trienode.New(common.Hash{}, node.SerializedBytes)) } // Serialize root commitment form return t.Hash(), nodeset From b4db8bacdf52660f0adc50fa8162140882e470ba Mon Sep 17 00:00:00 2001 From: stevemilk Date: Thu, 19 Sep 2024 00:42:59 +0800 Subject: [PATCH 2/5] add benchmark test --- trie/committer.go | 1 - trie/trie_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/trie/committer.go b/trie/committer.go index a2ad2c2b42ea..b853715a7973 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -222,7 +222,6 @@ func (c *committer) store(path []byte, n node) (node, *wrapNode) { if c.collectLeaf { if sn, ok := n.(*shortNode); ok { if val, ok := sn.Val.(valueNode); ok { - c.nodes.AddLeaf(nhash, val) wNode.leafHash = nhash wNode.leafBlob = val } diff --git a/trie/trie_test.go b/trie/trie_test.go index 505b517bc593..d7e2b8ac5949 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -35,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/internal/testrand" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/holiman/uint256" @@ -1206,3 +1207,43 @@ func FuzzTrie(f *testing.F) { } }) } + +func BenchmarkCommit(b *testing.B) { + benchmarkCommit(b, 500) + benchmarkCommit(b, 1000) + benchmarkCommit(b, 2000) + benchmarkCommit(b, 5000) +} + +func benchmarkCommit(b *testing.B, n int) { + b.Run(fmt.Sprintf("commit-%vnodes-single", n), func(b *testing.B) { + testCommit(b, n, false) + }) + + b.Run(fmt.Sprintf("commit-%vnodes-parallel", n), func(b *testing.B) { + testCommit(b, n, true) + }) +} + +func testCommit(b *testing.B, n int, parallel bool) { + // test 10 times to get a better average + N := 10 + tries := make([]*Trie, N) + for i := 0; i < N; i++ { + tries[i] = NewEmpty(nil) + for j := 0; j < n; j++ { + key := testrand.Bytes(32) + val := testrand.Bytes(32) + tries[i].Update(key, val) + } + tries[i].Hash() + if !parallel { + tries[i].mutate = 0 + } + } + + b.ResetTimer() + for i := 0; i < 10; i++ { + tries[i].Commit(true) + } +} From ed692c19b656588894db6f8e4cf8121cd58e2981 Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Thu, 19 Sep 2024 11:24:15 +0800 Subject: [PATCH 3/5] trie: polish the changes --- trie/committer.go | 37 +++++-------------------------------- trie/trie.go | 27 ++++++++------------------- trie/trie_test.go | 41 ----------------------------------------- 3 files changed, 13 insertions(+), 92 deletions(-) diff --git a/trie/committer.go b/trie/committer.go index b853715a7973..1d7b6fc5f0c1 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -18,7 +18,6 @@ package trie import ( "fmt" - "runtime" "sync" "github.com/ethereum/go-ethereum/common" @@ -115,36 +114,13 @@ func (c *committer) commit(path []byte, n node, topmost bool) (node, []*wrapNode } } -type task struct { - node node - index int - path []byte -} - // commitChildren commits the children of the given fullnode func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) ([17]node, []*wrapNode) { var ( wg sync.WaitGroup children [17]node results [16][]*wrapNode - tasks = make(chan task) ) - if parallel { - worker := func() { - defer wg.Done() - for t := range tasks { - children[t.index], results[t.index] = c.commit(t.path, t.node, false) - } - } - threads := runtime.NumCPU() - if threads > 16 { - threads = 16 - } - for i := 0; i < threads; i++ { - wg.Add(1) - go worker() - } - } for i := 0; i < 16; i++ { child := n.Children[i] if child == nil { @@ -163,15 +139,14 @@ func (c *committer) commitChildren(path []byte, n *fullNode, parallel bool) ([17 if !parallel { children[i], results[i] = c.commit(append(path, byte(i)), child, false) } else { - tasks <- task{ - index: i, - node: child, - path: append(path, byte(i)), - } + wg.Add(1) + go func(index int) { + defer wg.Done() + children[index], results[index] = c.commit(append(path, byte(index)), child, false) + }(i) } } if parallel { - close(tasks) wg.Wait() } // For the 17th child, it's possible the type is valuenode. @@ -215,7 +190,6 @@ func (c *committer) store(path []byte, n node) (node, *wrapNode) { path: string(path), node: trienode.New(nhash, nodeToBytes(n)), } - // Collect the corresponding leaf node if it's required. We don't check // full node since it's impossible to store value in fullNode. The key // length of leaves should be exactly same.. @@ -227,7 +201,6 @@ func (c *committer) store(path []byte, n node) (node, *wrapNode) { } } } - return hash, wNode } diff --git a/trie/trie.go b/trie/trie.go index 1c7e6bcf5338..025915994d40 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -37,24 +37,13 @@ import ( // // Trie is not safe for concurrent use. type Trie struct { - root node - owner common.Hash - - // Flag whether the commit operation is already performed. If so the - // trie is not usable(latest states is invisible). - committed bool - - // reader is the handler trie can retrieve nodes from. - reader *trieReader - - // tracer is the tool to track the trie changes. - tracer *tracer - - // The number of trie mutations that have been performed - mutate int - - // The number of mutations that have been hashed - hashed int + root node + owner common.Hash + committed bool // The Flag whether the commit operation is already performed + reader *trieReader // The handler trie can retrieve nodes from + tracer *tracer // The tool to track the trie changes + mutate int // The number of trie mutations that have been performed + hashed int // The number of mutations that have been hashed } // newFlag returns the cache flag value for a newly created node. @@ -311,7 +300,6 @@ func (t *Trie) Update(key, value []byte) error { } func (t *Trie) update(key, value []byte) error { - t.mutate++ k := keybytesToHex(key) if len(value) != 0 { _, n, err := t.insert(t.root, nil, k, valueNode(value)) @@ -645,6 +633,7 @@ func (t *Trie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet) { for _, path := range t.tracer.deletedNodes() { nodes.AddNode(path, trienode.NewDeleted()) } + // If the number of changes is below 100, we let one thread handle it t.root = newCommitter(nodes, t.tracer, collectLeaf, t.mutate > 100).Commit(t.root) t.mutate = 0 return rootHash, nodes diff --git a/trie/trie_test.go b/trie/trie_test.go index d7e2b8ac5949..505b517bc593 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -35,7 +35,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" - "github.com/ethereum/go-ethereum/internal/testrand" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/holiman/uint256" @@ -1207,43 +1206,3 @@ func FuzzTrie(f *testing.F) { } }) } - -func BenchmarkCommit(b *testing.B) { - benchmarkCommit(b, 500) - benchmarkCommit(b, 1000) - benchmarkCommit(b, 2000) - benchmarkCommit(b, 5000) -} - -func benchmarkCommit(b *testing.B, n int) { - b.Run(fmt.Sprintf("commit-%vnodes-single", n), func(b *testing.B) { - testCommit(b, n, false) - }) - - b.Run(fmt.Sprintf("commit-%vnodes-parallel", n), func(b *testing.B) { - testCommit(b, n, true) - }) -} - -func testCommit(b *testing.B, n int, parallel bool) { - // test 10 times to get a better average - N := 10 - tries := make([]*Trie, N) - for i := 0; i < N; i++ { - tries[i] = NewEmpty(nil) - for j := 0; j < n; j++ { - key := testrand.Bytes(32) - val := testrand.Bytes(32) - tries[i].Update(key, val) - } - tries[i].Hash() - if !parallel { - tries[i].mutate = 0 - } - } - - b.ResetTimer() - for i := 0; i < 10; i++ { - tries[i].Commit(true) - } -} From 8ef6da69a204087322535a570561a47d53eff035 Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Thu, 19 Sep 2024 11:38:28 +0800 Subject: [PATCH 4/5] trie: add back bench tests --- trie/committer.go | 6 ++--- trie/trie_test.go | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/trie/committer.go b/trie/committer.go index 1d7b6fc5f0c1..050bc39fda0d 100644 --- a/trie/committer.go +++ b/trie/committer.go @@ -47,8 +47,8 @@ func newCommitter(nodes *trienode.NodeSet, tracer *tracer, collectLeaf bool, par type wrapNode struct { node *trienode.Node path string - leafHash common.Hash // optional, the parent hash of the relative leaf - leafBlob []byte // optional, the blob of the relative leaf + leafHash common.Hash // optional, the parent hash of the related leaf + leafBlob []byte // optional, the blob of the related leaf } // Commit collapses a node down into a hash node. @@ -192,7 +192,7 @@ func (c *committer) store(path []byte, n node) (node, *wrapNode) { } // Collect the corresponding leaf node if it's required. We don't check // full node since it's impossible to store value in fullNode. The key - // length of leaves should be exactly same.. + // length of leaves should be exactly same. if c.collectLeaf { if sn, ok := n.(*shortNode); ok { if val, ok := sn.Val.(valueNode); ok { diff --git a/trie/trie_test.go b/trie/trie_test.go index 505b517bc593..038330e759fe 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -21,6 +21,7 @@ import ( "encoding/binary" "errors" "fmt" + "github.com/ethereum/go-ethereum/internal/testrand" "hash" "io" "math/rand" @@ -1206,3 +1207,70 @@ func FuzzTrie(f *testing.F) { } }) } + +// goos: darwin +// goarch: arm64 +// pkg: github.com/ethereum/go-ethereum/trie +// BenchmarkCommit/commit-100nodes-single +// BenchmarkCommit/commit-100nodes-single-8 13508 90490 ns/op 115151 B/op 1461 allocs/op +// BenchmarkCommit/commit-100nodes-parallel +// BenchmarkCommit/commit-100nodes-parallel-8 13897 87488 ns/op 115208 B/op 1462 allocs/op +// BenchmarkCommit/commit-200nodes-single +// BenchmarkCommit/commit-200nodes-single-8 5971 182548 ns/op 233411 B/op 2935 allocs/op +// BenchmarkCommit/commit-200nodes-parallel +// BenchmarkCommit/commit-200nodes-parallel-8 5972 194446 ns/op 235053 B/op 2967 allocs/op +// BenchmarkCommit/commit-500nodes-single +// BenchmarkCommit/commit-500nodes-single-8 2443 444320 ns/op 604342 B/op 7604 allocs/op +// BenchmarkCommit/commit-500nodes-parallel +// BenchmarkCommit/commit-500nodes-parallel-8 2930 360024 ns/op 606174 B/op 7638 allocs/op +// BenchmarkCommit/commit-1000nodes-single +// BenchmarkCommit/commit-1000nodes-single-8 1353 911020 ns/op 1174328 B/op 14818 allocs/op +// BenchmarkCommit/commit-1000nodes-parallel +// BenchmarkCommit/commit-1000nodes-parallel-8 2217 615980 ns/op 1175860 B/op 14849 allocs/op +// BenchmarkCommit/commit-2000nodes-single +// BenchmarkCommit/commit-2000nodes-single-8 684 1765588 ns/op 2305835 B/op 28858 allocs/op +// BenchmarkCommit/commit-2000nodes-parallel +// BenchmarkCommit/commit-2000nodes-parallel-8 1153 1025471 ns/op 2307711 B/op 28890 allocs/op +// BenchmarkCommit/commit-5000nodes-single +// BenchmarkCommit/commit-5000nodes-single-8 250 4762405 ns/op 6471036 B/op 74907 allocs/op +// BenchmarkCommit/commit-5000nodes-parallel +// BenchmarkCommit/commit-5000nodes-parallel-8 450 2725071 ns/op 6471357 B/op 74938 allocs/op +func BenchmarkCommit(b *testing.B) { + benchmarkCommit(b, 100) + benchmarkCommit(b, 200) + benchmarkCommit(b, 500) + benchmarkCommit(b, 1000) + benchmarkCommit(b, 2000) + benchmarkCommit(b, 5000) +} + +func benchmarkCommit(b *testing.B, n int) { + b.Run(fmt.Sprintf("commit-%vnodes-single", n), func(b *testing.B) { + testCommit(b, n, false) + }) + b.Run(fmt.Sprintf("commit-%vnodes-parallel", n), func(b *testing.B) { + testCommit(b, n, true) + }) +} + +func testCommit(b *testing.B, n int, parallel bool) { + tries := make([]*Trie, b.N) + for i := 0; i < b.N; i++ { + tries[i] = NewEmpty(nil) + for j := 0; j < n; j++ { + key := testrand.Bytes(32) + val := testrand.Bytes(32) + tries[i].Update(key, val) + } + tries[i].Hash() + if !parallel { + tries[i].mutate = 0 + } + } + b.ResetTimer() + b.ReportAllocs() + + for i := 0; i < len(tries); i++ { + tries[i].Commit(true) + } +} From f8bc1a0d1e8d620032518518d8489586dff718b4 Mon Sep 17 00:00:00 2001 From: stevemilk Date: Thu, 19 Sep 2024 14:24:30 +0800 Subject: [PATCH 5/5] sort imports --- trie/trie_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trie/trie_test.go b/trie/trie_test.go index 038330e759fe..671d2de90758 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -21,7 +21,6 @@ import ( "encoding/binary" "errors" "fmt" - "github.com/ethereum/go-ethereum/internal/testrand" "hash" "io" "math/rand" @@ -36,6 +35,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethdb" + "github.com/ethereum/go-ethereum/internal/testrand" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie/trienode" "github.com/holiman/uint256"