-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
VKT: Optimizations #147
VKT: Optimizations #147
Changes from all commits
0fedef4
45dd248
10d1f47
e889d40
fa84a2e
e5e29aa
d3f3017
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package tests | ||
|
||
import ( | ||
"fmt" | ||
"math/big" | ||
"math/rand" | ||
"testing" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/core/types" | ||
"github.com/ethereum/go-ethereum/ethdb/memorydb" | ||
"github.com/ethereum/go-ethereum/trie" | ||
"github.com/gballet/go-verkle" | ||
) | ||
|
||
func BenchmarkTriesRandom(b *testing.B) { | ||
numAccounts := []int{1_000, 5_000, 10_000} | ||
|
||
for _, numAccounts := range numAccounts { | ||
rs := rand.New(rand.NewSource(42)) | ||
accounts := getRandomStateAccounts(rs, numAccounts) | ||
|
||
b.Run(fmt.Sprintf("MPT/%d accounts", numAccounts), func(b *testing.B) { | ||
trie, _ := trie.NewStateTrie(trie.TrieID(common.Hash{}), trie.NewDatabase(memorydb.New())) | ||
b.ReportAllocs() | ||
b.ResetTimer() | ||
for i := 0; i < b.N; i++ { | ||
for k := 0; k < len(accounts); k++ { | ||
trie.TryUpdateAccount(accounts[k].address[:], &accounts[k].stateAccount) | ||
} | ||
trie.Commit(true) | ||
} | ||
}) | ||
b.Run(fmt.Sprintf("VKT/%d accounts", numAccounts), func(b *testing.B) { | ||
// Warmup VKT configuration | ||
trie.NewVerkleTrie(verkle.New(), trie.NewDatabase(memorydb.New())).TryUpdate([]byte("00000000000000000000000000000012"), []byte("B")) | ||
|
||
b.ReportAllocs() | ||
b.ResetTimer() | ||
for i := 0; i < b.N; i++ { | ||
trie := trie.NewVerkleTrie(verkle.New(), trie.NewDatabase(memorydb.New())) | ||
for k := 0; k < len(accounts); k++ { | ||
trie.TryUpdateAccount(accounts[k].address[:], &accounts[k].stateAccount) | ||
} | ||
trie.Commit(false) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
type randomAccount struct { | ||
address common.Address | ||
stateAccount types.StateAccount | ||
} | ||
|
||
func getRandomStateAccounts(rand *rand.Rand, count int) []randomAccount { | ||
randomBytes := func(size int) []byte { | ||
ret := make([]byte, size) | ||
rand.Read(ret) | ||
return ret | ||
} | ||
|
||
accounts := make([]randomAccount, count) | ||
for i := range accounts { | ||
accounts[i] = randomAccount{ | ||
address: common.BytesToAddress(randomBytes(common.AddressLength)), | ||
stateAccount: types.StateAccount{ | ||
Nonce: rand.Uint64(), | ||
Balance: big.NewInt(int64(rand.Uint64())), | ||
Root: common.Hash{}, | ||
CodeHash: nil, | ||
}, | ||
} | ||
} | ||
return accounts | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,9 +82,11 @@ func GetTreeKey(address []byte, treeIndex *uint256.Int, subIndex byte) []byte { | |
// 32-byte aligned big-endian representation (BE({00,...,AA,BB,CC})). | ||
// - poly[4]'s byte representation is the same as the *low* 16 bytes (trieIndexBytes[:16]) of | ||
// the 32-byte aligned big-endian representation (BE({00,00,...}). | ||
trieIndexBytes := treeIndex.Bytes32() | ||
verkle.FromBytes(&poly[3], trieIndexBytes[16:]) | ||
verkle.FromBytes(&poly[4], trieIndexBytes[:16]) | ||
if !treeIndex.IsZero() { | ||
trieIndexBytes := treeIndex.Bytes32() | ||
verkle.FromBytes(&poly[3], trieIndexBytes[16:]) | ||
verkle.FromBytes(&poly[4], trieIndexBytes[:16]) | ||
} | ||
Comment on lines
-85
to
+89
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. First optimization is avoiding work if |
||
|
||
cfg := verkle.GetConfig() | ||
ret := cfg.CommitToPoly(poly[:], 0) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -119,7 +119,7 @@ func (t *VerkleTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error | |
var ( | ||
err error | ||
nonce, balance [32]byte | ||
values = make([][]byte, verkle.NodeWidth) | ||
values = make([][]byte, 256) | ||
stem = utils.GetTreeKeyVersion(key[:]) | ||
) | ||
|
||
|
@@ -156,10 +156,9 @@ func (t *VerkleTrie) TryUpdateAccount(key []byte, acc *types.StateAccount) error | |
} | ||
|
||
func (trie *VerkleTrie) TryUpdateStem(key []byte, values [][]byte) { | ||
resolver := | ||
func(h []byte) ([]byte, error) { | ||
return trie.db.diskdb.Get(h) | ||
} | ||
resolver := func(h []byte) ([]byte, error) { | ||
return trie.db.diskdb.Get(h) | ||
} | ||
Comment on lines
-159
to
+161
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lint. |
||
switch root := trie.root.(type) { | ||
case *verkle.InternalNode: | ||
root.InsertStem(key, values, resolver) | ||
|
@@ -239,9 +238,23 @@ func nodeToDBKey(n verkle.VerkleNode) []byte { | |
// Commit writes all nodes to the trie's memory database, tracking the internal | ||
// and external (for account tries) references. | ||
func (trie *VerkleTrie) Commit(_ bool) (common.Hash, *NodeSet, error) { | ||
flush := make(chan verkle.VerkleNode) | ||
type vnflush struct { | ||
n verkle.VerkleNode | ||
value []byte | ||
dbKey []byte | ||
} | ||
flush := make(chan vnflush, 1024) | ||
resolver := func(n verkle.VerkleNode) { | ||
flush <- n | ||
value, err := n.Serialize() | ||
if err != nil { | ||
panic(err) | ||
} | ||
dbKey := nodeToDBKey(n) | ||
flush <- vnflush{ | ||
n: n, | ||
value: value, | ||
dbKey: dbKey, | ||
} | ||
Comment on lines
-242
to
+257
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking further at where the wall-clock time was going, I realized that after What I did in ethereum/go-verkle#314, is making To squeeze things more, the In a nutshell, since the resolver execution is exploiting all cores, we want to do as much work as possible there, so the main goroutine ranging L269 is receiving plain results to be stored in the This is important, since if the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So if #295 gets merged, |
||
} | ||
go func() { | ||
switch root := trie.root.(type) { | ||
|
@@ -255,12 +268,8 @@ func (trie *VerkleTrie) Commit(_ bool) (common.Hash, *NodeSet, error) { | |
var commitCount int | ||
for n := range flush { | ||
commitCount += 1 | ||
value, err := n.Serialize() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
if err := trie.db.diskdb.Put(nodeToDBKey(n), value); err != nil { | ||
if err := trie.db.diskdb.Put(n.dbKey, n.value); err != nil { | ||
return common.Hash{}, NewNodeSet(common.Hash{}), err | ||
} | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here we have the benchmarks from #146.
I only removed the statelessness one as we discussed, so we avoid test flags.