Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

evm-opcode-bench

Benchmark every EVM opcode individually using Revm. Measures real CPU nanoseconds per opcode execution, computes gas/ns efficiency ratios, and identifies mispriced opcodes.

Why

Ethereum gas costs are set by the protocol but don't always reflect actual computational cost. This tool measures how long each opcode takes on real hardware (via Revm v34, Cancun spec), making it easy to spot opcodes that are overpriced or underpriced relative to their peers.

The key metric is gas/ns (gas cost divided by measured nanoseconds). A high ratio means the opcode charges a lot of gas for little computation (overpriced). A low ratio means it's cheap in gas but expensive to execute (underpriced, potential DoS vector).

Quick start

# Clone and build
git clone https://github.com/0xMars42/evm-opcode-bench
cd evm-opcode-bench
cargo run --release

# Run with custom sample count
cargo run --release -- -n 500

# Filter by opcode name (substring match)
cargo run --release -- -o ADD -n 1000
cargo run --release -- -o EXP         # matches EXP_small, EXP_medium, EXP_large

# Single category
cargo run --release -- -c arithmetic

# CSV output
cargo run --release -- -f csv --output results/output.csv

# JSON output
cargo run --release -- -f json --output results/output.json

# Top 10 most mispriced opcodes
cargo run --release -- --top-mismatches 10

# Sort by gas efficiency ratio
cargo run --release -- --sort gas_ratio

# Multi-run for stable cold-storage measurements (median-of-medians)
cargo run --release -- --runs 5

# Verify all benchmarks execute correctly (dry run)
cargo run --release -- --verify

# List all available benchmarks
cargo run --release -- --list

# Show progress (useful for non-terminal output formats)
cargo run --release -- -f csv --output results.csv --verbose

What it measures

94 benchmarks across 14 categories:

Category Count Examples
Arithmetic 13 ADD, MUL, DIV, EXP (small/medium/large)
Comparison 6 LT, GT, SLT, SGT, EQ, ISZERO
Bitwise 8 AND, OR, XOR, SHL, SHR, SAR
Stack 8 PUSH0, PUSH1, PUSH32, POP, DUP1/16, SWAP1/16
Memory 5 MLOAD, MSTORE, MSTORE8, MSIZE, MCOPY
Storage 8 SLOAD warm/cold, SSTORE variants, TLOAD, TSTORE
Environment 13 ADDRESS, BALANCE, CALLER, EXTCODESIZE, SELFBALANCE
Block Info 9 BLOCKHASH, COINBASE, TIMESTAMP, BASEFEE
Crypto 3 SHA3 (32b, 256b, 1024b)
Control 2 PC, GAS
Logging 5 LOG0 through LOG4
Calls 4 CALL/STATICCALL/DELEGATECALL warm, CALL cold
System 2 CREATE, CREATE2
Precompiles 8 ecrecover, SHA-256, RIPEMD-160, identity, modexp, ecadd, ecmul, blake2f

Sample output

  evm-opcode-bench v0.1.0
  Revm v34 · Cancun spec · 2026-02-20 17:48 UTC
  AMD Ryzen 7 7800X3D 8-Core Processor (16 cores) · 31.7 GB RAM · Windows 11 Pro

  Opcode           Mean     Median        P95      Gas   Gas/ns  Pricing
  ──────────────────────────────────────────────────────────────────────

  ▸ Arithmetic (13 benchmarks)
  SUB             9.1ns       7.4ns      18.1ns       3    0.330  ·····
  ADD            12.4ns       9.1ns      29.3ns       3    0.241  ·····
  MUL            14.0ns      10.1ns      33.1ns       5    0.358  ·····
  DIV            21.5ns      18.9ns      39.4ns       5    0.233  ·····
  EXP_small      32.8ns      25.6ns      87.2ns      60    1.829  ▓▓▓▓▓ 6.4x above mean
  EXP_large    1206.0ns    1012.0ns    1914.0ns    1610    1.335  ▓▓▓▓· 4.7x above mean
  ...

  Key findings:
  ▲ Highest gas/ns:  EXP_small (1.8 gas/ns — 6x mean)
  ▼ Lowest gas/ns:   DIV (0.233 gas/ns — 1.2x below mean)
    Global mean: 0.286 gas/ns (IQR-filtered, 13 opcodes)

Output formats

  • Terminal (default, aliases: term, pretty): colored table with pricing indicators
  • CSV: machine-readable, one row per opcode
  • JSON: structured output with full statistics
  • Markdown (alias: md): GitHub-compatible table

Each row includes: opcode name, category, mean/median/p95 nanoseconds, gas cost, gas/ns ratio.

Methodology

Two benchmark strategies

Loopable opcodes (most opcodes): bytecode wraps the target opcode in a JUMPDEST/JUMPI counted loop. An empty baseline loop (same structure, no opcode) is measured separately. Per-opcode time = (full_elapsed - baseline_elapsed) / loop_count.

Non-loopable opcodes (cold storage, CREATE): each sample uses a fresh EVM and CacheDB to ensure cold state. A STOP-only baseline transaction is subtracted.

Stability measures

  • Thread pinned to core 0 (SetThreadAffinityMask on Windows, sched_setaffinity on Linux)
  • Thread priority raised (Windows: THREAD_PRIORITY_HIGHEST, Linux: SCHED_FIFO)
  • compiler_fence(SeqCst) before and after each timing measurement
  • Warmup phase before sampling (100 iterations for loopable, 20 for non-loopable)
  • Baseline measured once as median (not per-sample)
  • 3-sigma outlier removal on final statistics
  • Default: 1000 outer samples, 10000 inner loop iterations for fast opcodes
  • Multi-run mode (--runs N): runs N independent benchmark passes and takes the median-of-medians for each opcode. This eliminates run-to-run variance for cold storage and other noisy benchmarks. Use --runs 3 or --runs 5 for publication-quality results.
  • Verify mode (--verify): dry-runs every benchmark once and checks that the EVM execution succeeds without reverting. Use this to validate benchmark correctness after modifying opcode definitions.
  • IQR-filtered global mean: the summary's gas/ns mean excludes statistical outliers (beyond 1.5× IQR), so precompiles like ecrecover don't distort the comparison.

Known limitations

  • Stack opcodes (POP, DUP, SWAP): measured with their required PUSH setup. The reported time includes stack preparation overhead. This is inherent to EVM benchmarking since these opcodes can't execute without stack inputs.

  • Composite benchmarks (SHA3, LOG, MCOPY, precompiles): loop body includes an MSTORE to initialize memory before the target opcode. The baseline loop doesn't include this MSTORE, so a few nanoseconds of setup cost are included in the measurement.

  • Cold storage (SLOAD_cold, SSTORE variants): non-loopable strategy means each sample allocates a fresh CacheDB. Allocation noise causes higher variance (30-60% between runs) compared to loopable opcodes (<5%).

  • ecrecover is significantly slower than other precompiles (~150us vs ~0.3-3us) due to full ECDSA signature recovery. Its gas cost (3000) gives it the lowest gas/ns ratio of any benchmark.

Platform support

Works on Windows and Linux (including WSL). Thread pinning and priority use platform-specific APIs with graceful fallback.

Requires Rust 1.83+.

License

MIT

About

Benchmark every EVM opcode individually using Revm v34. Measures real CPU nanoseconds per opcode, computes gas/ns efficiency ratios, and identifies mispriced opcodes.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages