Skip to content

Conversation

@ilitteri
Copy link
Contributor

@ilitteri ilitteri commented Sep 23, 2025

Motivation

The original is_blacklisted function in JumpTargetFilter was a performance bottleneck, consuming ~30% of execution time during mainnet blocks stateless execution.

Description

Inspired by Geth's codeBitmap approach, this PR:

  1. Replaces incremental iteration with a one-time precompute method that scans the entire bytecode, building a BitVec<u8, Lsb0> where bits mark valid JUMPDEST positions, skipping PUSH1..PUSH32 data bytes.
  2. Updates is_blacklisted to O(1) bit lookup: address >= bytecode.len() || !jumpdests[address].

Performance Results

Execution Times
Average speedup: 1.083x

  • Main branch: Min 29.475s (Block 23619121), Max 67.000s (Block 23619120), Avg 45.458s
  • Optimized: Min 26.643s (Block 23619121), Max 64.000s (Block 23619120), Avg 42.109s
  • Speedup range: 1.047x–1.123x
Block Main (s) Optimized (s) Speedup
23619120 67.000 64.000 1.047x
23619121 29.475 26.643 1.106x
23619122 55.056 51.765 1.064x
23619123 41.581 38.142 1.090x
23619124 44.642 41.739 1.070x
23619125 32.549 28.983 1.123x
23619126 66.000 60.000 1.100x
23619127 42.999 40.370 1.065x
23619128 46.316 43.237 1.071x
23619129 36.977 34.184 1.082x
23619130 37.445 34.135 1.097x

Proving Times
Average speedup: 1.123x

  • Main branch: Min 844.000s (Block 23619121), Max 1937.000s (Block 23619126), Avg 1289.091s
  • Optimized: Min 731.000s (Block 23619121), Max 1707.000s (Block 23619126), Avg 1151.364s
  • Speedup range: 1.092x–1.155x
Block Main (s) Optimized (s) Speedup
23619120 1464.000 1325.000 1.105x
23619121 844.000 731.000 1.155x
23619122 1560.000 1429.000 1.092x
23619123 1138.000 1013.000 1.123x
23619124 1285.000 1158.000 1.110x
23619125 1045.000 915.000 1.142x
23619126 1937.000 1707.000 1.135x
23619127 1312.000 1187.000 1.105x
23619128 1486.000 1351.000 1.100x
23619129 1039.000 908.000 1.144x
23619130 1070.000 941.000 1.137x

Higher-gas blocks (e.g., 23619126) show the most gains, improving scalability for zkVM workloads.

@ilitteri ilitteri self-assigned this Sep 23, 2025
@github-actions github-actions bot added levm Lambda EVM implementation performance Block execution throughput and performance in general labels Sep 23, 2025
@github-actions
Copy link

github-actions bot commented Sep 23, 2025

Lines of code report

Total lines added: 1
Total lines removed: 0
Total lines changed: 1

Detailed view
+------------------------------------+-------+------+
| File                               | Lines | Diff |
+------------------------------------+-------+------+
| ethrex/crates/vm/levm/src/utils.rs | 425   | +1   |
+------------------------------------+-------+------+

@github-actions
Copy link

github-actions bot commented Sep 23, 2025

Benchmark Results Comparison

No significant difference was registered for any benchmark run.

Detailed Results

Benchmark Results: BubbleSort

Command Mean [s] Min [s] Max [s] Relative
main_revm_BubbleSort 4.796 ± 0.027 4.766 4.848 1.04 ± 0.01
main_levm_BubbleSort 4.623 ± 0.037 4.592 4.711 1.00
pr_revm_BubbleSort 4.818 ± 0.015 4.801 4.853 1.04 ± 0.01
pr_levm_BubbleSort 4.661 ± 0.017 4.646 4.694 1.01 ± 0.01

Benchmark Results: ERC20Approval

Command Mean [s] Min [s] Max [s] Relative
main_revm_ERC20Approval 1.564 ± 0.004 1.557 1.570 1.00
main_levm_ERC20Approval 1.631 ± 0.016 1.618 1.672 1.04 ± 0.01
pr_revm_ERC20Approval 1.591 ± 0.014 1.580 1.625 1.02 ± 0.01
pr_levm_ERC20Approval 1.654 ± 0.012 1.638 1.676 1.06 ± 0.01

Benchmark Results: ERC20Mint

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Mint 186.8 ± 0.8 185.9 188.3 1.00
main_levm_ERC20Mint 200.5 ± 4.1 198.2 210.3 1.07 ± 0.02
pr_revm_ERC20Mint 189.5 ± 0.3 188.9 189.8 1.01 ± 0.00
pr_levm_ERC20Mint 201.4 ± 1.6 199.3 204.3 1.08 ± 0.01

Benchmark Results: ERC20Transfer

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ERC20Transfer 357.5 ± 5.3 354.5 372.2 1.00
main_levm_ERC20Transfer 384.5 ± 3.4 381.0 390.5 1.08 ± 0.02
pr_revm_ERC20Transfer 363.3 ± 2.5 360.2 368.1 1.02 ± 0.02
pr_levm_ERC20Transfer 389.2 ± 3.5 385.7 395.3 1.09 ± 0.02

Benchmark Results: Factorial

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Factorial 236.1 ± 1.2 234.5 237.8 1.00
main_levm_Factorial 282.6 ± 8.3 277.6 306.0 1.20 ± 0.04
pr_revm_Factorial 241.4 ± 0.5 240.7 242.5 1.02 ± 0.01
pr_levm_Factorial 279.4 ± 4.1 276.3 287.7 1.18 ± 0.02

Benchmark Results: FactorialRecursive

Command Mean [s] Min [s] Max [s] Relative
main_revm_FactorialRecursive 1.726 ± 0.025 1.693 1.757 1.00
main_levm_FactorialRecursive 9.040 ± 0.087 8.915 9.180 5.24 ± 0.09
pr_revm_FactorialRecursive 1.773 ± 0.023 1.735 1.802 1.03 ± 0.02
pr_levm_FactorialRecursive 8.976 ± 0.075 8.890 9.114 5.20 ± 0.09

Benchmark Results: Fibonacci

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Fibonacci 211.9 ± 1.1 210.9 214.3 1.00
main_levm_Fibonacci 250.8 ± 4.4 247.9 262.7 1.18 ± 0.02
pr_revm_Fibonacci 223.8 ± 0.5 223.1 224.8 1.06 ± 0.01
pr_levm_Fibonacci 249.6 ± 2.6 247.7 256.3 1.18 ± 0.01

Benchmark Results: FibonacciRecursive

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_FibonacciRecursive 885.3 ± 7.1 874.6 896.1 1.00
main_levm_FibonacciRecursive 935.9 ± 16.4 919.7 976.5 1.06 ± 0.02
pr_revm_FibonacciRecursive 920.4 ± 11.5 896.0 934.5 1.04 ± 0.02
pr_levm_FibonacciRecursive 933.9 ± 11.4 924.2 963.0 1.05 ± 0.02

Benchmark Results: ManyHashes

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_ManyHashes 12.6 ± 0.3 12.4 13.5 1.00
main_levm_ManyHashes 14.0 ± 0.2 13.7 14.3 1.11 ± 0.03
pr_revm_ManyHashes 13.0 ± 0.1 12.9 13.1 1.03 ± 0.03
pr_levm_ManyHashes 14.0 ± 0.2 13.9 14.5 1.11 ± 0.03

Benchmark Results: MstoreBench

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_MstoreBench 291.1 ± 83.6 262.4 528.9 1.09 ± 0.31
main_levm_MstoreBench 336.5 ± 3.8 332.9 346.6 1.26 ± 0.02
pr_revm_MstoreBench 267.0 ± 3.6 263.9 273.6 1.00
pr_levm_MstoreBench 336.5 ± 5.2 332.4 350.2 1.26 ± 0.03

Benchmark Results: Push

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_Push 297.1 ± 1.0 295.8 299.3 1.00
main_levm_Push 387.8 ± 5.9 379.9 396.3 1.31 ± 0.02
pr_revm_Push 299.8 ± 5.4 296.5 314.2 1.01 ± 0.02
pr_levm_Push 390.5 ± 3.2 384.4 394.3 1.31 ± 0.01

Benchmark Results: SstoreBench_no_opt

Command Mean [ms] Min [ms] Max [ms] Relative
main_revm_SstoreBench_no_opt 220.9 ± 2.9 219.0 228.9 2.40 ± 0.04
main_levm_SstoreBench_no_opt 92.2 ± 0.9 89.9 93.4 1.00
pr_revm_SstoreBench_no_opt 220.8 ± 3.5 218.8 230.3 2.40 ± 0.05
pr_levm_SstoreBench_no_opt 92.5 ± 3.8 89.3 102.7 1.00 ± 0.04

@github-actions
Copy link

github-actions bot commented Sep 23, 2025

Benchmark Block Execution Results Comparison Against Main

Command Mean [s] Min [s] Max [s] Relative
base 85.659 ± 0.160 85.453 85.921 1.05 ± 0.01
head 81.354 ± 0.466 81.099 82.651 1.00

@ilitteri ilitteri marked this pull request as ready for review September 23, 2025 16:53
@ilitteri ilitteri requested a review from a team as a code owner September 23, 2025 16:53
Copilot AI review requested due to automatic review settings September 23, 2025 16:53
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR optimizes the JumpTargetFilter implementation to address a performance bottleneck where the original is_blacklisted function consumed ~30% of execution time during mainnet block execution.

  • Replaces incremental iteration with precomputed bitmap approach using BitVec<u8, Msb0>
  • Changes is_blacklisted from potentially O(n) to O(1) lookup operation
  • Adopts Geth's codeBitmap strategy for identifying valid JUMPDEST positions

Reviewed Changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.

File Description
crates/vm/levm/src/utils.rs Refactors JumpTargetFilter to use bitmap-based jumpdest tracking instead of incremental filtering
crates/vm/levm/Cargo.toml Adds bitvec dependency for bitmap functionality

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Contributor

@JereSalo JereSalo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just check if it's a jumpdest rather than checking that it's not blacklisted now that we have a bitvec with jumpdests? It feels more straightforward and less complex but I don't know if the other approach has more benefits

@edg-l
Copy link
Contributor

edg-l commented Sep 29, 2025

image

old gas bench looks good

@ilitteri ilitteri requested a review from damiramirez October 2, 2025 01:15
None => {
let code = &self.bytecode;
let len = code.len();
let mut jumpdests = bitvec![u8, Msb0; 0; len]; // All false, size = len
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could try using the default usize instead of u8 here, as the documentation states:

If you are only using this crate to discard the seven wasted bits per bool in a collection of bools, and are not too concerned about the in-memory representation, then you should use the default type argument of usize. This is because most processors work best when moving an entire usize between memory and the processor itself, and using a smaller type may cause it to slow down. Additionally, processor instructions are typically optimized for the whole register, and the processor might need to do additional clearing work for narrower types.

Also, Lsb0 might be a better default here, according to the docs:

The default ordering is Lsb0, as it typically produces shorter object code than Msb0 does.

@github-project-automation github-project-automation bot moved this to In Review in ethrex_l1 Oct 21, 2025
@ilitteri ilitteri added this pull request to the merge queue Oct 21, 2025
Merged via the queue into main with commit f4170c7 Oct 21, 2025
60 checks passed
@ilitteri ilitteri deleted the jump_dest_filter_opt branch October 21, 2025 02:58
@github-project-automation github-project-automation bot moved this from Todo to Done in ethrex_performance Oct 21, 2025
@github-project-automation github-project-automation bot moved this from In Review to Done in ethrex_l1 Oct 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

levm Lambda EVM implementation performance Block execution throughput and performance in general

Projects

Status: Done
Archived in project

Development

Successfully merging this pull request may close these issues.

8 participants