Repository navigation
Wire dense live-prefix KV commit through kv_commit geometry (seq-major); floor is granule-bound on qwen0.5b (#797 #801 #812 #811 #787 #777) - #827
Conversation
…r); floor is granule-bound on qwen0.5b (#797 #801 #812 #811 #787 #777) Route the seq-major fixed-stride KV commit path through the shared `kv_commit::live_prefix_ranges` geometry instead of duplicating the byte arithmetic inline, so the engine's committed seq-major residency and the driver-level residency measurement (`vmm_kv_layout_residency_gpu`) are single-sourced and provably follow `kv_commit.rs`. Head-major stays byte-identical on its flat bucket commit: on a growing packed bucket its per-head stride is the bucket, so the kv_heads live-prefix fragments tile the same contiguous `[0, bucket_bytes)` run - its dense ranges equal its bucket ranges, and it is left alone (documented on `vmm_growth_requests`). Preserves the #811 seq-major keep decision (device pointers + physical shapes unchanged across a dense-range commit), the idempotent re-commit contract (governor bills only newly mapped granules), the #748 MappedGrowthGrant path, and #814 governor claim ordering. No Drop-time asserts; no map/grow inside a captured region. Measured (process-isolated, `mobius_seqmajor_growth_parity_native_cuda`, all four configs) on qwen2.5-0.5b: token IDs byte-identical across every config; vmm-inplace `physical_committed_bytes` = 100,663,296 both layouts, realloc = 786,432 both; seq-major `kv_bytes_moved`=0 / `growth_keeps`=3 / invalidations collapse onto the no-growth control (captures/replays/invalidations 1/45/1), head-major moves 688,576 B and re-captures (4/39/4). The floor does not move: at head_dim 64/fp16 with a 512-token hard max, a single binding's entire reservation (131,072 B) is sub-granule, so both layouts pin at exactly one 2 MiB granule per binding = the 48-granule (layers x 2) floor. The kv_heads x separation needs a per-head stripe that crosses a granule (>= ~8192 tokens at head_dim 128/fp16, #776), which this harness never approaches. The commit is therefore floor-faithful, and this is a precise negative result on this model, not an un-wired commit. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Coordinator validation on the merged branch: The negative result is correct, and I checked the arithmetic myselfThe floor does not move on qwen2.5-0.5b, and the explanation is precise rather The entire reservation of a single binding is sub-granule, so both layouts pin The
What did land, and why it still matters
Head-major is left byte-identical on its flat bucket commit, with the reason What this tells us about demonstrating the 8xThe That reframes #384 from "a missing metadata file" to "the blocker on demonstrating Merging. |
🔴 Benchmark Regression DetectedComparison of criterion micro-benchmarks: PR head vs merge-base, measured on the same runner in the same job (base first → PR second).
Visual flags: Host infoWhat this cannot catch
|
…ative) + #384 metadata generator (#834) ## Summary Demonstrates the KV-cache committed-**physical**-bytes floor end-to-end on **qwen14b** via the native CUDA decode path, comparing **head-major (BNSH)** vs **seq-major (BSNH)** layouts in the same session, swept across context capacities that bracket the 2 MiB-per-stripe granule threshold (#776). Token IDs are **byte-identical** between layouts at every point. This is the first time this line (chased since #797) has been driven through the *engine* on a model whose head stripe actually reaches a full granule (qwen14b @ 8192 ctx: `8192 x 128 x 2 = 2,097,152 B = exactly 2 MiB`), rather than the sub-granule qwen0.5b of #827. ## Headline result — honest negative (per #794 / #812 / #827 precedent) Head-major and seq-major commit **byte-identical** physical KV bytes at every swept capacity: | KV capacity (tokens) | committed bytes (both layouts) | granules | ratio seq/head | |---:|---:|---:|---:| | 1024 | 402,653,184 | 192 | 1.00x | | 2048 | 603,979,776 | 288 | 1.00x | | 4096 | 1,006,632,960 | 480 | 1.00x | | 8192 | 1,811,939,328 | 864 | 1.00x | Expected-if-it-separated: head-major `layers x 2 x kv_heads` = **768 granules (~1.5 GiB)** vs seq-major `layers x 2` = **96 granules (~192 MiB)** — the 8x that never appeared. ## Why it does not separate `growth_events == 0` and `committed_len == capacity` for **both** layouts: the engine commits the full KV bucket **eagerly** on reservation — reservation *is* the commit, so layout cannot change the total. Seq-major's fixed full-context stride *is* active and correct (`max_len == 8192` at every capacity vs head-major `max_len == capacity`, tokens match), which proves the seq-major kernel/layout resolution works — but a fixed stride only makes **growth** free (#797's 0 bytes moved) and preserves the captured graph (#811/#812); it does not shrink an eagerly-committed full bucket. The 768-vs-96 (8x) floor stays a **driver-level** property (`vmm_kv_layout_residency_gpu`) realized only by a **live-prefix commit-on-demand** path, which the engine does not do on initial reservation. The new guardrail assertions (`growth_events==0`, `committed_len==capacity`, `head==seq committed`) will **turn red** the moment a future change makes seq-major commit less — i.e. they are a tripwire for the desired win. Measurement used the in-place **VMM** allocator (`ONNX_GENAI_CUDA_VMM=1`), which reports granule-rounded **physical** bytes; the legacy/governor allocator reports nominal bytes and was deliberately avoided. Capture was declined throughout (`ONNX_GENAI_CUDA_GRAPH=0`); offload/weight-streaming (16.6 GB model vs 7.7 GB budget, #796) was active and did not perturb the KV commit counters. ## Deliverables 1. **`crates/onnx-genai-engine/tests/qwen14b_kv_floor_sweep_native_cuda.rs`** — child-process-isolated sweep harness (mirrors `mobius_seqmajor_growth_parity_native_cuda`), honoring process-frozen config (#804/#807). Self-execs per `(layout, capacity)`; asserts token parity + layout resolution + the deterministic guardrails above. `#[ignore]`, gated on `cuda,native-backend`. 2. **`scripts/gen_inference_metadata.py`** (#384) — emits `inference_metadata.yaml` from `genai_config.json` for any such export. Reproduces the hand-written qwen14b metadata **byte-for-byte**. Turns the one-off local `qwen14b-zp` fix (which unblocked native loading for this whole measurement) into a reproducible artifact; the model file itself stays local (models live outside the repo). 3. **Docs** — `MEMORY_ARCHITECTURE.md` floor-progression table + eager-full-bucket explanation; `MODEL_METADATA.md` #384 generator section. ## Method notes - Seq-major was obtained by patching a **copy** of the model (`kv_layout=1` on all 48 GQA nodes), as #801/#805 did for mobius — the original model directory was never modified. - Reported committed **physical** bytes throughout, never nominal content bytes. - Deterministic counters lead; wall-clock is omitted (this box's identical runs ranged 3.9-28 tok/s) and no number was extrapolated that was not measured. ## Unrelated pre-existing fix (disclosed) `crates/onnx-runtime-ep-cpu/src/kernels/matmul_nbits.rs`: added a `#[cfg(not(target_arch = "aarch64"))] let _ = dot_kernel;` guard in `borrowed_affine_int4_matmul` to silence a pre-existing x86 unused-variable lint that blocked `-D warnings` (matches sibling functions at 3779/4272/4448). Behavior-neutral; the mobius ignored test still passes (2 passed). ## Validation - `cargo fmt -p onnx-genai-engine -p onnx-runtime-ep-cpu -- --check` (per-package; `--all` hits Windows `os error 206`) - `cargo clippy --locked --all-targets -p onnx-genai-engine --features native-backend -- -D warnings` — pass - `cargo clippy -p onnx-runtime-ep-cuda --features cuda -- -D warnings` — pass - `cargo test -p onnx-runtime-session` (full) — pass - `cargo test -p onnx-genai-engine --features cuda,native-backend --test mobius_seqmajor_growth_parity_native_cuda -- --ignored --test-threads=1` (#814 policy) — 2 passed - New sweep harness run twice; all guardrails passed. Refs #797 #787 #827 #384 #777. Do **not** merge; does **not** close any issue. --------- Co-authored-by: justinchuby <223556219+Copilot@users.noreply.github.com> Copilot-Session: d60eb808-7cc6-4abc-b48d-2a6dd3841624
… baseline (#841) (#849) Follow-up to #841, correcting the single-source doc. #841 measured, end to end on qwen14b with on-demand commit **active**, that head-major and seq-major commit **byte-identical** physical KV. The mechanism is in `native_decode/cuda.rs`: head-major growth sets `new_shape[2] = new_capacity`, so its per-head stride is *the current bucket*, not a fixed full context. It re-packs dense and already sits on the `layers × 2` floor (96 granules) — **0.25× of the 768-granule figure this line of work has quoted since #797**. So the `kv_heads ×` ("8×") saving seq-major was pursued for does not exist on the path the engine actually runs, and no further layout work would have produced it. What this changes in the doc: - The floor table now distinguishes **head-major with a fixed full-context stride** (768 granules — a geometry the engine never instantiates) from **head-major as the engine actually runs it** (96 granules, measured). - The driver-level `vmm_kv_layout_residency_gpu` 8× ratio is still correct *as measured*, but is now explicitly marked as **not transferring to the engine**, since it is measured on that fixed stride. - The `layers × 2 × kv_heads` prose earlier in the section is now qualified with the stride condition it silently assumed. - Seq-major's real, measured advantage is recorded plainly: **growth cost, not residency** — 0 bytes moved and capture retained on growth, against head-major's 100,667,392 bytes moved plus invalidation. That is what the layout chain (#782/#792/#794/#797/#801/#812/#827) bought, and it is worth having; it is simply not a residency saving. Lesson recorded in the doc: **before quoting a floor, confirm the code instantiates the geometry that floor assumes.** The arithmetic was right throughout; the baseline was not. Notably `cuda.rs` has said head-major grows a *packed* bucket since #827 — the fact was in the tree before the measurement caught up to it. Docs only. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d60eb808-7cc6-4abc-b48d-2a6dd3841624
Summary
Realises the
layers × 2KV floor through the engine by wiring the seq‑major fixed‑stride KV commit path through the sharedkv_commit::live_prefix_rangesgeometry, the last increment in the chain named by #797, #801 and #812.DecodeCudaState::seq_major_kv_commit_requestsnow consumes the samekv_commit.rsgeometry the driver‑level residency test (vmm_kv_layout_residency_gpu) and thekv_commit.rsunit tests exercise, instead of duplicating the byte arithmetic inline — so the live commit geometry and the measured floor are single‑sourced and cannot drift (previouslykv_commit.rscarried a#![cfg_attr(not(test), allow(dead_code))]because nothing in a non‑test build called it).Head‑major stays byte‑identical: on a growing packed bucket its per‑head stride is the bucket, so the
kv_headslive‑prefix fragments tile the same contiguous[0, bucket_bytes)run — head‑major's dense ranges equal its bucket ranges.vmm_growth_requestsis left as the flat bucket commit, now with a doc comment saying exactly that.Refs #797 #801 #812 #811 #787 #777.
Headline: committed‑bytes comparison
physical_committed_bytes, process‑isolated,mobius_seqmajor_growth_parity_native_cuda, qwen2.5‑0.5b:min_bucket=64)The floor does not move on this model, and that is the correct result, not an un‑wired commit. At
head_dim=64/fp16 with a 512‑token hard max, a single binding's entire reservation is512 × 2 × 64 × 2 = 131,072 B = 128 KiB, far below the 2 MiB CUDA granule. So both layouts pin at exactly one granule per binding:48 bindings × 2 MiB = 100,663,296 B, which is thelayers × 2 = 48‑granule floor. Seq‑major already sits on that floor; head‑major coincides because its 64‑token bucket is also sub‑granule.The
kv_heads×separation (vmm_kv_layout_residency_gpu, qwen14b, 32,768‑token stride) only materialises once a single head's live stripe crosses a granule —capacity × head_dim × elem ≥ 2 MiB, i.e. ≈8,192 tokens at head_dim 128/fp16 (the measured head‑major crossover, #776). A 512‑max, 48‑token qwen0.5b run never approaches it, so #797's driver‑levelkv_heads×win is not reproducible end‑to‑end on this harness — its geometry never leaves a single granule. This is the same class of precise negative result as #794 (identical bytes) and #812, stated with the same precision.Full per‑config counters (measured)
" Paris. It is the largest city…", 48 tokens).growth_keeps=3, forced‑growth graph accounting1/45/1collapses onto the no‑growth control) — the Make CUDA-graph invalidation on KV growth conditional (seq-major keep: 4 -> 0 growth invalidations) #811 keep decision is preserved; the dense‑range commit changes neither device pointers nor physical shapes, so the four keep dependencies still hold.4/39/4,growth_keeps=0) — unchanged.Wall‑clock intentionally omitted (deterministic counters answer the question; this box's identical runs vary 3.9–28 tok/s).
Invariants held
seq_major_kv_commit_requests→commit_binding_ranges_with_mapped_growth).MappedGrowthGrantgrowth path, Use committed granules for VMM weight admission #745 committed‑granule admission, Fix GQA workspace growth from unassigned device capacity #814 governor claim ordering, pre‑header 429 refusal (Return overload response for KV admission refusal #743) — all unchanged.Drop.What this unblocks / does not
layers × 2geometry is realised end‑to‑end wherever a per‑head stripe exceeds a granule (largehead_dim/context). Demonstrating thekv_heads×win end‑to‑end needs such a model, not a change to this commit path.read_present_kv/seed_prefix), which still refuse under seq‑major (Gate the fourth place the KV layout lives: refuse seq-major on head-major-only KV consumers (#777 #801 #797 #794 #809) #812). Prefix sharing under seq‑major therefore still needs the BSNH seed as a separate follow‑on; the doc bullet is corrected to say so.Validation (all green, on an RTX 4060 Laptop, ORT 1.27, CUDA 13 wheels)
cargo fmt -p onnx-genai-engine -- --check✔ (--all-targetsfull‑workspace fmt hits Windows os error 206, a command‑length artifact, not a formatting problem)cargo clippy --locked --all-targets -p onnx-genai-engine --features native-backend -- -D warnings✔cargo clippy -p onnx-runtime-ep-cuda --features cuda -- -D warnings✔cargo test -p onnx-runtime-session✔ (277 passed)cargo test -p onnx-genai-engine --features native-backend --lib✔ (454 passed;kv_commit9/9)mobius_seqmajor_growth_parity_native_cuda --ignored --test-threads=1✔ (2 passed, incl. the head‑major negative oracle)gqa_seqmajor_parity_gpu✔ (2),gqa_shared_prefix_parity_gpu✔ (1),group_query_attention_gpu✔ (26),vmm_kv_contiguous_tail_gpu✔ (3),vmm_kv_layout_residency_gpu✔ (2),vmm_kv_token_major_floor_gpu✔ (2) — all--ignored --test-threads=1.Do not merge / do not close any issue.