bench: add vanilla revm/op-revm baselines to bench suite#301
Conversation
Add four baseline rows -- revm_pinned, revm_latest, op_revm_pinned, op_revm_latest -- to the criterion workloads so each group shows how far the mega specs sit from vanilla revm/op-revm, at both the currently-depended versions and the latest crates.io releases (revm 38 / op-revm 20). The shared adapters and CacheDB builder live in benches/common/baseline_adapters.rs and are reused by revm_bench, transact, and mega_bench. revm_latest / op_revm_latest are added as renamed dev-dependencies (op-revm 20 transitively pulls revm 38, so both _latest baselines share one revm tree). criterion gains html_reports for local violin plots.
Extract `SPEC_IDS`, `make_mega_evm`, and `build_mega_tx` into `benches/common/baseline_adapters.rs` so the `MegaContext` + `modify_chain` + `MegaEvm::new` dance and the `MegaTransaction` envelope-wrap live in one place instead of seven across the three bench files (net -35 lines). Also drop now-stale version numbers from adapter docstrings, document why `transact_call_op_revm_latest` does not pin a spec, and merge the split import block in `revm_bench.rs`.
Drop the verbose Cargo.toml criterion-features comment, strip rotty version numbers and implementation counts from baseline-adapter docstrings, remove redundant WHAT comments around CREATE/CREATE2 helpers, and fix a stale group name in the mega_bench module doc.
|
LGTM. The abstraction in One minor note: |
| group.bench_function("revm_latest", |b| { | ||
| b.iter(|| { | ||
| let mut evm = ContextLatest::mainnet() | ||
| .modify_cfg_chained(|cfg| cfg.set_spec_and_mainnet_gas_params(SpecIdLatest::CANCUN)) |
There was a problem hiding this comment.
The CANCUN pin here silently carries the EIP-7825 tx_gas_limit_cap avoidance rationale from transact_call_revm_latest, but this workload uses gas_limit(100_000) so the cap (2^24 ≈ 16 M) is never reached anyway. A brief inline comment (or just dropping the pin) would make future maintenance easier:
| .modify_cfg_chained(|cfg| cfg.set_spec_and_mainnet_gas_params(SpecIdLatest::CANCUN)) | |
| .modify_cfg_chained(|cfg| cfg.set_spec_and_mainnet_gas_params(SpecIdLatest::CANCUN)) // avoid EIP-7825 tx_gas_limit_cap on default Osaka spec |
|
/benchmark |
| #[path = "common/baseline_adapters.rs"] | ||
| mod common; |
There was a problem hiding this comment.
nit: since common/baseline_adapters.rs is the only file under common/, renaming it to common/mod.rs would let all three bench files drop the #[path] attribute — mod common; would resolve via the standard sibling-folder lookup. Same change in mega_bench.rs:34-35 and revm_bench.rs:59-60.
Trade-off: requires renaming the file, so probably only worth doing if you're already touching this area. If a second shared file ever joins, you'd switch to a mod.rs that re-exports submodules anyway.
| #[path = "common/baseline_adapters.rs"] | |
| mod common; | |
| mod common; |
| pub fn add_baseline_rows_suffixed<FP, FL>( | ||
| group: &mut criterion::BenchmarkGroup<'_, criterion::measurement::WallTime>, | ||
| variant: &str, | ||
| params: &CallParams, | ||
| make_pinned_db: &FP, | ||
| make_latest_db: &FL, | ||
| ) where | ||
| FP: Fn() -> MemoryDatabase, | ||
| FL: Fn() -> CacheDBLatest<EmptyDBLatest>, | ||
| { | ||
| let with = |base: &str| -> String { | ||
| if variant.is_empty() { | ||
| base.to_string() | ||
| } else { | ||
| format!("{base}/{variant}") | ||
| } | ||
| }; | ||
| group.bench_function(with("revm_pinned"), |b| { | ||
| b.iter(|| transact_call_revm_pinned(make_pinned_db(), params)) | ||
| }); | ||
| group.bench_function(with("revm_latest"), |b| { | ||
| b.iter(|| transact_call_revm_latest(make_latest_db(), params)) | ||
| }); | ||
| group.bench_function(with("op_revm_pinned"), |b| { | ||
| b.iter(|| transact_call_op_revm_pinned(make_pinned_db(), params)) | ||
| }); | ||
| group.bench_function(with("op_revm_latest"), |b| { | ||
| b.iter(|| transact_call_op_revm_latest(make_latest_db(), params)) | ||
| }); | ||
| } |
There was a problem hiding this comment.
All three bench files repeat the same pipeline per subject — build the DB, build a tx, transact, assert — written seven times per group because each subject needs its own DB type, EVM constructor, and tx envelope. The current add_baseline_rows_* helper plus the parallel mega-row loop in each caller is the closest we can get to deduping under this shape.
Consider a follow-up refactor that hoists this into a portable Workload + Subject trait:
pub struct Workload {
pub accounts: Vec<Account>, // address → { balance, code, storage }
pub txs: Vec<TxSpec>, // single-tx benches pass vec![tx]; transfer_multi
// passes 1000 and a Subject loops internally
}
pub trait Subject {
fn name(&self) -> &str;
fn run(&self, workload: &Workload); // owns DB build, EVM build, tx loop, assert
}The bench file shrinks to declaring a Workload and calling one of register_all / register_baselines / register_mega. Each Subject impl absorbs its own quirks — Cancun pin, operator-fee zero-out, MegaTransaction envelope wrap, is_success() assert.
Two design points worth flagging:
- Keep
TxSpecminimal (today'sCallParams, ~5 fields). Reusingrevm::TxEnvdirectly would tie the abstraction to one revm version — both_latestsubjects would have to translate it into their ownTxEnvanyway, since revm 27 and revm 38 are separate crates. Vec<TxSpec>absorbsbench_transfer_multiwithout a parallel "sequence workload" type — the subject decides build-once-loop.
Not for this PR — #301 is a clean introduction of the baselines and is better merged as-is, with the refactor landing on top.
| let r = evm.transact(build_mega_tx(tx)).expect("transfer should succeed"); | ||
| black_box(&r); |
There was a problem hiding this comment.
Missing the is_success() assertion that all four baseline blocks above have (lines 437-442, 461-467, 488-494, 516-522). expect() on transact() only catches internal errors — a transaction that halts (out-of-gas, a per-tx resource limit being exceeded under one of the mega specs, etc.) returns Ok(ResultAndState) with result.is_success() == false, and the bench keeps spinning. The mega rows would then report numbers from "1000 transfers where some fraction actually halted," which is silently incomparable to the baseline rows that always assert success — defeating the cross-row comparison this bench exists to enable.
| let r = evm.transact(build_mega_tx(tx)).expect("transfer should succeed"); | |
| black_box(&r); | |
| let r = evm.transact(build_mega_tx(tx)).expect("transfer should succeed"); | |
| assert!( | |
| r.result.is_success(), | |
| "mega transfer should succeed: {:?}", | |
| r.result | |
| ); | |
| black_box(&r); |
| criterion = { workspace = true, features = ["html_reports", "plotters", "cargo_bench_support"] } | ||
| hex.workspace = true | ||
| mega-evm = { path = ".", features = ["test-utils"] } | ||
| op_revm_latest = { package = "op-revm", version = "20.0.0", default-features = false, features = ["dev", "serde", "std"] } |
There was a problem hiding this comment.
The two renamed packages use snake_case (op_revm_latest, revm_latest) while the rest of [dev-dependencies] follows the crate's upstream name — kebab-case for mega-evm and revm-inspectors, snake_case only for serde_json because that's literally the crate's name on crates.io. Since these are renamed packages, the local key is whatever we choose — kebab-case matches house style.
Cargo auto-converts dashes to underscores in Rust identifiers, so use op_revm_latest::... and use revm_latest::... keep working unchanged across all three bench files. Only Cargo.toml changes.
| op_revm_latest = { package = "op-revm", version = "20.0.0", default-features = false, features = ["dev", "serde", "std"] } | |
| op-revm-latest = { package = "op-revm", version = "20.0.0", default-features = false, features = ["dev", "serde", "std"] } |
Same change on line 52:
revm-latest = { package = "revm", version = "38.0.0", default-features = false, features = ["dev", "serde", "std"] }
Criterion Benchmark ComparisonBaseline gap (HEAD only — how far is each EVM layer from
|
| spec | time | × vs revm_pinned |
|---|---|---|
revm_pinned |
20.46 µs | 1.00× (baseline) |
revm_latest |
22.63 µs | 1.11× |
op_revm_pinned |
21.24 µs | 1.04× |
op_revm_latest |
23.80 µs | 1.16× |
equivalence |
22.00 µs | 1.08× |
mini_rex |
27.33 µs | 1.34× |
rex4 |
27.79 µs | 1.36× |
empty_transaction
| spec | time | × vs revm_pinned |
|---|---|---|
revm_pinned |
2.11 µs | 1.00× (baseline) |
revm_latest |
2.60 µs | 1.23× |
op_revm_pinned |
3.23 µs | 1.53× |
op_revm_latest |
3.71 µs | 1.76× |
equivalence |
3.66 µs | 1.73× |
mini_rex |
4.01 µs | 1.90× |
rex4 |
4.03 µs | 1.91× |
mixed_workload
| spec | time | × vs revm_pinned |
|---|---|---|
revm_pinned |
15.89 µs | 1.00× (baseline) |
revm_latest |
14.78 µs | 0.93× |
op_revm_pinned |
16.90 µs | 1.06× |
op_revm_latest |
15.71 µs | 0.99× |
equivalence |
17.45 µs | 1.10× |
mini_rex |
26.51 µs | 1.67× |
rex4 |
27.25 µs | 1.72× |
simple_ether_transfer
| spec | time | × vs revm_pinned |
|---|---|---|
revm_pinned |
2.36 µs | 1.00× (baseline) |
revm_latest |
2.92 µs | 1.24× |
op_revm_pinned |
3.47 µs | 1.47× |
op_revm_latest |
3.89 µs | 1.65× |
equivalence |
3.92 µs | 1.66× |
mini_rex |
4.26 µs | 1.81× |
rex4 |
4.28 µs | 1.82× |
snailtracer
| spec | time | × vs revm_pinned |
|---|---|---|
revm_pinned |
52.39 ms | 1.00× (baseline) |
revm_latest |
50.83 ms | 0.97× |
op_revm_pinned |
53.23 ms | 1.02× |
op_revm_latest |
50.55 ms | 0.96× |
equivalence |
52.89 ms | 1.01× |
mini_rex |
124.13 ms | 2.37× |
rex4 |
167.99 ms | 3.21× |
subcall_1000_nested
| spec | time | × vs revm_pinned |
|---|---|---|
revm_pinned |
947.51 µs | 1.00× (baseline) |
revm_latest |
671.97 µs | 0.71× |
op_revm_pinned |
1.00 ms | 1.06× |
op_revm_latest |
680.73 µs | 0.72× |
equivalence |
1.27 ms | 1.34× |
mini_rex |
1.83 ms | 1.93× |
rex4 |
2.01 ms | 2.12× |
subcall_1000_no_value
| spec | time | × vs revm_pinned |
|---|---|---|
revm_pinned |
488.14 µs | 1.00× (baseline) |
revm_latest |
352.50 µs | 0.72× |
op_revm_pinned |
511.73 µs | 1.05× |
op_revm_latest |
359.50 µs | 0.74× |
equivalence |
654.76 µs | 1.34× |
mini_rex |
981.33 µs | 2.01× |
rex4 |
1.05 ms | 2.15× |
subcall_1000_transfer_1wei
| spec | time | × vs revm_pinned |
|---|---|---|
revm_pinned |
342.63 µs | 1.00× (baseline) |
revm_latest |
273.92 µs | 0.80× |
op_revm_pinned |
347.36 µs | 1.01× |
op_revm_latest |
279.66 µs | 0.82× |
equivalence |
447.57 µs | 1.31× |
mini_rex |
755.41 µs | 2.20× |
rex4 |
851.88 µs | 2.49× |
transfer_multi_1000
| spec | time | × vs revm_pinned |
|---|---|---|
revm_pinned |
1.13 ms | 1.00× (baseline) |
revm_latest |
763.93 µs | 0.67× |
op_revm_pinned |
1.74 ms | 1.54× |
op_revm_latest |
1.25 ms | 1.10× |
equivalence |
1.85 ms | 1.63× |
mini_rex |
2.08 ms | 1.83× |
rex4 |
2.07 ms | 1.83× |
weth9_transfer
| spec | time | × vs revm_pinned |
|---|---|---|
revm_pinned |
17.62 µs | 1.00× (baseline) |
revm_latest |
19.86 µs | 1.13× |
op_revm_pinned |
18.66 µs | 1.06× |
op_revm_latest |
20.60 µs | 1.17× |
equivalence |
19.35 µs | 1.10× |
mini_rex |
23.14 µs | 1.31× |
rex4 |
23.77 µs | 1.35× |
PR-base → PR-head regression check
147 benchmarks total, 18 with >5% change
| Benchmark | Baseline | Feature | Delta | |
|---|---|---|---|---|
| add/mini_rex | 16.0 µs | 15.9 µs | -0.6% | ✅ |
| address/mini_rex | 7.8 µs | 7.8 µs | +0.9% | ✅ |
| analysis/equivalence | 22.2 µs | 22.0 µs | -1.1% | ✅ |
| analysis/mini_rex | 27.9 µs | 27.3 µs | -2.1% | ✅ |
| analysis/rex4 | 28.7 µs | 27.8 µs | -3.0% | ✅ |
| batch_transfer_high_complexity_1x1/equivalence | 260.8 µs | 264.9 µs | +1.5% | ✅ |
| batch_transfer_high_complexity_1x1/mini_rex | 437.8 µs | 441.0 µs | +0.7% | ✅ |
| batch_transfer_high_contention_10x10/equivalence | 458.4 µs | 456.9 µs | -0.3% | ✅ |
| batch_transfer_high_contention_10x10/mini_rex | 921.7 µs | 883.4 µs | -4.2% | ✅ |
| batch_transfer_little_complexity_1x1/equivalence | 29.5 µs | 29.2 µs | -0.9% | ✅ |
| batch_transfer_little_complexity_1x1/mini_rex | 52.8 µs | 51.6 µs | -2.2% | ✅ |
| batch_transfer_low_contention_1x1/equivalence | 17.1 µs | 16.8 µs | -1.7% | ✅ |
| batch_transfer_low_contention_1x1/mini_rex | 31.9 µs | 30.7 µs | -3.7% | ✅ |
| batch_transfer_medium_complexity_1x1/equivalence | 138.7 µs | 139.2 µs | +0.4% | ✅ |
| batch_transfer_medium_complexity_1x1/mini_rex | 238.3 µs | 231.2 µs | -3.0% | ✅ |
| batch_transfer_medium_contention_5x5/equivalence | 132.3 µs | 132.2 µs | -0.1% | ✅ |
| batch_transfer_medium_contention_5x5/mini_rex | 260.6 µs | 251.1 µs | -3.6% | ✅ |
| batch_transfer_some_complexity_5x5/equivalence | 838.9 µs | 844.9 µs | +0.7% | ✅ |
| batch_transfer_some_complexity_5x5/mini_rex | 1462.3 µs | 1425.7 µs | -2.5% | ✅ |
| block_executor_deploy/rex4/deploy_1 | 27.5 µs | 27.2 µs | -1.1% | ✅ |
| block_executor_empty_txs/rex4/10_txs | 70.5 µs | 70.5 µs | +0.0% | ✅ |
| block_executor_empty_txs/rex4/1_txs | 26.9 µs | 26.5 µs | -1.4% | ✅ |
| block_executor_empty_txs/rex4/50_txs | 258.9 µs | 266.5 µs | +2.9% | ✅ |
| block_executor_mixed_txs/rex4/10_txs | 220.0 µs | 222.7 µs | +1.2% | ✅ |
| block_executor_mixed_txs/rex4/1_txs | 49.0 µs | 48.9 µs | -0.3% | ✅ |
| block_executor_spec_comparison/equivalence/5_mixed_txs | 93.3 µs | 93.6 µs | +0.4% | ✅ |
| block_executor_spec_comparison/mini_rex/5_mixed_txs | 68.0 µs | 67.9 µs | -0.1% | ✅ |
| block_executor_spec_comparison/rex4/5_mixed_txs | 125.3 µs | 126.0 µs | +0.6% | ✅ |
| block_executor_spec_comparison/rex5/5_mixed_txs | 125.6 µs | 126.5 µs | +0.8% | ✅ |
| call_value_empty_account/equivalence/empty_account_50 | 37.7 µs | 34.6 µs | -8.2% | ✅ |
| call_value_empty_account/equivalence/existing_account_50 | 38.1 µs | 34.6 µs | -9.0% | ✅ |
| call_value_empty_account/mini_rex/empty_account_50 | 52.5 µs | 47.9 µs | -8.8% | ✅ |
| call_value_empty_account/mini_rex/existing_account_50 | 51.8 µs | 47.4 µs | -8.5% | ✅ |
| call_value_empty_account/rex4/empty_account_50 | 55.1 µs | 50.3 µs | -8.9% | ✅ |
| call_value_empty_account/rex4/existing_account_50 | 54.3 µs | 50.1 µs | -7.6% | ✅ |
| create_deploy/equivalence/create2_10 | 26.4 µs | 25.8 µs | -2.0% | ✅ |
| create_deploy/equivalence/create_10 | 20.8 µs | 20.6 µs | -1.1% | ✅ |
| create_deploy/mini_rex/create2_10 | 39.2 µs | 39.6 µs | +0.9% | ✅ |
| create_deploy/mini_rex/create_10 | 28.5 µs | 28.9 µs | +1.3% | ✅ |
| create_deploy/rex4/create2_10 | 39.9 µs | 39.8 µs | -0.3% | ✅ |
| create_deploy/rex4/create_10 | 29.2 µs | 29.2 µs | +0.2% | ✅ |
| delegatecall_system_contract/rex4/delegatecall_not_intercepted | 6.0 µs | 6.2 µs | +2.4% | ✅ |
| delegatecall_system_contract/rex4/staticcall_intercepted | 6.3 µs | 6.4 µs | +1.0% | ✅ |
| empty_transaction/equivalence | 3.5 µs | 3.7 µs | +4.6% | ✅ |
| empty_transaction/mini_rex | 3.9 µs | 4.0 µs | +4.1% | ✅ |
| exp_256bit/mini_rex | 304.2 µs | 303.2 µs | -0.3% | ✅ |
| gas_detention_computation/equivalence/compute_only_500 | 45.1 µs | 43.9 µs | -2.7% | ✅ |
| gas_detention_computation/equivalence/volatile_then_compute_500 | 45.6 µs | 44.3 µs | -2.9% | ✅ |
| gas_detention_computation/mini_rex/compute_only_500 | 61.1 µs | 59.3 µs | -2.9% | ✅ |
| gas_detention_computation/mini_rex/volatile_then_compute_500 | 61.2 µs | 59.6 µs | -2.5% | ✅ |
| gas_detention_computation/rex4/compute_only_500 | 68.1 µs | 66.7 µs | -2.1% | ✅ |
| gas_detention_computation/rex4/volatile_then_compute_500 | 68.4 µs | 66.9 µs | -2.2% | ✅ |
| keccak256_1KB/mini_rex | 372.0 µs | 360.9 µs | -3.0% | ✅ |
| keccak256_32B/mini_rex | 62.3 µs | 63.8 µs | +2.5% | ✅ |
| log_opcodes/equivalence/log0_256b | 10.8 µs | 11.1 µs | +3.4% | ✅ |
| log_opcodes/equivalence/log0_32b | 11.0 µs | 10.6 µs | -3.8% | ✅ |
| log_opcodes/equivalence/log2_32b | 16.5 µs | 16.1 µs | -2.3% | ✅ |
| log_opcodes/equivalence/log4_256b | 20.5 µs | 20.8 µs | +1.4% | ✅ |
| log_opcodes/equivalence/log4_32b | 20.5 µs | 20.1 µs | -1.9% | ✅ |
| log_opcodes/mini_rex/log0_256b | 12.8 µs | 12.6 µs | -1.7% | ✅ |
| log_opcodes/mini_rex/log0_32b | 12.9 µs | 12.7 µs | -1.5% | ✅ |
| log_opcodes/mini_rex/log2_32b | 19.1 µs | 18.7 µs | -2.0% | ✅ |
| log_opcodes/mini_rex/log4_256b | 25.2 µs | 25.0 µs | -0.9% | ✅ |
| log_opcodes/mini_rex/log4_32b | 25.4 µs | 24.9 µs | -1.9% | ✅ |
| log_opcodes/rex4/log0_256b | 13.5 µs | 13.4 µs | -1.1% | ✅ |
| log_opcodes/rex4/log0_32b | 13.5 µs | 13.3 µs | -1.1% | ✅ |
| log_opcodes/rex4/log2_32b | 20.2 µs | 19.9 µs | -1.4% | ✅ |
| log_opcodes/rex4/log4_256b | 26.6 µs | 26.7 µs | +0.4% | ✅ |
| log_opcodes/rex4/log4_32b | 26.6 µs | 26.4 µs | -0.8% | ✅ |
| mixed_workload/equivalence | 18.0 µs | 17.5 µs | -2.9% | ✅ |
| mixed_workload/mini_rex | 27.8 µs | 26.5 µs | -4.6% | ✅ |
| mixed_workload/rex4 | 28.0 µs | 27.3 µs | -2.6% | ✅ |
| oracle_sload/equivalence/oracle_sload_50 | 16.3 µs | 16.4 µs | +0.5% | ✅ |
| oracle_sload/equivalence/regular_sload_50 | 16.2 µs | 15.8 µs | -2.8% | ✅ |
| oracle_sload/mini_rex/oracle_sload_50 | 17.8 µs | 17.9 µs | +0.8% | ✅ |
| oracle_sload/mini_rex/regular_sload_50 | 17.6 µs | 17.4 µs | -1.2% | ✅ |
| oracle_sload/rex4/oracle_sload_50 | 19.1 µs | 18.0 µs | -5.8% | ✅ |
| oracle_sload/rex4/regular_sload_50 | 18.6 µs | 18.6 µs | +0.1% | ✅ |
| precompile_blake2f_1round/mini_rex | 114.1 µs | 113.9 µs | -0.2% | ✅ |
| precompile_bls12_381_g1add/mini_rex | 608.6 µs | 610.6 µs | +0.3% | ✅ |
| precompile_bls12_381_g1msm/mini_rex | 22468.9 µs | 22815.5 µs | +1.5% | ✅ |
| precompile_bls12_381_g2add/mini_rex | 855.9 µs | 855.9 µs | -0.0% | ✅ |
| precompile_bls12_381_g2msm/mini_rex | 43171.0 µs | 44276.8 µs | +2.6% | ✅ |
| precompile_bls12_381_map_fp2_to_g2/mini_rex | 19769.6 µs | 19790.8 µs | +0.1% | ✅ |
| precompile_bls12_381_map_fp_to_g1/mini_rex | 6169.2 µs | 6170.9 µs | +0.0% | ✅ |
| precompile_bls12_381_pairing/mini_rex | 137216.9 µs | 136893.3 µs | -0.2% | ✅ |
| precompile_ecadd/mini_rex | 530.0 µs | 532.2 µs | +0.4% | ✅ |
| precompile_ecmul/mini_rex | 540.6 µs | 540.8 µs | +0.0% | ✅ |
| precompile_ecpairing/mini_rex | 133136.0 µs | 130689.9 µs | -1.8% | ✅ |
| precompile_ecrecover/mini_rex | 5200.5 µs | 5190.7 µs | -0.2% | ✅ |
| precompile_kzg_point_evaluation/mini_rex | 160645.1 µs | 160769.2 µs | +0.1% | ✅ |
| precompile_modexp_32B/mini_rex | 3751.4 µs | 3718.7 µs | -0.9% | ✅ |
| precompile_ripemd160_1KB/mini_rex | 546.8 µs | 548.9 µs | +0.4% | ✅ |
| precompile_ripemd160_32B/mini_rex | 139.5 µs | 141.9 µs | +1.7% | ✅ |
| precompile_sha256_1KB/mini_rex | 194.0 µs | 195.8 µs | +0.9% | ✅ |
| precompile_sha256_32B/mini_rex | 116.9 µs | 117.9 µs | +0.8% | ✅ |
| rex5_pre_block/bootstrap | 19.3 µs | 19.7 µs | +2.0% | ✅ |
| rex5_pre_block/no_change | 12.1 µs | 12.7 µs | +4.6% | ✅ |
| selfdestruct/equivalence | 4.9 µs | 4.9 µs | +0.5% | ✅ |
| selfdestruct/rex2 | 5.2 µs | 5.2 µs | -0.2% | ✅ |
| selfdestruct/rex4 | 5.3 µs | 5.3 µs | +0.4% | ✅ |
| simple_ether_transfer/equivalence | 3.7 µs | 3.9 µs | +4.6% | ✅ |
| simple_ether_transfer/mini_rex | 4.0 µs | 4.3 µs | +5.2% | ✅ |
| snailtracer/equivalence | 53882.4 µs | 52893.5 µs | -1.8% | ✅ |
| snailtracer/mini_rex | 130587.6 µs | 124130.6 µs | -4.9% | ✅ |
| snailtracer/rex4 | 159593.9 µs | 167987.6 µs | +5.3% | ✅ |
| sstore_heavy/equivalence/sload_100 | 27.3 µs | 25.8 µs | -5.7% | ✅ |
| sstore_heavy/equivalence/sstore_100 | 38.3 µs | 34.8 µs | -9.0% | ✅ |
| sstore_heavy/equivalence/sstore_sload_100 | 49.3 µs | 46.2 µs | -6.4% | ✅ |
| sstore_heavy/mini_rex/sload_100 | 29.5 µs | 28.4 µs | -4.1% | ✅ |
| sstore_heavy/mini_rex/sstore_100 | 74.4 µs | 70.0 µs | -5.8% | ✅ |
| sstore_heavy/mini_rex/sstore_sload_100 | 89.9 µs | 83.1 µs | -7.5% | ✅ |
| sstore_heavy/rex4/sload_100 | 31.1 µs | 29.5 µs | -5.1% | ✅ |
| sstore_heavy/rex4/sstore_100 | 70.5 µs | 68.8 µs | -2.4% | ✅ |
| sstore_heavy/rex4/sstore_sload_100 | 84.5 µs | 83.1 µs | -1.6% | ✅ |
| subcall_1000_nested/equivalence | 1222.1 µs | 1265.2 µs | +3.5% | ✅ |
| subcall_1000_nested/mini_rex | 1753.4 µs | 1831.0 µs | +4.4% | ✅ |
| subcall_1000_nested/rex4 | 1926.6 µs | 2005.4 µs | +4.1% | ✅ |
| subcall_1000_no_value/equivalence | 611.5 µs | 654.8 µs | +7.1% | ✅ |
| subcall_1000_no_value/mini_rex | 900.1 µs | 981.3 µs | +9.0% | ✅ |
| subcall_1000_no_value/rex4 | 987.8 µs | 1048.3 µs | +6.1% | ✅ |
| subcall_1000_transfer_1wei/equivalence | 436.3 µs | 447.6 µs | +2.6% | ✅ |
| subcall_1000_transfer_1wei/mini_rex | 776.5 µs | 755.4 µs | -2.7% | ✅ |
| subcall_1000_transfer_1wei/rex4 | 840.5 µs | 851.9 µs | +1.4% | ✅ |
| system_contract_100x/rex4/access_control | 109.4 µs | 111.0 µs | +1.4% | ✅ |
| system_contract_100x/rex4/limit_control | 103.7 µs | 102.9 µs | -0.8% | ✅ |
| system_contract_100x/rex4/regular_contract | 119.6 µs | 115.6 µs | -3.4% | ✅ |
| system_contract_single/rex4/access_control | 6.4 µs | 6.3 µs | -0.8% | ✅ |
| system_contract_single/rex4/limit_control | 6.3 µs | 6.3 µs | -0.3% | ✅ |
| system_contract_single/rex4/regular_contract | 7.1 µs | 7.1 µs | +0.7% | ✅ |
| transfer_multi_1000/equivalence | 1852.8 µs | 1845.1 µs | -0.4% | ✅ |
| transfer_multi_1000/mini_rex | 2100.4 µs | 2075.2 µs | -1.2% | ✅ |
| transfer_multi_1000/rex4 | 2119.2 µs | 2070.1 µs | -2.3% | ✅ |
| volatile_data/equivalence/baseline_add | 12.6 µs | 12.2 µs | -3.0% | ✅ |
| volatile_data/equivalence/coinbase | 6.0 µs | 6.0 µs | +0.2% | ✅ |
| volatile_data/equivalence/number | 6.0 µs | 6.0 µs | -0.5% | ✅ |
| volatile_data/equivalence/timestamp | 6.0 µs | 6.0 µs | -0.4% | ✅ |
| volatile_data/mini_rex/baseline_add | 16.1 µs | 15.8 µs | -2.3% | ✅ |
| volatile_data/mini_rex/coinbase | 8.2 µs | 8.3 µs | +1.2% | ✅ |
| volatile_data/mini_rex/number | 8.0 µs | 8.2 µs | +2.0% | ✅ |
| volatile_data/mini_rex/timestamp | 8.0 µs | 8.1 µs | +1.4% | ✅ |
| volatile_data/rex4/baseline_add | 17.5 µs | 17.2 µs | -2.1% | ✅ |
| volatile_data/rex4/coinbase | 8.9 µs | 9.1 µs | +1.5% | ✅ |
| volatile_data/rex4/number | 8.9 µs | 8.9 µs | -0.0% | ✅ |
| volatile_data/rex4/timestamp | 9.3 µs | 8.9 µs | -3.7% | ✅ |
| weth9_transfer/equivalence | 20.1 µs | 19.4 µs | -3.5% | ✅ |
| weth9_transfer/mini_rex | 23.5 µs | 23.1 µs | -1.5% | ✅ |
Significant changes (>5%):
| Benchmark | Baseline | Feature | Delta | |
|---|---|---|---|---|
| call_value_empty_account/equivalence/empty_account_50 | 37.7 µs | 34.6 µs | -8.2% | ✅ |
| call_value_empty_account/equivalence/existing_account_50 | 38.1 µs | 34.6 µs | -9.0% | ✅ |
| call_value_empty_account/mini_rex/empty_account_50 | 52.5 µs | 47.9 µs | -8.8% | ✅ |
| call_value_empty_account/mini_rex/existing_account_50 | 51.8 µs | 47.4 µs | -8.5% | ✅ |
| call_value_empty_account/rex4/empty_account_50 | 55.1 µs | 50.3 µs | -8.9% | ✅ |
| call_value_empty_account/rex4/existing_account_50 | 54.3 µs | 50.1 µs | -7.6% | ✅ |
| oracle_sload/rex4/oracle_sload_50 | 19.1 µs | 18.0 µs | -5.8% | ✅ |
| simple_ether_transfer/mini_rex | 4.0 µs | 4.3 µs | +5.2% | ✅ |
| snailtracer/rex4 | 159593.9 µs | 167987.6 µs | +5.3% | ✅ |
| sstore_heavy/equivalence/sload_100 | 27.3 µs | 25.8 µs | -5.7% | ✅ |
| sstore_heavy/equivalence/sstore_100 | 38.3 µs | 34.8 µs | -9.0% | ✅ |
| sstore_heavy/equivalence/sstore_sload_100 | 49.3 µs | 46.2 µs | -6.4% | ✅ |
| sstore_heavy/mini_rex/sstore_100 | 74.4 µs | 70.0 µs | -5.8% | ✅ |
| sstore_heavy/mini_rex/sstore_sload_100 | 89.9 µs | 83.1 µs | -7.5% | ✅ |
| sstore_heavy/rex4/sload_100 | 31.1 µs | 29.5 µs | -5.1% | ✅ |
| subcall_1000_no_value/equivalence | 611.5 µs | 654.8 µs | +7.1% | ✅ |
| subcall_1000_no_value/mini_rex | 900.1 µs | 981.3 µs | +9.0% | ✅ |
| subcall_1000_no_value/rex4 | 987.8 µs | 1048.3 µs | +6.1% | ✅ |
147 benchmarks: 0 regressions, 0 warnings, 0 improvements
Summary
Add vanilla
revmandop-revmbaseline rows to the criterion bench suite at both the currently-pinned versions and the latest crates.io releases, so each group shows how far the mega specs sit from upstream — at versions we depend on today and at versions we'll likely move to next.What's new
revm_pinned,revm_latest,op_revm_pinned,op_revm_latest. Joined by the three mega rows (equivalence,mini_rex,rex4) so each criterion group emits seven comparable rows.benches/common/baseline_adapters.rs, pulled intomega_bench,revm_bench, andtransactvia#[path = ...]. Also exposesSPEC_IDS,make_mega_evm, andbuild_mega_txso the operator-fee zero-out and theMegaTransactionenvelope-wrap exist in one place instead of seven.revm 38+op-revm 20added as renamed dev-dependencies (revm_latest/op_revm_latest).op-revm 20transitively pullsrevm 38, so both_latestbaselines share one revm tree.html_reports,plotters,cargo_bench_support) for local violin plots undertarget/criterion/report/.Notes
transact_call_revm_latestpinsCancunto dodge EIP-7825'stx_gas_limit_capagainst the multi-Ggas_limitworkloads.op_revm_latestdoesn't need this — its default Isthmus spec lacks the cap; the comment notes what to do if a future op-revm release inherits it.bench_transfer_multireuses one EVM across 1000 txns, so it inlines the baseline setup instead of using the single-shottransact_call_*adapters.Test plan
cargo check -p mega-evm --benchescargo fmt --all --checkcargo clippy -p mega-evm --benches --all-features --lockedcargo bench -p mega-evm --bench transact -- --quick— 7/7 rows pass pergroup
cargo bench -p mega-evm --bench mega_bench -- --quickcargo bench -p mega-evm --bench revm_bench -- --quick