GPU trace-gen (part 1): device-resident fills for 7 tables#803
GPU trace-gen (part 1): device-resident fills for 7 tables#803ColoCarletti wants to merge 32 commits into
Conversation
- Reattach the collect_ops_from_cpu doc block to the function (it was landing on struct RegRow together with a stray #[allow]) and update its Returns list to the MemwBuckets shape - Replace references to deleted code and internal review artifacts: the 'Shared by BOTH collectors' rationale (the MemwOperation collector is gone), the E6/E7 notes, and mu_column's 'legacy path' label (update_multiplicities is live for continuation epochs) - Document fill_multiplicities' overwrite semantics: it assumes zeroed MU columns and layered lookups (continuation L2G) must be added strictly after - Remove BitwiseHistogram::total, a pub method with no callers
MEMW_R: - Move RegRow and the direct column fill into memw_register.rs; generate_memw_register_trace is now a thin wrapper (ops -> RegRow::from_memw -> shared fill), so the unit-tested generator and the production fast path run the same code and cannot drift - RegRow::new is the single definition of the row encoding (halved address, masked old_ts_lo); the walk fast path and from_memw both delegate to it - Move the IS_HALFWORD collector next to bus_interactions() so the lookup a row sends and the lookup counted derive from the same module Routing: - Add MemwRoute + classify_memw, shared by MemwBuckets::push, the push_reg_access fallback (which now delegates to push), and count_table_lengths' partition_memw — one classification, three consumers - Drop the single-use push_register/push_register_row helpers BITWISE: - BitwiseOperationType::ALL is the single origin of NUM_LOOKUP_TYPES; type_mu_column is defined as mu_column(ALL[i]), removing the arithmetic column-contiguity assumption instead of guarding it - Replace the runtime histogram_column_map_guard test with a compile-time bijection assert (a mismatch is now a compile error, not a test failure) - Correct bump()'s comment: in release an out-of-domain z would mis-count in another lane rather than panic; constructors' masking upholds the invariant
MemwOperation::new and with_old take [u32; 8] directly and pack_register_value returns u32 limbs, so the u64->u32 narrowing debug_asserts (and the release-mode silent-truncation hazard behind them) are deleted rather than guarded: out-of-domain values are now unrepresentable. The register fast path's bare `as u32` casts, which skipped even the debug_assert, disappear for the same reason.
…ations - Collectors now take &mut BitwiseHistogram instead of returning Vec<BitwiseOperation>. The heavy sources count with no per-source vector at all: MEMW_R bumps one IS_HALFWORD per row (tens of millions of rows), PAGE bumps one ARE_BYTES per byte of every touched page, and CPU padding collapses to two bump_n calls instead of an O(padding_rows) vector of identical zero ops. - reduce_with replaces reduce(identity, ..) in the rayon tree-reduce, eliminating one zeroed 80 MiB identity histogram per reduce leaf. - RegRow.address shrinks to u16 (register index 0..=255), taking the largest persisted array of the walk from 40 to 32 bytes per row.
Docs and dead-code cleanup for tracegen optimizations
…of-truth Single-source the MEMW_R fill and the BITWISE type↔column map
The bitwise-histogram comments were phrased against the pre-refactor code
("byte-identical to the previous serial .extend() chain", "instead of an
O(n) op vector") — narration that is meaningless once this merges and the
old path is gone. Restate them as standalone rationale: the multiplicities
are order-independent (permutation-invariant bus) so parallel collection is
sound, and the reduce_with note now explains why to prefer it over
reduce(identity) rather than referencing a removed path. Also fix the stale
add_padding_byte_checks doc (it described the pre-shrink 14-op CPU layout).
Repo-wide sweep of the trace-generation code for comments that narrate a
change the next reader can't see, or that contradict the code:
- MemwBuckets doc and collect_all_ops no longer reference "the old two-stage
partition" / "byte-identical to partition-ing one combined vec" — that
partition sweep no longer exists anywhere (grep '.partition(' → 0 hits).
Restated as the current invariant (register-first-then-aligned, deterministic
insertion order the multiplicity counts rely on).
- Fix the MEMW_R ADDRESS column doc: register index range is 0-255 (x0-x31 plus
the x254 commit index and x255 PC), not 0-31.
The Bus-14 comment in collect_store_op_from_cpu said the packed value "must match CPU M7 which sends full rv2 as [lo32, hi32]", but M7 (the CPU's old inline store MEMW at timestamp+1) was removed in the ALU-bus migration. The store value now flows CPU -> MEMORY/MEMOP (rv2 as [lo32, hi32]) -> STORE chip -> MEMW write. Reword to describe that path; the byte-layout requirement it gestured at is unchanged.
Feed bitwise collectors straight into the histogram; cut reduce allocations
Make the u32 value domain a compile-time fact for MemwOperation
The bitwise multiplicity phase ran each source as one atomic collector across a capped par_chunks, so the two dominant sources — the in-walk lookups and MEMW_R (each tens of millions of items) — each pinned a single core while the rest idled, and the in-walk fold ran serially before the parallel region. Split those two sources into ~cap row-range slices and round-robin every unit (whole collectors + the heavy slices) into exactly cap buckets, one 80 MiB histogram each. Peak memory is unchanged (still cap concurrent histograms), but the heavy work is now spread across buckets instead of piled onto one core, and the in-walk fold moved into the parallel region. add_ops/bump/merge form a commutative monoid, so multiplicities are byte-identical (prove+verify pass). PAGE is left whole for now; if it becomes the bottleneck it can be sliced the same way in a follow-up.
…tighter visibility, stale docs (#795) - BITWISE MU columns now derive from one `MU_COLUMNS` array with a compile-time distinctness assert, so a duplicate column is a build error rather than a silent overwrite in fill_multiplicities. - push_reg_access takes [u32;2] val/old pairs and builds its own fallback op instead of an 8-scalar signature plus a repacking closure. - Narrow BitwiseHistogram + the MU-column/lookup-type helpers to pub(crate); scope the test-only generate_memw_register_trace wrapper. - Fix stale docs (MemwSink Vec impl is the sizing pass, not tests; generate_bitwise_trace MU columns are filled by fill_multiplicities).
|
/ai-review |
|
Review: GPU trace-gen (part 1) Reviewed the full diff, focusing on kernel↔Rust correctness, the trace-builder integration, VRAM lifetime, and the LDE/commit seam. Overall this is careful, well-documented work and I found no correctness bugs. The seven fill kernels each match their Rust reference table-generator; I verified column indices and bit-slicing against Notes (no blockers)
Things I checked that are correct
|
|
/bench |
|
/bench-gpu |
GPU Benchmark (ABBA) —
|
What this PR does
Moves the first slice of trace generation onto the GPU. Seven table fills now build their main trace directly in device memory and feed the LDE/commit from there — no host→device upload for those tables.
Tables on GPU: CPU, MEMW_R, MEMW_A, LOAD, STORE, LT, SHIFT
Core pieces:
*_keep_dev): a trace already on the GPU feeds the LDE device-to-device instead of being uploaded.commit_main_trace) takes the device buffer directly when present, and frees it after commit to keep VRAM flat on large blocks.Measured (ethrex 10-tx, RTX 5090): main-trace H2D drops from ~4.5 GiB to
~166 MiB (~96% less). Proofs verify.
What's left for future PRs
BITWISE, DECODE, PAGE, precompiles).
Total time is still FFT/proving-math dominated, so this part is correctness + plumbing groundwork; the bulk of the trace-gen speedup lands as the remaining stages move over in follow-ups.