Skip to content

Commit f41e8be

Browse files
committed
Add walk benchmark
1 parent c237a1a commit f41e8be

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

lib/trie/proof/generate.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ func Generate(rootHash []byte, fullKey []byte, database Database) (
4747
return encodedProofNodes, nil
4848
}
4949

50-
// TODO use pointer to slice to avoid recursive appending
5150
func walk(parent *node.Node, fullKey []byte) (
5251
encodedProofNodes [][]byte, err error) {
5352
if parent == nil {
@@ -81,7 +80,8 @@ func walk(parent *node.Node, fullKey []byte) (
8180
}
8281

8382
commonLength := lenCommonPrefix(parent.Key, fullKey)
84-
nextChild := parent.Children[fullKey[commonLength]]
83+
childIndex := fullKey[commonLength]
84+
nextChild := parent.Children[childIndex]
8585
nextFullKey := fullKey[commonLength+1:]
8686
deeperEncodedProofNodes, err := walk(nextChild, nextFullKey)
8787
if err != nil {

lib/trie/proof/generate_test.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import (
77
"errors"
88
"testing"
99

10+
"github.com/ChainSafe/gossamer/internal/trie/codec"
1011
"github.com/ChainSafe/gossamer/internal/trie/node"
12+
"github.com/ChainSafe/gossamer/lib/trie"
1113
"github.com/golang/mock/gomock"
1214
"github.com/stretchr/testify/assert"
15+
"github.com/stretchr/testify/require"
1316
)
1417

1518
func Test_Generate(t *testing.T) {
@@ -384,3 +387,39 @@ func Test_lenCommonPrefix(t *testing.T) {
384387
})
385388
}
386389
}
390+
391+
// Note on the performance of walk:
392+
// It was tried to optimise appending to the encodedProofNodes
393+
// slice by:
394+
// 1. appending to the same slice *[][]byte passed as argument
395+
// 2. appending the upper node to the deeper nodes slice
396+
// In both cases, the performance difference is very small
397+
// so the code is kept to this inefficient-looking append,
398+
// which is in the end quite performant still.
399+
func Benchmark_walk(b *testing.B) {
400+
trie := trie.NewEmptyTrie()
401+
402+
// Build a deep trie.
403+
const trieDepth = 1000
404+
for i := 0; i < trieDepth; i++ {
405+
keySize := 1 + i
406+
key := make([]byte, keySize)
407+
const trieValueSize = 10
408+
value := make([]byte, trieValueSize)
409+
410+
trie.Put(key, value)
411+
}
412+
413+
longestKeyLE := make([]byte, trieDepth)
414+
longestKeyNibbles := codec.KeyLEToNibbles(longestKeyLE)
415+
416+
rootNode := trie.RootNode()
417+
encodedProofNodes, err := walk(rootNode, longestKeyNibbles)
418+
require.NoError(b, err)
419+
require.Equal(b, len(encodedProofNodes), trieDepth)
420+
421+
b.ResetTimer()
422+
for i := 0; i < b.N; i++ {
423+
_, _ = walk(rootNode, longestKeyNibbles)
424+
}
425+
}

0 commit comments

Comments
 (0)