Skip to content

Optimize WASM trigger instantiation#6364

Open
lutter wants to merge 5 commits intomasterfrom
lutter/wasm
Open

Optimize WASM trigger instantiation#6364
lutter wants to merge 5 commits intomasterfrom
lutter/wasm

Conversation

@lutter
Copy link
Collaborator

@lutter lutter commented Feb 14, 2026

  • Enable Cranelift OptLevel::Speed for WASM compilation (configurable via env var)
  • Move per-trigger state (gas, deterministic_host_trap) out of the shared context into WasmInstanceData so the linker can be built once
  • Cache the Linker and InstancePre on ValidModule so trigger instantiation skips re-linking and re-compilation
  • Cache asc_type_id results on ValidModule to avoid repeated lookups
  • Register chain host functions explicitly instead of discovering them dynamically, removing BUILTIN_IMPORT_NAMES

The common thread is making the WASM runtime faster and cleaner — the first four commits reduce per-trigger overhead, and the last one is a cleanup enabled by the linker extraction in commit 3.

Switch the default Cranelift optimization level from `None` to `Speed`,
improving WASM handler execution performance. The optimization level is
configurable via the `GRAPH_WASM_OPT_LEVEL` environment variable
(valid values: `none`, `speed`, `speed_and_size`; default: `speed`).

This is safe because Cranelift adheres to the Wasm spec and NaN
canonicalization is already enabled. The increased compilation time is a
one-time cost per module, amortized over thousands of triggers.
Move the per-trigger GasCounter and deterministic_host_trap flag from
standalone variables captured by linker closures into the Store data
(WasmInstanceData). This is a pure refactoring with no behavior change.

Previously, GasCounter and an Arc<AtomicBool> for
deterministic_host_trap were created as separate variables and captured
by each linker closure. Now they live on WasmInstanceData and are
accessed through caller.data()/caller.data_mut() inside the closures.

This decouples the linker closures from per-trigger state, which is a
prerequisite for caching InstancePre on ValidModule (reusing the linker
across triggers).
…ation

Extract linker construction from per-trigger `from_valid_module_with_ctx`
into a standalone `build_linker()` function called once at module
validation time. The linker is pre-linked via `linker.instantiate_pre()`
and the resulting `InstancePre` is stored on `ValidModule`.

This eliminates the per-trigger cost of:
- Rebuilding a Linker with ~60 func_wrap_async registrations
- Resolving imports against the module

Chain-specific host functions (e.g. ethereum.call) are now dispatched
generically: the linker registers them by import name and looks up the
actual HostFn from caller.data().ctx.host_fns at call time.

Conditional functions (ipfs.getBlock, arweave.transactionData,
box.profile) are now linked unconditionally since they already check
feature flags or return errors internally.
Every WASM heap allocation (API version > 0.0.4) called asc_type_id(),
which did a call_async into the WASM module for a trivial idof<T>()
switch. The result is deterministic per compiled module, yet every
allocation paid ~200-500ns of call_async overhead (fiber creation, epoch
checking, context switching).

Cache the results on ValidModule using a parking_lot::RwLock<HashMap>,
so after the first trigger warms the cache, all subsequent lookups are
cheap read-lock hits. Lock guards never span .await points.
…ic discovery

Replace the dynamic loop that discovered chain-specific host functions by
excluding BUILTIN_IMPORT_NAMES with explicit registration calls for each
chain function (ethereum.call, ethereum.getBalance, ethereum.hasCode).

Extract the dispatcher into a `link_chain_host_fn` helper that:
- Takes a `&'static str` name, eliminating the `Box::leak` for name strings
- Precomputes metrics strings once rather than on every call
- Returns a proper error instead of panicking when a chain host function
  is not available for the current chain

Delete the BUILTIN_IMPORT_NAMES constant (55 entries) which is no longer
needed.
@lutter lutter requested a review from isum February 14, 2026 00:11
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