Skip to content

perf(aot): accelerate Pure and Full execution paths - #1394

Merged
hero78119 merged 65 commits into
masterfrom
feat/extract_aot_bb_workload
Aug 12, 2026
Merged

perf(aot): accelerate Pure and Full execution paths#1394
hero78119 merged 65 commits into
masterfrom
feat/extract_aot_bb_workload

Conversation

@hero78119

@hero78119 hero78119 commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Problem

PR #1393 moved Preflight accounting and FullTracer replay into native AOT artifacts, but the remaining production path still repeated expensive invariant guards, planner descriptor setup, state reloads, per-access MMIO extrema updates, and allocation-heavy public secp256k1 host arithmetic. The public API also exposed experimental cumulative tracking stages that were useful during profiling but were not intended to become supported execution modes.

This PR finishes that cleanup and leaves two explicit user-facing paths:

  • Pure: diagnostic value execution without proof-compatible FullTracer accounting.
  • Full: production Preflight planning followed by proof-compatible FullTracer replay.

Design Rationale

The production path keeps accounting at the widest boundary that preserves exact shard, tape, witness, and fallback semantics. A block is admitted only after its complete instruction budget, planner descriptors, bucket ceilings, memory ranges, tape capacity, and transition are known to be safe. Failed admission, capacity proximity, bucket crossings, unsupported transitions, dynamic targets, syscalls, traps, and interior entry use the exact scalar path.

Three retained native optimizations reduce repeated work without changing those checks:

  1. Group memory guards that are invariant across an admitted block.
  2. Keep admitted-block register and dense-memory state resident until a guarded exit.
  3. Hoist planner descriptor bases and immutable descriptor data while retaining generation, ceiling, rollback, and shard-split checks.

Full preflight reconstructs heap, stack, and hint extrema once from canonical initialization events instead of updating them on every memory access. The finalized shard plan carries its exact maximum shard size into FullTracerConfig; replay validates boundary ordering, alignment, coverage, shard count, and capacity before allocating its one-record pending buffer.

The LLVM .llvm_bb_addr_map feature from #1393 remains part of the design. cargo ceno build emits the map, the ELF loader validates it, and its workload-independent roots are always compiled as possible AOT entries. Coverage training is retained for dynamic targets, hot layout, event sizing, and planner identity. Static roots are included in cache identity.

Public-data secp256k1 arithmetic uses the crates.io halo2curves-axiom backend with Ceno-local variable-time normalization. AIR behavior, syscall witnesses, invalid-input behavior, infinity handling, parity, and aliasing remain unchanged. Variable-time arithmetic is restricted to public emulator data and is not used for secrets.

Change Highlights

  • ceno_emul::aot
    • add the benchmark-only Pure executor and retain one production Full preflight path;
    • remove public cumulative-stage selectors and stale generic AOT entry points;
    • group invariant memory guards, keep admitted-block state resident, and hoist planner descriptor state;
    • preserve exact scalar fallback for failed admission and unsupported transitions;
    • include LLVM static roots in block coverage and cache identity;
    • grow the preflight tape safely when a new input exceeds trained capacity.
  • ceno_emul::tracer / ceno_zkvm::e2e
    • carry finalized shard capacity into FullTracer replay;
    • validate reconstructed boundaries, step coverage, shard count, and maximum shard size;
    • expose bounded Pure/Full replay APIs and preserve ordered next-access events and syscall witnesses.
  • ceno_emul::syscalls
    • share allocation-free Pure syscall kernels;
    • use OpenVM-style public secp256k1 host arithmetic while preserving Ceno syscall semantics.
  • docs
    • document training, cache identity, runtime ABI, block admission, resident state, planner accounting, memory events, replay, syscalls, and benchmarking requirements.
  • non-AOT builds remain lint-clean; private emitter variants are implementation strategies rather than public modes.

How the Full Path Reached 4.95s

The reduction comes from moving repeated scalar work to safe block or execution boundaries while retaining the exact fallback path:

  • Compile and admit exact native blocks: LLVM basic-block roots, trained dynamic targets, complete instruction budgets, planner descriptors, bucket ceilings, memory ranges, tape capacity, and transitions are resolved before admission. Unsafe or unsupported entries fall back to scalar execution.
  • Keep hot state native: packed memory-access state, registers, dense-memory state, and immutable planner descriptor data remain resident across an admitted block. Invariant memory guards are grouped instead of repeated per instruction.
  • Remove per-access bookkeeping: heap, stack, and hint extrema are reconstructed once from the canonical initialization tape; initialized-register probes and redundant memory-region setup are skipped or reused.
  • Use direct, allocation-free syscall paths: Pure syscall kernels and the generated runtime ABI avoid temporary allocations and unnecessary host round trips while preserving tape and witness order.
  • Size replay from the finalized plan: Full preflight hands its measured maximum shard capacity to FullTracer, avoiding both one-step-buffer exhaustion and defensive over-allocation.
  • Accelerate public secp arithmetic: the retained halo2curves-axiom affine formulas plus Ceno-local variable-time U256::inv_mod reduce the final Full median from 5.364432s to 4.949843s (7.73%). The secp fallback portion alone falls from 1.366264s to 0.976211s (28.55%).

Benchmark / Performance Impact

End-to-end result: 12.47s -> 4.95s

Pinned CPU-0 measurements on canonical block 25580200 show the production Full path improving from the #1393/master baseline to the final candidate:

Operation control (s) this PR (s) Improve (control -> this PR)
Full Preflight, block 25580200 12.476584 4.949843 60.33%

The final number is the median of five alternating samples: 4.949843s, 4.937121s, 4.986585s, 4.928285s, and 4.969867s. All five samples meet the <5.0s target while preserving exact output and accounting parity.

The secp comparison is a controlled five-pair measurement of the isolated final change. Earlier intermediate checkpoints were collected in separate frequency windows, so they are supporting diagnostic evidence rather than additive rows in the end-to-end table. Rejected compact-tape, planner-epoch, syscall-fusion, aggregate-region, and timestamp-cache experiments are not present in production code.

One paired Pure check improved from 2.130265s to 1.770192s (16.90%). On secondary block 25687400, Full improved from 3.915112s to 3.614206s (7.69%) with exact parity.

Benchmark command:

taskset -c 0 env \
  CENO_MAX_CELL_PER_SHARD=4500000000 \
  CENO_AOT_CACHE_DIR=<isolated-cache> \
  target/release/ceno-reth-benchmark-bin \
    --mode aot-full \
    --block-number 25580200 \
    --chain-id 1 \
    --input-path block_data/input/1/25580200.bin

Environment: AMD Ryzen 9 5900XT, CPU 0, Linux 6.8, jemalloc,gpu,aot, rustc 1.93.0-nightly, frozen cached block input, and warm isolated AOT artifacts. Timings are observed measurements; isolated-candidate conclusions use alternating paired runs where stated.

Testing

cargo fmt --all -- --check
cargo make clippy
cargo clippy -p ceno_emul --all-targets --features aot-x86_64 -- -D warnings
cargo check -p ceno_zkvm --features aot-x86_64
cargo check -p cargo-ceno --features aot-x86_64
cargo test -p ceno_emul --features aot-x86_64 aot::tests
cargo test -p ceno_emul --features aot-x86_64 elf::tests
mdbook build docs

All commands pass locally. The current focused suites report 46 AOT tests and 7 LLVM basic-block-map parser tests passing. A real release guest built through cargo ceno contains .llvm_bb_addr_map; cold production AOT preflight completed with zero dynamic-PC and memory-guard fallbacks and prepared the FullTracer replay artifact.

Canonical differential checks preserve:

  • block 25580200: hash 34439c597563024690ce3c91a082c34507569c7e18cc4d1b3b68550b791a2773, exit 0, 994,896,527 instructions, cycle 3,979,586,112, 35 shards / 36 boundaries, and 16,865,461 ordered events;
  • block 25687400: hash d9beb945e65579fa6d95d14012936cf8c7dcf7c52ed54d96f53aa3b0538ff899, exit 0, 663,258,404 instructions, cycle 2,653,033,620, 25 shards / 26 boundaries, and 14,472,131 ordered events.

Pure/Full guest state, planner output, tape order, syscall witnesses, and replay records match their generic reference paths in focused differential tests.

Risks and Rollout

  • Pure is diagnostic and must not be presented as proof-compatible execution.
  • Generated-code and runtime-layout changes are isolated by AOT ABI/cache identity; corrupt or incompatible artifacts rebuild instead of loading.
  • LLVM static roots are validated on ELF load and included in the program digest; trained dynamic roots remain a safe supplement.
  • Full replay validates the complete shard-capacity handoff before allocating records.
  • Every native admission optimization retains exact scalar fallback and rollback behavior.
  • Public secp256k1 host arithmetic is variable-time by design and must remain restricted to public data.
  • Generated Full artifacts remain large and frontend pressure is still measurable; rollback is a source-level revert of the individual retained optimization commits.

Follow-ups (optional)

  • Continue profiling only when a candidate has a soundness argument and a measured causal saving large enough to justify additional generated-code complexity.

Copilot Reviewer Directive (keep this section)

When Copilot reviews this PR, apply .github/copilot-instructions.md strictly.

hero78119 added 30 commits July 27, 2026 13:26
Train dynamic roots across the complete preflight workload and persist ABI-keyed native artifacts with checksum validation and atomic replacement. Track fallback reasons and recover safely through dynamic control flow and guarded memory accesses.
…t_aot_bb_workload

# Conflicts:
#	ceno_emul/src/aot.rs
#	ceno_zkvm/src/e2e.rs
Admit only aligned LW/SW accesses sharing a base register and byte offset. Check the full affine interval for wrapping and region membership once, while retaining scalar guards for ungrouped or rejected accesses. Bump the cache identity because emitted code changes.
After block admission, keep the register base, dense-memory base, and memory ordinal base in their documented callee-saved registers. Emit memory events from the loaded cell metadata and defer next-PC/status stores until block exit. Scalar fallback, shard transitions, syscalls, and non-admitted entries continue to refresh context state.
Load generation, instance-count, and bucket-ceiling table bases once per admitted planner sequence. Preserve the existing generation and capacity checks, rollback path, and slow fallback for stale generations or bucket crossings.
Move public secp256k1 add/double normalization to halo2curves-axiom with Ceno-local variable-time field inversion. Preserve syscall witnesses, invalid inputs, infinity output, parity, and alias fallback; add deterministic differential and edge-case coverage.
Remove public cumulative preflight stages, tracking trainers, and generic compilation APIs. Production preflight now uses private scalar and admitted-block strategies, while tests exercise Pure value execution and FullTracer-compatible execution directly.
Provide a narrow production API that consumes the finalized preflight plan and replays every shard through FullTracer without assigning circuit witnesses. The replay preserves the exact preflight capacity and validates step, shard, exit-code, next-access, and boundary parity.
Gate AOT-only tracer, syscall, and benchmark support at their feature boundaries. Modernize deprecated secp byte conversions, make unsafe conversion types explicit, and document unavoidable transitive dependency-version lint exceptions so workspace all-target Clippy passes with warnings denied.
@hero78119 hero78119 changed the title Feat/extract aot bb workload perf(aot): accelerate Pure and Full execution paths Aug 11, 2026
@hero78119
hero78119 merged commit f17c6c1 into master Aug 12, 2026
6 of 7 checks passed
@hero78119
hero78119 deleted the feat/extract_aot_bb_workload branch August 12, 2026 08:08
hero78119 added a commit that referenced this pull request Aug 13, 2026
It was accidently included in previous PR
#1394

Benchmark shows although It bring benefit to main sumcheck univariate
evaluation, however a side effect is performance regressed due to the
new resident column bring more overhead to GPU vram which reduce the
multi-tower concurrency scheduling.
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