-
Notifications
You must be signed in to change notification settings - Fork 760
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
VM: add simple benchmarking tool for mainnet blocks #794
Conversation
Codecov Report
Flags with carried forward coverage won't be shown. Click here to find out more. |
Hi @s1na, great start on this! 😄 Can we move this out of |
Yeah I did that first but couldn't get it quickly working with the current tsconfig and didn't want to struggle too much with that. I can look into it again before merging or would appreciate if somebody has ideas how I can change tsconfig. I didn't want to use |
add `tsconfig.benchmarks.json` and npm run script `build:benchmarks` add benchmarks instructions to `developer.md`
ok great in ee21a7b I did the following:
|
The
Can we get this data from Infura? If so I could write a block fetcher script to eliminate the need for storing the fixture. |
Oh amazing thanks a lot for doing that! Re the fixture file: I have the scripts already but we unfortunately can't use Infura as it doesn't have the
|
…loper doc improvements
Added an additional CL option here to determine the number of samples run, together with some other UX improvements. One thing which catches the eye is that block processing times increase close to linearly with the number of samples run, some output: 30 Blocks Total number of blocks: 50
Blocks to proceed: 30
running block 9422905
Running block 9422905 took 46 s, 577.091 ms
running block 9422906 3 Blocks Total number of blocks: 50
Blocks to proceed: 3
running block 9422905
Running block 9422905 took 6 s, 41.155 ms
running block 9422906
Running block 9422906 took 7 s, 60.951 ms
running block 9422907
Running block 9422907 took 9 s, 386.196 ms (just a small extract, but this is repeatable) Cause is likely due to the preState being aggregated before block run, since this causes a larger initial state. I nevertheless wonder if this is already a hint to a strong performance bottleneck, since having a linear run time increase here together with a linear state size increase seems very much too much to me. @s1na Side question: was this an intentional decision to aggregate this preState all before? Wouldn't the results be more repeatable if every block preState is just added/replaced before the respective block execution? |
Flamegraphs on this are actually impressive, the following is the 3 blocks graph: The following the 30 block graph (with an additional conditional break after 3 blocks for comparison): This is the source of the single most impressively grown graph block, being in MPT: This refers to the For reference: this is the commit @s1na mentioned being the likely source for speed deterioration in MPT (both necessarily doesn't need to be completely logically interlinked though and can at least partly point to different problems). |
Played around with this for 2 hours, some observations and ideas. One preceeding note: the MPT _walkTrie code with all these nested callbacks and passed-on function executions is absurdly complicated to follow and it is close to impossible to identify structural suboptimalities. This is in SUPER need for a rewrite/refactor, maybe some of the most important ones we have right now I would say. Ok, on to the performance topic:
Ok, so far. 🙂 Yes, I can confirm that this is fun. 😜 Tried this for /**
* Flushes cache by updating accounts that have been modified
* and removing accounts that have been deleted.
*/
async flush(): Promise<void> {
const it = this._cache.begin
let next = true
const batch = []
while (next) {
if (it.value && it.value.modified) {
it.value.modified = false
it.value.val = it.value.val.serialize()
//console.log('Written to trie (flush)')
// await this._trie.put(Buffer.from(it.key, 'hex'), it.value.val)
batch.push({ type: 'put', key: Buffer.from(it.key, 'hex'), value: it.value.val})
next = it.hasNext
it.next()
} else if (it.value && it.value.deleted) {
it.value.modified = false
it.value.deleted = false
it.value.val = new Account().serialize()
//console.log('Deleted from trie (flush)')
// await this._trie.del(Buffer.from(it.key, 'hex'))
batch.push({ type: 'del', key: Buffer.from(it.key, 'hex') })
next = it.hasNext
it.next()
} else {
next = it.hasNext
it.next()
}
}
await this._trie.batch(batch)
} |
Once we get to some stable ground here we should likely also reapply this PR towards a to be created vm/4.x branch branching off the latest |
Blog post on how to post a comment from a JS script with GitHub Actions: https://dev.to/koushikmohan1996/writing-your-first-github-action-42cg Should be doable. Not sure about the part on how to get results from the target branch (normally: master) and do a comparison within the script against the PR branch results. |
configure rhysd/github-action-benchmark
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.
Looks good
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.
Renewed approval after editing merge conflict
@ryanio Sorry, I was eventually a bit too much in a merge-mode yesterday and didn't check too well 😬 , just gave this another test locally and the script actually doesn't come to an end (on my machine), so this is my output: $ npm run benchmarks
> @ethereumjs/[email protected] benchmarks /ethereumjs-vm/packages/vm
> node --max-old-space-size=4096 ./scripts/benchmarks/mainnetBlocks.js scripts/benchmarks/fixture/blocks-prestate.json
Total number of blocks in data set: 15
Number of blocks to sample: 15
Block 9422905 x 1,879 ops/sec ±8.36% (81 runs sampled)
Block 9422906 x 2,070 ops/sec ±1.05% (89 runs sampled)
Block 9422907 x 1,535 ops/sec ±14.69% (69 runs sampled)
Block 9422908 x 1,624 ops/sec ±6.96% (73 runs sampled)
Block 9422909 x 1,856 ops/sec ±3.67% (83 runs sampled)
Block 9422910 x 1,938 ops/sec ±1.23% (91 runs sampled)
Block 9422911 x 766 ops/sec ±20.47% (36 runs sampled)
Block 9422912 x 1,881 ops/sec ±1.16% (91 runs sampled)
Block 9422913 x 1,845 ops/sec ±1.38% (86 runs sampled)
Block 9422914 x 1,792 ops/sec ±2.72% (82 runs sampled)
Block 9422915 x 618 ops/sec ±17.75% (33 runs sampled)
Block 9422916 x 344 ops/sec ±73.57% (34 runs sampled)
Block 9422917 x 1,648 ops/sec ±7.34% (83 runs sampled)
Block 9422918 x 1,711 ops/sec ±3.01% (78 runs sampled)
Block 9422919 x 1,750 ops/sec ±1.19% (87 runs sampled) Here, the script comes to a halt and doesn't continue or finish. Also, the CI run on master failed, seems there need to be the |
@holgerd77 no worries! That is the end of the script actually, the results are then used for github-action-benchmarks I opened #838 to resolve the package-lock issue. |
This helps us see how the VM performs when running mainnet blocks. The script is still WIP and has a few known issues, but it's good for a rough estimate. To use it build the VM and run:
If you want to get a more detailed look to find bottlenecks we can use 0x. So run:
and open the link it generates.