Skip to content

cmd/utils: expose executor perf toggles as --exec.* CLI flags#20797

Merged
mh0lt merged 1 commit intomainfrom
feat/exec-perf-flags
Apr 24, 2026
Merged

cmd/utils: expose executor perf toggles as --exec.* CLI flags#20797
mh0lt merged 1 commit intomainfrom
feat/exec-perf-flags

Conversation

@mh0lt
Copy link
Copy Markdown
Contributor

@mh0lt mh0lt commented Apr 24, 2026

Summary

Promotes executor performance toggles from env-var-only to first-class CLI flags so they're discoverable via --help and settable without prefixing every invocation with env vars. Matches the surface other EL clients expose: reth's --engine.disable-prewarming and besu's --bonsai-parallel-tx-processing-enabled are direct analogues of --exec.batched-io.

New flags (all in --exec.* namespace)

Flag Default Purpose
--exec.batched-io true Composite toggle: enables BAL-driven read-ahead (pre-warms DB page cache with account/code/storage reads before block execution — warmBody at blocks_read_ahead.go:111) and BAL-driven version-map pre-population (parallel executor seeds write-dependency map from BAL hints — exec3.go:612). Flipping this off disables both in lockstep for clean "BAL on" vs "BAL off" comparisons. Env aliases: READ_AHEAD, IGNORE_BAL (inverted).
--exec.state-cache true Executor domain-shared read cache. Distinct from the existing --state.cache (which sizes the rpcdaemon RPC-path cache — different cache entirely). Env alias: USE_STATE_CACHE.
--exec.workers NumCPU/2 Parallel executor worker count. Wired into both cfg.ExecWorkerCount and dbg.Exec3Workers. Env alias: EXEC3_WORKERS.
--exec.no-merge false Disable state-aggregator file merges for Domain / History / Inverted-Index. Diagnostic / perf-comparison use. Env alias: NO_MERGE.
--exec.no-prune false Disable state-aggregator pruning of historical steps. Diagnostic / perf-comparison use. Env alias: NO_PRUNE.

EXEC3_PARALLEL (default true) deliberately stays env-only — it's not a knob users tune.

Why --exec.batched-io controls both

BAL (EIP-7928) drives two different optimisations in the executor:

  1. Read-ahead (I/O side) — reads account data, code, and storage slots listed in the BAL into the DB page cache before execution begins. Purely a cache-warming operation; no effect on execution semantics.
  2. Version-map pre-population (scheduling side) — seeds the parallel executor's write-dependency version map with BAL entries so speculative tx scheduling can skip dependency discovery.

Both are BAL-driven optimisations that users either want together (normal perf mode) or disabled together (measuring "cold state + no BAL scheduling" baseline). One flag for both avoids users having to toggle two env vars in sync.

Semantics / backwards compatibility

Env vars remain the source of truth when no CLI flag is explicitly set: dbg reads them at package init; SetEthConfig overrides only on ctx.IsSet(flag). Existing launch scripts (e.g. our bal-devnet-3 setup using ERIGON_EXEC3_WORKERS=12 USE_STATE_CACHE=false) keep working unchanged.

Why now

We've been running bal-devnet-3 perf comparisons against reth, besu, geth and nethermind where all other clients expose equivalent knobs on the CLI. Having to preface erigon invocations with ERIGON_EXEC3_WORKERS=N IGNORE_BAL=false READ_AHEAD=false USE_STATE_CACHE=false ./build/bin/erigon … hurts both discoverability and script parity — the launch scripts for other clients in ethpandaops' ethereum-package pass perf knobs as flags, not env vars.

Test plan

  • go test -short ./cmd/utils/... — new TestExecPerfFlags_OverrideDbg covers: (a) no-flag-set path leaves dbg untouched so env vars still drive behaviour; (b) --exec.batched-io=false disables read-ahead and sets IgnoreBAL=true in one go; (c) --exec.batched-io=true enables read-ahead and clears IgnoreBAL; (d) each other flag's override semantics.
  • make lint — 0 issues, verified twice (non-deterministic per CLAUDE.md).
  • make erigon — binary builds, --help shows all 5 flags with correct defaults and usage.
  • Hive / devp2p / race-tests green on rebased base.

Files touched

  • cmd/utils/flags.go — 5 flag definitions + wiring in SetEthConfig.
  • cmd/utils/flags_test.go — new test.
  • common/dbg/experiments.go — 6 setters + new ReadAhead env var (READ_AHEAD=true default).
  • execution/exec/blocks_read_ahead.go — gate warmBody on dbg.ReadAhead.
  • node/cli/default_flags.go — register flags in DefaultFlags.

~180 LOC including tests.

@mh0lt mh0lt force-pushed the feat/exec-perf-flags branch from ab07a50 to 50031d9 Compare April 24, 2026 17:03
@mh0lt mh0lt enabled auto-merge April 24, 2026 17:13
@mh0lt mh0lt disabled auto-merge April 24, 2026 17:14
Promotes five existing env-var-only executor performance toggles to
first-class CLI flags so they're discoverable via --help and settable
without prefixing every invocation with env vars. Matches the surface
other EL clients (reth, besu) expose — e.g. reth's `--engine.disable-prewarming`
and besu's `--bonsai-parallel-tx-processing-enabled` are direct analogues
of --exec.batched-io.

New flags (all in --exec.* namespace):

  --exec.batched-io   bool, default true
      Use BAL hints to pre-populate the parallel executor's version map.
      Inverted alias for IGNORE_BAL: --exec.batched-io=false disables the
      prefetch and forces runtime dependency tracking. Matches reth's
      --engine.disable-prewarming semantically.

  --exec.state-cache  bool, default true
      Executor domain-shared read cache (alias for USE_STATE_CACHE).
      Distinct from the existing --state.cache (which sizes the
      rpcdaemon's RPC-path cache — different cache, different code path).

  --exec.workers      int, default NumCPU/2
      Parallel executor worker count (alias for EXEC3_WORKERS). Wired
      into cfg.ExecWorkerCount directly plus dbg.Exec3Workers.

  --exec.no-merge     bool, default false
      Disable state-aggregator file merges for Domain/History/II
      (alias for NO_MERGE). Diagnostic / perf-comparison use.

  --exec.no-prune     bool, default false
      Disable state-aggregator pruning of historical steps (alias for
      NO_PRUNE). Diagnostic / perf-comparison use.

EXEC3_PARALLEL (default true) deliberately stays env-only — it's not a
knob users tune.

Env vars remain the source of truth when no CLI flag is explicitly set:
dbg reads them at package init; SetEthConfig overrides only on
ctx.IsSet(flag). Existing launch scripts (e.g. our bal-devnet-3 setup)
keep working unchanged.

Test: cmd/utils/flags_test.go TestExecPerfFlags_OverrideDbg covers the
no-flag-set path (dbg untouched) and each flag's override semantics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mh0lt mh0lt force-pushed the feat/exec-perf-flags branch from f2b0bc1 to c7e1211 Compare April 24, 2026 17:22
@mh0lt mh0lt requested a review from yperbasis as a code owner April 24, 2026 17:22
@mh0lt mh0lt enabled auto-merge April 24, 2026 18:02
@mh0lt mh0lt added this pull request to the merge queue Apr 24, 2026
Merged via the queue into main with commit 3fa93ab Apr 24, 2026
37 checks passed
@mh0lt mh0lt deleted the feat/exec-perf-flags branch April 24, 2026 19:14
@yperbasis yperbasis added the Glamsterdam https://eips.ethereum.org/EIPS/eip-7773 label Apr 25, 2026
mh0lt added a commit that referenced this pull request Apr 28, 2026
…I flags (#20862)

Cherry-pick of #20797 to bal-devnet-3.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mh0lt added a commit that referenced this pull request Apr 28, 2026
Follow-up to #20797. Adds a single-purpose boolean that forces serial
execution by clamping the parallel executor's worker count to 1 — wins
over both --exec.workers and EXEC3_WORKERS. Cleaner than `--exec.workers=1`
because it states intent ("force serial") at the call site rather than
relying on a magic value, and it can't be accidentally undone by a stale
EXEC3_WORKERS env var that gets re-read by tooling.

Use case: like-for-like baseline comparisons against the parallel executor
(devnet A/B runs, profiling cold paths) where the operator explicitly
wants serial irrespective of any other knob.

Wiring: applied AFTER --exec.workers in SetEthConfig, so:
  --exec.serial=true                          → workers=1
  --exec.workers=12 --exec.serial=true        → workers=1 (serial wins)
  --exec.workers=12                           → workers=12
  --exec.serial=false  (default)              → no override

Test: TestExecPerfFlags_OverrideDbg covers serial-true, serial-vs-workers
precedence, and serial-false-leaves-untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
mh0lt added a commit that referenced this pull request Apr 28, 2026
…orkers to 1 (#20863)

Cherry-pick of #20853 to bal-devnet-3. Depends on #20862 (#20797
cherry-pick).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sahil-4555 pushed a commit to Sahil-4555/erigon that referenced this pull request Apr 28, 2026
…0853)

## Summary

Follow-up to erigontech#20797. Adds a single-purpose boolean — \`--exec.serial\` —
that forces serial execution by clamping the parallel executor's worker
count to 1. Wins over both \`--exec.workers\` and \`EXEC3_WORKERS\`.

## Why a separate flag rather than just \`--exec.workers=1\`

- States intent at the call site (\"force serial\"), so logs / launch
scripts / dashboards read clearly.
- Can't be accidentally undone by a stale \`EXEC3_WORKERS\` env var
picked up by a test harness or wrapper script.
- Lets operators do like-for-like baseline comparisons against the
parallel executor (A/B perf runs on bal-devnet-3, profiling cold paths)
without juggling worker numbers.

## Precedence (resolved in \`SetEthConfig\`)

| Flags / env | Result |
|---|---|
| \`--exec.serial=true\` | \`workers=1\` |
| \`--exec.workers=12 --exec.serial=true\` | \`workers=1\` (serial wins)
|
| \`--exec.workers=12\` | \`workers=12\` |
| \`--exec.serial=false\` (default) | no override; env var / default
applies |

## Test plan

- [x] \`go test -short ./cmd/utils/...\` —
\`TestExecPerfFlags_OverrideDbg\` extended with three new subtests:
serial=true clamps, serial=true wins over --exec.workers, serial=false
leaves Exec3Workers untouched.
- [x] \`make lint\` — 0 issues, twice.
- [x] \`make erigon\` — \`--help\` shows the new flag with the correct
usage and default.

## Files touched

- \`cmd/utils/flags.go\` — flag definition + wiring in SetEthConfig
(post --exec.workers so it overrides cleanly).
- \`cmd/utils/flags_test.go\` — three new subtests.
- \`node/cli/default_flags.go\` — register flag in DefaultFlags.

~35 LOC including tests.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Glamsterdam https://eips.ethereum.org/EIPS/eip-7773

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants