Repository navigation
Conversation
|
I exercised the conversation-cache path listed as untested here on Windows: Ryzen 9 7940HS, RTX 4070 Laptop 8 GB, 64 GB RAM, Swift 1.5 IQ3_XXS, 65,536 context, The 17-request smoke test passed, including:
On this small card the automatic expert cache increased from 993 to 1,028 entries versus INT8 KV. I didn't see a speed benefit in this workload, but the bounded RAM conversation-cache and image-history checks worked. |
K8V4 (INT8 K + rotated Q4_0 V, 816 B/cell) was refused with --kv-resident. It now streams like the other formats: - kv_stream: a fourth block format, kKvHybrid (= 3, the number conversation snapshots already use for K8V4), moved as three runs per block - K codes, K scales, V q4_0 - by the same resolve, copy, ring-restore and stage paths; kv_block_bytes knows its size. - kv_hybrid_k_half / kv_hybrid_v_half: each half of the host copy (and of the prompt path's staging pool) as the single-format append kernels see it, so a hybrid layer's host copy is written by the same folded calls that write its VRAM pools. Both fields of a half point at the same array: the kernels test the K-side pointer for presence and pick K or V per lane. - The decode (layer.cpp), verify-window (verify.cpp) and prompt (prefill.cpp) appends pass those halves; the prompt path's staging pool gets a K8V4 layout; the host copy is allocated in it. - Conversation snapshots read a streamed K8V4 state's host copy, as they do for the others. - qsa_kv_format returns kKvHybrid instead of exiting; the two refusals are gone. setup.py still keeps K8V4 unstreamed: enabling it there needs a MIN_ENGINE that has this. Tests: kv_stream_parity runs K8V4 too (streamed vs resident attention, bitwise): 306 batches, 70,449 misses, 0 failures, ring restore identical; a negative control (the V half's K-side pointer left null) fails it from the first batch. kv_hybrid_parity: all pass.
f8481d2 to
573fc26
Compare
|
@midhatn thanks for this. I hadn't tested the conversation-cache restore at all, and you covered the two cases I worried about most: a 57K-token restore after an unrelated request, and an image prefix that comes back with the right color. I've added your rig to the description under "Tested by others". There's one open report against this change. @fishlikeX runs a port of #711 on 2x V100 with a layer split and sees two failures under I'll run their probe ( |
The verify batch path (the captured-graph replay form) wrote k8v4 cells to VRAM only. The four non-hybrid branches beside it pass &st.host, and record_window's per-step k8v4 branch mirrors through the hybrid halves helpers - this one branch was left with nullptr, violating the every-writer-writes-both invariant the resume path relies on (kv_restore is skipped because 'the main layers' host copies and slots are always current'). On a hybrid layer every decode-written cell therefore left a stale host copy, and the parking / restore chain read that stale copy back. The batch branch came in with the upstream k8v4 code (2aa8f72, Sep 29); the Niko1221#711 port fixed record_window's per-step branch and missed this one. A single-run streamed-vs-resident comparison does not catch it: nothing reads the host copy until a conversation parks or restores. Measured on 2x V100-SXM2-32GB (AD dynamic-quant pack, IQ3_S/IQ2_S experts, --kv k8v4 --kv-resident 65536, parking on): with the mirror restored, the stateless prompt probe (tools/stateless_prompt_ probe.py, #34) goes from 1 ok / 11 bad / 4 inconclusive - dictated numbers answered 2048 for 4096, echoes truncated, all six reused-prefix requests answering from unrelated conversations - to 14 ok / 0 bad / 2 inconclusive, with the previously-failing reused-prefix rounds (cached_tokens 55-57) all correct. int8 on the same build is untouched (different branch). Co-Authored-By: Hermes-Tianji
|
Update from the fork side (fishlikeX here — I run the V100 port where I reported the two failures): root cause found and fixed — jmnargi#36 — and it changes the expected outcome of your 4090 run. The failures are not the Volta prompt attention or the layer split. This fork's verify path writes K/V through a captured-graph batch replay ( The fix is five lines — fold the hybrid halves and pass the host pools in the batch branch, the same pattern as the per-step branch. The exact diff: https://github.com/jmnargi/Strata-V100/pull/36/files. On the same rig the probe goes from 1 ok / 11 bad / 4 inconclusive ("4096" answered "2048", echoes truncated, six reused-prefix requests answering from unrelated conversations) to 14 ok / 0 bad / 2 inconclusive, with the previously-failing reused-prefix rounds (cached_tokens 55-57) all correct. Two notes for this PR:
The probe lives in the fork at https://github.com/jmnargi/Strata-V100/blob/main/tools/stateless_prompt_probe.py (merged via jmnargi#34) if you want it for the back-to-back run. Thanks for taking the report seriously and adding the rig to the description — and to @midhatn for the 4070 restore coverage. |
Setup no longer excludes K8V4 from KV streaming (KV_CELL_BYTES prices 816 B/cell), and docs/DETAILS.md says it streams. This needs the engine of the PR #711 commit: MIN_ENGINE must be raised to 0.1.40 at the release, or an older engine refuses the pair. Co-authored-by: Trevin <132922589+T-Crypt@users.noreply.github.com> Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…CMake version 0.1.40 MIN_ENGINE >= RESIDENT_SPLIT_ENGINE now turns on the resident low-RAM mode on a layer split: the golden baseline records the new 2-GPU configs (both cards, --resident-experts, --remote-expert-opt), and the tests of the pre-0.1.40 behaviour pin MIN_ENGINE to 0.1.39. CMakeLists' project version is what source_version() reads, so a compiled engine must say 0.1.40 to satisfy MIN_ENGINE. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
|
Fixed in 0.1.40: K8V4 now streams with --kv-resident (your commit, kept as it is). Thank you for the kv_stream_parity cases. |
Setup no longer excludes K8V4 from KV streaming (KV_CELL_BYTES prices 816 B/cell), and docs/DETAILS.md says it streams. This needs the engine of the PR #711 commit: MIN_ENGINE must be raised to 0.1.40 at the release, or an older engine refuses the pair. Co-authored-by: Trevin <132922589+T-Crypt@users.noreply.github.com>
…CMake version 0.1.40 MIN_ENGINE >= RESIDENT_SPLIT_ENGINE now turns on the resident low-RAM mode on a layer split: the golden baseline records the new 2-GPU configs (both cards, --resident-experts, --remote-expert-opt), and the tests of the pre-0.1.40 behaviour pin MIN_ENGINE to 0.1.39. CMakeLists' project version is what source_version() reads, so a compiled engine must say 0.1.40 to satisfy MIN_ENGINE.
|
Field report: Setup: Qwen3.8-Flash-Next (qwen4exp MoE, 12 QSA layers),
What works:
The artifact: the "count from 1 to 300" decode probe repeats each integer under k8v4: The striking part: the corrupted output is byte-identical between IQ3_S and Q2_0 — two substrates sharing nothing about their weights (1.94 vs 1.32 MiB experts, different quantization entirely). The only shared component is the k8v4 KV path, so the repetition is introduced by the value quantization itself, deterministically, at temperature 0. That signature reads more like a systematic grid/scale bias in the Q4_0 dequant than random distortion — possibly fixable rather than inherent. It's also exactly the asymmetry the design predicts: K stays INT8-exact (pointer → retrieval fine, needle survives), V is rotated Q4_0 (payload → short-range recency signal blurs, and counting depends on "what did I just emit"). Recommendation from our side: k8v4 looks clearly right for chat/voice seats (decode latency dominates, enumeration rare); for agent seats that count, enumerate, or emit structured output, int8 is the safer default until the repetition is understood. Single run per leg, and we've only characterized the counting probe — other structured outputs (code, JSON) untested. Happy to run more legs on our box if useful. |
…221#705) Setup no longer excludes K8V4 from KV streaming (KV_CELL_BYTES prices 816 B/cell), and docs/DETAILS.md says it streams. This needs the engine of the PR Niko1221#711 commit: MIN_ENGINE must be raised to 0.1.40 at the release, or an older engine refuses the pair. Co-authored-by: Trevin <132922589+T-Crypt@users.noreply.github.com>
…8V4 streaming); CMake version 0.1.40 MIN_ENGINE >= RESIDENT_SPLIT_ENGINE now turns on the resident low-RAM mode on a layer split: the golden baseline records the new 2-GPU configs (both cards, --resident-experts, --remote-expert-opt), and the tests of the pre-0.1.40 behaviour pin MIN_ENGINE to 0.1.39. CMakeLists' project version is what source_version() reads, so a compiled engine must say 0.1.40 to satisfy MIN_ENGINE.
…221#705) Setup no longer excludes K8V4 from KV streaming (KV_CELL_BYTES prices 816 B/cell), and docs/DETAILS.md says it streams. This needs the engine of the PR Niko1221#711 commit: MIN_ENGINE must be raised to 0.1.40 at the release, or an older engine refuses the pair. Co-authored-by: Trevin <132922589+T-Crypt@users.noreply.github.com>
…8V4 streaming); CMake version 0.1.40 MIN_ENGINE >= RESIDENT_SPLIT_ENGINE now turns on the resident low-RAM mode on a layer split: the golden baseline records the new 2-GPU configs (both cards, --resident-experts, --remote-expert-opt), and the tests of the pre-0.1.40 behaviour pin MIN_ENGINE to 0.1.39. CMakeLists' project version is what source_version() reads, so a compiled engine must say 0.1.40 to satisfy MIN_ENGINE.
What
--kv k8v4(INT8 K + rotated Q4_0 V, 816 B/cell) now streams with--kv-resident N, like fp16, int8 and q4_0. Both refusals are gone (generate.cppand the backstop inqsa_state_init).How
The streaming machinery already moves a block as a list of byte runs (
runs_ofinkv_stream.cu), so K8V4 is a fourth format with three runs, and everything that moves blocks (resolve, copy, ring restore, prompt-path staging) takes it unchanged.KvFormatgainskKvHybrid = 3, the number conversation snapshots already use for K8V4. Its runs are K codes, K scales and V q4_0, andkv_block_bytesknows its size.qsa_kv_formatreturns it instead of exiting.kv_append_q8_step(k_q, k_q, ...),kv_append_q4_step(v_q4, v_q4, ...)). Two helpers inkv_stream.hpp,kv_hybrid_k_halfandkv_hybrid_v_half, give each half's host copy (and staging pool) in the shape those kernels expect. Both fields of a half point at the same array on purpose: the kernels test the K-side pointer for presence (if (host.k_q4 != nullptr)) and then pick K or V per lane, so a V half with onlyv_q4set would silently skip the host write. The decode (layer.cpp), verify-window (verify.cpp) and prompt (prefill.cpp) appends pass them.qsa_state_initallocates the host copy in the three runs, andtake_stagegives the prompt path's staging pool the K8V4 layout (pools_ofthen reads it as mode 3).setup.pyis unchanged and still keeps K8V4 unstreamed: a prebuilt engine without this refuses the pair, so turning it on there needs aMIN_ENGINEthat includes it. I left that for you to time.Tests
kv_stream_paritynow runs K8V4 too, with the engine's folded appends. Streamed and resident attention are bitwise equal: 306 batches, 702,021 block lookups, 70,449 misses, 0 failures, and the ring restore is identical. The other three formats are unchanged and still pass.k8v4 pos 130 n_q 8: streamed attention differs).kv_hybrid_parity: all pass.Measured
RTX 4090 24 GB (sm_89), i9-14900K, 31 GB RAM, Linux, CUDA 13. Qwen3.8-Flash-Next IQ2_XS,
--max-context 262144 --expert-cache auto --prefill auto --spec 4 --spec-min-p 0.5 --mtp <rt> --resident-experts, one engine start per row. Long prompts are synthetic log lines with one planted line in the middle, and the answer was right in every row. "Decode at depth" is a ~300-token second turn on the cached prompt.--kv--kv-resident 32768--kv-resident 32768Streamed K8V4 holds 2.39 GiB of KV in pinned RAM, 95.7% of its KV block reads hit VRAM, and its freed VRAM went to 1,745 more expert slots (11,208 -> 12,953). Prompt-cache checkpoints were restored on the streamed K8V4 state (114,688 and 229,376 tokens reused) and decoded normally.
Single runs, so read the decode differences of a few percent as noise, except the short-decode gain, which comes from the larger expert cache.
Not tested
kv_stream.cu, so a HIP build should pick it up the same way it does for the other formats.--gpus). A port of this change on 2x V100 with a layer split reports wrong answers on short stateless prompts under k8v4 that int8 does not show (tools: a stateless prompt probe (k8v4 on 2x V100: dropped prompt tokens and stale-context replies) jmnargi/Strata-V100#34). Not reproduced on sm_89 yet; see the thread below.Tested by others
--kv k8v4 --kv-resident 20480, 2 GiB two-slot conversation cache: a 17-request smoke test passed, including a 57,745-token conversation restore after an unrelated request and an image prefix restore.kv_stream_parityandkv_hybrid_paritypass on that GPU. Built on v0.1.39 with Overlap streamed KV uploads with prefill computation #732, Pipeline CPU expert work without a batch-wide phase barrier #733 (opt-ins off) and Respect Windows commit capacity #749.