Skip to content

perf(timing): reduce native replay evidence overhead - #295

Merged
jthomson04 merged 8 commits into
mainfrom
jthomson04/optimize-native-evidence-builder
Sep 23, 2026
Merged

jthomson04 merged 8 commits into
mainfrom
jthomson04/optimize-native-evidence-builder

Conversation

@jthomson04

@jthomson04 jthomson04 commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Native replay added per-operation timing evidence in #211. Each prediction then copied and revalidated evidence, and each cache miss converted operator results through Python before constructing evidence again. This PR reduces that CPU work while preserving latency, power, energy, coverage, source attribution, diagnostics, defaults, and errors.

  • Share immutable validated cache entries with Arc, and borrow them during accumulation.
  • Add a private accumulation path for matching operation layouts, with reusable numeric scratch storage and validation before committing updates. Keep the checked public accumulator as the fallback and independent reference.
  • Call run_static_per_op on the native engine returned by the canonical constructor. Keep the Python bridge as a test-only differential reference.
  • Move native operation names and convert borrowed source tags directly. Build cached phases from the provider's already grouped rows, without repeated validation or duplicate-name searches.

The five original implementation commits remain separate, followed by three signed review-fix commits. The full diff is four Rust files, +1093/-89 lines. No public API, model data, golden, estimator selection, cache key/capacity, mutex, scheduler, or reporting changes.

Latest rebase: head 50ab2abb591c1714d4a3cabc0bbb4bdce89dc478 is based on main e95d37863fb30232e089b21f058bc28d1dfa1729. All eight signed commits remain. The rebase preserves main's evidence-reset test, updates the reset method to use TimingEvidenceAccumulator, and supplies the new original_fmha_quant_mode field in the missing-data test fixture. git range-diff confirms that the remaining patch changes are context adjustments. No benchmarks were rerun after this rebase; all measurements below describe the explicitly pinned earlier revisions.

  • Fix default-feature warnings, share the known source-tag table, strengthen debug-only builder contracts, use the exported stride, and improve native-provider coverage.
  • Reuse one immutable empty phase and skip empty accumulation only for operation-backed state. Empty and phase-only accumulated states keep the checked path.
  • Keep the independent checked accumulator/builder, release-time provider contract, branch-local selection, and existing error mapper. The wider refactors are explicitly deferred in the review replies.

The fresh comparison below measures the full PR against its pinned base. It does not isolate the two review-fix commits or make a separate performance claim for the zero-work changes.

Review map

  • Risk level: medium, because exact floating-point values and failure behavior must remain unchanged.
  • Start with crates/core/src/engine/timing.rs: the immutable wrapper, private accumulator, and native-row builder. Review crates/core/src/python.rs for native-provider ownership, conversion, and cache publication.
  • Public or serialized contract changed: no. The original checked constructors/accumulator remain unchanged; the native builder documents unique names in first-encounter order and checks uniqueness in debug builds.
  • Arithmetic and error handling: retain ordered additions and totals reconciliation, missing/zero-energy behavior, source merging, row-error precedence, and atomic failure. FPM scalar, fixed, and polynomial timing paths are unchanged.
  • Compatibility/rollback: the five implementation commits and three review commits remain separate; main's decode and diagnostics behavior is retained.

Validation

Local checks for the latest rebase (50ab2abb):

  • Fresh native SDK build passes.
  • Default Rust workspace: 1,727 passed, one existing ignored test.
  • Rust workspace with embed-python,replay-bench: 1,788 passed, one existing ignored test. AIC_REQUIRE_EMBEDDED_ROUND_TRIP=1 was set; native-versus-Python parity, the embedded round trip, and the preserved evidence-reset test all executed and passed.
  • Python power contracts and diagnostics: 164 passed.
  • Formatting and diff whitespace checks pass. All eight commits retain DCO sign-offs.
  • Full CI for this exact head is in progress; its result is separate from these local checks.

Local rebase checks at 4a95f4ea:

  • Fresh native SDK build and default-feature workspace check pass.
  • Embedded-Python Rust core: 1,585 passed, one existing ignored test. AIC_REQUIRE_EMBEDDED_ROUND_TRIP=1 was set, so native-versus-Python parity executed.
  • Power contracts and diagnostics: 167 passed.
  • Formatting and diff whitespace checks pass. All eight commits retain DCO sign-offs.
  • Full CI was restarted for this exact head; its result is separate from these local checks.

Local checks at review head 7fddbd927f760ce3122992eede314a3be91fbc5d:

  • Default-feature workspace check and embedded-Python core/test check pass, with zero compiler warnings.
  • Debug Rust core: 1,468 passed with default features; 1,517 passed with embed-python. Each has one existing ignored test. Debug contract assertions are exercised.
  • Power contracts and diagnostics: 167 passed.
  • Native CLI: 13 passed.
  • Timing/source/detail CLI tests from feat(cli): add native timing and source detail reports #272: 109 passed.
  • Formatting and diff whitespace checks pass. Clippy including test code matches pinned main in both modes: 223 default-feature warnings and 224 embedded-Python warnings; no new warnings.
  • The native-versus-bridge test covers public prefill/decode calls, repeated cache hits, changing geometry and exact accumulated evidence. Empty-result coverage exercises both native evidence and diagnostics.
  • No goldens were refreshed. A separate final-head benchmark confirmation followed the review checks, as reported below. CI results are separate from these local checks.

The initial embedded-Python run used a stale library path in the relocated Python installation and failed importing _contextvars. After correcting the test environment, the complete suite passed without a source change.

The differential tests compare numeric fields by bits against the unchanged checked implementations. They cover repeated/changed layouts, duplicate-name folding, missing and positive energy, partial coverage, unknown sources, signed zero, invalid inputs, overflow, error precedence, and unchanged state after failure. Native-versus-bridge checks cover prefill/decode, prefixes, changing contexts, cache hits, provenance, invalid-mode errors, and missing data. No goldens were refreshed.

Fresh release-build qualification at 7fddbd92 has exact per-request results and exact summaries/evidence on AgentX and the fixed-ID synthetic fixture. Exclusions are only wall_time_ms, processed_tokens_per_s, processed_output_tokens_per_s, and generated request UUIDs. The original random-ID synthetic run has exact request results and evidence, with three retained aggregation-order differences: mean_e2e_latency_ms (147950.05294399973 vs 147950.05294399976), std_ttft_ms (363.6550848106251 vs 363.65508481062517), and std_tpot_ms (0.08880466051541563 vs 0.08880466051541555). The fixed-ID fixture matches exactly.

Matched measurements before the September 21 rebase

Pinned main 7ae483e942b0a2593d55e4e30957f94640580441 versus PR 7fddbd927f760ce3122992eede314a3be91fbc5d. Both fresh builds include #272 and #289. Separate worktrees, Python environments and Cargo targets use matching dependencies and measured data. Native --stack engine, CPU 4, optimized builds with debug symbols, warm filesystem caches, and no concurrent builds or profiles. Optional timing/source-detail diagnostics are off.

Workload Pairs Main CPU PR CPU CPU change Main wall PR wall Wall change
AgentX 2 35.4101 s 22.8888 s -35.36% 35.4486 s 22.9329 s -35.31%
Synthetic long decode 2 2.1636 s 1.8550 s -14.27% 2.1889 s 1.8980 s -13.29%

Values are medians. CPU includes the supervisor and descendants. Both workloads improve in both pairs; all eight timed runs are included, with no exclusions. Expected completion and output-token counts pass in every run. Revision order reverses in the second pair.

  • AgentX nominal paired 95% intervals: CPU [-39.69%, -30.72%]; wall [-39.34%, -31.01%].
  • Synthetic nominal paired 95% intervals: CPU [-14.29%, -14.24%]; wall [-26.01%, +1.63%]. The wall interval supports the 3% regression limit but does not establish a wall-time benefit.
  • The original 25% AgentX CPU target and all 3% CPU/wall regression limits pass. No extra pairs were needed. These are small-sample Student-t intervals on paired log ratios, assuming independent, approximately normal ratios, without an adjustment for adaptive stopping. The narrow synthetic CPU interval describes these two pairs only.
  • AgentX CPU/output token: 7.8355 to 5.0648 microseconds; internal replay: 31.6856 to 19.1076 s. Median max-process RSS: 430.49 to 435.40 MiB; sampled aggregate peak RSS: 467.21 to 471.69 MiB. Synthetic memory is approximately unchanged.

The local confirmation worktree retains REPORT.md, RESULTS.md, REPRODUCE.md, full provenance, qualification comparisons and every raw run. No new profile or microbenchmark was collected; the profiles below remain historical.

Matched measurements before the final #272 rebase

Previous main 7cfa4f20 versus the earlier rebased PR 7c0e0e89. These measurements do not include #272 or describe the post-#272 review head. Both builds include the same later main changes, including #289. These results measure the full PR, not only its last two commits.

Workload Pairs Main CPU PR CPU CPU change Main wall PR wall Wall change
AgentX 2 33.9092 s 22.3678 s -34.04% 33.9776 s 22.4080 s -34.05%
Synthetic long decode 2 2.1180 s 1.8465 s -12.82% 2.1369 s 1.8874 s -11.68%

AgentX: nominal paired 95% CPU interval [-43.70%, -22.70%]; wall interval [-43.61%, -22.86%]. CPU improves in 2/2 pairs.

Synthetic: nominal paired 95% CPU interval [-13.65%, -11.97%]; wall interval [-17.34%, -5.63%]. CPU improves in 2/2 pairs.

That pre-#272 two-pair comparison passed the CPU/wall regression checks. Its AgentX interval crosses the original 25% improvement target. That earlier sample did not establish the 25% target; its stopped third pair remains excluded. Pairs alternate revision order. Paired Student-t log-ratio intervals are nominal small-sample intervals, not adjusted for adaptive stopping. All trials, ranges, per-token costs, replay time and both memory measures are retained in RESULTS.md.

No new profile or microbenchmark was collected for either rebase. Profiles and diagnostic values below describe the preserved historical revisions only.

Historical stage measurements (before rebase)

Two separate campaigns measure the stages. Do not add their percentages or treat them as one matched baseline-to-final measurement.

Comparison Workload Paired rounds Control median CPU Candidate median CPU Change
a2eae639 → 92ea946a (cache, accumulation, native bridge) AgentX 6 33.8926 s 24.7750 s -26.90%
a2eae639 → 92ea946a Synthetic long decode 6 2.1007 s 1.8827 s -10.38%
92ea946a → 0e35fae1 (source conversion and builder) AgentX 2 24.9389 s 22.4274 s -10.07%
92ea946a → 0e35fae1 Synthetic long decode 4 1.8848 s 1.8251 s -3.17%

The first campaign's AgentX nominal paired 95% interval is a 25.42–27.51% reduction; all six pairs improve. The builder campaign's interval is an 8.28–11.83% reduction; both pairs improve. Its AgentX wall time falls 10.08%, and synthetic wall time falls 2.69%. All four synthetic pairs improve. Both campaigns meet their respective 25% and 5% CPU gates and the 3% CPU/wall regression limits.

Both campaigns start with two alternating pairs and add pairs only to resolve a threshold. In the builder campaign, only the synthetic CPU interval needed two more pairs. Intervals use paired Student-t log ratios and assume independent, approximately normal pair log ratios. These are nominal small-sample intervals, not adjusted for adaptive stopping.

Native --stack engine, serial performance CPU 4, warm filesystem caches, matching Python/Rust/dependencies/data, separate optimized builds with debug symbols, and no concurrent builds or profiles during measurement. Process CPU includes waited and adopted descendants, verified by accounting probes. Detailed request capture is off during timing.

  • AgentX: saved 32-session Qwen3.8 trace, SGLang 0.5.17, GB300, TP16, MoE TP4/EP4; 4,265 requests / 4,519,160 output tokens.
  • Synthetic: 1,024 input / 4,096 output tokens, concurrency 32, 256 requests / 1,048,576 output tokens.
  • Builder campaign CPU/output token: 5.5185 → 4.9627 microseconds; internal replay: 21.2230 → 18.6979 s. Median max-process RSS: 513.62 → 514.44 MiB; sampled aggregate RSS: 550.41 → 550.21 MiB.
  • Separate 99 Hz AgentX profiles: evidence-validation self weight falls from 6.497 billion cycles (4.81%) to 1.279 billion (1.05%). Leaf-only unwind weight is 12.55% / 14.13%; inclusive groups overlap and incomplete stacks limit attribution.
  • The construction diagnostic falls from 2.550 → 0.873 microseconds for 24 operations and 3.457 → 1.117 microseconds for 32. Native input creation is outside the timer; conversion, construction, and destruction are inside. Both variants retain 5,957 cache hits, 2,237 provider calls, and 53,688 operations. Microbenchmark improvements are not additional end-to-end savings.

The harness, configurations, traces, complete reports, raw profiles, and flamegraphs remain in the profiling worktrees and are not part of the production diff. Exact commands for the pre-rebase confirmation:

cd /home/jothomson/Desktop/dynamo/.worktrees/aisimulate-pr295-confirm-candidate-20260918
CONFIRM_ROOT="$PWD/benchmark-harness/pr295-confirmation"
python3 "$CONFIRM_ROOT/scripts/build.py" control candidate
python3 "$CONFIRM_ROOT/scripts/provenance.py"
python3 "$CONFIRM_ROOT/scripts/qualify.py" candidate
AISIM_ROUNDS='[1,2]' python3 "$CONFIRM_ROOT/scripts/campaign.py" candidate
python3 "$CONFIRM_ROOT/scripts/analyze.py" candidate
python3 "$CONFIRM_ROOT/scripts/tables.py"

These commands refer to the retained local harness. It refuses to replace existing run directories; use unused round numbers to repeat measurements.

Modeling or data provenance

No estimation or measured-data changes. The pre-rebase comparison uses matching 132 external Python packages, Cargo/uv locks, and 1,483 measured-data files (126,134,657 bytes). Full identities and config hashes are retained in analysis/provenance.json.

  • Data manifest SHA-256: 5b017086065f0923f7db054e2aa685276f5bad2a1df6da0bc3685732591b2410.
  • AgentX input SHA-256: d156d09055ce272e3e490bb8490ed3379e579435947a4fedd76beaed16818abe.
  • Fixed-ID input SHA-256: 7cc9fcf593f8e7b36e9076066ccc516d97f738815c87f75f71b757bf2944c10b.
  • Pre-rebase control extension SHA-256: c955adb4395ddc8c61c7a431643fb118a793f2d1ac5cbda9515eaa544406d4c7.
  • Pre-rebase candidate extension SHA-256: f2d378b30231e8957e8ba2294a67ad4f55e9518827942d41ccc0963357aa98d0.
  • Pre-feat(cli): add native timing and source detail reports #272 control extension SHA-256: c364db87b30914c885afd29c6162f1c51da71012176fe1c832544dc42e23458e.
  • Pre-feat(cli): add native timing and source detail reports #272 candidate extension SHA-256: 028c123ea7e63b8005d720157ac8aacf6d87ca9e2ddfec1f33ae67ea718d12cb.

The historical ~60% slowdown is context for this work, not a claim that all historical overhead has been removed. The historical stage comparisons exclude later main changes, including #289; the pre-rebase comparison includes them in both variants.

Tracking

@coderabbitai

coderabbitai Bot commented Sep 19, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: ai-dynamo/aisimulate/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 081ae7d0-f50f-4353-a371-31303b4bfc17

📥 Commits

Reviewing files that changed from the base of the PR and between 4a95f4e and 50ab2ab.

📒 Files selected for processing (3)
  • crates/core/src/engine/mod.rs
  • crates/core/src/engine/timing.rs
  • crates/core/src/python.rs
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • ai-dynamo/dynamo (manual)
  • ai-dynamo/aiconfigurator (manual)

Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review.

📜 Recent review details
⏰ Context from checks skipped due to timeout. (21)
  • GitHub Check: Prediction Regression / Collect prediction snapshot (new)
  • GitHub Check: Prediction Regression / Collect prediction snapshot (old)
  • GitHub Check: Platform Wheels / Build wheels (macosx_arm64)
  • GitHub Check: Platform Wheels / Build wheels (manylinux_2_28_aarch64)
  • GitHub Check: Platform Wheels / Build wheels (manylinux_2_28_x86_64)
  • GitHub Check: Collector Data / Perf data sanity (informational)
  • GitHub Check: Collector Data / Check collector data
  • GitHub Check: Release Artifact Contract (amd64)
  • GitHub Check: Python Dependency Licenses
  • GitHub Check: Rust (amd64)
  • GitHub Check: Release Artifact Contract (arm64)
  • GitHub Check: Engine Golden Regression
  • GitHub Check: Rust feature modes
  • GitHub Check: Python 3.11 compatibility
  • GitHub Check: Python 3.13 compatibility
  • GitHub Check: Application Test Wheel (amd64)
  • GitHub Check: Application Test Wheel (arm64)
  • GitHub Check: Rust (arm64)
  • GitHub Check: Public API Rust (amd64)
  • GitHub Check: Public API Rust (arm64)
  • GitHub Check: Forward Prediction Performance (advisory)
🧰 Additional context used
📓 Path-based instructions (4)
Review scheduler state transitions and event ordering, including cancel, preempt, drain, retry, duplicate, empty, and terminal paths.

⚙️ CodeRabbit configuration file

Files:

  • crates/core/src/engine/mod.rs
  • crates/core/src/engine/timing.rs
Treat top-level exports and bindings as public and release boundaries.

⚙️ CodeRabbit configuration file

Files:

  • crates/core/src/python.rs
Read REVIEW.md before commenting.

⚙️ CodeRabbit configuration file

Files:

  • crates/core/src/engine/mod.rs
  • crates/core/src/engine/timing.rs
  • crates/core/src/python.rs
Before making any change under: `python/aisimulate/src/aiconfigurator/generator/**` MUST read: `python/aisimulate/.claude/rules/generator-development.md` Before making any change under `python/aisimulate/collector/**` MUST read: `python/ais...

📄 CodeRabbit inference engine (AGENTS.md)

Files:

  • crates/core/src/engine/mod.rs
  • crates/core/src/engine/timing.rs
  • crates/core/src/python.rs
🔀 Multi-repo context ai-dynamo/dynamo, ai-dynamo/aiconfigurator

Linked repositories findings

ai-dynamo/dynamo

  • Cargo.toml:59 pins aisimulate-core exactly to 0.12.0; dependency tests enforce matching Python, container, Cargo, and lockfile versions. Any release version change needs coordinated updates. [::ai-dynamo/dynamo::]
  • lib/bindings/python/rust/llm/aic_callback.rs:39-64 uses only existing AicEngine latency APIs. A broad search found no consumers of TimingEvidenceAccumulator, ValidatedTimingPhase, or run_static_per_op. [::ai-dynamo/dynamo::]

ai-dynamo/aiconfigurator

  • _aiconfigurator_core.pyi:54-83 defines run_static_per_op as returning two lists of (name, latency, energy, source) tuples. [::ai-dynamo/aiconfigurator::]
  • API.md:237-241 documents this four-field PerOpValue shape as the compatibility contract, with missing per-op energy represented as 0.0. [::ai-dynamo/aiconfigurator::]
  • engine/runtime.rs:539-562 requires name folding before stride weighting, preserving (r1 + r2) * k semantics. The new accumulator’s fast path must remain equivalent to this ordering. [::ai-dynamo/aiconfigurator::]
🔇 Additional comments (3)
crates/core/src/engine/timing.rs (1)

861-927: LGTM!

Also applies to: 1365-1586

crates/core/src/engine/mod.rs (1)

43-44: LGTM!

crates/core/src/python.rs (1)

418-429: LGTM!

Also applies to: 435-435, 438-439, 470-470, 487-487, 490-490, 502-507, 532-601, 611-611, 615-615, 619-619, 624-624, 628-652, 668-668, 699-700, 750-751, 759-762, 770-770, 2511-2511, 2516-2516, 2519-2519, 2524-2732, 2955-2955, 2961-2963, 3413-3413, 3427-3427, 3440-3440, 3462-3462, 3486-3486, 3511-3511, 3531-3534, 3552-3552, 3590-3590, 3609-3610, 3616-3617, 3619-3619, 3622-3640, 3643-3643, 3645-3645, 3649-3653, 3660-3664, 3667-3819, 3825-3825


📝 Summary

Risk level: Medium.

Human attention should focus on:

  1. Fast-path accumulation, validation, and atomic failure handling.
  2. Native-engine parity with the Python bridge.
  3. Cache sharing, empty evidence, and uncommon operation layouts.

Changes

  • Production timing evidence now uses the native performance-model engine.
  • Validated phases and accumulators add a fast path for matching operation layouts.
  • Updates validate before commit, so failed updates do not partially modify state.
  • Immutable cache entries use shared ownership through Arc.
  • Native operation names and source tags reduce allocation.
  • Empty evidence is reused, and empty operation-backed updates are skipped.
  • Python implementations remain available as differential-test references.
  • Crate-visible re-exports were added for TimingEvidenceAccumulator and ValidatedTimingPhase.
  • aic_to_py and parse_mode are now pub(crate).

Public serialization, diagnostics, fallback implementations, and builder contracts are intended to remain unchanged.

Evidence supplied

  • Local Rust, Python, power, diagnostics, CLI, formatting, and clippy checks passed.
  • Release qualification produced exact results on AgentX and the fixed-ID synthetic fixture.
  • AgentX CPU time decreased by 35.36%.
  • Synthetic CPU time decreased by 14.27%.
  • AgentX wall time decreased by 35.31%.
  • Synthetic wall time remained within the stated regression limit.
  • Tests cover parity, caching, accumulation equivalence, atomicity, invalid data, topology, capacity, and empty-provider behavior.

Evidence still missing

  • Current review finding counts are unavailable.
  • No independent review result is supplied.
  • No CI or deployment qualification result is supplied.
  • Repository cleanliness is not established by the supplied command result.

Technical quality and merge readiness

The implementation adds validation before commit, retains fallback behavior, and includes targeted parity and failure coverage. The main risks are divergence between native and Python evidence generation and incorrect behavior for uncommon operation layouts.

The supplied evidence supports continued review. It does not establish merge readiness without independent review and CI or deployment results.

Walkthrough

The change adds validated timing phases and atomic evidence accumulation. Python timing predictions use native providers, cached validated phases, and accumulator snapshots. Python conversion remains available for test parity and validation.

Changes

Native timing evidence

Layer / File(s) Summary
Timing contracts and accumulation
crates/core/src/engine/mod.rs, crates/core/src/engine/timing.rs
Adds feature-gated exports, shared tag parsing, ValidatedTimingPhase, and TimingEvidenceAccumulator. Accumulation validates before commit and preserves state on failure.
Native prediction pipeline
crates/core/src/python.rs, crates/core/src/perfmodel/py.rs
AicTimingModel uses native phase providers, validated cached phases, and accumulator snapshots. Native and Python evidence conversion validates energy and preserves provenance.
Pipeline parity and failure validation
crates/core/src/python.rs, crates/core/src/engine/timing.rs
Tests cover provider parity, caching, provenance, invalid evidence, overflow, empty results, and rollback behavior.

Priority: ➖ Normal

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: ⚪ Minimal · up to 50ab2

Native replay timing now uses the in-process performance engine and a faster evidence accumulator. The existing checks show the same latency, energy, and coverage results as before. No concrete correctness, data, or availability problem was found at this head. Earlier suggestions about warnings in default-feature builds, duplicated logic, and test coverage remain optional follow-ups.

🚥 Pre-merge checks | ✅ 8
✅ Passed checks (8 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cross-Layer Contract ✅ Passed The diff changes four Rust files. New evidence types and the newly visible aic_to_py and parse_mode helpers are crate-private; TimingEvidenceSource::from_provider retains its existing tag mappin…
Modeling And Data Evidence ✅ Passed The PR changes four Rust source files and changes how timing evidence is obtained; it does not change model/performance data or estimation formulas. The changed provider switches from the Python bridg…
Compatibility Boundaries ✅ Passed No compatibility boundary change is introduced. The reviewed diff changes only four Rust source files; the added evidence types and widened helper visibility are pub(crate), and no Python binding si…
Review Evidence ✅ Passed The description reports named local build/test suites and results, gives exact benchmark harness commands and measured outcomes, and lists boundary checks including invalid inputs, overflow, empty res…
Title check ✅ Passed The title precisely describes the main change: reducing native replay timing-evidence overhead.
Description check ✅ Passed The description covers the change, review risks, validation, provenance, and tracking. It does not identify the Codex-reviewed commit, which the template requires for a medium-risk change.

Comment @coderabbitai help to get the list of available commands.

@jthomson04
jthomson04 force-pushed the jthomson04/optimize-native-evidence-builder branch 2 times, most recently from 7c0e0e8 to 2019d04 Compare September 19, 2026 02:35

@jthomson04 jthomson04 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: perf(timing) native replay evidence — 13 findings

Posting as a comment-only review: the PR is a draft, so no approve / request-changes.

What I actually verified (please read this first)

The fast paths are not wrong, as far as I can tell. The central risk in this PR is that the private accumulator and the name-folded builder must stay bit-identical to the checked implementations, so I tried to break that empirically rather than by reading alone. Everything below ran against head 2019d04c:

Check Result
cargo check --workspace --offline (default features) compiles, 7 new warnings — see finding 1
cargo check -p aisimulate-core --offline --features embed-python --tests clean
cargo test -p aisimulate-core --offline --lib engine::timing 19/19 pass
Randomized differential fuzz of TimingEvidenceAccumulator::record vs TimingPhaseEvidence::try_accumulate — 400 seeds × 40 steps no divergence
Randomized differential fuzz of ValidatedTimingPhase::from_name_folded_operations vs try_from_operations — 3000 cases no divergence

The accumulator fuzzer compared struct equality and to_bits() on every phase and per-operation latency_ms / energy_wms / covered_latency_ms, plus source, details and error strings, across: None/Some(0.0)/Some(-0.0)/subnormal/f64::MAX * 0.4 energies, signed-zero and overflowing latencies, all five TimingEvidenceSource variants including Other, ops carrying and not carrying details, and randomly varying op counts and name sets so that layout changes, duplicate-name folding and the checked-fallback branch were all hit. The builder fuzzer covered unique-name inputs up to 5 ops with the same value classes including f64::MAX.

So: none of the 13 findings below is an observed numeric regression. They are contract, hygiene and structural issues. I also independently re-derived the equivalence of the two implementations by hand (error ordering, reduce-vs-sum energy reduction, the canonicalized() energy filter, operation_totals_match(), phase-only fallback, source merge) and agree with the PR's reasoning.

I separately confirmed that run_static_per_op's PerOpFold really does name-fold in first-encounter order, that reset_provenance / parse_mode ordering matches the pyclass method exactly, that reset_provenance is an atomic on a shared PerfDatabase (so dropping the GIL introduces no new race), and that AicPhaseProvider::Native and self.engine wrap the same Arc<Engine>.

Confidence

All 13 are marked CONFIRMED inline — each is either verified by a command I ran or directly readable from the code. Three are flagged latent (findings 2, 3 and the details aspect of 4): the defect is real in the code but not reachable today, and would be triggered by a plausible future change rather than by current inputs. Nothing is posted as speculative.

Where I proposed a concrete change I offered a suggestion block only after applying it and re-running the builds and tests. Four qualified: the cfg gate here, the record early-return, the OnceLock empty phase, and DEFAULT_STATIC_STRIDE. Each was checked under default features, under --features embed-python --tests, against engine::timing's 19 tests, against my fuzzer, and with cargo fmt --check. The from_provider delegation is prose only, because the lines it would replace fall outside this PR's diff hunks.

Findings outside the diff

None — all 13 anchor to lines inside the changed hunks.

Retracted during review

I had a 14th finding claiming the provenance assertion at python.rs:2255 was vacuous in the missing-data half of native_phase_evidence_matches_python_bridge, on the theory that raw and missing are different engines. That is wrong and I withdraw it: missing is built with Arc::clone(raw.database()), and Engine::last_provenance() reads self.db.worst_provenance(), so the two engines share the atomic and the assertion is meaningful. Recording it here rather than dropping it silently.

Two things I'd genuinely push on

Of the 13, the two worth arguing about rather than just fixing are finding 4 (the private accumulator duplicates bit-exact arithmetic that has no compile-time tie to the original — #272's details field already forced a hand-patch, and the next one gets no warning; a try_accumulate_ref(&mut self, &Self) on TimingPhaseEvidence would deliver the same win from one implementation) and finding 13 (the test helper now defaults to a cfg(test)-only provider, so ten existing tests no longer cover the code that ships).

The measured 34% CPU reduction on AgentX looks well-earned; none of this is a reason to hold the performance work.

Comment thread crates/core/src/engine/mod.rs
Comment thread crates/core/src/engine/timing.rs
Comment thread crates/core/src/engine/timing.rs
Comment thread crates/core/src/engine/timing.rs
Comment thread crates/core/src/engine/timing.rs
Comment thread crates/core/src/python.rs Outdated
Comment thread crates/core/src/python.rs
Comment thread crates/core/src/python.rs
Comment thread crates/core/src/python.rs
Comment thread crates/core/src/python.rs
@jthomson04
jthomson04 marked this pull request as ready for review September 21, 2026 17:21
@jthomson04
jthomson04 requested review from a team as code owners September 21, 2026 17:21
@jthomson04
jthomson04 force-pushed the jthomson04/optimize-native-evidence-builder branch from de81c65 to 4a95f4e Compare September 21, 2026 20:10

@Harrilee Harrilee left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 4a95f4ea3f8208a96289698769890232dd55a328 against e8828036e3d32d8361e2abb819e0ee60e569f518. No blocking findings after tracing provider construction, cache ownership, checked/fast accumulation, energy/coverage/source handling, error precedence and atomicity, empty work, and diagnostics fallback.

Independent correctness evidence on this head:

  • Fresh optimized native builds with identical Cargo/uv locks and the same 1,537 performance-data files.
  • Embedded-Python Rust suite: 1,585 passed, one existing ignored test; native-versus-Python bridge parity explicitly executed. Power tests: 164 passed.
  • Additional standalone differential harness: 100,000 randomized inputs; 94,756 successful updates matched the checked accumulator bitwise, 2,087 constructor rejections, and 3,157 matching atomic overflow rejections. All 28 included timing/support/differential tests passed.
  • Public AgentX: all 4,198 per-request results and all 105 report keys, including timing evidence, matched exactly except the three host-speed metrics (wall_time_ms, processed_tokens_per_s, processed_output_tokens_per_s). The deterministic synthetic fixture likewise matched all 256 requests and 104 report keys. Every counted performance pair also had zero prediction/evidence differences.
  • Diagnostics enabled (--detail time,source) also matched exactly on a separate 162-request trace. These benchmark profiles have zero positive power coverage; positive-energy arithmetic is covered separately by the power tests and randomized differential checks.
  • Independently downloaded the exact-head CI old/new prediction artifacts: all 30 CSVs were byte-identical at their serialized precision (170,800 rows, including 83,379 successful predictions; remaining misses/invalid/error outcomes were also unchanged). No goldens changed.

Independent end-to-end measurement: optimized Linux x86_64 builds on an i9-14900K, CPU 4 pinned, warm filesystem caches, default diagnostics/capture off, fixed five alternating revision pairs per workload. CPU includes the CLI supervisor and waited descendants; subprocess accounting was separately verified. All 20 counted runs are retained.

Workload Base CPU median PR CPU median CPU reduction Base wall median PR wall median Wall reduction
Public AgentX, 32 plays 74.040 s 41.743 s 43.62% (1.774x) 74.077 s 41.795 s 43.58%
Synthetic long decode 1.807 s 1.596 s 11.70% (1.133x) 1.821 s 1.669 s 8.33%

AgentX uses public Weka dataset revision 8fecd2fc56694469f758f0afbbb6335ad3043740, first 32 rows, 4,198 requests / 4,072,673 output tokens, Qwen3.8-2.4T-A95B-FP8 / GB300 / SGLang 0.5.17 / TP16 / MoE TP4 EP4, one client-play lane, explicit trace/KV block size 64. Input SHA-256: ba7a19e045828db8d8299e71305d046b2ed3259e515907711a9a15e05d6c140c. Synthetic uses 256 independent one-request plays, 32 lanes, 1,024 input / 4,096 output tokens, stable identities, and the same model/hardware topology.

The AgentX CPU reduction's nominal paired-log Student-t 95% interval is 38.49–48.39%; synthetic is 10.59–12.40%. The host is shared and brief unrelated compiler activity was observed; all samples and contemporaneous load records were retained. These intervals are small-sample estimates, not isolation guarantees. This is an independent, similarly sized public workload, not the author's original 4,265-request trace. The claimed speedup direction and magnitude are credible.

Setup receipts are retained: an initial resource precheck overestimated trace memory when source block size was omitted; explicitly matching the corpus's block size 64 admitted both revisions without changing token lengths. The initial non-agentic synthetic fixture generated random UUIDs and showed only tiny aggregation-order differences (about 6e-11 maximum) after requests were aligned; the stable-identity fixture above eliminates those differences without changing production code.

I also reviewed the five open, explicitly deferred author self-review threads. Current callers uphold the private builder's unique-name contract, and the independent checked reference and existing error mapper preserve the intended compatibility boundary. Those maintenance discussions do not establish a reachable blocking defect in this head. Their resolution and branch currency remain repository merge requirements.

Full CI run 35649460908 passed on this exact head. Approval is scoped to this commit.

@jthomson04
jthomson04 enabled auto-merge (squash) September 21, 2026 23:09
Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
Follow the existing embedded round-trip test policy: skip an unavailable SDK when optional and fail when the test is required. Keep later construction, data, and assertion failures visible.

Clarify the private provider-input contract used by the empty-update shortcut.

Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
@jthomson04
jthomson04 force-pushed the jthomson04/optimize-native-evidence-builder branch from 4a95f4e to 50ab2ab Compare September 23, 2026 03:14
@jthomson04
jthomson04 merged commit 2e01b14 into main Sep 23, 2026
67 checks passed
@jthomson04
jthomson04 deleted the jthomson04/optimize-native-evidence-builder branch September 23, 2026 03:28
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.

3 participants