-
Notifications
You must be signed in to change notification settings - Fork 180
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
[EN Performance] Optimize MTrie reading single path by adding Ledger.GetSingleValue() to boost speed and reduce memory use #2473
[EN Performance] Optimize MTrie reading single path by adding Ledger.GetSingleValue() to boost speed and reduce memory use #2473
Conversation
- Added Ledger.GetSingleValue() to improve speed, alloc/op, and allocs/op - Modified delta.View.readFunc to use Ledger.GetSingleValue() - Optimized existing mtrie batch read for single path Bench comparision between current Ledger.Get() vs Ledger.GetSingleValue() Benchstat results: name old time/op new time/op delta LedgerGetOneValue/batch_get-4 6.54µs ± 0% 5.24µs ± 0% -19.92% (p=0.000 n=9+10) name old alloc/op new alloc/op delta LedgerGetOneValue/batch_get-4 1.74kB ± 0% 1.62kB ± 0% -6.85% (p=0.000 n=10+10) name old allocs/op new allocs/op delta LedgerGetOneValue/batch_get-4 21.0 ± 0% 15.0 ± 0% -28.57% (p=0.000 n=10+10) Bench comparision between optimized new Ledger.Get() vs Ledger.GetSingleValue() Benchstat results: name old time/op new time/op delta LedgerGetOneValue/batch_get-4 5.70µs ± 0% 5.23µs ± 0% -8.24% (p=0.000 n=9+10) name old alloc/op new alloc/op delta LedgerGetOneValue/batch_get-4 1.69kB ± 0% 1.62kB ± 0% -3.79% (p=0.000 n=10+10) name old allocs/op new allocs/op delta LedgerGetOneValue/batch_get-4 18.0 ± 0% 15.0 ± 0% -16.67% (p=0.000 n=10+10)
Codecov Report
@@ Coverage Diff @@
## master #2473 +/- ##
==========================================
- Coverage 56.94% 56.93% -0.02%
==========================================
Files 653 651 -2
Lines 60019 59979 -40
==========================================
- Hits 34180 34149 -31
+ Misses 22913 22897 -16
- Partials 2926 2933 +7
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report at Codecov.
|
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.
Nice work, excited for this one
we might actually add a single empty line to the FVM code to trigger the FVM benchmarking. |
Change Forest.Read to return []ledger.Value without deep copying payload keys. This avoids 4 heap allocation per key. This change doesn't affect the caller (Ledger.Get) because it discards the payload keys. name old time/op new time/op delta TrieRead-4 524µs ± 1% 420µs ± 1% -19.77% (p=0.000 n=10+10) name old alloc/op new alloc/op delta TrieRead-4 190kB ± 0% 95kB ± 0% -50.04% (p=0.000 n=10+10) name old allocs/op new allocs/op delta TrieRead-4 1.52k ± 0% 0.32k ± 0% -79.17% (p=0.000 n=10+10)
Changed Forest.ReadSingleValue to return ledger.Value without deep copying payload keys. This avoid 4 heap allocation per key. This change doesn't affect the caller (Ledger.GetSingleValue) because it discards the payload key.
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.
Thanks for taking the time to write complete test 👏🏼
ledger/complete/mtrie/trie/trie.go
Outdated
for !head.IsLeaf() { | ||
depth := ledger.NodeMaxHeight - head.Height() // distance to the tree root | ||
bit := bitutils.ReadBit(pathBytes, depth) | ||
if bit == 0 { | ||
head = head.LeftChild() | ||
} else { | ||
head = head.RightChild() | ||
} | ||
} |
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.
maybe sliiightly faster :)
for !head.IsLeaf() { | |
depth := ledger.NodeMaxHeight - head.Height() // distance to the tree root | |
bit := bitutils.ReadBit(pathBytes, depth) | |
if bit == 0 { | |
head = head.LeftChild() | |
} else { | |
head = head.RightChild() | |
} | |
} | |
depth := ledger.NodeMaxHeight - head.Height() // distance to the tree root | |
for !head.IsLeaf() { | |
bit := bitutils.ReadBit(pathBytes, depth) | |
if bit == 0 { | |
head = head.LeftChild() | |
} else { | |
head = head.RightChild() | |
} | |
depth++ | |
} |
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.
This optimization improves speed by 0.49% on Haswell CPU. Thanks for suggestion @tarakby. Co-authored-by: Tarak Ben Youssef <[email protected]>
…llocs Optimize Ledger.Get() by making Forest.Read() use ~5x fewer allocs/op and run ~20% faster
Changes
When reading a payload from a single path, avoid needlessly path partitioning and recursive calls. Also, optimize MTrie batch read.
Closes #1876
Benchmark comparisions
Current Ledger.Get() vs Ledger.GetSingleValue()
Optimized new Ledger.Get() vs Ledger.GetSingleValue()