Skip to content

Configurable EVM shared-memory pre-allocation (SharedMemoryCapacity) - #5

Merged
KaiCode2 merged 1 commit into
phase-5-cow-snapshotsfrom
configurable-shared-memory
Jun 17, 2026
Merged

Configurable EVM shared-memory pre-allocation (SharedMemoryCapacity)#5
KaiCode2 merged 1 commit into
phase-5-cow-snapshotsfrom
configurable-shared-memory

Conversation

@KaiCode2

Copy link
Copy Markdown
Owner

Makes the per-context EVM shared-memory (working-memory) buffer configurable, instead of hardcoded to 64 KB. Stacked on phase-5-cow-snapshots (#4) because it extends that branch's shared-memory-buffer machinery.

Motivation

The 64 KB buffer was tuned for a state-heavy upstream workload where resizing revm's memory to accommodate loaded chain state was hot. For general users that is often overkill — a wide parallel fan-out of small simulations pays 64 KB per overlay — while state-heavy users may want more. So: let users pick, and auto-size from a loaded state file.

API

SharedMemoryCapacity { Fixed(usize), Auto } (default Fixed(64_000)), set on the builder:

let cache = EvmCache::builder(provider)
    .cache_config(cfg)
    .shared_memory_capacity(SharedMemoryCapacity::Auto) // or Fixed(n)
    .build()
    .await;
  • Fixed(n) pins the buffer; the 64 KB default preserves today's behavior.
  • Auto sizes from the chain state loaded at build time (e.g. a bincode state file via cache_config): loaded_slots * 16, clamped to a 64 kB floor / 4 MiB ceiling. It reads the post-load layer-2 slot count, so it reflects the maintain-list filter and any load source — not just raw file bytes.

Auto is an honest heuristic (persisted state size is a proxy for working-set, not a peak-memory model); the 16 bytes/slot factor and floor/ceiling are named, documented constants, and Fixed is the escape hatch for anyone who has profiled.

Plumbing (no breakage)

  • Resolution lives in a new with_cache_capacity constructor (the builder's worker). new/with_cache/from_backend keep their signatures and default to Fixed(64_000), so existing call sites are untouched.
  • Resolved size stored on EvmCache, exposed via EvmCache::shared_memory_capacity(), raised by the existing reserve_shared_memory, and copied onto every EvmSnapshot so snapshot-backed EvmOverlays pre-allocate the same amount (overlay gains a buffer_capacity field; the old hardcoded overlay constant is removed — both buffers now honor one knob).

Tests

  • resolve heuristic unit test (floor / linear / ceiling; both feature configs).
  • tests/shared_memory_capacity.rs end-to-end over the builder: default → 64 000; Fixed(8192) honored; Auto with no state → 64 000 floor; Auto after persisting + reloading 10 000 slots → 160 000.
  • Full suite 335 (default) / 282 (--no-default-features), zero failures; fmt + clippy (both configs) + doc + bench --no-run clean.

🤖 Generated with Claude Code

The per-context EVM working-memory buffer was hardcoded to 64 KB in two places
(EvmCache + EvmOverlay), tuned for a state-heavy upstream workload. Make it a
first-class knob:

- `SharedMemoryCapacity { Fixed(usize), Auto }`, default `Fixed(64_000)`,
  configured via `EvmCacheBuilder::shared_memory_capacity`. `Fixed` pins the size
  (general users running wide fan-outs of small sims can lower it to cut
  per-overlay memory); `Auto` sizes from the chain state loaded at build time
  (e.g. a bincode state file) — `loaded_slots * 16`, clamped to a 64 KB floor /
  4 MiB ceiling.
- Resolution happens in the new `with_cache_capacity` constructor (the builder's
  worker; `with_cache`/`new`/`from_backend` keep their signatures, defaulting to
  Fixed(64_000)). `Auto` reads the post-load layer-2 slot count, so it captures
  the maintain-list filter and any source, not just the raw file.
- The resolved size is stored on EvmCache, exposed via
  `EvmCache::shared_memory_capacity()`, raised by `reserve_shared_memory`, and
  copied onto every EvmSnapshot so snapshot-backed EvmOverlays pre-allocate the
  same amount (overlay gains a `buffer_capacity` field; the hardcoded overlay
  constant is removed).

Tests: a `resolve` heuristic unit test (floor/linear/ceiling, both feature
configs) and `tests/shared_memory_capacity.rs` end-to-end over the builder
(default, Fixed, Auto-with-no-state floor, and Auto sizing 10k loaded slots →
160_000). Full suite 335 (default) / 282 (--no-default-features); fmt + clippy
(both configs) + doc + bench --no-run clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@KaiCode2
KaiCode2 force-pushed the configurable-shared-memory branch from 1a095a2 to 776fe3e Compare June 17, 2026 08:45
@KaiCode2
KaiCode2 merged commit a140fc6 into phase-5-cow-snapshots Jun 17, 2026
2 checks passed
@KaiCode2
KaiCode2 deleted the configurable-shared-memory branch June 30, 2026 15:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant