890 Commits
Author SHA1 Message Date
Niko1221 e3bd5cfdef Merge f-0213-defaults (a04860fad): DFlash2 per-device defaults - Strix Halo and Blackwell cc 12.0 cards with >= 48 GB draft window 6 -> 8 (all sets), conf 0.55 for IQ3_S only on that Blackwell class; end to end through the Terminal's flags, 3 interleaved rounds: Strix UD-Q4_K_XL x1.052 (output differs, deterministic; owner 11-08: ship as is), Strix UD-IQ4_XS-v31 x1.020 (identical), l620 IQ3_S x1.028 (identical); every other card unchanged 2026-11-08 22:09:21 +01:00
Niko1221 d362bc5f00 Engine: no Windows 2560 MiB reserve floor on an integrated (UMA) HIP device (G16)
On Windows HIP, an auto expert cache with no --vram-reserve-mib kept a floor of 2560 MiB free on any card of 15 GiB or more (#1376, made for a 20 GB discrete
card that paged). On a Strix Halo that room is not free: the RAM budget's page-locked complement takes it straight back (cache + complement 71.72 GiB at 2560 and
71.73 GiB at 700 on UD-Q4_K_XL), so the prompt path's own buffers found 0 MiB and the engine stepped its chunk down 16384 ... 1024 for ever; strata launch of a
UD-Q4_K_XL config with no reserve (pictures off, or a model with no picture reader) never started.

The floor now goes through strata::core::wddm_auto_reserve_mib(integrated, total, current, floor): a discrete card of 15 GiB or more still gets 2560, an
integrated GPU (the device property the UMA sizing already reads) keeps the engine's default 700. Discrete cards, Linux and every config that passes
--vram-reserve-mib are unchanged (the block is under _WIN32 + STRATA_USE_HIP and behind !vram_reserve_given). Unit test in uma_cache_test.

CUDA sm_120 sm build (vendored ggml), base vs change from the same path: the binaries are bit-identical (sha256 2b603395...).
Strix (gfx1151, public-0.2.12-style config with no reserve) with the new engine: starts in 77 s and answers 3 chats; the old engine never started it.
2026-11-08 21:13:59 +01:00
Niko1221 6ec4d68ab2 DFlash2 per-device defaults (11-08 CONF-SWEEP): Strix Halo window 5 -> 8; Blackwell cc 12.0 with >= 48 GB conf 0.35 -> 0.55 and window 6 -> 8
Strix Halo (gfx1151): engine cap 5 -> 8 and the Terminal writes --spec 8; conf stays 0.35.
Measured (5 interleaved pairs, 5/5 faster): UD-Q4_K_XL +5.3%, UD-IQ4_XS-v31 +2.1%.
UD-Q4_K_XL greedy output differs from the old width's (deterministic run to run); v31 is identical.

Blackwell sm_120 (cc 12.0) with at least 48 GB: cap 6 -> 8, --draft-conf 0.55 (RTX PRO 5000 72 GB,
IQ3_S +2.4%, 5/5 pairs, output identical). The DGX Spark (cc 12.1) and consumer cards under 48 GB keep
conf 0.35 and cap 6. dflash2_auto_cap now takes the compute minor and the card's memory; drafting.py
writes --spec 8 only on these two classes (window_for), so no other card's effective window changes.

draft_cap_test, tests/terminal drafting tests (new test_drafting_card_window.py) and the snapshot
goldens (nv_resident and strix_halo_win only) are updated.
2026-11-08 20:04:02 +01:00
Niko1221 b12773820f #5327: the owner's wording for the "loads anyway" warning, and the RAM notices on stdout in --serve mode only
The warning now reads "the experts need X GiB of RAM and Y GiB is free, but free memory, file cache and reserved huge pages can hold
them, so they load anyway (same answers). STRATA_ARENA_FILE_CACHE=0 reads them from the file instead."  It and the "not enough RAM for
the expert arena ... reads the experts from the file" notice go to stdout only with --serve (before READY, which the server ignores; a
service log has them).  A plain generate run keeps its token stream clean: stderr only, as before the PR.
2026-11-08 19:02:58 +01:00
Niko1221 4890fd9539 #5327 review: the arena shortfall credit leaves out locked file pages, reserved huge pages, a non-2 MiB pool and a pool smaller than the padded mapping
Review of #5531 on top of the contributor's two commits.  The credit read Cached - Shmem - Dirty as droppable, but file pages the
process itself or an engine still exiting has locked (the PLE table's mlock is a mapping of the model file) sit in Cached and the kernel
cannot drop them; MemAvailable leaves them out.  An engine with --ple-io ram and a short arena was told its own locked table could serve
the arena - the shape of #4051's stall.  Now: Mlocked is subtracted; HugePages_Rsvd is subtracted from the free pool; the pool counts only
at the 2 MiB size the arena maps; STRATA_NO_LARGEPAGES (no MAP_HUGETLB try) credits no pool; and the pool must hold the padded mapping
(the pin-by-need stride padding plus the spare blob), not want + blob.  Tests for each.
2026-11-08 17:39:12 +01:00
pjgmobile 41e20da530 #5327: correct the comments - MemAvailable does not credit "only about half" of the page cache (it counts nearly all of it, minus the low watermark); the false alarm this fixes is the reserved hugetlb pool, which MemAvailable does not count at all. The file-cache credit stays as a small secondary margin. Comments only, no code change. 2026-11-08 17:24:35 +01:00
pjgmobile 28bd0185f9 #5327: on Linux an expert-arena shortfall the file cache can serve loads through it again - the 0.1.55 warn-and-proceed (free pages + Cached+Buffers+SReclaimable-Shmem-Dirty cover the need: MemAvailable credits only half the cache), said loudly on stdout as well, because a service setup never sees stderr; the #4846 refusal stays for shortfalls it cannot serve (#4051's anonymous RAM), under a cgroup limit, and on Windows, and STRATA_ARENA_FILE_CACHE=0 turns the credit off; tests 2026-11-08 17:24:35 +01:00
Niko1221 db137d917a Merge f-q4-sycl (41717f29c): the Intel Arc (SYCL) engine follows the compiled geometry, so q4_lite/q4_mid/q4_big build; default build unchanged (CUDA SASS 3573/3573, HIP gfx1201 3920/3920, gfx1151 string offsets only, Metal 85/85 objects, SYCL 22/22 checksums); A750 gate 2 q4_lite 0.00021 vs floor 0.00017; one conflict with f-clean-6-0 in sycl/src/prefill/prefill.cpp resolved as tested by Q4-SYMERGE (Qwen4 prep) 2026-11-08 09:42:22 +01:00
Niko1221 41717f29c1 qsa_real_shapes() takes the compiled geometry; gdn_parity's prefill cases and native_grouped_parity follow the build's shape
qsa_real_shapes() (24 / 2 / 256 / 64, indexer 4 x 128) is the shape every QSA parity program builds from; it now reads kCompiledGeometry (the same values for the default build), so the
q4_* builds' kv_stream / qsa_prompt_attn / snapshot checks run at their own head counts instead of being refused.  gdn_parity's prefill cases used 48 value heads; native_grouped_parity's
compiled-shape loop no longer asks the K-quant checker for an IQ4_NL down.
2026-11-08 07:00:42 +01:00
Niko1221 09eb827914 Merge f-q4-hipkg2 (da7b1d022): the AMD prompt-expert kernels (F16 K-quant, native-format fused IQ, Q2 blobs) follow the compiled geometry; default build unchanged (HIP gfx1201 182/182 and gfx1151 194/194 touched functions, CUDA SASS 3573/3573 and 160/160 host objects, SYCL 129/129 objects and 22/22 checksums, Metal 85/85 objects); HIP q4_lite gate 2 0.000183 vs floor 0.000173 (Qwen4 prep) 2026-11-08 06:15:05 +01:00
Niko1221 b273c8006e HIP/CUDA native-format prompt experts (moe_fused_iq.cu): K of gate/up and down, the weight-row counts, the grids and the down store stride follow the compiled geometry
GU_ROWS_K, D_ROWS_K and the 1280 / 2560 weight rows of the int8, WMMA and F16 kernels come from kMoeEmbd / kMoeFF /
kMoeGuRows, with a static_assert that a product's rows are whole work items.  Flash-Next's device code (gfx1151)
is unchanged.
2026-11-08 04:48:52 +01:00
Niko1221 3d209733d2 HIP F16 K-quant prompt experts: the work-item counts, activation strides and down stride follow the compiled geometry
moe_fused.hpp gets kMoeEmbd, kMoeFF and kMoeGuRows from kCompiledGeometry (2560, 640, 1280 for Flash-Next).
moe_f16_common.cuh and moe_f16_kq.cu take GU_NFB, D_NFB, the activation and H row strides, the stage counts and the down
store stride from them, with a static_assert on the divisibility the tiles need.  The default geometry's device code
(gfx1151) is unchanged.
2026-11-08 04:48:52 +01:00
Niko1221 4dad59ab37 Merge f-q4-geometry (fc1c4e429): the model shape is fixed at build time (-DSTRATA_GEOMETRY / -DSTRATA_GEOMETRY_FILE); the default Flash-Next build is unchanged (CUDA SASS 3573/3573, HIP gfx1201 3920/3920, gfx1151 path-string offsets only, SYCL 22/22 checksums, Metal 10/10 tokens, CUDA 130/130 tokens); Qwen4 test shapes q4_lite/q4_mid/q4_big pass logits gate 2 on CUDA (Qwen4 prep) 2026-11-08 04:48:39 +01:00
Niko1221 f3e99e58d5 geometry: attention G, fused_gr tiles and fast up for hc_lr 256-512, top-k from the geometry in native_moe, native activation buffers follow n_embd/n_ff, PLE hash constants read from the model file 2026-11-07 21:21:16 +01:00
Niko1221 499d971666 q4geo_synth: the PLE tensors and keys (sparse table); ngram.hpp: the PLE head width follows the hidden size 2026-11-07 20:44:07 +01:00
Niko1221 88e6634390 Revert "engine: on AMD that is not gfx12, a UD-Q5_K_XL / UD-Q6_K_XL style file (most expert gate/up tensors Q5_K or Q6_K) runs the K-quant MMQ prompt kernels by default (STRATA_MMQ_KQ=1; was setup's unsloth_default_env; owner yes 11-07); STRATA_MMQ_KQ=0 turns it off"
This reverts commit ffb94c578c.
2026-11-07 18:40:47 +01:00
Niko1221 055274c882 Merge main b0fc432ed (step 4, step 2, 1A) into f-clean-1c
# Conflicts:
#	data/settings-register.json
2026-11-07 18:40:24 +01:00
Niko1221 4041af8e6c prefill, fused_gr, expert kernels: the shape constants are read from kCompiledGeometry (values unchanged for Flash-Next) 2026-11-07 18:08:12 +01:00
Niko1221 af7759b69e geometry: the compiled shape is a header chosen at configure time (STRATA_GEOMETRY / STRATA_GEOMETRY_FILE), with the constraints every shape must meet in one place 2026-11-07 18:04:24 +01:00
Niko1221 e62f3c1ffd Retire STRATA_DF2_GATE and STRATA_DF2_ROW_MS: the calibrated DFlash2 gate (cleanup 4.5 batch D)
Removes AdaptiveGate, df2_gate_on() and df2_gate_row_ms() (window_rule.hpp), their three
sites in generate.cpp and their block in window_rule_test.cpp. The opt-in gate measured
2.7-4.9% slower; with it off (the default) the window rule is unchanged. The register
marks both retired in 0.2.13.
2026-11-07 16:28:46 +01:00
Niko1221 ffb94c578c engine: on AMD that is not gfx12, a UD-Q5_K_XL / UD-Q6_K_XL style file (most expert gate/up tensors Q5_K or Q6_K) runs the K-quant MMQ prompt kernels by default (STRATA_MMQ_KQ=1; was setup's unsloth_default_env; owner yes 11-07); STRATA_MMQ_KQ=0 turns it off 2026-11-07 14:55:49 +01:00
Niko1221 567c46873f engine: on CUDA a GGUF that carries the hyper-connection projections as Q8_0 (Unsloth UD-* files) reads them as Q8_0 by default (STRATA_HC_Q8=1; was setup's unsloth_default_env; owner yes 11-07); STRATA_HC_Q8=0 turns it off 2026-11-07 14:55:06 +01:00
Niko1221 0a50eda160 engine: on Linux with every card gfx12 the chunked GDN scan is on from the first chunk (STRATA_GDN_CHUNKED=1 by default; was the launcher's GDN_STACK_GFX12; owner yes 11-07); STRATA_GDN_CHUNKED=0 turns it off 2026-11-07 14:54:00 +01:00
Niko1221 6858c919ca engine: STRATA_GDN_TC=1 and STRATA_GDN_CONVL2=2 are the Linux CUDA engine's own defaults (was the launcher's GDN_STACK_CUDA; owner yes 11-07); =0 turns each off 2026-11-07 14:53:32 +01:00
Niko1221 6bb7e7a2a3 Move the unused reserve proposal out of stage_reserve.hpp (cleanup 4.2)
proposed_window_mib / proposed_reserve_mib and their two constants go to
research/stage-reserve-proposal/ with a README and their own checks; the
production header keeps reserve_mib / room_bytes, and stage_reserve_test keeps
its real-arithmetic checks unchanged.
2026-11-07 14:17:30 +01:00
Niko1221 c9abd38a7f engine: the exact parallel-request stack is the Linux CUDA engine's own default with 2 or more batch slots (was the launcher's PARALLEL_STACK_ENV); each switch keeps =0, a value you set is kept 2026-11-07 14:09:51 +01:00
bulhenvaster bca7931f3d peer tier: STRATA_ADAPT_OVERLAP=1 with --peer-device (the peer's copies land while the next window runs)
In peer mode the adaptive overlap was refused, so every decode window first waited for the previous round's copies. With the overlap the peer
tier issues its copies in layer order, signals each layer's landing the way the primary does (a stream-ordered D2H copy of the layer number into
a pinned int, or host functions), its residency table takes the swaps at the window's start (flip_pending), and a layer waits for a tier's copies
only when that tier swapped in it (AdaptGate: peer_landed, peer_has, per-tier last). The wait before a window clears the peer's marks with the
primary's. Without the variable nothing changes.

Ported from #2720 (bulhenvaster), rebased by hand onto the current gate (the watchdog label stays). Not ported: STRATA_PEER_LAUNCH_IN_POOL
(the author measured no gain on his build), the new decode timing line and the documentation paragraph.

(cherry picked from commit e78b64a7348d685dfd11799fdb395661f2120436)
2026-11-06 15:47:43 +01:00
sergqwer 24c6c2f682 Admit the PCIe share's fetched misses to the GPU cache (opt-in STRATA_ADAPT_FETCH=1|2)
Decode reads missed expert blobs from host RAM three ways; the PCIe share's
blobs cross into VRAM anyway and were dropped after the window. With the
switch set, the share takes each layer's most-routed misses and a fetched
expert routed enough more than the layer's least-routed resident expert that
the window does not route is copied straight into that expert's slot
(fetch_blobs gets an optional dst2 target per blob). =2 leaves the tier's own
swaps out of a layer where an admission ran. STRATA_ADAPT_FETCH_VERIFY=1 reads
every admitted slot back. Off, with a log line saying why, where it cannot run.
Unset changes nothing.

Ported from PR 2964 (sergqwer) onto f-0216-core; the strata generate verify
loop was merged by hand (main's speculative-q lines kept) and the DETAILS.md
note became a row of the opt-in switch table.

l620 (RTX PRO 5000, IQ3_S, 3,896-slot cache, --pcie-frac 0.25): decode =2 +10.2%,
=1 +5.0% (4 rounds); token forcing over 14,167 tokens: mismatch 2.73% vs 2.53% /
2.53% for two unset arms (+0.19 pt, 90% CI -0.02..+0.42), PASS.

(cherry picked from commit b2bfaef906acee4f86bdf9f052aee6a4d295fb4e)
2026-11-06 15:47:43 +01:00
bitaccesscomau 386f9959f1 Exact two-pass QSA prompt selection (opt-in STRATA_SELECT_TWO_PASS=1)
Prompt-path block scores in single-pass TF32 with a per-block error bound,
3xTF32 rescoring only near each query's top-k cut-off, so qsa_block_topk
returns the same cells in the same order, ties included. Off unless the
variable is set; says once where it cannot run (HIP, Metal, SYCL, layer-major
path). Adds qsa_two_pass_test, qsa_two_pass_status_test and the GPU parity
test qsa_two_pass_parity.

Ported from PR 4119 (bitaccesscomau); the log line of the per-prompt counters
is shortened without dropping a field.

l620 (sm_120, IQ3_S), greedy ids identical off vs on in every pair:
prompt 128K +1.65% (n=12), 256K +4.10% (n=8), 32K -0.14% (noise).

(cherry picked from commit bbf7c55f1351d913233250fe7869642f7c2b98a1)
2026-11-06 15:47:43 +01:00
Niko1221 78c5a834e3 Merge f-0216-dfship into f-0216-all 2026-11-06 09:36:34 +01:00
Niko1221 51548e5539 Merge f-0216-strix2 into f-0216-all 2026-11-06 09:36:34 +01:00
Niko1221 7597e383cf Merge f-0216-rtx into f-0216-all 2026-11-06 09:36:30 +01:00
cctan 7bf5ec4ebf prefill: opt-in int8 kernel for the IQ4_XS / IQ4_NL expert products (STRATA_IQ4_W4A8), MMQ's bits
Ported from #4871 (cctan): src/prefill/moe_iq4_w4a8.cu, tried first by mmq::Context::run; unset, nothing changes.
Changes on top of the PR: the "would MMQ split this launch along K" test is now mmq::launch_splits_k, which reads the
device's real MMQ configs (tile width, stream_k flag, tile efficiency) instead of an Ampere table, so the kernel declines
exactly the launches whose sums MMQ adds in another order, on any architecture; sm_120 joins sm_80..sm_88 (bit-for-bit
against MMQ on an RTX PRO 5000 and an RTX 3060); the kernel counts what it ran and why it declined and prints that at exit;
prefill_iq4_w4a8_test takes --tokens N (tails), --wide (scale extremes) and --bench (MMQ against the kernel per product set).

Class E: 0 differing output words in every case (tokens 97 / 2049 / 4096 / 8191 / 15360 / 32768, uniform and log-normal routing,
group buffers and pointer table). Kernel time against MMQ on the down products (IQ4_NL): +9..+70% on sm_86, +13..+50% on sm_120.
2026-11-06 01:49:09 +01:00
Niko1221 b0b0348c2b kernels: opt-in fused gate/up rows in ggml order for 2+ tokens (STRATA_IQ512_FUSED_MAX; N, after PR 5243's row_gu_dot); STRATA_ROUTE_DUMP routing trace for offline placement replays 2026-11-06 00:39:11 +01:00
Michel Pollet f000d4a455 cpu/experts: the 512-bit VNNI rows on a CPU without AVX-512-VBMI (PR 5120)
cpu_vnni_ok() = AVX-512 F + DQ + BW + VL + VNNI + OS state, cpu_vbmi_ok() = F + VL + VBMI; the Q2_0 row dot and the q8 quantizer take the 512-bit form
on VNNI without VBMI (the one VBMI op, vpmultishiftqb, has a bit-for-bit substitute unpack), and the i-quant / Q5_0 rows of iq_avx512.cpp, whose object holds
no VBMI instruction, gate on cpu_vnni_ok() instead of cpu_avx512_ok().  Adjustments over the PR: DQ is asked for (the file is compiled with it), the i-quant rows
gate on VNNI (the rows use vpdpwssd/vpdpbusd), and STRATA_NO_VBMI=1 runs the substitute unpack on a CPU that has VBMI (a test knob).
2026-11-06 00:22:30 +01:00
Niko1221 6368dc68ab cpu: drop the IQ4_NL 512-bit down rows (5-11% slower than iq4nl256_down_rows at 2-4 tokens on Zen 4); Q5_0 down keeps its 512-bit rows; vpdpwssd in the i-quant rows' integer sums (same integers, one op less) 2026-11-06 00:22:29 +01:00
Niko1221andbsorensen110 55dc17697c cpu: IQ4_XS gate/up and Q5_0 / IQ4_NL down rows in 512-bit lanes on AVX-512 CPUs, bit-identical to the code they replace
IQ4_XS gate/up: ggml-cpu's dot order (the integer lanes of its AVX2 dot, f16 scale times y.d, eight float lanes, its hsum) for every token count;
before, an AVX-512 CPU ran ggml's one-token dot per token.  Q5_0 down: ggml's dot order, weights decoded once per block pair for all tokens.
IQ4_NL down: iq4nl256_down_rows' order, 512-bit.  Each is checked once against the code it replaces; STRATA_NO_IQ4XS512=1 / STRATA_NO_QD512=1 switch
them off.  The IQ4_XS nibble-plane decode follows the layout of PR 5243.

Co-authored-by: bsorensen110 <[email protected]>
2026-11-06 00:22:29 +01:00
Niko1221 89f4fa18ee Run manifest (lite): STRATA_MANIFEST=<file> writes the selected fast paths, fallback reasons, tensor formats, engine choice and budgets as JSON (P0.1)
A diagnostic for testers and for the performance work, off by default. With STRATA_MANIFEST unset every call returns at once
and nothing is printed or written. With it set, the engine writes <file> (whole file, replaced by rename) when it is ready and
again after a request if something new was recorded; the launcher (strata_control/split_engine.py) writes the all-cards split
decision to <file>.launch.json. Sorted keys, no timestamps, process ids or addresses, so two matched runs give the same text.

Content:
- engine: version, engine kind (single GPU or layer split), stages, KV format, drafter, spec window, pipeline windows, PLE I/O.
- budgets: context, KV resident cells, expert slots and cache MiB (all tiers and primary), VRAM reserve, prefill chunk cap and
  stages, pool workers, memory limit, resident budget, batch slots, conversation cache.
- paths: one entry per decision with selected/declined and the reason in plain words: prompt experts per format class (MMQ,
  FP16 WMMA tiles, native fused kernels, FP16 GEMM, with the gate/up and down formats and the layer count), MMQ direct and group
  sort, HC_Q8, the output head (VRAM or pinned host, repacked or not), route tail skip, DMA batch mode.
- tensors: dense and head formats as held (count, bytes), the packed and HC_Q8 copies made at load.
- launch: split-engine mode, engine chosen, reasons, card architecture and count, routed-expert types, and the AMD auto rule
  condition by condition (architecture, card count, expert types), so four gfx1201 with the IQ3_S set is recognised and two or
  three cards are not promoted by the four-card rule.

The only text it prints is "strata: STRATA_MANIFEST: cannot write <file>" on stderr, once, when the variable is set and the file
cannot be written.

Tests: tests/core/run_manifest_test.cpp (off is free and writes nothing, matched runs in any recording order give the same text,
replace-on-rerecord, escaping, dirty tracking, unwritable target), tests/split/test_split_engine.py::LaunchManifest.
2026-11-06 00:21:53 +01:00
Niko1221andquantforge-br f225844d19 Prompt MMQ row tables get the stream-k fixup's over-read margin, sized from the backend's tile bound (P1.9, part 1)
Correctness (class E, not a speedup): the product values do not change; the rows past T*K are never routed to.

llama.cpp's mul_mat_q_stream_k_fixup loads ids_dst[col_low + jt*J + j] for a whole J-column tile before it compares
the tile with the expert's rows (the main kernel skips an empty tile first; the fixup only skips its writes), and its
tiles run to ceil(max_rows / J) * J for every expert of the launch. A table of exactly T*K entries is read past its
end by up to roundup(max_rows, J), and the main kernel reads up to J - 1 past its last row. Strata's `ids_identity`
was an exact-sized allocation: when it ended a 2 MiB page the over-read faulted on the next (Xid 31 FAULT_PDE,
"prefill copy_i32: an illegal memory access" on a long prompt on a CUDA layer split; issue #1468 and others).

PR #5108 added T + 256 rows by hand. Here the margin is derived: J is bounded by ggml's mul_mat_q_switch_J
(J = 8 .. 128 in steps of 8), the tile loops of moe_mmq.cu now use that one constant (kMmqTileColsMax /
kMmqTileColsStep), and the table is T*K + roundup(T, J) + J rows (an expert takes at most one row per token), with
checked 64-bit arithmetic: a size that does not fit fails the carve instead of wrapping to a small table. The same
size is used by carve, bytes_needed_impl and the three places that write the identity (helper rebind, normal prompt,
layer-major), so the estimate and the carve stay identical. The peer prefill's row table, an exact cudaMalloc used by
the same MMQ launches, gets the same margin.

Tests: tests/prefill/mmq_ids_margin_test.cpp enumerates every index the fixup and the main kernel can read for 2000
random layouts (late experts, empty tiles, every J), checks the exact-sized table of before is overrun by the late
expert layout, and the overflow refusals. Builds on CUDA sm_86 (z440).

Co-authored-by: quantforge-br <[email protected]>
2026-11-05 23:46:57 +01:00
40849df0a8 Transfer completion: flag B stays behind queued copies, and the adaptive-copy range covers the whole round (P1.1)
Correctness (class E): kept even without a speedup.

Flag B (PR #5096): the graph waits for "flag B >= layer + 1" and flag B is one counter that only rises. A non-empty
plan raises it from a host function on the copy stream, after its uploads. An empty plan (n <= 0) raised it on the
spot, even when the copy stream still held an earlier layer's, or the other token group's, uploads: the counter
jumped past a layer whose bytes had not landed. Verifier::raise_flag_b_ordered() now raises it through the copy
stream whenever copies were queued in this window, and directly only when none were. The same ordering is used at
the four places that publish an empty plan when the pool did not (run, run_slot_rows, batch_serve, service), which
had the same hazard. A failed host-function launch used to be ignored (flag B never rose and the window hung); it
now stops the engine like a failed upload does, after releasing the GPU waits.

Adaptive-copy bookkeeping (PR #4844): a round planned on the pipelined loop whose loop drained before step 3 is
marked resident on the serial rule, which used the lo/hi/bi of an earlier round, so only that range of swaps was
marked and the others were lost (the slot held the new expert, the table still named the old one). The pipelined plan
now names the whole round. The range arithmetic moved into AdaptiveCopyRange (adaptive_range.hpp) so a host test can
walk the rounds.

Tests: tests/core/flag_order_test.cu (delayed host-function copy standing in for a slow DMA, a consumer kernel that
reads staging once flag B allows it, a negative control that shows the old direct raise releases it early, flag only
rises, nothing queued, graph replay twice, every device; passes on both A4000s of z440), tests/program/
adaptive_range_test.cpp (serial batches for 0, 1, many swaps and several caps, the stale-range loss, empty round).

Co-authored-by: AlanJager <[email protected]>
Co-authored-by: uvlad23 <[email protected]>
2026-11-05 23:39:06 +01:00
a5b820a415 Request accounting and prompt timing marks: yielded prompt legs summed once, admission time without a double count, unknown stays unknown (P0.4)
Reporting only (class E): no engine speedup, no change to what the engine computes.

serve/server.py
- A prompt read that gives way (BYIELD) and resumes keeps the request's external prefix boundary, and the prompt
  time and tokens of every leg are summed exactly once (prefill_leg_stats; PR #5318).
- The admission's DONE times one token and BDONE counts that token but times only the slot: the slot time now
  includes the admission time, and the output token is not counted twice. A figure the engine never reported
  (a close at the admission token, in the slot, a carry back to the solo path) stays unknown (None) instead of
  turning into 0 or into the API's output count (PR #5307).
- The two patches overlap in the request finalization; ended_on_yield is taken before the unknown-figures step so
  the identity check still sees the yield's own record.

PfTimer::mark(): a mark in the phase already running is not recorded (PR #4006). The totals are the same, a
fraction of the event records; under WDDM every record is a submission of its own and the launch gaps they made
were charged to "dequant". The rule is a pure function in prefill/timer_marks.hpp with a host test.

Tests: serve/test_yield_accounting.py (new: two yields, solo and admission yields, cancel after one and two
yields), serve/test_parallel.py BatchLegAccounting (EOS and length finishes, zero slot time, close at the
admission token and in the slot, slot to solo carry), serve/test_request_accounting.py (unknown stays unknown,
explicit zero), tests/prefill/timer_marks_test.cpp (same totals with 18 of 23 records skipped).

Co-authored-by: YusenZhang0601 <[email protected]>
Co-authored-by: shoucandanghehe <[email protected]>
Co-authored-by: Vop3p <[email protected]>
2026-11-05 23:31:14 +01:00
Niko1221 b97433df05 spec: STRATA_DF2_GATE=1 (opt-in): DFlash2's verify window from a per-request calibrated survival (position x confidence bucket, prior C^1.3) against the cost of one more row, instead of a fixed --draft-conf; window_rule_test covers it 2026-11-05 23:18:51 +01:00
Niko1221 6e31946cbe Strix Halo (gfx1151, Windows): the F16 prompt expert kernels write the down rows as FP16 and a combine kernel reads them (STRATA_PF_DM16, on by default there, =0 turns it off; from the Strix dm16 work patch, extended to the F16 K-quant and IQ kernels). 8K prompt, same engine, interleaved pairs: IQ3_S +2.2% (4 of 4), UD-IQ4_XS +2.6% (3 of 3), UD-Q4_K_XL +1.2% (3 of 4); first-token KL 1e-4 at 8K, 0.02-0.04 on agent transcripts 2026-11-05 19:59:50 +01:00
Niko1221 aa12025515 NVIDIA: a bare --prefill auto takes a 32768-token chunk ceiling on cards of compute capability 8.0 and up (owner 11-03, after the full suite passes)
The gfx12 rule in generate.cpp now serves both: nv_chunk.hpp (STRATA_NV_CHUNK=0 or STRATA_DEFAULTS=026 keep 8192, =16 keeps 16384, =1 skips the RAM guard), the fit scan still picks a smaller chunk when the cache cannot lend the buffers, the #2090 RAM guard steps 32768 -> 16384 -> 8192, and a layer split takes 8192 back (STRATA_SPLIT_CHUNK16K=1 keeps the ceiling). An explicit --prefill N, auto:N or STRATA_PREFILL_AUTO_MAX is never touched. Volta / Turing / Pascal keep 8192.
A6000 UD-Q4_K_XL, 13.1K of 24.6K experts in VRAM, MMQ_KQ on: prompt 20K +43.4%, 32K +22.5%, 64K +21.3%, 8K 0.0%; cards that hold every expert: flat.
nv_defaults_test covers the ceiling, the switches, the card rule and the step-down.
2026-11-03 20:37:28 +01:00
Niko1221 938b76eb3e gfx12 prompt staging ring (a1e6ef324): only on a gfx12 card. The branch was keyed on the matrix-core attention being active, which the Strix Halo (gfx1151) also has on by default on Windows, so it took the 256 / 192 slot ring that was measured on an R9700 only. gfx1151 keeps the 96-slot ring of 0.2.10; gfx12 is unchanged. 2026-11-03 16:13:46 +01:00
Niko1221 c65b9f8be8 Merge branch 'f-0212-int' into f-0212-splitdf2 2026-11-03 13:57:10 +01:00
Niko1221 2d8ead05b8 Merge f-0212-parallel (final) into f-0212-int 2026-11-03 12:56:48 +01:00
Niko1221 212d15ba88 Merge f-0212-nvsingle (final 52ac4e733) into f-0212-int 2026-11-03 12:22:49 +01:00
Niko1221 52ac4e7337 NVIDIA: STRATA_MMQ_KQ=1 is on by default for compute capability 8.0 and up (owner yes 11-03): K-quant experts (UD-Q4/Q5/Q6_K_XL) read the prompt on the MMQ kernels
kNvKqDefaultOn is true; STRATA_MMQ_KQ=0, STRATA_NV_KQ_DEFAULT=0 and STRATA_DEFAULTS=026 turn it off, a STRATA_MMQ_KQ the user sets is kept, Volta / Turing / Pascal keep the FP16 prompt path. A pack without K-quant experts never reads the variable.
Start check (RTX PRO 6000, UD-Q4_K_XL, no STRATA variable set): the start prints the K-quant MMQ line and loads libstrata_kq; 4K prompt GPU timeline 1,047 ms (dequant 7.3%) against 1,500 ms (dequant 25.1%) with STRATA_MMQ_KQ=0, prompt 2,854 vs 2,233 tok/s (one request each).
2026-11-03 12:20:34 +01:00
Niko1221 c850b979b5 split: DFlash2 as the draft source of the all-cards split engine (--draft dflash2 --draft-model PACK, FNX_DRAFT=dflash2). One drafter a lane on card 0 through df2_bridge (src/core/dflash2.cpp with bind() compiled out); the window graphs tap layers 5/15/25/35/45 on card 0 (df2_tap_gr), the prompt path taps each card's own rows into a host ring per lane; Session and BatchDecoder take the drafts after the commit. Greedy 6.4K and 27K answers identical to no drafter and to the draft layer (UD-Q4, 2 x A6000) 2026-11-03 12:16:09 +01:00