Compare commits

...
912 Commits
Author SHA1 Message Date
Niko1221 1cbcacbcae fix(build): dma_batch.hpp copy_expert_blobs uses plain arrays (nvcc on Linux rejects its std::array locals)
dma_batch_parity.cu failed to compile on Linux/WSL (nvcc 13.0 with g++): 'template argument 2 is invalid' at the
std::array<T, cap> locals of copy_expert_blobs, whatever the form of the size (int, size_t, a literal). The engine
objects and the Windows build were not affected; the Linux tests build was.
2026-10-06 03:12:25 +02:00
Niko1221 12d835dd61 test(vmm): drain the device before unmapping chunks, and poll the free-VRAM readout after the release
vmm_test failed on the RTX 5070 / driver 610.47: the pageable host-to-device copy was still in flight when
a.unmap() pulled the chunks out from under it, an illegal memory access that stuck to every later call (the last
two checks, the 8-chunk free-VRAM gain and cudaGetLastError, failed as a result). It was not a VRAM leak:
released memory comes back at once (18 MiB gained for 9 chunks of 2 MiB, polled 10 s). generate.cpp already
synchronizes before it unmaps.
2026-10-06 02:50:22 +02:00
Niko1221 89ae08e67f fix(hip): package_windows copies rocBLAS arch subfolders (the gfx1151 wheel's library/gfx1151/) instead of crashing 2026-10-06 02:03:21 +02:00
Niko1221 c4a329fefe setup: recognize AMD Strix Halo (gfx1151) exactly, size its unified memory, recommend UD-IQ4_XS
gfx1151 is now a supported AMD arch (TheRock gfx1151 index; HIP build on Linux, docs/STRIX_HALO.md). The check is exact (gfx_arch_is, as the
engine's gfx_arch.hpp): gfx1150 / gfx1152 / gfx1103 are named as Strix Point / Krackan / Phoenix-Hawk Point and stay unsupported. PCI 1002:1586
(one id for the 8060S / 8050S / 8040S) and the Windows adapter names map to gfx1151; the KFD simd_count names the 8060S / 8050S / 8040S.
Unified memory: the BIOS carve-out + the shared pool (GTT; Windows half the RAM) size the context; only the carve-out counts as extra
room in the low-RAM mode. A discrete card is picked before an APU. A Windows zip without gfx1151 code is refused with the reason.
UD-IQ4_XS is the recommended model from ~80 GB of memory; setup changes no host setting. tools/test_setup_strix_halo.py uses Aurora's real sysfs.
2026-10-06 01:02:10 +02:00
Niko1221 e8e11a915f Windows HIP zip: build for gfx1151 (Strix Halo) too
The default STRATA_HIP_ARCHS of tools/hip/build_windows.bat gains gfx1151. The ROCm 10.2.0a20260930 Windows SDK compiles the strata target for
gfx1151 (stream 140-j built it on this PC) and its rocm-sdk-device-gfx1151 wheel carries the rocBLAS kpack and the hipBLASLt kernels
package_windows.py copies, as for gfx1201. Unvalidated on a Windows Strix Halo.
2026-10-06 01:02:10 +02:00
Niko1221 023dd01531 fix(mtp): a NUL byte had replaced the backslash-zero of the STRATA_NO_MULTI_GR flag (#783 PR-g) 2026-10-06 00:51:56 +02:00
Niko1221 660e495e2d perf(quantize): quantize_act.cu is already one warp a block in f-140; keep f-140's file (#783 PR-k) 2026-10-06 00:51:56 +02:00
Niko1221 46d0136607 perf(gr): STRATA_GR_DOWN_MAX4 stays opt-in (reverts the sm_120 default of 6d60dfc1)
Bitwise on the 5070 (identity gate: Q2_0 and IQ3_XXS identical 10/10 with it on against off, same exe), but the 10-pair
interleaved decode A/B (Q2_0, default config) shows no win: B/A medians 0.97 / 0.97 / 0.99 on the three greedy requests.
2026-10-06 00:51:56 +02:00
Niko1221andstuchapin909 b1efb70c01 test(rope): rope_parity check 6 is skipped where the fused norm+rope kernel is not enabled (#783 PR-f)
On the HIP build the fused kernel is off until check 6 passes there, so check 6 reports SKIPPED unless STRATA_NORM_ROPE=1 asks for it. (gfx1151 on Aurora, 0.1.40: with STRATA_NORM_ROPE=1 it does not pass - about 7% of the rotated elements differ - which is why the kernel stays off on HIP.)

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:56 +02:00
Niko1221andstuchapin909 0c86bbecb6 fix(gdn): gdn_step_norm_multi takes its norm shuffles outside the rg == 0 branch (#783 PR-b)
On gfx1151 the shuffle reduction of the sum of squares inside the divergent-looking branch rounded differently for ~3% of the outputs than the single-token kernel (gdn_parity section 5, Aurora); the base kernel had the shuffles outside it, and with them back out the multi kernel is bitwise the single one for T=1..8 on gfx1151. No change for CUDA.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:56 +02:00
Niko1221 118937c1ee test(gdn): gdn_parity section 5 says how many y words differ and whether the state does 2026-10-06 00:51:56 +02:00
Niko1221andstuchapin909 9d9c9ca2a4 fix(moe): spell out the FMA chain of the float4 k=10 combine (#783 PR-c)
Found by native_multi_parity on gfx1151 (Aurora): the float4 combine differed from the scalar kernel there, because the first pair's other product was contracted into the FMA. Written as fmaf per expert it is the pinned contract (first product rounded, FMA per expert in order) on every compiler.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:56 +02:00
Niko1221andstuchapin909 868f2ef0c0 perf(mtp): multi-token router and combine in the drafter (#783 PR-c, MTP wiring)
For a window of more than one token the drafter routes with one multi-column router GEMV and one multi-row top-10 and combines all rows in one launch (verify already did; each row is bitwise the single-token call, native_multi_parity). Needs the native router (512 experts, k = 10) and the native combine; otherwise the per-token calls stay.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:56 +02:00
Niko1221andstuchapin909 3281ac326d perf(quantize): one-warp-per-block Q8_0 scaled quantize and fused SwiGLU + Q8_0 in the grouped S2 experts (#783 PR-k)
quantize_q8_0_scaled_kernel reduces the block's max with a warp shuffle (one warp per 32-value block) instead of one thread walking the block; fmax ignores NaN the same way in both. moe_grouped_s2 fuses SwiGLU with that quantize and writes the activation back to gate_up, so the grouped parity checks see the same buffer. STRATA_S2_SWIGLU_Q8=0 keeps the two launches; a static_assert pins FF % 32 == 0 for the fused kernel.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:56 +02:00
Niko1221andstuchapin909 8b5dd7adef perf(verify): the shared expert forks after the doorbell when CPU experts are in the window (#783 PR-j)
STRATA_SH_FORK_LATE=0 forks at the top as before. The other two commit-4 changes of the PR are not taken: the shared-expert
Q8_1 reuse is already in f-140 as the opt-in STRATA_VERIFY_QDEDUP (and the fused q8_1 store), and the PLE native-key batch is
already in f-140 as the opt-in STRATA_PLE_BATCH=1; both would have changed output on the native packs by default.
Dropped on purpose: STRATA_VERIFY_PRELAUNCH and the dead copy_rows_from_mapped<ZERO_HITS>.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:56 +02:00
Niko1221andstuchapin909 3fd0460ba2 perf(mtp): the drafter's catch-up skips the K/V of rejected rows (#783 PR-i)
MtpDrafter::draft now runs the round for T = a + 1: the catch-up writes the K/V of the accepted cells [0, a) and the full layer covers row a, instead of writing all T cells and rewriting cell a. No later attention reaches a cell past the one being drafted and the next round writes it first, so the draft tokens and probabilities are unchanged. draft_first (a = 0) no longer writes its repeated rows at all.
STRATA_MTP_CATCHUP_ALL=1 restores the whole-window catch-up (and the old staging sizes).

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:30 +02:00
Niko1221andstuchapin909 2715a75248 perf(iq): 16-lane sub-warp expert gate/up and down kernels, exact-N MMVQ columns, decoded-once small-format tables, two rows per block (#783 PR-h)
iq_kernels.cu: row_dot_80_sub16 (two rows per warp, all lanes active) for the n_embd == 2560 gate/up of every split format, exact-N instantiations of the multi-column MMVQ (launch_mmvq_multi_nc), the 3-entry tail in the grouped gate/up and down kernels. native_mmvq.cu: SmallTraits for Q4_0, Q5_0, Q8_0 and IQ4_NL decode the weight chunks and block scale once per (row, block) and apply them to every activation column with the arithmetic of small_q8_dot, and the multi-column launch runs two rows per block for any K.
Kill switches: STRATA_NO_SUB16_GU=1 (sub-warp gate/up/down), STRATA_OLD_IQ_MMVQ=1 (per-column kernels, existing), STRATA_NO_MMVQ_ROWS2=1 (one row per block at large K). mmvq_multi_parity, iq_multi_parity, native_grouped_parity and native_expert_parity pin the columns to the single-column results.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:30 +02:00
Niko1221andstuchapin909 104a8485e9 perf(gr): multi-token hyper-connection read/write, exact-T GR and BF16 projections (#783 PR-g)
gr_read_multi / gr_write_multi (and native_gr_rms_norm_weighted_multi, native_gr_pre_gated_multi, native_gr_post_multi under them) run T tokens in one launch per step; the verify window's PLE writes, last-layer write and final mixer, and the MTP drafter's write and final mixer use them. The BF16 MMVF multi kernel and the GR up / staged down kernels are instantiated per exact T (1..6, generic above), the BF16 weight tile is unpacked once for all tokens, with the same FMA order as before. STRATA_NO_MULTI_GR=1 restores the per-token calls and the generic kernels.
STRATA_GR_DOWN_MAX4 keeps its meaning from the previous commit (sm_120 default on, explicit setting decides); this commit does not change that default.
gr_multi_parity (new, memcmp): gr_read_multi (with and without injection) and gr_write_multi (in place and out of place) against the single-token calls at the real geometry, T=1..8.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:30 +02:00
Niko1221 5400f39a1f perf(gr): STRATA_GR_DOWN_MAX4 defaults on for sm_120 only (bench #832)
The 4-token accumulator variant of the fused GR down read keeps the same tile, block size, accumulation order and
variant as the kFusedGrMaxT one, so its bits are the same; #832 measured +2.8-3.5% decode with it on an RTX 5070.
Unset, the engine now turns it on for compute capability 12.0 only (decided once per device), and off on every
other card and on the HIP build, where it was not measured. STRATA_GR_DOWN_MAX4=0 or =1 still decides explicitly.
2026-10-06 00:51:30 +02:00
Niko1221andstuchapin909 088e8a8220 perf(rope): fused per-head RMSNorm + RoPE for the verify window and the MTP drafter, off on HIP (#783 PR-f)
native_qsa_rms_norm_rope does norm<256> and the rope in one launch with the same FMA order as the pair (register barriers keep nvcc from contracting across the norm/rope boundary); rope_parity check 6 compares it with native_qsa_rms_norm_weighted + native_rope_apply by memcmp for head_dim 128/256, strided q|gate and contiguous inputs, unscaled and YaRN. The in-place rope also launches one 32-thread block per row.
Verify's norm_rope and q split, and the MTP drafter's q path (all T tokens at once; K for a one-token window) use it. native_norm_rope_usable() gates it: on the CUDA build it is on unless STRATA_NO_NORM_ROPE=1; on the HIP build it is off until rope_parity check 6 passes on AMD hardware, and STRATA_NORM_ROPE=1 turns it on there. The MTP q path's split, FWHT and gate-apply now run over all T tokens in one call each (row-independent).

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:29 +02:00
Niko1221andstuchapin909 fe4de5de85 perf(verify): resident_plan as a parallel grouping and prefix scan (#783 PR-e)
The plan kernel grouped duplicate experts and numbered the groups with thread 0 walking all entries; every entry now finds its group in parallel and a packed (entries << 16 | groups) warp prefix scan numbers them. The residency check, the empty plan and *plan_err of #871 are kept as they are. static_asserts pin the 4-warp / packing limits.
resident_plan_parity (new, memcmp): n=1..80 entries over pools of 3..512 experts with and without a slot table, with and without a skip word, plus the non-resident case, against a host replay of the plan's contract.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:29 +02:00
Niko1221andstuchapin909 44ffa86c53 perf(kv): batched K/V and indexer append for the verify window, the commit graph and the MTP catch-up (#783 PR-d)
kv_append_q8_steps / kv_append_q4_steps append n cells in one 3D-grid launch per pool, and native_qsa_indexer_append_steps walks the n indexer cells in order inside one CTA (one barrier between cells). Verify record_window, the commit graph and MtpDrafter::record_forward use them; a multi-slot batch keeps the per-token loop (each row has its own K/V). STRATA_NO_BATCH_KV_STEP=1 restores the per-token calls.
The kv single-cell calls are now the n=1 case of the same kernel. kv_steps_parity (new, memcmp) covers INT8, Q4_0 and the hybrid's folded single-plane calls for n=1..8; qsa_parity gains append_steps against the sequential indexer append at strides 1 and 5 under none/linear/YaRN.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:29 +02:00
Niko1221andstuchapin909 822251bef6 perf(moe): multi-token router kernel, float4 k=10 combine and float4 sigmoid scale (#783 PR-c)
native_router_top10_multi runs one warp per token (8 per CTA) instead of one CTA per token; native_moe_combine(_multi) takes a float4 kernel for k=10 with a shared row on aligned buffers; the shared expert's sigmoid-scale is vectorised. Same arithmetic order, so same bits.
New native_multi_parity (memcmp): the multi router against the single call for n=1..19 on random, tied and NaN logits, and the combine against a host replay of its contract for the float4 and scalar paths.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:29 +02:00
Niko1221andstuchapin909 ae3b249fd2 perf(gdn): exact-T gdn_ab_multi, double-buffered gdn_step_norm_multi with an all-outputs path, and the gdn_parity T=1..8 memcmp check (#783 PR-b)
gdn_ab_multi is instantiated per T=1..6 (generic above) with the weight unpack hoisted out of the token loop; gdn_step_norm_multi prefetches the next token's q/k while the current one runs, and when no state is written and every token is an output (the verify half) it skips the per-token bookkeeping. gdn_step_norm_kernel splits its reduction buffer so one barrier goes.
gdn_parity gains section 5: for every T = 1..8, gdn_ab_multi against fused_gdn_ab, and gdn_step_norm_multi (verify half, commit half, t_out_begin, state-only commit) against the single-token kernel chained, compared with memcmp.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:29 +02:00
Niko1221andstuchapin909 1690a4a38b perf(qsa): early exit in block_scores_multi_kernel and skip a no-op atomic in kv_stream resolve (#783 PR-a)
A CTA of the fixed 256-CTA grid whose first block is past the batch's largest n_bid returns before staging the queries. Same scores, same bits.
STRATA_QSA_EARLY_EXIT=0 restores the old staging. kv_stream resolve_kernel: only threads that looked something up add to the shared counter.

Ported from #783 (stuchapin909, head 4327807), split per piece.

Co-authored-by: stuchapin909 <[email protected]>
2026-10-06 00:51:29 +02:00
Niko1221 16642363bd arena: the per-layer deferred registration is opt-in (STRATA_DEFERRED_REGISTER=1); the default is 0.1.39's order
On the RTX 5070 (Windows, 4 KB pages, the whole-arena registration refused) the deferred per-layer registration made
greedy decode 4-10% slower than registering the sliced arena after the load (0.1.39's order), with identical output
(Q2_0: STRATA_DEFERRED_REGISTER=0 gave +10% on the same build; 12-pair A/B against 0.1.39 flat after).
2026-10-06 00:35:02 +02:00
Niko1221 3ed6276cae docs: STRIX_HALO.md - the shared-expert fork is a gfx1151 default 2026-10-06 00:27:30 +02:00
Niko1221 58f91c144c docs: STRIX_HALO re-measured on the merged 0.1.40 code; STRATA_SH_STREAM=1 on gfx1151 2026-10-06 00:26:51 +02:00
Niko1221 ae93de6261 gfx1151: the shared-expert stream fork is an arch default there (decode +1.8% UD-IQ4_XS, +6.7% UD-Q4_K_XL at 8K, ids identical)
#826 turned the fork off on HIP (it costs discrete RDNA cards). On Strix Halo's unified memory it pays, measured on the
merged 0.1.40 code (stream 140-m). The switch is read on first use, after the arch table ran.
2026-10-06 00:26:51 +02:00
Niko1221 44b0ed4aa6 iq_kernels: q4_0_centred in unsigned arithmetic (signed overflow made the Q4_0 expert kernel wrong on sm_60)
(b & 0x08080808) * 0x1E reaches 0xF0F0F0F0 and overflowed a signed int; on sm_60 (strata_dp4a
fallback) the compiler turned that into garbage: native_expert_parity q4_0/q4_0 and q4_0/q4_1
gpu rel 1.7e4 and 6.8e2. Unsigned wrap is defined and gives the same bits.
2026-10-05 23:54:06 +02:00
Niko1221 4a7a9871fb serve tests: the image-marker test no longer pins control-token text as special (#931 makes it text) 2026-10-05 22:46:53 +02:00
Niko1221 f53eb1b96a tools tests: the golden compare replaces only the whole engine name (#973)
On Linux the engine is called strata, which also rewrote strata-<model>.log and made
every Enter-for-every-question case differ from the baseline.
2026-10-05 22:46:53 +02:00
Niko1221 d1ec32b4ff tools tests: no WSL in the unsloth tests, and the HIP zip test names the engine for the platform (#974 #975) 2026-10-05 22:46:53 +02:00
Gabe Ortiz bae372b9aa serve: pin Claude Code's per-request billing stamp, so the conversation cache reuses agent prompts
Claude Code starts its system prompt with
`x-anthropic-billing-header: cc_version=2.1.170.bf4; cc_entrypoint=sdk-cli; cch=b145e;`.
cch changes on every request and the version's 4th part on every session. The
template renders the tool list first, so every turn's prompt differed ~22K
tokens in and only the last 16K checkpoint was reused. Both stamps are pinned to
f's, as llama.cpp does (ggml-org/llama.cpp#21793); only a header at the very
start of the system text is touched.
2026-10-05 22:46:53 +02:00
Niko1221 e9fc48f3f7 tools tests: the #425 disk-room test starts its second run without a draft layer (#897 counts an existing one) 2026-10-05 22:46:53 +02:00
Niko1221andChanyeong Lim 98b7ea944d serve: a control token's text in a message is encoded as text (<|im_start|>, <|im_end|>, <|endoftext|>) (#931)
Port of PR #931 onto the #554 vision-tag marks: literal_tags() adds the tokenizer's
control tokens to LITERAL_TAGS, longest first; a prompt with none of them is
rendered and encoded exactly as before.

Co-authored-by: Chanyeong Lim <[email protected]>
2026-10-05 22:46:53 +02:00
Niko1221 3ce3358232 setup: kv_streaming_wanted follows the current rule (K8V4 streams since the KV_CELL_BYTES change)
Port of #945 onto 0.1.40: the PR excluded k8v4, which setup no longer does.
2026-10-05 22:46:53 +02:00
pipeob0andStrata qwen3.8-flash-next-iq3_s 3b2e14cc11 setup: the low-RAM and KV-streaming decisions as functions (low_ram_wanted, kv_streaming_wanted)
Step 5 and step 7 decided these two settings inline. A front-end that has to say what a model would change needs the
same answer, so the rules are named and setup calls them itself: low_ram_wanted is the old `budget is None and (...)`
(budget is set only for a size that has a RAM budget), and the streaming branches keep their messages and say they
are kv_streaming_wanted.

Behaviour unchanged, and checked: test_setup_risk's new RulesAgreeWithTheWrittenConfig runs 54 mocked installs over
three sizes, two contexts, three --kv and three --kv-streaming choices, and 24 more over two PCs and four --low-ram
choices, and compares each written config's --kv-resident / --resident-experts / --mmap-experts with the function.

Co-Authored-By: Strata qwen3.8-flash-next-iq3_s <strata@localhost>
AI-developed: written by an agent (pi) running on Strata's own local model, qwen3.8-flash-next-iq3_s; tested by hand on an RTX 5060 Ti 16 GB / Ryzen 7 5700X3D / 64 GB PC with engine 0.1.39
2026-10-05 22:46:53 +02:00
bsvinay c8c7e216ba sycl/tools/build.sh: keep the REPO override next to the git-root default (#972) 2026-10-05 22:46:53 +02:00
bsvinay ed15a3d04b setup: the disk check counts only what step 6 still writes
An existing pack experts.bin (low-RAM copy or the AVX-512 Q2_0 conversion) and an
existing MTP draft layer need no new room. A re-run of setup on an installed model
used to demand ~arena_gb + 9 GB free and fail on a nearly full models volume.
2026-10-05 22:46:53 +02:00
Joe-Huber 1c59b7087f chore(git): add standard IDEs to gitignore
- Idea/ for jetbrains
- .vscode/ for vs code
- .cursor/ for cursor
2026-10-05 22:46:53 +02:00
LJYBowser c7aec446e3 Fix hard-coded path in sycl/tools/build.sh 2026-10-05 22:46:53 +02:00
Niko1221 e02815a5e5 serve: ending the server removes the image encoder's scratch directory (#914) 2026-10-05 22:46:53 +02:00
Niko1221 4f131fcdcc setup --check: RAM below every model's floor is a warning and the verdict says so (#977)
The RAM line was [ok] and the verdict 'This PC can run Strata' although every size
said 'does not fit'. Now the line is [!], the verdict says no size fits, and the exit
code is 1 for scripts. Check only: --model NAME --yes still installs one anyway.
2026-10-05 22:46:53 +02:00
Niko1221 d034539560 docs: --kv-grow's conditions as the engine states them 2026-10-05 21:53:03 +02:00
Niko1221 07780dae1c docs: the 0.1.40 opt-ins and switches without a doc line; Strix Halo linked from the README (7 languages) 2026-10-05 21:50:43 +02:00
Niko1221 4552a7f164 setup: MIN_ENGINE 0.1.40 (#848 split+resident, #711 K8V4 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.
2026-10-05 21:48:46 +02:00
Niko1221 3772ded7c6 setup: bench-data recommendations (tips only), calibrate tries more pool-worker counts
- bench_tips(): a warning for a fixed --expert-cache on Windows (#780 #781), --prefill auto:32768 only as a tip
  with 96+ GB RAM and a warning below 64 GB, STRATA_RESIDENT_HEADROOM_GIB=6 on resident configs with <= 48 GB,
  --conversation-cache-mib 8192 for agent clients when 24+ GB stay free, --vision cpu on <= 12 GB cards.
- a 2-socket tip for --pool-workers (one socket's cores - 1).
- calibrate also tries a quarter of the default, P-cores - 1 and one socket's cores - 1.
No default, config or engine argument changes; --mtp-window left out on purpose.
2026-10-05 21:44:09 +02:00
Niko1221andEddoursul 076108957c F12: --host-core first|last (fork 5137b33)
--host-core: the host thread's core, first (the default) or last, the workers on the others.

Windows sends a GPU's interrupts to one logical processor, usually the first, and every copy that lands raises one
(~13 us in the ISR and a DPC): a host that spins on the GPU's flags there waits for them (eddoursul's fork, F12:
the host saw a layer's ring up to 30-110 us late, p99).  --host-core last (or STRATA_HOST_CORE=last) puts the host
on the last physical core and lets the workers have the first.  The default is the layout the pool has always used;
a hybrid CPU keeps it.  The startup log names the processors the pool workers and the host thread run on.  The
placement changes no result, only where threads run.  The fork's other part (a per-second re-pinning from the
processors' interrupt time) is not ported.
Ported from eddoursul's fork, commit 5137b33 (MIT).

Co-authored-by: Eddoursul <[email protected]>
2026-10-05 21:00:01 +02:00
a3642eb4be F12: one copy_blobs helper for the expert uploads: the PCIe share's and the adaptive refills' copies as one batch.
Builds on midhatn's #807 (cudaMemcpyBatchAsync for the verifier's DMA group).  dma_batch.hpp now holds one
helper, copy_blobs, for independent host-to-device copies on a stream, which the verifier's PCIe share
(copy_expert_blobs) and the adaptive tier's refills (both loops of generate.cpp: --serve's main device, the CLI's)
use.  Changes against the pull request, from the review: mode 0 is the old loop untouched (it never stops the
engine: the PR aborted on any copy error, which 0.1.39 ignored); the Windows host alias (cudaHostGetDevicePointer)
is looked up once per blob; a batch the runtime refuses is redone as the loop with one warning; HIP, CUDA before 13
and groups over 128 keep the loop; the batch order is the stream's.  eddoursul's fork batches the same copies
(F12: under WDDM each copy raises an interrupt where it lands, on the processor the GPU's interrupts go to).

STRATA_DMA_BATCH is 0 (off) unless set; 1 batches, 2 adds CUDA 13.4's overlap hint.

Co-authored-by: midhatn <[email protected]>
Co-authored-by: Eddoursul <[email protected]>
2026-10-05 21:00:00 +02:00
midhatn c8a73fbf98 cuda: add opt-in batched expert upload submission (PR #807 by midhatn)
Cherry-picked unchanged from the pull request, for F12; the follow-up commit turns its helper into the single
copy_blobs helper and fixes what the review found.
2026-10-05 20:59:49 +02:00
Niko1221andEddoursul edc592b1ef F7: the final mixer in one fused read (fork 2ec7a80)
The final mixer in one fused read.

The hyper-connection read before the head ran gr_read's kernels once per token of the window (lm_head_mix), and once
per draft pass in the draft layer.  Both now go through fused_gr_read_multi, the layers' read (no injection weight:
the final mixer), the window's tokens in one launch.  Its sums are gr_read's (fused_gr_read_multi is bitwise
fused_gr_read, which gr_parity checks against the plain read).  CUDA only; HIP keeps gr_read per token
(STRATA_HEAD_MIX_MULTI=0 does too).  This tree's opt-in STRATA_FUSE_HEAD_GR path is unchanged.
Ported from eddoursul's fork, commit 2ec7a80 (MIT).

Co-authored-by: Eddoursul <[email protected]>
2026-10-05 20:59:49 +02:00
Niko1221andEddoursul 4a5713fbb4 F7: the draft pass's kernels in the main layer's forms (fork d3d48b1)
The draft pass's kernels in the main layer's forms.

- quantize_q8_0_scaled runs a warp a 32-value block (it ran a thread a block: 80 threads for the draft layer's
  input): the block's |max| over the same values, then each value's bytes as before.  CUDA only.
- The draft graphs' inputs from mapped memory in one copy kernel (copy_from_mapped_multi): 7 launches in the round
  graph and 2 in a step become one each (CUDA; HIP keeps its separate copies).
- The shared expert on a branch of the draft graphs beside the router and the routed experts, joined before the
  combine (CUDA; HIP keeps one stream; STRATA_MTP_SHARED_BRANCH=0 turns it off).

The fork's verify_router in the draft pass and its native-format draft experts are not part of this commit (they
belong to F1 and F15).  Ported from eddoursul's fork, commit d3d48b1 (MIT).

Co-authored-by: Eddoursul <[email protected]>
2026-10-05 20:59:49 +02:00
Niko1221andEddoursul 352cad8f0d F7: a one-token window commits itself (fork 235784c)
A one-token window commits itself.

A one-token window always keeps its token, so its graph now advances the sequence state itself: the GDN step kernel
writes the state (n_keep = 1, the arithmetic the commit's replay used), the conv kernel writes the history it read
(gdn_conv_l2_multi's commit flag), and its indexer append and PLE history were final already.  Verifier::commit
launches no commit graph after it: the draft round graph then runs alone instead of beside the commit's kernels,
which read and write each GDN layer's 3 MB state.

CUDA only (HIP keeps the commit graph after every window; STRATA_ONE_TOKEN_COMMIT=0 does too); batch windows keep
theirs.  Ported from eddoursul's fork, commit 235784c (MIT).

Co-authored-by: Eddoursul <[email protected]>
2026-10-05 20:59:49 +02:00
Niko1221andEddoursul ca83311616 F7: the draft round graph runs the draft layer's front once (fork 22b46b6)
The draft round graph runs the draft layer's front once.

MtpDrafter::capture_round ran the draft layer's front (the embedding, the fc projections, the attention
hyper-connection read, the K/V projections and appends) over the window's T cells, then the whole layer again for
row a, repeating row a's front.  record_forward is now record_front (T rows) and record_rest (one row: the attention
from the q projection, the MLP, the final mixer, the head); the round graph runs the front once, copies row a's
residual, injection and mixed input to row 0 (copy_row_to_first, the row read on the device) and runs the rest
there.  The multi-row front is per row the one-row front's arithmetic (checked by the window hashes on fixed text).
The coupled-sampling and rotated-KV paths of this tree stay in the same functions.
Ported from eddoursul's fork, commit 22b46b6 (MIT).

Co-authored-by: Eddoursul <[email protected]>
2026-10-05 20:59:26 +02:00
Niko1221andEddoursul 3e4aa1d618 F7: the head's argmax and the draft's top probability over many blocks a row (fork fbb8bfa)
The verify head's argmax and the draft's top probability over many blocks a row.

The draft head's top probability ran row_top_prob, one 1024-thread block a row over the 40,525-token draft head
(and the head's greedy pick, sampler_greedy_kernel, one block a row on sm_80 to sm_89).  argmax_rows scans a row
in up to 128 blocks (4,096 logits each), the row's last block merging their picks (the larger value, on equality
the lower index: the one-block kernel's order); row_top_prob_split computes row_top_prob's 32 warps' sums in 8
blocks, the row's last block adding them in order.  Both keep their counters and partials in per-row slots of one
scratch.  Bitwise: the new verify_parity test checks them against sample_tokens' greedy pick and row_top_prob (ties,
NaN, -inf, 1-8 rows on one scratch).

CUDA only: argmax_rows is used on sm_80 to sm_89 (sm_90+ keeps sample_tokens' cluster kernel); row_top_prob_split on
every CUDA card; HIP and the cards below sm_80 keep the old kernels (STRATA_MULTI_BLOCK_ARGMAX=0 turns both off).
Ported from eddoursul's fork, commit fbb8bfa (MIT).

Co-authored-by: Eddoursul <[email protected]>
2026-10-05 20:59:25 +02:00
Niko1221andEddoursul ac131a3af2 F19: --spec-follow and --window-hashes test tools (from eddoursul's fork)
--spec-follow PATH makes a generate run emit a given continuation (token ids)
instead of the window's argmax, and accept the drafts that match it, so runs
with different speculation settings (or two builds) process the same text.
--window-hashes PATH writes one line per verify window: its index, position,
size, an FNV-1a hash of its final residual rows and its argmaxes; two builds
doing the same arithmetic write the same file.  Both are off by default and
change nothing when unused.

Co-authored-by: Eddoursul <[email protected]>
2026-10-05 20:59:25 +02:00
Niko1221 654f4af665 CMake: conversation_file.cpp back in strata_engine after the rebase 2026-10-05 19:58:18 +02:00
Benjamin Larsson d69424c965 decode: STRATA_ADAPT_LAG - #463's reproducibility without its stall (#764, ported onto 0.1.40's adaptive tier)
A verify window takes the previous adapt round's swaps once they are STRATA_ADAPT_LAG windows old. The default is 1,
exactly 0.1.39; lag 2 is opt-in. pending_age resets after every pending.clear(). The batch paths, --pipeline-windows
and the peer tier are not lagged.

Co-authored-by: Benjamin Larsson <[email protected]>
2026-10-05 19:58:18 +02:00
Niko1221 9c2be9fdb3 Revert "STRATA_HC_Q8: raise the dynamic shared-memory cap of the Q8 down-kernel instances (the verify window failed in capture)"
This reverts commit e44764435abc2907dbed1019be1bfb7bccd4d6a9.
2026-10-05 19:58:18 +02:00
Niko1221 2fb9b6440a STRATA_HC_Q8: raise the dynamic shared-memory cap of the Q8 down-kernel instances (the verify window failed in capture) 2026-10-05 19:58:18 +02:00
Niko1221 956fdfcbfb iq_kernels: redo the Q6_K gate/up hunks on the rebased file (opt-in STRATA_Q6K_EXPERTS) 2026-10-05 19:58:17 +02:00
Niko1221 b55c48b29e CMake: fix the merge of the parity-pair list after the rebase (q4_0 pairs, Q6_K refusal test when the option is off) 2026-10-05 19:58:17 +02:00
Niko1221 edc0cb6490 rebase onto f-140: leave the PLE Q8_0 reader to the #651 series already in f-140 (drops the duplicate hunks of #860) 2026-10-05 19:58:17 +02:00
Niko1221andJakub Luwierski 4a9b9041c2 prefill: owned buffers take the ring in one allocation, exact owned pricing (STRATA_OWNED_PRICE=exact), OOM diagnostics (#796 part A)
- carve: with owned buffers the streamed ring is one cudaMalloc instead of up to 1,024 pieces each rounded to 2 MiB
  (~0.5 GiB). A borrowed region keeps its per-slot layout and price, so the loans' slot counts do not move.
- Prefill::bytes_needed_owned prices the real allocation (2 MiB pages, the ring in one piece). The cache sizing uses it
  only with STRATA_OWNED_PRICE=exact; the default is still 0.1.39's 160 + chunk * 680 / 1024 rule.
- the "device buffers do not fit" error names the free VRAM, the bytes taken and the buffer that failed.
No refusal was added: parts B (borrow_residency) and C (the advisory planner) stay out.

Co-authored-by: Jakub Luwierski <[email protected]>
2026-10-05 19:58:16 +02:00
Niko1221 aaf99d3074 native experts: IQ3_S one-token AVX-2 kernel is opt-in (STRATA_IQ3S_MT1=1); the default keeps 0.1.39's rounding
Items 1-2 of #863 (gathered decode per core, AVX-VNNI rows) are bitwise and stay. Item 3 changes a lone token's IQ3_S
rounding on Intel hybrid CPUs, so it needs the switch. The #706 bit-plane path stays in front of the VNNI/plain rows.
2026-10-05 19:58:15 +02:00
Francesco Albano d4b8b6ad5c native experts: IQ3_S takes the AVX-2 kernel for one token too where its grid is gathered
#152's rule gives a lone token's gate/up rows to ggml's dot, because the multi-token kernels were no faster at one
token. With the gathered decode that no longer holds for IQ3_S on the Intel cores that gather it: an expert's gate/up
rows for one token on an i9-14900KF P-core take 0.34 ms with ggml's dot and 0.19 ms with the AVX-2 kernel. And in
decode most CPU experts serve one token of the window.

So on a CPU without AVX-512 where cpu_gather_fast() holds (Intel, Alder Lake or later, see the gather commit) and
STRATA_IQ256_GATHER is not 0, IQ3_S takes the multi-token kernel from one token on. This only pays together with the
gathered decode: on the same CPU's E-cores, which keep the scalar decode, it is 0.71 -> 0.68 ms, about even. That is
why it follows the gather's machine-wide rule and not the per-thread one. Measured in the engine with Swift 1.5
IQ3_XXS (whose IQ3_S layers this reaches): the CPU expert time per verify window -4%.

This changes results. A lone token's IQ3_S gate/up rows now round like the multi-token kernel's (the order of the
float additions), no longer like ggml's dot. They are the same rows the token gets in a group, so on these CPUs IQ3_S
experts no longer depend on how many drafts a window held (#152), and every core rounds them alike. Down rows and
the other formats keep the default rule. STRATA_IQ_MT_MIN set (2 is the old default) keeps its rule for every format.

The decision is native_gu_mt_min(): every probe is in expert_layout.cpp and cpu_avx2_ok() comes first. Nothing
compiled for AVX2 runs before that check, including on an older-CPU build (STRATA_ISA_FLOOR) on an AVX-only CPU.
iq_avx2_parity checks native_gu_rows wherever native_gu_mt_min is 1: each token's rows must match alone and in groups
of 2..8. docs/DETAILS.md notes the new default next to STRATA_IQ_MT_MIN.
2026-10-05 19:58:15 +02:00
Francesco Albano b211ba173a cpu kernels: AVX-VNNI forms of the AVX-2 i-quant, IQ4_NL and Q2_0 rows (cpu_avxvnni_ok)
Alder Lake, Sapphire Rapids and later have AVX-VNNI on every core: vpdpwssd does the madd and the add of an i-quant
row in one uop, and vpdpbusd the maddubs + madd(ones) of the IQ4_NL and Q2_0 down rows. The sums are integer, so the
results are bit for bit those of the AVX2 forms: vpdpwssd wraps like madd + add, and the maddubs it replaces in the
down rows cannot saturate (IQ4_NL |w| <= 127, Q2_0 codes 0..3).

The row kernels move to iq_avx2_rows.inl and q2_avx2_rows.inl, which iq_avx2.cpp and q2_avx2.cpp include twice: once
as they were (namespace plain) and once with AVX-VNNI (namespace vnni). In the second copy every function is declared
with target("avxvnni") under GCC/Clang, so the intrinsics compile there and nowhere else: neither file gets
-mavxvnni, which would let the compiler use the extension in the plain path. MSVC takes the intrinsics under
/arch:AVX2. CMake checks that the compiler has them (GCC 11, Clang 12) and otherwise builds without the copies
(STRATA_AVXVNNI=0).

cpu_avxvnni_ok() in expert_layout.cpp, which is not compiled for AVX2: cpu_avx2_ok() and CPUID 7.1:EAX[4], off under
STRATA_FORCE_ISA (a CPU that stops at AVX2), off in a STRATA_ISA_FLOOR build, and STRATA_NO_AVXVNNI=1 turns it off.
The VNNI copies are reached only through the AVX2 kernels' entry points, which the engine already calls only behind
cpu_avx2_ok().

Measured on an i9-14900KF on top of the gathered decode: another 4-10% on a P-core's i-quant gate/up rows, 15-25% on
an E-core's Q2_0 down rows.

iq_avx2_parity runs the VNNI variants as well (iq4nl256_down_rows_v, q2_0_gguf_rows_multi_avx2_v): every combination
bit for bit against the scalar one-token rows, 1..8 tokens.
2026-10-05 19:58:15 +02:00
Francesco Albano a733617558 iq_avx2: the gathered IQ3_XXS / IQ3_S / IQ2_S decode on the cores where it is faster (STRATA_IQ256_GATHER auto)
0736f05 reads the IQ3 grid words with one gather under STRATA_IQ256_GATHER=1, on every core, and keeps it off by
default because AVX2 gather throughput depends on the core. This makes the gathered decode its own Fmt32 (118, 121,
122), chosen once per call instead of a branch in every decode, and takes it further:

- IQ3_XXS: the four even-sign masks by one 64-bit gather as well;
- IQ3_S: the 9th index bit by one sllv and one and; the sign bytes by one broadcast and one shuffle;
- IQ2_S: the four 10-bit grid indices built in a register and read by one 64-bit gather, the signs as IQ3_S's.

Each is its format's scalar decode bit for bit: the same words land in the same lanes. IQ2_XXS measured 4% slower
gathered and IQ2_XS has its own sign decode, so both keep the scalar one.

STRATA_IQ256_GATHER: unset = auto, 0 = the scalar decode everywhere (as before), 1 = the gathered one everywhere.
Auto gathers on a thread whose core is an Intel performance core of Alder Lake / Sapphire Rapids or newer:

- GenuineIntel with AVX-VNNI (CPUID 7.1:EAX[4]) as the generation marker. That leaves out Haswell/Broadwell (slow
  gathers) and Skylake through Ice Lake / Tiger Lake (gathers slowed by the Downfall/GDS microcode);
- not the E-core-only parts, which are not hybrid: Alder Lake-N / Twin Lake, Grand Ridge, Sierra Forest and
  Clearwater Forest, by model;
- on a hybrid CPU only a thread on a P-core (CPUID 1Ah core type 40h): the E-cores gather slower than they assemble.

AMD keeps the scalar decode (Zen 2/3 gather slowly; Zen 4/5 take the AVX-512 kernels). STRATA_FORCE_ISA turns auto
off. The probes are in expert_layout.cpp, which is not compiled for AVX2, and the core type is asked once per thread
(the pool pins its workers).

Measured on an i9-14900KF, gate/up rows of one expert at three tokens on one P-core, scalar -> gathered: IQ3_S 0.40
-> 0.27 ms, IQ2_S 0.31 -> 0.27, IQ3_XXS 0.26 -> 0.24. On its E-cores the gathered decode was slower.

iq_avx2.cpp has no runtime initializer again (d072203): the switch and STRATA_IQ_PREFETCH are read on first use.

iq_avx2_parity, a CPU-only CTest: random blocks (every grid index and sign pattern occurs) for IQ2_XXS, IQ2_XS, IQ2_S,
IQ3_XXS, IQ3_S and IQ4_XS gate/up rows and IQ4_NL / Q2_0 down rows; every variant, 1..8 tokens, each token's rows bit
for bit the scalar variant's rows for that token alone; the scalar rows against ggml-cpu's vec_dot (Q2_0: a double
reference). --bench: ms per expert on one thread, each variant, ggml's per-token dot and the engine's dispatch, over
more expert blobs than an L3 holds.
2026-10-05 19:58:14 +02:00
Niko1221andThomas Weaver ac7db2e522 UD-Q6_K_XL: Q6_K gate/up kernels behind -DSTRATA_Q6K_EXPERTS=ON; the Q8_0 PLE hunk is left to the #651 series
The PLE Q8_0 reader duplicates #651 and is dropped here. The grouped Q6_K instance is built only on request
because every instance is loaded at engine start (EAGER) and costs slots for every other model.

Co-authored-by: Thomas Weaver <[email protected]>
2026-10-05 19:58:13 +02:00
Thomas Weaver 8c4a6e1de7 docs: record the UD-Q6_K_XL server run and register its parity pair
Gate/up is Q6_K on 47 of 48 layers and Q8_0 on layer 2; down is Q8_0 on
every layer. The page had those roles swapped. native_expert_parity
q6_K/q8_0 is now a normal test: the old one expected the pair to be
refused, and native_expert_supported accepts it.

The measured server runs are on this machine (RTX PRO 4500 Blackwell,
engine 0.1.39 after the rebase, and one cold prefill on 0.1.38). Quality
against llama.cpp is still unmeasured, and the three Q6_K parity
programs have not been run on a GPU.
2026-10-05 19:58:05 +02:00
Thomas Weaver 87659162ed Q6_K gate/up through the native expert paths (Unsloth's UD-Q6_K_XL experts) 2026-10-05 19:58:05 +02:00
Thomas Weaver 9227973b36 PLE table as Q8_0 (Unsloth's UD-Q6_K_XL) + docs
PleTable accepts per_layer_token_embd.weight as Q8_0 (170-B rows): the
UD-Q6_K_XL file ships its PLE table in Q8_0, not IQ4_NL. The row reader
is already parameterized by bytes-per-row; only the type check, a
dequantize_q8_0 block loop (5 x 34 B) and the PLE_ROW_BYTES_MAX bump
(160 -> 170) were new. No GPU kernel changes: gather outputs floats.

- ple_reader_test --selftest also runs 170-B rows (90/110 were already run)
- ple_q8_parity: real-artifact Q8_0 PLE rows against ggml's reference
  dequantizer, through Mmap and Direct (bit-exact on the synthetic
  fixture from tools/ple_q8_fixture.py)
- docs/UNSLOTH_Q6.md: the manual workflow, verified shard inventory
  (169.2 GB, 6 shards, table alone in shard 3), pending real-run numbers
2026-10-05 19:57:36 +02:00
Niko1221 fa9bd5fbfa layer split auto: the coverage curve only from 4 GPUs (2- and 3-GPU placements keep the 0.1.39 curve) 2026-10-05 19:57:36 +02:00
Gopi e2b32892a6 layer split: score every four-way placement instead of guessing it
A four-GPU run picked its split from a formula that reads only `layer_ms`
(SMs x clock) and shares the layers in proportion to speed; the free VRAM
that decides how many experts a stage can actually hold never entered it,
so the search could hand the most layers to the card with the least room
and never notice.  All C(L-3,3) placements are now scored - 15,180 at 48
layers - and 2,068 of them cost nothing extra, because a stage's fill
depends only on its own layer range and its own free VRAM: `predict`
already hands each ranked pair to the one stage that owns its layer and
stops each stage at its first pair that does not fit, so a range is walked
once and memoised.

The cost model's mass curve changes with it.  `mass[r]` was (r+1)^-1.2,
fitted to the 5080+3090 sweep - still right on that rig (99.35% predicted
at 20,000 held, 99.4% measured) and wrong on IQ3_S, where it claims the
top 5,805 pairs hold 94.9% of the routed mass and the rig measures 69.2%
over four boots and 14.9M decode lookups.  No exponent reconciles them,
because the curve is a property of the model's routing and the profile
carries only a ranking, with no counts.  The mass is now the increment of
H(f) = 1 - (1 - f)^b over the held fraction, whose prefixes sum to exactly
H(N/total); b = 3 (STRATA_SPLIT_COVER_B overrides it) is chosen to leave
the validated regime where it was - at f = 0.8138 it gives the old fit's
99.35% - while at f = 0.59 it gives 93.2% against 92.2% measured.

This is the placement search from #584, carried on v0.1.39 and without the
weight carve it rode in on: v0.1.39 ships its own carve (#559 / #639), and
the search only runs under `--layer-split auto`, where nothing is carved -
so `cap[i]` is already net of the dense weights and a stage's room is what
`predict` already subtracts, its session.

Measured on the 4-way IQ3_S rig (2x RTX 3060 + 2x RTX 5060), same config and
same flags in both arms, the binary the only difference: the four-way split
moves from K=10,19,34 to K=14,31,41, the prompt chunk the starved cards allow
grows 768 -> 1280 tokens, prefill goes 425 -> 597 tok/s (+40%) and decode
44 -> 51 tok/s (+16%), with the decode expert-cache hit 74.7% -> 83.3%.  Two
boots per arm, and the split is deterministic.  The curve and the search are
one commit, so that measures the pair, not the search alone.
2026-10-05 19:57:36 +02:00
konijiwa110 1bb5c72484 qsa top-k: Turing prefill above ~90K cells takes the wide kernel (from #743; STRATA_TOPK_STREAM=0 restores)
The duplicate block_topk_stream_kernel is dropped: 0.1.39's block_topk_wide_kernel gives the same ids.
Only the 90-135K Turing band is new (counted bound, sm_75). Parity cases from the PR are kept.
2026-10-05 19:57:36 +02:00
Niko1221andarchitectds 5e53c516b3 prefill: equal chunks per prompt segment, opt-in STRATA_PREFILL_EQUAL=1 (from #693)
A segment reads in ceil(tokens / max_chunk) chunks of equal size, kept only where the last chunk would stream
every expert anyway. Used only at the segment call sites; request_chunk is unchanged.

Co-authored-by: architectds <[email protected]>
2026-10-05 19:57:36 +02:00
Niko1221 f07f060ae7 session files: RESTORE makes room in the elastic K/V (--kv-grow) before the device copy (review finding) 2026-10-05 19:57:36 +02:00
Niko1221andBenjamin Larsson 2467bb6899 cpu: Q2_0 AVX2 bit-plane kernel is opt-in (STRATA_Q2_BITPLANE=1), image built only when on, q2_bitplane_parity test
Co-authored-by: Benjamin Larsson <[email protected]>
2026-10-05 19:57:36 +02:00
Benjamin Larsson 9c9f639f25 cpu: Q2_0 bit-plane rows reduced four at a time
Down rows are only 10 blocks, so the per-row reduction was a large share; four rows now share one hadd tree. The single-row reduction uses the same tree, so a row's bits do not depend on how rows are split into tasks. Down rows +6-7% per core.
2026-10-05 19:57:36 +02:00
Benjamin Larsson 1048d2392b cpu: bit-plane AVX2 Q2_0 row kernel
The activation is pre-permuted once per token into the 2-bit codes' plane order (ActQ::qp/psum/pscale), so rows need no unpack interleave: four planes summed in int16, one madd, the -1 code offset subtracted exactly in the integers, one FMA per two blocks per token. 2.3-2.8x faster per core than the b256 kernel, closer to exact (rms rel 1.0e-7 vs 2.7e-7), width-invariant. STRATA_Q2_LEGACY=1 selects the previous kernel.
2026-10-05 19:57:36 +02:00
Maurizio Verde ffaf958eaa session files on 0.1.39: refused with --batch (#465 parallel requests: the server answers 501, the engine SERR); the STRATA_ARENA_MMAP arena records its experts.bin as a model input; docs 2026-10-05 19:57:36 +02:00
Maurizio Verde 1263ccdc91 docs: session files r4 (SWAIT/progress protocol, preflight wording, version identity, POSIX/Windows flush, continuation limit, r4 measurements) 2026-10-05 19:57:36 +02:00
Maurizio Verde 8b2160888b session files r4: SAVE RAM preflight before any checkpoint copy; progress after every block and bounded SWAIT allowances for blocking steps (review A/B) 2026-10-05 19:57:36 +02:00
Maurizio Verde 07e0c26f94 session files r3: RAM preflight for save; keep.bin.tmp planted-name test 2026-10-05 19:57:35 +02:00
Maurizio Verde d0289b88ba session files r3: include <memory>; Out initialised by members 2026-10-05 19:57:35 +02:00
Maurizio Verde 796bb8fc9c session files: resolved expert inputs, runtime read bounds, published-save status, typed errors, strict protocol, UNC free space (review R1-R6) 2026-10-05 19:57:35 +02:00
Maurizio Verde 71faad4f4d conversation_file_test: format v1 golden (header offsets, size and hash of the fixed sample) 2026-10-05 19:57:35 +02:00
Maurizio Verde ace0cfc866 docs: session files after the review fixes (identity, durability, errors, measured) 2026-10-05 19:57:35 +02:00
Maurizio Verde e41463a995 Session files: review fixes (exclusive temp files, no-follow restore, full identity, bounds, durability, server hardening) 2026-10-05 19:57:35 +02:00
Maurizio Verde 0c9f21e257 docs: session files (the slot save/restore API, its answers and errors, format v1, the checks, measured at 63K) 2026-10-05 19:57:35 +02:00
Maurizio Verde aa17fe8648 Session files: save and restore a conversation to disk (SAVE/RESTORE, POST /slots/0?action=save|restore)
A conversation the engine holds (what a parked snapshot holds) goes to one file and comes back, also after a
restart, so a long prompt is not read again:
- engine: `SAVE <path>` / `RESTORE <path>` between requests, answered `SAVED|RESTORED <tokens> <bytes> <ms>` or
  `ERR <reason>`; single GPU only (refused with --layer-split) and needs --prompt-cache > 0.
- format v1 (src/core/conversation_file.cpp): 64-byte header bound to a model fingerprint (name, size, first and
  last MiB of each weight file) and a config fingerprint (engine version, --kv, STRATA_KV_ROT, --kv-resident,
  --max-context, --mtp-window, control vectors), the payload, a payload hash and an end marker; written to
  `<path>.tmp` and renamed over `path` (MoveFileExW on Windows).
- fail-closed restore: size, header, both fingerprints, every count against the bytes left, the payload hash and
  the usual snapshot validation all run before any device write; a refused file leaves the session untouched.
- only the deepest checkpoint is saved (the next turn's resume point) and the K/V is streamed from the pools
  straight into the file's 16 MiB blocks, without a full host capture; Linux uses O_DIRECT when the filesystem
  takes it (buffered otherwise or with STRATA_SESSION_BUFFERED=1), Windows buffered Win32 I/O.
- serve/server.py: llama-server's `POST /slots/0?action=save|restore {"filename": NAME}` with --slot-save-path DIR
  (or "slot_save_path" in the config); NAME must be a plain file name inside DIR.

RTX 4070 Ti, IQ3_XXS, a 63,025-token conversation: file 1.20 GB, save 0.72 s, restore 0.89 s, the next 32-token
turn after a restore 1.15 s (first token 0.55 s) with the same output tokens as without saving.
Tests: conversation_file_test (CPU, no model; also built for Windows and run under Wine),
conversation_snapshot_test, serve/test_slots.py, serve/test_security.py.
2026-10-05 19:57:35 +02:00
Niko1221 f81876ecef kv-grow: ported over --vram-elastic (#533); off, with a warning, under --batch, --vram-elastic and --peer-device
The expert cache arena now has three backings (segmented #533, one VMM range for --kv-grow, cudaMalloc), tried in
that order.
2026-10-05 19:57:35 +02:00
sergiywith 025bf3b2ef Elastic K/V: VMM access failures roll back, failed growth stops the engine, the trim maps one run
From an audit of this PR, each finding checked against the code:
- VmmRange: a run whose cuMemSetAccess failed stayed counted as mapped (a later map_range skipped it, so the chunks
  were never made accessible); it is unmapped and freed again (commit_run).
- a failed growth or trim could leave host_res, d_res and the slot range half-changed while serve went on to the
  next request; such a failure now stops the engine, as other CUDA failures do. The residency uploads are checked.
- the trim maps the chunks it takes back as one run (one cuMemSetAccess instead of one per 2 MiB chunk) and refills
  the slots with async copies and one sync instead of a blocking cudaMemcpy per expert.

IQ2_XS: the served scenario (grow at a request and mid-decode, trim and refill, regrow, a parked conversation's
restore) runs as before; vmm_test passes.
2026-10-05 19:57:35 +02:00
sergiywith 9e3dbfe74a Elastic K/V (--kv-grow): the K/V takes VRAM as the context grows, the expert cache holds the rest
At --max-context 262144 the K/V is allocated whole at start (3.35 GiB at int8 with the drafter's) and the expert
cache is sized around it. With --kv-grow (or STRATA_KV_GROW=1) the K/V pools and the cache arena are CUDA VMM ranges
(core/vmm.hpp; the driver calls through the runtime's entry-point query, nothing links the driver library). The K/V
maps 2 MiB chunks for the cells the requests reach (16384 at start); when a request needs more, slots just below the
prompt path's loan give theirs up, a hotter expert in them first moving into the slot of the coldest one in the loan
region. A short request after a long one hands the chunks back and the slots refill from the profile. No address
moves, so no graph is captured again, and --max-context cells always fit.

- serve: grows at a request (its prompt, and a parked conversation before its restore) and in the decode rounds;
  trims once the outgoing session is parked
- generate: grows once for the prompt and max_new, before the loan
- one GPU with a profile, the whole K/V in VRAM (no --kv-resident), every expert in RAM (not the low-RAM tier);
  STRATA_KV_GROW_INIT / _STEP / _FLOOR for tests. Off by default: more slots move experts between GPU and CPU.
- tests/core/vmm_test: map, a chunk moved between ranges keeps its bytes, release

IQ2_XS, RTX 5090, 262K, fixed cache: first-token logits and 64 tokens bit-identical to 0.1.31 off, mapped whole,
grown into new VRAM, and grown by giving up 266 slots. Cache auto: 15,119-15,207 -> 17,300-17,503 slots, short chat
15.06-15.33 -> 14.71-14.83 ms a round; an emulated 16 GB card: 3,396 -> 5,719 slots, short chat 100 -> 115 tok/s,
a 32K prompt 7.44 -> 6.36 s and 24.6 -> 22.2 ms a round after it.
2026-10-05 19:57:35 +02:00
Niko1221 91cc8149b0 serve: the message-boundary checkpoint is the tail kind (evicted first, like --prompt-cache-tail's) 2026-10-05 19:57:35 +02:00
Moor Wu b5de344b73 Reuse long chat history when the last user message is edited 2026-10-05 19:57:35 +02:00
imanuandCodex 9c139846d5 GPT6-CACHE-Salva un checkpoint opzionale vicino alla fine del prompt
Co-Authored-By: Codex <[email protected]>
2026-10-05 19:57:35 +02:00
Niko1221 f71a128126 prefill: KV prefetch - return early while a prefetch is pending, read the env once (#732 review) 2026-10-05 19:57:34 +02:00
Moor Wu f1635c2174 Overlap streamed KV uploads with prefill computation 2026-10-05 19:57:34 +02:00
Benjamin LarssonandTrevin 458bcbff6f setup: --kv k8v4 streams with --kv-resident (the setup hunks of #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 #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 <[email protected]>
2026-10-05 19:57:34 +02:00
Trevin fea9ff5a4d kv: --kv k8v4 streams with --kv-resident
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.
2026-10-05 19:57:34 +02:00
Niko1221 65fc896329 iq_kernels: the aligned shared declaration is HIP only; CUDA keeps alignas(16) (#778)
The attribute-after-declarator form from #778 does not compile with nvcc and MSVC as host (the CUDA build failed in mmvq_multi_kernel). The macro uses it under __HIPCC__ only, so CUDA is as it was.
2026-10-05 18:34:29 +02:00
Niko1221 1e3a9a4700 tests: gemm_f16_io_parity builds its BF16 weights by hand and refuses an all-zero reference (#835) 2026-10-05 18:34:29 +02:00
Niko1221andxjc10 01f21ea683 hip: FP16 prompt GEMMs are opt-in (STRATA_HIP_PROMPT_F16=1), CUDA-guarded, decided once per stage, non-finite count (#835 review)
Review changes on #835: off unless STRATA_HIP_PROMPT_F16=1 (a tip on gfx103x); act16/g_act_f16 and set_act_f16 are HIP only so CUDA kernels are unchanged; Prefill::init decides the mode once per stage on the stage's own device and bf16x2 takes it as an argument; widen_rows_f16 counts non-finite outputs under STRATA_DBG_NAN; new hip_gemm_f16_io_parity test.

Co-authored-by: xjc10 <[email protected]>
2026-10-05 18:34:29 +02:00
xjc10 5d83b431ba docs: AMD_HIP.md RDNA2 - the FP16 prompt GEMMs, their switch, the measured gain and the HIP ctest result
A bullet in the RDNA2 section: rocBLAS on gfx1030 only has tuned FP16-in/FP16-out kernels, what #835 changes,
STRATA_HIP_PROMPT_F16=0 for the old path, the measured prompt speeds on a second community machine (2x RX 6900 XT,
ROCm 10.0, engine 0.1.39), that the output is not bit-identical (link to the distribution check), and the ctest result
with -DSTRATA_BUILD_TESTS=ON: 60 of 65 pass with and without the change, the 2 skipped and 3 failing tests and why.
2026-10-05 18:34:17 +02:00
xjc10 99a3fe8df9 bench: where the FP16 prompt path's rounding moves, and what the distribution check does not show
Per-value rounding bounds of both paths (BF16-weight products: the BF16 activation rounding goes, an FP16 output
rounding comes; quantized-weight products: an FP16 output rounding comes), why the two are not compared by argument,
how the BF16X2 reference relates to them, and the open follow-up (an fp32 forward pass as reference).
2026-10-05 18:34:17 +02:00
xjc10 972cad1bc5 HIP gfx103x: the prompt path's 16-bit GEMMs in FP16 in and out (prompt reads ~2x on RX 6900 XT)
rocBLAS on gfx103x has tuned GEMMs for FP16 in / FP16 out only; FP16 in / FP32 out (Gemm::f16, Gemm::native) and BF16 in
(Gemm::bf16) fall back to generic kernels, 5.6 / ~5.3 TFLOPS against 37.7 on gfx1030 (N=10240, T=7313, K=2560).

On gfx103x only (prompt_f16(), per device; STRATA_HIP_PROMPT_F16=0/1 overrides):
- Gemm::f16 / native run FP16 out into the start of each FP32 row of Y (ldc = 2 ldy halves); widen_rows_f16 widens each
  row in place from its end - no extra buffer, no host sync
- Gemm::bf16 converts W in row slices to FP16 through the dequantization scratch and takes X as the FP16 image the
  gr_* / to_bf16 kernels now write (set_act_f16; saturated, a NaN stays a NaN); BF16X2 is off there
- Gemm::set_f16_io is an explicit per-instance switch that only Prefill::init turns on, so every other caller
  (gemm_bf16_parity) runs what it ran; CUDA builds are unchanged

2x RX 6900 XT, IQ3_S: one card 439 / 466 / 461 -> 744 / 915 / 926 tok/s at 9.4K / 34.7K / 105.8K tokens; layer split
444 / 707 -> 833 / 1,356 at 8.3K / 33.6K. Needle 15/15 on both paths; teacher-forced, the FP16 path is closer to a
higher-precision reference (BF16X2) than the old path. Details: bench/results/2026-10-04-rdna2-fp16-prompt/README.md.
2026-10-05 18:34:16 +02:00
Niko1221 771d5b73a7 hip: STRATA_HIP_ADAPT_KERNEL_COPY=1 copies adaptive swaps with a kernel instead of SDMA (#884, opt-in)
Workaround for the gfx1030 hang that needs MMQ prompt + adaptive swaps + SDMA together. Off by default; a source outside the registered arena, or not 16-byte aligned, takes the normal cudaMemcpyAsync. Untested on the reporter's 2x RX 6900 XT.
2026-10-05 18:33:39 +02:00
Niko1221andMagh97 b72ea678be sycl setup: write_run_script takes setup.py's open_browser argument; Arc Pro B60 also as PCI id e211 (#870)
Fixes 1 and 4 of #870, plus a test that every function setup_intel.py swaps into setup.py accepts all of the original's parameters. Fixes 2 and 3 are PR #784's session/native_dense ports.

Co-authored-by: Magh97 <[email protected]>
2026-10-05 18:33:39 +02:00
Niko1221andunimo-chan fa228b094d device (Windows HIP): one hipFree(0) warm-up and one hipMemGetInfo retry per process, before the DXGI budget (#873, #654)
Reworked from #873: no 8 x 250 ms retry at every failing call site, no #if in device_info (cudaMemGetInfo already maps to this function), no retry of real failures (only hipErrorInvalidValue, once), before/after lines in the log. The strata-device 5x retry loop is dropped.

Co-authored-by: unimo-chan <[email protected]>
2026-10-05 18:33:39 +02:00
Niko1221 e3336a13ba cmake: gfx1034 joins the unvalidated HIP archs (#778)
The native_dense split-shard arch guard from the same PR is #648's change and is left to it.
2026-10-05 18:33:39 +02:00
jollyroger1480 d81a57d5f4 iq_kernels: portable aligned shared-memory declaration for gfx1030
HIP clang for gfx1030 (ROCm 7.1) rejects 'alignas(16)' placed between
__shared__ and the declaration ('alignas attribute cannot be applied to
types'). Use __attribute__((aligned(16))) after the declarator instead —
same layout, compiles everywhere.
2026-10-05 18:33:30 +02:00
xxDoman 6b2572e45f hip/gfx906: cudaFuncSetAttribute as a function, not a macro
A function-like macro splits its arguments on the commas inside a template
argument list, so cudaFuncSetAttribute(kernel<1, 6, true>, ...) failed to
compile (fused_gr.cu:1089-1093, 'too many arguments provided to function-like
macro invocation'). Restore the template function 0.1.38's hip_compat/
cuda_runtime.h had, and add the two carveout definitions used beside it.

gfx906-only: include/strata/platform/hip_compat/ is on the include path only
inside if(STRATA_HIP_GFX906); CUDA and the wave32 RDNA backend are untouched.
2026-10-05 18:33:30 +02:00
bsorensen110 fd98b23849 tests: the tuning-header gate's test builds on Windows, and RDNA1/RDNA2 stays rejected (#695)
Two findings from the Copilot review on #695.

The five-character prefix match (replaced by the named sibling sets in the
parent commit) also grouped gfx1010 (RDNA1) with gfx1030 (RDNA2), so the gate
would have passed a table between two architectures that share no solution
IDs.  The test now pins that pair in both directions, and the third RDNA3
member (gfx1102) alongside the pair already covered.  Measured against the two
implementations with MSVC, same test binary source: the prefix-match gate
fails exactly these two cases (13 cases, 2 failures), the sibling-set gate
passes all 13.

<unistd.h>/getpid() and a hard-coded /tmp broke the test on Windows/MSVC with
STRATA_BUILD_TESTS=1.  It now uses std::filesystem::temp_directory_path with a
steady-clock token and a per-case file name, the shape
tests/core/gguf_split_test.cpp already uses, and it reports a scratch-file
write failure instead of letting it read as a gate rejection and pass for the
wrong reason.

Built and run with MSVC 14.4x (/std:c++20, /W4): 13 cases, 0 failures.
2026-10-05 18:33:30 +02:00
Soren-ldandCopilot Autofix powered by AI 12d6af092b Refactor architecture check for tuning compatibility
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-10-05 18:33:30 +02:00
bsorensen110 2748e1471c hip: the tuning table's arch gate accepts the RDNA4 sibling (gfx1200 <-> gfx1201)
The header gate compared the table's architecture to the runtime's with
`arch != expected_arch`.  A card that reports its RDNA4 sibling - a Radeon
AI PRO R9700 (gfx1201) under HSA_OVERRIDE_GFX_VERSION=12.0.0 reports
gfx1200 - rejected its own calibration at startup and lost the tuned
prefill route entirely:

  prefill gemm: tuning architecture mismatch: file=gfx1201 runtime=gfx1200; using hipBLASEx

Solution IDs are scoped to the architecture FAMILY (gfx1200/gfx1201 share
them, as gfx1100/gfx1101/gfx1102 do), and a solution ID that does not exist
on the running card already fails the per-solution gate in prefill/gemm.cu
(getAlgosFromIndex / matmulIsAlgoSupported) and falls back to hipBLASEx per
call.  The header gate can therefore be family-wide: the version gate stays
strict, cross-family pairs stay rejected, and the per-row gate decides which
rows actually run.

Adds tests/prefill/tuning_header_arch_family_test.cpp (synthetic tables, no
model, no GPU): 10 cases, RED on the strict gate (3 sibling failures),
GREEN on the family gate.
2026-10-05 18:33:30 +02:00
lawsirlawsir-png 534d07f5da tools/hip: add gfx1100 hipBLASLt tuning table for hipBLASLt 1.2.2 (100202)
Calibrated with tools/hip/tune_hipblaslt.cpp on a Radeon PRO W7800 (gfx1100) under ROCm 7.2.4. setup.py:hipblaslt_table() resolves tools/hip/<arch>-hipblaslt-<version>.txt, and no 100202 table exists for gfx1100, so prefill silently falls back to plain hipBLAS. Requested in #505.
2026-10-05 18:33:30 +02:00
Zac Chen d74e110f0e hip: hipBLASLt tuning table for gfx1100 (RX 7900 XTX) with ROCM 10.2.0a nightly (hipBLASLt 1.5.0)
tools/hip/gfx1100-hipblaslt-100500.txt: the same 16 dense GEMM geometries as
the other gfx1100 tables (bf16 and f16, T=4096 and T=8192, 32 rows), calibrated
on an RX 7900 XTX with tune_hipblaslt (relative L2 <= 1e-4, max abs <= 1e-2, no
padding writes) against a ROCm 10.2.0a20261003 nightly SDK
(libamdhip64.so.7.17.26392), hipBLASLt 1.5.0 (version number 100500).

The engine refuses a table of another hipBLASLt version, so on this ROCm the
shipped gfx1100 tables (100100, 100200) are refused and prefill runs on plain
hipBLAS - the same gap the gfx1201 1.5.0 table (#481) closed for the R9700.
setup picks this one by name once the installed hipBLASLt reports 100500.

Measured on a 0.1.38-lineage nightly build of this tree, Qwen3.8-Flash-Next
IQ3_S greedy, arms differing only in STRATA_HIPBLASLT_TUNING (median of 3
clean runs each):

| prompt tokens | with table | plain hipBLAS | gain |
| 131071        | 1687 tok/s | 926 tok/s     | 1.82x |

decode unchanged (62.3 vs 60.7 tok/s, overlapping ranges). Per-run data,
the calibration command and the tuner log: #745
(bench/results/2026-10-04-community-rx7900xtx-hipblaslt-100500/).

docs/AMD_HIP.md: the shipped-tables list carries the entry.
2026-10-05 18:33:30 +02:00
miskahm 7984688e3c hip: ship a gfx1100 tuning table for hipBLASLt 100401 (ROCm 10.0.0)
ROCm 10.0.0's hipBLASLt is 1.4.1, whose solution ids are version 100401, and no
gfx1100 table shipped for it - so on an RX 7900 XTX with a packaged ROCm 10 the
prompt path's dense GEMMs fell back to plain hipBLAS. This is the same version
mismatch PR #745 measured on ROCm 10.2 (their 100500), reproduced on 10.0.0.

tools/hip/gfx1100-hipblaslt-100401.txt: calibrated with tools/hip/tune_hipblaslt
over the 26 dense geometries of the shipped gfx1100 table, on a Ryzen 7 9800X3D.
Swift 1.5 IQ3_XXS, 262144 ctx, --kv int8, fresh prompts (a nonce per request, or
the server's prompt checkpoint reads nothing), medians of 3:

  1.7K tokens   682 -> 1,038 tok/s  (+52%)
  6.5K tokens   857 -> 1,524 tok/s  (+78%)

Decode unchanged (79.0 vs 80.3 tok/s, inside this machine's 2.3% run drift), and
hip_prefill_hipblaslt_gemm with STRATA_HIPBLASLT_VERBOSE=1 reports fallbacks=0.
2026-10-05 18:33:29 +02:00
Niko1221 ce37456ccd prefill: dense MMQ is HIP only; no q6_k instance or untested code in CUDA builds (#820)
Gemm::native_mmq, its call, the f16_to_f32/set_bounds kernels and the Q6_K case are under __HIPCC__; the CUDA type list loses q6_k. The K % 256 != 0 out-of-bounds read is already refused in native_mmq (kept). Still opt-in: STRATA_DENSE_MMQ=1 on a STRATA_MMQ_KQUANTS=ON HIP build.
2026-10-05 18:33:29 +02:00
xendak 43881f14a3 prefill: the dense GGUF projections through MMQ on HIP (opt-in STRATA_DENSE_MMQ=1), the K-quant instances on the HIP build
The prompt path's dense projections (attention qkv/gate, the PLE key, the shared
experts, the router, the head) run dequantize-to-FP16 + cuBLAS: on the RDNA2
cards that is 68% of the prefill GPU time at ~25% of the card's fp32-accumulate
rate, while the same shapes through llama.cpp's int8 MMQ run ~7x faster
(measured with bench_dense_gemm).  This wires Gemm::native's beta = 0 products
through the MMQ path the MoE experts already take: quantize the FP16 activations
to q8_1 (they are converted to FP32 in the dequant scratch, which the old path
only fills afterwards) and run one mul_mat_q product per 1024-row chunk.  It is
opt-in (STRATA_DENSE_MMQ=1; unset, nothing changes) and falls back silently to
the old path on any shape MMQ does not take.

- STRATA_MMQ_KQUANTS also compiles the Q4_K / Q5_K / Q5_1 / Q6_K instances on
  the HIP branch (the mixed-quant packs' dense tensors are K-quants: this
  model's attention/PLE matrices are IQ4_XS/IQ3_S/Q4_K/Q5_K/Q6_K), adds Q6_K to
  the CUDA list, and defines STRATA_MMQ_KQUANTS for the HIP target.
- Gemm::native_mmq: one MMQ context, xq/ident/bounds buffer (~9.5 MB) and a
  failed-flag per Gemm; fp16->fp32 and the {0, rows} bounds helper join
  moe_mmq's kernel set.
- K must be a full 256-value multiple.  MMQ loads the weights in 256-value K
  chunks, and past a partial row the chunk reads bytes past the row - the next
  row's, or for the last weight row bytes past the tensor, which no caller
  guarantees to be zeros (the MoE path is safe because its gather buffers end
  in a zeroed tail).  On this pack the 640-value IQ4_NL shared-expert down
  picked up a NaN scale from the next tensor's blocks and zeroed the output;
  the odd shapes stay on the dequantize + cuBLAS path.

Measured on the RX 6900 XT (gfx1030), swift-1.5-iq3_xxs, WORKERS=15 ADAPT=1
PREFILL=8192, bench_prefill.py fresh medians: 4K prefill 436.1 -> 757.2 tok/s,
8K fresh 447.7 -> 773.9 tok/s, 8K followup 163.9 -> 206.1 tok/s; decode within
noise (40.6 vs 40.3 tok/s at --pcie-frac 0, 52.7 vs 49.9 at the 0.55 default).
Greedy output: bit-identical for the first 200 tokens of a short prompt; a 4K
prompt's greedy text diverges at token ~26 (the q8_1 activation rounding) and
stays coherent.
2026-10-05 18:33:29 +02:00
Niko1221 0f1390bd11 hip: fence after the doorbell ring store so the host sees it (#697)
HIP only (__HIPCC__); the CUDA kernels are unchanged. A volatile store to mapped host memory can stay in L2 on RDNA4 until the stream syncs; __threadfence_system() after the store flushes it. Reporter's one-line diagnostic fix, applied to doorbell_ring/publish/publish_res (publish_value already had it). For #579 and #613 to test.
2026-10-05 18:33:19 +02:00
pugolini 7fd67ddd6d verify: the shared-expert stream fork starts off on HIP (#816)
The fork overlaps the shared expert with the routed experts on a second stream.
It pays off on CUDA, where a36be1d added it, but on HIP the cross-stream event
dependency costs more than the shared expert takes to run, so there the fork
starts off and STRATA_SH_STREAM=1 turns it back on. CUDA's default is unchanged.

Same shape as mtp.cpp's STRATA_MTP_PREFILL_SYNC (#382): the env var always wins,
only the default differs per backend. The profiler takes the fork off to time the
stages, so a profiled run never showed this - which is why STRATA_SH_STREAM=0 was
the only way to see it.

Radeon AI PRO R9700 (gfx1201, ROCm 6.4.3), Qwen3.8-Flash-Next IQ3_XXS, --kv int8
--kv-resident 32768 --resident-experts, temp 0, 3 runs each, same binary and
prompt, 48,067-token prompt so the KV stream path runs:

  stock 0.1.39 (fork on, default)   43.40 t/s   (38.90 - 44.60)
  this change (fork off, default)   62.90 t/s   (55.40 - 63.80)
  STRATA_SH_STREAM=1                43.50 t/s   (39.10 - 45.20)
  STRATA_SH_STREAM=0                63.00 t/s   (55.90 - 64.10)

The fork is a scheduling change only: the same four prompts answer byte for byte
the same with it on and off. #816 reports the same fall on a gfx1030 (RX 6800,
Windows, 42.5 -> 56.4 t/s), and a comment on #646 sees it on a gfx1100.

Short prompts are barely affected here (65.4 against 62.7 t/s at 256 tokens), so
this only shows once the KV stream path is in play.
2026-10-05 18:33:19 +02:00
Niko1221 a2ef9db5cd docs: STRIX_HALO.md - IQ3_XXS 8K re-measured (6 pairs): prompt equal 2026-10-05 17:24:55 +02:00
Niko1221 2e0f28e7d7 Merge branch 'f-140' into f-140-j 2026-10-05 16:36:52 +02:00
Niko1221 254415eac4 docs: STRIX_HALO.md - build from source, the defaults, the opt-in switches, the measured table 2026-10-05 16:36:48 +02:00
Niko1221 0d5b12b82e serve: the image encoder's file arguments are absolute (it now runs in its own directory, #480) 2026-10-05 15:58:38 +02:00
Niko1221 4f41b51c6b setup: the 200K step is never the recommended context (#608)
ram_ctx() skips 204800: where 200K fits and 256K does not, the rule stays at 128K. A test covers every RAM size.
2026-10-05 15:58:38 +02:00
Niko1221 3982b2250a docs: TROUBLESHOOTING for Smart App Control, the port error, the engine rollback, Linux read-ahead and THP (#735 #769 #670 #699 #771) 2026-10-05 15:58:38 +02:00
Niko1221 74d566bd1c generate: warn when the profile caps an explicit --expert-cache; retry a split stage's cache at 90% (#831 #841)
- #831: an explicit --expert-cache above the profile's length was cut to it with no word on the native-pack path; a
  warning now says so (the allocation is unchanged).
- #841: a layer-split stage whose expert cache fails to open (out of memory with the VRAM free) is retried with 90% of
  the slots, up to 3 times, each try logged. Nothing changes when the first open works.
2026-10-05 15:58:38 +02:00
Niko1221 bb19becc24 pinned arena: no VirtualLock on large pages, no MADV_HUGEPAGE under THP always (#779 #771)
- #779: a large-page arena cannot be paged out, so the three working-set lock sites skip it (the note says so).
- #771: with /sys/kernel/mm/transparent_hugepage/enabled = [always] the kernel already backs the arena with huge
  pages where it can; the extra MADV_HUGEPAGE only added direct reclaim and compaction on every fault (a 25 s start
  took 432 s on a fragmented machine). It is not requested there, and STRATA_NO_ARENA_THP=1 skips it anywhere.
2026-10-05 15:58:38 +02:00
Niko1221andjordicor f60ae8d0a4 Windows mapped-page release: the switch is STRATA_FILE_RELEASE (#818)
STRATA_ARENA_RELEASE already exists and means the opposite (=0 keeps the experts a GPU holds, generate.cpp), so the
opt-in is renamed in the engine, the tests, DETAILS.md and the bench folder. The working-set assert in
file_expert_source_test reports, not fails, a trimmed page that Windows maps straight back with the switch on. The
bench folder keeps the README and the two scripts (the raw export and the harness self-tests are dropped).

Co-authored-by: jordicor <[email protected]>
2026-10-05 15:58:38 +02:00
jordicor 441a8f792a Add opt-in Windows mapped expert page release 2026-10-05 15:58:38 +02:00
sergiywith ebe1db1a0b Start: register the expert arena per layer on a thread ahead of the readers (Windows; part 2 of #285)
0.1.31 registers the whole arena with CUDA before the first byte is read. With 4 KB pages, which every account
without the Lock Pages privilege gets, that registration is ~1.5 s of the start that nothing hides (IQ2_XS:
33 GiB).

- PinnedArena(bytes, bounds, Deferred) reserves only. register_slices() registers the per-layer slices in order on
  a thread and publishes how many are done.
- Every reader (load_experts_gguf buffered and unbuffered, load_experts_ranges, load_experts_direct) writes layer L
  only once slices L and L+1 are registered. Writing a page while cudaHostRegister runs on it corrupted the arena
  under WDDM, even on large pages. A layer boundary inside a page puts that page in both registrations, so the next
  slice must be done too (page-aligned in effect, without moving the slice bounds an expert must not straddle).
- A slice CUDA refuses ends the registration, and the rest is locked resident as in the sliced fallback.
- Only where the whole arena would be registered anyway: no cap (STRATA_ARENA_PIN_GIB, multi-GPU under WDDM) and no
  shared arena file. Linux keeps #253's whole-arena pin. STRATA_DEFERRED_REGISTER=0 restores the old order.
- STRATA_VERIFY_ARENA=1 prints the loaded arena's FNV-1a checksum (tests).

Checksums: the same with the old order and the deferred one, 4 KB and large pages, the GGUF in place and experts.bin
(IQ2_XS; 13 deferred loads).

IQ2_XS without experts.bin, RTX 5090, 128 GB. Each cell is the time until the arena is loaded / until a 16-token
answer is done. Cold: the files pushed out of the file cache first. Two to three runs each:

| | cold | restart |
|---|---|---|
| 4 KB pages (STRATA_NO_LARGEPAGES=1), 0.1.31 | 12.4-13.0 / 16.3-16.8 s | 7.8-8.5 / 10.9-11.7 s |
| 4 KB pages, parts 1+2 | 11.1-11.5 / 14.9-15.4 s | 5.5-5.7 / 8.5-8.9 s |
| large pages, 0.1.31 | 17.6-18.7 / 21.1-22.4 s | 4.6-5.1 / 7.0-7.6 s |
| large pages, parts 1+2 | 17.6-19.9 / 21.3-23.6 s | 4.1-4.5 / 6.7-7.1 s |

The cold spread with large pages comes from the drive: the same build gave 17.6 and 19.9 s with the deferred
registration and the cache probe switched off as well.
2026-10-05 15:58:38 +02:00
Pc1 066094c81f file tier: STRATA_UNBUFFERED_LOAD=1 is not honoured without a RAM budget
Review of #773 (2 x RTX 5060 Ti 16 GB, 32 GB RAM, --mmap-experts, no --resident-budget-gib): with no RAM copy the
file cache is the expert tier, and forcing unbuffered reads there re-read 163-629 GB from the drive and halved the
speed. The automatic decision never armed in that mode; now the forced one does not either, and the log says so.
2026-10-05 15:58:38 +02:00
Pc1 2d929a28b3 file tier: unbuffered reads on Linux too (O_DIRECT + the kernel's asynchronous reads)
through the page cache, as page faults of the mapped GGUF - small requests on the critical path, and pages that a
32 GB PC cannot keep beside a 16 GiB RAM copy anyway, so they were read again and again.
- open_direct opens the files with O_DIRECT; read_direct queues every 4 KiB-aligned window of a batch with one
  io_submit (linux/aio_abi.h, no library; allowed by Docker's default seccomp profile, unlike io_uring) and waits for
  all of them, each thread with its own context and aligned buffer.  Windows merges windows up to 1 MiB apart for
  NTFS; here only windows that touch are merged.  A refused submit or a failed read falls back to the mapping, as on
  Windows.
- The same decision as Windows' `cache_counts = false` arm: unbuffered when the file cache could not keep the expert
  bytes outside the RAM copy (platform::file_cache_keeps, from MemAvailable and the tightest cgroup limit), re-checked
  once the copy is built (#577).  STRATA_UNBUFFERED_LOAD=1 / 0 forces it either way.  A pack's experts.bin works too
  (its Linux open now records the path).
- direct_fallbacks() counts the blobs an unbuffered read could not deliver.
- Tests: file_expert_source_test reads a synthetic pack unbuffered - one blob at a time, a batch of adjacent experts,
  copy_blob - and requires the file's bytes and no fallback (a mutation that fails every read is caught).  ctest: 63
  of 66 pass; the three others need a Q2_0 pack, a higher `ulimit -l` and AVX-512, as before.
Measured on an RTX 3080 Ti Laptop 16 GB, i9-12900H, 30 GB RAM, KIOXIA PCIe 4 NVMe, Linux 7.0, ext4: Qwen3.8-Flash-Next
Abliterated Q4_K_M in place (--native), --resident-budget-gib 16, --expert-cache auto, 8K context, greedy; three
prompts (code, Russian prose, a 7.8K-token summary), each with and without MTP, two rounds of buffered
(STRATA_UNBUFFERED_LOAD=0) against unbuffered, the same binary.  Decode 4.38 -> 7.90 tok/s on average (x1.80;
x1.49-x2.01 per prompt and mode), the 7.8K prompt read at 154/172 -> 184/290 tok/s, startup 36 -> 18-21 s.  The
code prompt's answer is the same text in all 16 runs; the other two differ between runs of either arm (the
adaptive GPU cache changes which experts the CPU computes), as before.
2026-10-05 15:58:38 +02:00
Jesus Gulfo 760c775434 Linux: read ahead of the head, embedding and vision encoder loads; time them
The native output head (437 MB) and the token embedding (260 MiB) were copied
out of the mapped GGUF one page fault at a time, and strata-vision's projector
(907 MB) went through llama.cpp's sequential reads, all before the server was
ready. Each now asks for its bytes ahead (the vision encoder honours
STRATA_READ_AHEAD=0 too), and the head, the embedding, the projector load, the
encoder warm-up and the pinned cache complement log their times.
2026-10-05 15:58:38 +02:00
Jesus Gulfo cb33c0bac5 Linux: read ahead of the mapped loads at start
On Linux every load phase read its files one page fault (one 128 KB readahead)
at a time, so a cold start spent most of its time waiting on the drive at
queue depth ~2. A new platform::advise_willneed asks the kernel for a range in
128 KiB steps (WILLNEED reads at most one readahead window per call), and is
called before the weight load, the native dense upload, the profile fill (256
pairs ahead, STRATA_FILL_AHEAD), the peer tier's fill (--peer-device), the
resident RAM copy and the MTP draft files. STRATA_READ_AHEAD=0 turns it off.
Each phase logs its time.

Gen3 NVMe, RTX 5090, 32 GB, Q2_0 resident at 262K: ready in 70 s, was ~920 s.
2026-10-05 15:58:38 +02:00
Maxim Shipko 2de94bca5e Respect Windows commit capacity 2026-10-05 15:58:37 +02:00
Niko1221 fb57b6cd81 setup: quick fixes and OS items (#657 #737 #670 #798 #775 #779 #841 #881)
- #657: check_shards refuses a one-tensor shard that is longer than its tensor (the PLE table), naming both sizes.
- #737: UD-Q4_K_XL on several GPUs below the 135 GB estimate is a warning and a question (explicit --gpus --yes is
  the consent), not a refusal.
- #670: an engine update keeps the engine it replaces in engine/.previous (one generation, all-or-nothing swap);
  setup.py --rollback-engine puts it back.
- #798: setup counts P/E cores from the hybrid PMU lists, else by 90% of the largest capacity (tests on a fake /sys).
- #775: a learned --expert-profile / --expert-profile-save added by hand survives a setup run.
- #779: a tip (--vram-reserve-mib 1500) when nvidia-smi says the card drives a display.
- #841: typed-ahead keys are flushed before a setup question on a terminal.
- #881: read_text() with encoding utf-8 in setup.py and package_windows.py; the CPU image encoder build finds vcvars on
  Windows; PCI 73DF (RX 6700 XT / 6800M) is gfx1031 with a self-build hint.
2026-10-05 15:58:36 +02:00
Niko1221 bea064293f ngram: the PLE size-mismatch message says a longer-than-its-table file is a bad download (#657) 2026-10-05 15:58:36 +02:00
Niko1221 7b80403c7b cpu pool: tell P-cores from E-cores by the hybrid PMU lists or 90% of the largest capacity (#798)
Linux counted a core as a P-core only when cpu_capacity equalled the maximum. Turbo Boost Max 3.0 gives the "favored"
P-cores a slightly higher capacity, so a Core Ultra 7 270K Plus (8P + 16E) counted 2 P-cores and started one pool
worker. Intel's /sys/devices/cpu_core/cpus and cpu_atom/cpus decide when they exist; without them an E-core is one
under 90% of the largest capacity. A CPU whose capacities differ by a few percent is no longer hybrid.
2026-10-05 15:58:36 +02:00
Niko1221andziphao2010 2ab6304867 serve: vision temp files, Smart App Control message, engine start line, real listen error (#480 #874 #735 #779 #769)
- #480: the image encoder's directory has no space in its path (a TEMP under a user name with a space broke every
  image: the ENC and GENI lines are split at spaces); the ENC line names its files relative to the encoder's cwd.
- #874: the per-request combined embeddings file goes to /dev/shm on Linux when it has room, and is opened
  short-lived (FILE_ATTRIBUTE_TEMPORARY) on Windows, instead of heavy steady disk writes.
- #735: WinError 4551 / 1260 on starting the engine or the encoder says Windows blocked the (unsigned) program
  (Smart App Control) and what to do. A message only; no signing.
- #779: a timestamped "engine started: exe args" line in the engine log.
- #769: only EADDRINUSE says "already in use"; any other listen error says what the OS said.

Co-authored-by: ziphao2010 <[email protected]>
2026-10-05 15:58:36 +02:00
Niko1221 8fb2dd34cb winjob: opt the server and its children out of Windows power throttling (#691)
A minimized console window made Windows 11 treat the server and its children as background work and move their
threads to the E-cores (about 20% slower on a hybrid CPU). contain() now sets ProcessPowerThrottling off for each
child, and the server does it for itself. Windows 10 knows only the EXECUTION_SPEED bit, so it is tried on its own
when both bits are refused.

Reported with the patch by mozophe.
2026-10-05 15:58:36 +02:00
Niko1221andWesleyvdk 035da7f8c1 iq_pack: IQ3_XXS and IQ4_XS PLE keys stay native (#381)
NativeDense serves these formats; the packer sent them down the BF16 path, so such packs failed at start.

Co-authored-by: Wesleyvdk <[email protected]>
2026-10-05 15:58:35 +02:00
Niko1221andLéon Avic Simmons 4f4c923cb2 strata_pack build --force; setup passes it when it rebuilds a pack (#634)
Co-authored-by: Léon Avic Simmons <[email protected]>
2026-10-05 15:58:35 +02:00
Léon Avic Simmons f0b083efed strata_pack.py build: refuse an output directory that already holds a pack, naming the file
build did mkdir(exist_ok=True) and then wrote experts.bin, dense.bin,
embd.bin and manifest.json over whatever pack the directory held, with
nothing said. Now a manifest.json, index.txt or native_experts.txt in
--out (the files the engine reads a pack's identity from) stops build
before it opens the GGUF or writes a byte, naming the directory and the
file; it returns 1 like the other refusals. An empty or absent directory
proceeds as before, and so does experts.bin without manifest.json: build
writes the manifest last, so that is a build that did not finish, not a
pack.

tools/test_shards.py: each marker is refused with the path and the file
named and nothing in the directory touched; an empty and an absent
directory go on into the build; an unfinished build is rebuilt.
2026-10-05 15:58:35 +02:00
Niko1221andChristoph Wübbels 62aaea4e14 setup: the shared Chat settings file is no model config (#346)
model_config_files() leaves strata-<model>.shared-settings.json out in the start menu, previous_config, the
data-folder move and strata_mcp.configs().

Co-authored-by: Christoph Wübbels <[email protected]>
2026-10-05 15:58:35 +02:00
MingShi_ 621f84e62d setup: a 200K context choice between the 128K rule and 256K (#406)
#406 lets a PC below setup's 256K estimate keep 256K with a note, but the list
jumped 128K -> 256K: there was no step between the 128K rule and a size that PC
may not hold.  204800 is inside the trained 262144, so it needs no rope scaling,
and with IQ3_S it costs ~2.8 GB of 8-bit KV against ~3.6 GB at 256K.

Measured on an RTX 4080 16 GB, Ryzen 9 9950X3D, 62 GB usable, IQ3_XXS, engine
0.1.37, 8-bit KV (setup turns KV streaming off at this size, so the KV stays in
VRAM and the expert cache loses the difference):

  context            128K      200K
  decode, shallow     94.1     85.1 t/s   (median of 10, warm)
  decode, 30K deep    87.2     85.3 t/s
  decode, 124K deep   94.1     79.2 t/s
  prefill          3257-3284  3189-3318 t/s
  experts cached      3661     2951       (-710)
  a 203259-token prompt: 3093 t/s prefill, 68.6 t/s decode

tools/strata_mcp.py's fallback list mirrors CONTEXTS and moves with it, so a PC
that cannot import setup sees the same menu.  tools/test_setup_risk.py picks 256K
at "6" now and a new test covers a 200K pick: kept, no rope scaling, and the RAM
note a 64 GB PC gets.
2026-10-05 15:58:35 +02:00
Akido 5f6b7c2766 setup: a download stopped before its rename is finished without asking for more
A .part holding every byte (setup stopped between the last byte and the
rename) was resumed with a range past its end; the server answers 416,
which download() retried 30 times 10 s apart before renaming the file.
2026-10-05 15:58:35 +02:00
Sunil Srivatsa 645cbb66e4 fix(setup): drop an engine archive that fails to unpack
get_prebuilt kept an engine archive that is not a zip (or a damaged one)
together with its .done mark. download() trusts the mark, so every later run
failed on the same file, even after the right archive was published; on the
update path the engine was never updated. The archive and its mark are now
dropped before the error propagates, as 0.1.32 does for a refused archive.
2026-10-05 15:58:35 +02:00
Niko1221 d215016f40 Merge f-140 (3f8f333e) into the Aurora port 2026-10-05 14:54:29 +02:00
Niko1221 a751fbb128 gfx906 compat build: s26_tsum.cuh takes its AMD branch only on gfx10+ (permlanex16 / DPP), device_free_bytes skips the integrated-GPU attribute the compat layer lacks
Compile check on ROCm 7.14.1 (Aurora): f-140 itself stops in fused_gr.cu (12 errors) and mtp.cpp (2) for gfx906 there; with this
commit the port adds no error of its own (fused_gr.cu's pre-existing ones remain).
2026-10-05 13:59:39 +02:00
Niko1221 92dc6f1de8 tests: hip_gdn_rec_head compares y16 and the state (the FP32 scratch y is no longer stored by the base norm kernel) 2026-10-05 13:27:10 +02:00
Niko1221 0fff115dfd Merge branch 'f-140' into f-140-j 2026-10-05 13:24:21 +02:00
Niko1221 3f8f333e92 docs: DETAILS lines for --adapt-async limits and STRATA_EXCHANGE_ROTATE 2026-10-05 13:19:39 +02:00
Niko1221 d90028c755 tests: batch_test --dump (an A/B of two engine builds) and the parallel-above-8 message with --batch-mtp 2026-10-05 13:19:39 +02:00
Benjamin Larsson 3216d27118 serve: --mtp is optional
Without --mtp, serve drafts with the suffix/prompt-lookup drafter only (or one
token per round), as the plain generate command already does; every token is
still verified against the model. The draft layer's VRAM goes to the expert
cache instead (1,000 -> 1,678 slots in an A/B on an RTX 2060 SUPER 8 GB). The
bind, the prompt path's draft prefill (batched and per token), the draft-KV
restore, prompt length, max drafts, draft sampling, coupled-draft history and
the draft call itself are skipped without it. The conversation cache is off
without it: a parked conversation always carries the draft layer's K/V.
2026-10-05 13:19:39 +02:00
Niko1221andMoor Wu 028cb234a4 disjoint helper cache (#731) on top of #854: a live RemoteExperts::holds() check in the serve, async and CLI adapt loops, STRATA_DISJOINT_ADAPT off by default, no static mask
Co-authored-by: Moor Wu <[email protected]>
2026-10-05 13:19:39 +02:00
Niko1221andFrancesco Albano 2bfac510d7 pipeline-windows (#859): every STRATA_PIPELINE_* debug hook behind STRATA_PIPELINE_DEBUG=1, exclusive with --adapt-async, merged with batch MTP and the async tier
Co-authored-by: Francesco Albano <[email protected]>
2026-10-05 13:19:39 +02:00
Francesco Albano bfa532e97c Layer split: pipelined verify windows (--pipeline-windows, opt-in)
With a split the two cards take turns on every verify window: stage 0 runs its
layers and hands off, then waits while stage 1 runs the rest, the head and the
draft. The batch pipeline (--batch-groups) overlaps different conversations;
one conversation's decode stayed serial.

--pipeline-windows 2 runs window K+1 on stage 0 while stage 1 verifies window
K. The guess for K+1 comes from the MTP chain, launched as soon as K's verdict
is known and teacher-forced through K+1's drafts: if K is accepted as guessed,
K+1 is already half done; if not, stage 0 restores its GDN state from a
snapshot, replays K's commit with the real count, and K+1 is rebuilt from the
real tokens. --pipeline-windows 1 overlaps only the prompt's short reads
through the windows (--short-read). Default 0: nothing changes.

What it adds:
- Verifier: a non-blocking form of run()/commit() (capture_all, pl_launch,
  prestage, service, done, pl_finish, pl_commit_async), the batch pipeline's
  batch_launch/batch_poll pattern for one sequence. The window, its staging,
  the PLE gather at layer 0, the zero-doorbell graph's flag, the #267 release
  on a timeout and the commit graph are run()'s. Two verifiers per stage (one
  per window parity) share one stream of their card (set_stream) and each
  pair has its own hand-off.
- set_always_publish: the pipelined verifiers copy the token rows to the host
  at every layer, because the adaptive tier now marks experts evicted on the
  host while windows are in flight, before the device residency table follows.
- MtpDrafter: chain_launch (the round and its steps back to back, an event
  after each output, the first steps fed the in-flight window's drafts by a
  one-thread forcing kernel), prefill without a host sync, 8 rows with 2, the
  drafter's stream at the highest priority (CUDA only).
- the adaptive tier beside the pipeline: evictions are marked first, then the
  refill copies wait (on the tier's thread) for every window in flight; the
  RAM side of a swap (exchange, release, unpin) waits for the windows that may
  still pull the incoming experts over PCIe.
- an agreement gate: a speculative window is launched only when the chain's
  estimate says it is likely kept (STRATA_PIPELINE_THETA, default 0.2); a
  window known to be wrong gets empty plans for its remaining layers; a lookup
  window's continuation becomes the speculative window behind it.
- VRAM: 160 MiB more kept out of each card's cache for the second verifier,
  and the two GDN snapshots on the first card.
- off, with one log line saying why, for anything it does not support: --batch
  slots, --peer-device, the helper caches, three or more stages, a split on
  one GPU, no drafter. Requests with repetition penalties or coupled draft
  sampling decode serially. Nothing is in flight outside the two pipelined
  loops, so checkpoints, parking and the serial paths are unchanged.

Measured: Swift 1.5 IQ3_XXS at 160K (q4_0 KV, the stock draft layer), RTX 4060
Ti (layers 0-19) + RTX 5080 (20-47), i9-14900KF, 32 GB of RAM, the resident
RAM mode on the split (#848); greedy, 500 tokens, two interleaved pairs of
three rounds, decode tok/s, serial -> pipelined: Python code 90.4 -> 103.1,
C code 76.6 -> 81.6, English prose 63.0 -> 71.1, Italian prose 41.6 -> 46.3,
a copy-heavy edit (a 5 KB file back with a rename) 90.5 -> 117.9; mean
72.4 -> 84.0 (+16%). With the experts read through the OS file cache
(--mmap-experts on that PC) the file reads dominate and it measured no faster.

Correctness: with STRATA_IQ_MT_MIN=1 --pcie-frac 0 --adapt-every 0 the
greedy text is identical to the serial loop's when both have the same expert
caches (4/4 prompts, 500 tokens; the serial run given the pipeline's reserve
through --vram-reserve-mib). The same text with STRATA_PIPELINE_THETA=2 (no
speculative window), STRATA_PIPELINE_FORCE_MISS=1 (every speculative window
wrong, rolled back) with and without DOOM_SKIP, PRESTAGE=0 and
SNAP_OVERLAP=0. Against a run without the flag a few experts move from a card
to the CPU (the pipeline's VRAM), which rounds them differently, so a near-tie
can flip. With the adaptive tier on: 22 varied requests at temperature 0.6
(thinking on and off, five languages, code), and 11 more with
STRATA_PIPELINE_FORCE_MISS=2, gave no degenerate answer, no stall.

The watchdog prints the pipelined loop's state when it fires;
STRATA_PIPELINE_TRACE=<file> writes a timeline.
2026-10-05 13:19:38 +02:00
Francesco Albano 8ba583fec2 MTP drafter: a teacher-forced chain as one asynchronous launch
For the pipelined verify windows of a layer split (next commit). Nothing calls
it yet, and nothing changes unless set_force_capture is set before load.

- chain_launch: the catch-up round and its steps launched back to back with no
  host wait, an event after each output (chain_outputs_ready reads them as they
  land, chain_poll once the chain is done). Its first steps can take given
  tokens as their input instead of their own picks (teacher forcing: the drafts
  of a window already in flight), through a one-thread kernel at the end of the
  round and step graphs that does nothing while its mapped token is -1; the
  outputs stay the chain's own picks.
- prepare_chain / prepare_prefill: capture every graph and size the prefill's
  input records up front, so neither a later chain nor prefill(sync = false)
  waits for the device.
- set_source_R: the rows a round reads, copied into the bound buffer first (the
  pipelined loop has one stage-1 verifier per window parity).
- with forcing on, the drafter's stream gets the highest priority (CUDA;
  STRATA_MTP_PRIORITY=0: the default).

draft() resets the forced tokens and copies the source rows the same way, so
the serial loop's drafts are unchanged.
2026-10-05 13:19:38 +02:00
David d91f2960f7 bench: document the standard Q2 token-identical rotation pair 2026-10-05 13:19:38 +02:00
David 82db014cc1 bench: verify rotation-only build with an exact native 1K pair 2026-10-05 13:19:38 +02:00
Niko1221andDavid e57c907221 exchange rotation (#864) on top of the async tier (#876): rotation-aware commit_flip/commit_copies/resident_blob, test only under STRATA_BUILD_TESTS, drop a banner edit
Co-authored-by: David <[email protected]>
2026-10-05 13:19:38 +02:00
David 1e6cec80d1 perf: opt in to resident expert exchange buffer rotation
Extract rotation and atomic ownership publication from aa6e0e3 and 1a50d91 onto upstream a1641e9. Preserve current host-memory tests. Include one historical token-identical A/B with explicit provenance and document fresh CPU/CUDA validation.
2026-10-05 13:19:38 +02:00
Niko1221andFrancesco Albano 5288cd2902 adapt-async (#876): keep the blocking tier when the exchange buffers are pageable, and report ms per round
Co-authored-by: Francesco Albano <[email protected]>
2026-10-05 13:19:38 +02:00
Francesco Albano b437b8ea13 Asynchronous adaptive expert tier (--adapt-async 1, opt-in)
In the resident RAM mode (--resident-experts) an adaptive round runs on a
thread the decode loop joins after the draft: choose, copy the evicted slots
back with a stream sync, copy the new experts in from the RAM copy (through
the driver's staging when it is pageable). With ~90 swaps that was ~24 ms
every 4th window (measured on our fork). --adapt-async 1 splits a round into
four steps that advance between windows on a helper thread, so no window
waits for one:

  1. choose (adapt()'s rule, over snapshots of the counts and the residency)
     and copy the evicted slots back (D2H), each from the cache of the card
     that owns its layer
  2. stage the exchanges, mark the evicted experts non-resident (the CPU reads
     them from the exchange buffers), copy the new experts in: straight from
     a page-locked RAM copy, else through a pinned bounce buffer
  3. mark the new experts resident, move the evicted blobs into the RAM places
     the new ones left
  4. flip the copy's offsets

A slot is overwritten only after its old expert stopped being planned for the
GPU, and a RAM place is reused only once its expert is resident. The residency
tables on the devices are uploaded at steps 2 and 3, as apply_pending does
(the verify graph's doorbell reads them). A request starts with the round
drained, before its prompt lends any slot. --expert-profile-save counts the
routing at the start of each round, as the blocking tier does. Swaps that
need no exchange (the evicted expert is in the RAM copy already, or the new
one is not: a RAM budget) take the same steps without a copy back; a new
expert outside the RAM copy is read from the files on the helper thread.

Default off: which window first computes a swapped-in expert on the GPU
depends on when its copy lands, so the tier is not bit-exact from run to run.
Without the flag nothing changes. With it, the blocking tier still runs
outside --serve, without the resident RAM copy, and with --batch slots,
--peer-device or --remote-expert-opt (said once at startup). The exchange
buffers are twice as many with it (the bounce half): 96 more blob-sized
pinned buffers, ~130 MiB with 1.38 MB blobs.

Layer split (with the resident mode on a split, #848): each swap's copies run
on the owning card's refill stream under that card's device; the homes are
looked up the way #848's resident_stage_swaps does.

Measured: Swift 1.5 IQ3_XXS at 160K (q4_0 KV), i9-14900KF, 32 GB of RAM,
Windows 11, greedy, decode tok/s, blocking -> --adapt-async 1:
- RTX 4060 Ti + RTX 5080 layer split with the resident RAM mode (#848),
  --trim-stage-weights, the stock draft layer, five prompts x two rounds,
  two interleaved pairs: 79.7 / 78.8 -> 87.6 / 86.2 (+10%).
- the same split with a fine-tuned draft layer and --spec-min-p 0.65, four
  prompts x three rounds:
  81.0 / 81.8 -> 108.1 / 107.0 (+32%).
- RTX 5080 alone with --resident-experts: 26.7 / 26.6 -> 29.5 / 28.5 (noisy).
Without the flag the greedy output is the same as main's, byte for byte (4/4
prompts, 500 tokens, STRATA_IQ_MT_MIN=1 --pcie-frac 0 --adapt-every 0). With
it, 22 varied requests at temperature 0.6 on the split (43,825 experts
swapped in over 622 rounds) gave no degenerate answer.
2026-10-05 13:19:38 +02:00
Niko1221 388db6b106 layer split (#880): later stages' weights load after the search only for --layer-split auto with the trim asked; every other run keeps the 0.1.39 order and log
Drops the dead stage_pool trim block (the search only runs for auto, where stage_trim is false), keeps the search's number
for each card unchanged (the full untrimmed arena), and fixes the 'needs an explicit --layer-split' warning, which now
fires only when there is no GPU split at all.
2026-10-05 13:19:38 +02:00
Gopi 4cee400777 layer split: the stage weight trim works under auto too
--trim-stage-weights (PR #559) / STRATA_STAGE_TRIM=1 (PR #639) gives a stage only its own layers' dense
weights, but it refuses to run unless --layer-split is written out: `auto` chooses the split points 590
lines after the stages' weights are loaded, so by the time the split is known there is nothing left to trim.

Those weights now load after the search. The search still prices each card's arena from the pack index
(`WeightTable::pool_bytes` reads the index and allocates nothing), and takes it off the card's measured
free VRAM, so the number it sees is the number it has always seen - the split it picks is the split it has
always picked. This buys cache, not a different placement. The expert caches are sized later, from live
free VRAM, so they collect the freed bytes.

On the 4-way IQ3_S rig, `--layer-split auto` (which picks K=10,19,34):

  CUDA1 3650 -> 4608 expert slots, CUDA2 1241 -> 2485, CUDA3 533 -> 1772
  prompt chunk 768 -> 6144 tokens
  prefill 469.7 -> 1929.7 tok/s on the same 107,082-token prompt

CUDA0 still trims only with an explicit --layer-split. Its arena is read out to build the prompt path's PLE
tables, 590 lines before the split exists, so moving it is the larger half of this change. It is also the
cheap half to leave: measured, it costs 1% (1929.7 against 1950.8 for an explicit `10,19,34
--trim-stage-weights`, where CUDA0's cache is 4598 slots instead of 3017).
2026-10-05 13:19:38 +02:00
Niko1221andrkcth c8c79b17ea batch MTP (#846): opt-in --batch-mtp / STRATA_BATCH_MTP=1, warn instead of refusing, 1-row groups keep the 0.1.39 commit kernel, LRU graph cache only under the flag, the real draft geometry
Co-authored-by: rkcth <[email protected]>
2026-10-05 13:19:38 +02:00
rkcth 8cfb3fd7cc Keep MTP drafting in concurrent batch slots 2026-10-05 13:19:38 +02:00
xjc10 5ab99da482 bench, docs: the helper GPU's experts and the PCIe share on 2x RX 6900 XT; SECOND_GPU.md states the HIP measurement
bench/results/2026-10-04-rdna2-helper-pcie-share: the rig (two cards on PCIe 4.0 x8, probe 14.1 GB/s -> pcie_frac 0.39),
the method (STRATA_DECODE_TIMING per request), and the per-window breakdown for the baseline on a1641e9 (with and
without #835 on top: 59.6-60.4 ms per window, 4 PCIe entries per layer-window, the GPU-reach wait at 43 ms), for the fix
with the probed share (two runs: 37.2 / 33.8 and 35.2 / 33.8 ms, the share down to 0.06-0.26 entries) and with
--pcie-frac 0, and for the --pcie-frac 0 workaround on the baseline; the limits and the configuration used.

docs/SECOND_GPU.md: the helper section said HIP had not been validated; it now gives the two-card HIP measurement, what
the share cost before this change and the workaround, and keeps three/four cards as not validated.
2026-10-05 13:19:38 +02:00
xjc10 abe8919c06 expert plan: a helper GPU's experts are not part of the PCIe share
The verify window's GPU plan counted a layer's misses and moved the last pcie_num/256 of them to the primary over PCIe,
leaving out the primary's resident experts and the peer tier's but not those a helper GPU (RemoteExperts) holds.  The
plan runs before RemoteExperts::begin(), which only claims rows the plan left at kind -1, so a PCIe share above 0 read
part of the helper's experts over the primary's link while the helper idled for them.

RemoteExperts::holds(layer, expert) (the helper cache's slot_of), and the plan treats such an expert as it treats the
peer tier's: not a miss, never in the PCIe share; its rows stay at kind -1 for begin().  No default changes.

2x RX 6900 XT, IQ3_S, --remote-expert-opt with the probed share 0.39: 59.6 / 58.5 -> 37.2 / 33.8 ms per window,
PCIe entries per layer-window 4.00 -> 0.26 / 0.06, decode 40.6 / 39.3 -> 65.6 / 67.7 tok/s (--pcie-frac 0: 66.9 / 67.1).
2026-10-05 13:19:38 +02:00
Yoshiki-MatsudaandCursor affb999c63 verify: batch windows honor the all-resident stage (no host doorbells)
Co-authored-by: Cursor <[email protected]>
2026-10-05 13:19:38 +02:00
Niko1221 8e368af984 serve: tool_choice required with a single tool names it (#790) 2026-10-05 13:16:54 +02:00
Niko1221 82579827e9 serve tests: put the StopStrings and ConnectionClose classes back together after a merge (#715) 2026-10-05 13:16:54 +02:00
Niko1221 ee412cd776 serve: a <tool_call> in the reasoning that never closes stops holding the thinking back after 32 KiB (#804) 2026-10-05 13:16:54 +02:00
Niko1221 378dc39348 setup: a tip for a Q8_0 vision encoder on the CPU; docs: the llama-quantize command and measured fidelity (#625) 2026-10-05 13:16:54 +02:00
Niko1221 0eacbaba81 vision: --min-tokens N passes mtmd's image_min_tokens (vision.min_tokens, hand-edited); CPU encode time in the docs (#767) 2026-10-05 13:16:54 +02:00
wangmeng c347326242 serve: opt-in recovery from repeated reasoning passages
Maintainer: separate stop and recover modes (reasoning_loop_recovery: false|stop|recover), token-level splice of the effort sentence (EFFORT_TEXT), a client's top_p/top_k never touched, checks at the first clean boundary after each 512 tokens, bounded history, tests incl. a literal think tag (#728, #869)
2026-10-05 13:16:54 +02:00
Elias Klughammer add41aef65 server: "return_progress": true puts the prompt's PP line on the stream as llama.cpp's prompt_progress
Maintainer: prompt_progress() returns nothing under --batch (one global progress line), test (#837)
2026-10-05 13:16:54 +02:00
Breno Perucchi 600c428821 ckpt=0: still print STRATA_STATE_HASH for the request, so the parity gates see every request 2026-10-05 13:16:54 +02:00
Breno Perucchi 5f317a3afc ckpt=0: its session is neither continued nor parked; docs say what is skipped and when the root is taken 2026-10-05 13:16:54 +02:00
Breno Perucchi f6af1ddef9 serve: "strata_checkpoint": false lets a one-shot request skip its conversation checkpoint (#830)
A request with "strata_checkpoint": false sends ckpt=0 to the engine. That request reads its prompt in one part and
saves no checkpoint at its last turn boundary, nor the periodic ones of a long prompt. It still resumes from a
checkpoint it matches and still saves the system-prompt root. Absent or true: today's behavior; an engine without the
key skips it.
2026-10-05 13:16:54 +02:00
sergiywith d50dc91177 serve: a request's combined image file is deleted when the request is refused or its answer never starts
prepare() wrote the request's combined embeddings file (req-<id>.sve in the vision directory, ~10 MB a picture) right
after encoding, and only run()'s finally deleted it. But prepare() could still raise after writing it - EngineStarting
(the 503 while the engine starts, #344), the "no room to answer" and "exceeds the context" 400s - and a request can end
between prepare() and run(): its client gone before the first chunk was written, anything raised in between. run() is
a generator, so one that never started has no finally to run. Each of these left its file behind for good, and
clients that retry 503s added one per retry.

prepare() now writes the file only after those checks, and records its path before writing it. run() takes the path
over as it starts and deletes the file as before; do_POST's finally calls the new Service.drop_embeddings(), which
deletes a file that no run() took over.

Tests: EngineStarting, no room and exceeds-the-context leave no req-*.sve; over HTTP, on both APIs, a 503, a 400, a
client gone after prepare() and answered requests leave none.
2026-10-05 13:16:54 +02:00
sergiywith d6527e395a serve: the vision markers inside a message's text stay text and no longer take a picture's place (#150 follow-up)
The markers are special tokens only where the template writes them for an image item. The same strings in a
message's text (an agent reading chat_template.jinja, a tool result quoting it) became the same special ids, so text
with <|vision_start|><|image_pad|> before a picture took that picture's embeddings, every later picture moved up one
and the last real marker became text - every count still matched.

On 0.1.39 this takes #537's path: the vision markers join <think> / </think> as literal tags (frontend.VISION_TAGS),
swapped for private-use marks before the template and encoded as text through the tokenizer's plain spans. A pair
of markers cut apart across text parts is refused ("the prompt and its images do not match") instead of shifting.
2026-10-05 13:16:54 +02:00
sergiywith 3709c15f1d serve: a tool's picture the server cannot read becomes a note, not a 400
With tool_result pictures reaching the encoder, a server without one (every lazy-start config is text-only) or an
encoder that refuses a picture (WebP without Pillow, an error from strata-vision) answered 400. Clients resend the
whole history every turn, so one such picture failed every later request of the conversation; before, the picture
was dropped silently. Now a tool's picture that cannot be read becomes "[image omitted: <reason>]" in its place; a
picture the user sends keeps the 400.

Maintainer: log a left-out tool picture, a tool picture's URL is downloaded once (bytes reused by prepare), tests (#529; #582 and #819 are duplicates)
2026-10-05 13:16:54 +02:00
sergiywith d6b3f57811 serve: an image in an Anthropic tool_result reaches the encoder (Claude Code's Read of a picture)
Claude Code returns a picture it opens with Read as an image block inside a tool_result. The Anthropic
path turned every tool_result into its text, so the image never reached the encoder and the model
described a picture it had not seen. The tool message now carries the image item, as the OpenAI path's
tool messages already did; the chat template renders it inside <tool_response>. An image sent beside
tool results in the same user turn is kept too. A text-only tool result is still one string, so text
prompts are unchanged.
2026-10-05 13:16:54 +02:00
Niko1221 64be7561c5 serve tests: a fenced or prose-wrapped JSON object is now accepted in json_object mode (#762) 2026-10-05 13:16:54 +02:00
sergiywith 2190b48a82 serve tests: test_json_schema_text_format's schema failure only where jsonschema is installed
jsonschema is optional (serve/structured.py): without it a json_schema answer is checked to be one JSON object, so
the answer the test expects to fail passes, and the test failed on every install without it (0.1.39's own as well).
2026-10-05 13:16:54 +02:00
cipgysmo 0d95958f51 serve: extract JSON from prose and code fences 2026-10-05 13:16:54 +02:00
robwijnhoven 3794826b07 serve: map namespace calls written as namespace__name back to their namespace
Codex sends its MCP tools as namespace tools (mcp__websearch with web_search
inside). The Responses adapter shows the model mcp__websearch.web_search, but
Qwen3.8-Flash-Next writes the call as mcp__websearch__web_search, the flat
form Codex used for MCP tools. That name had no entry in the reverse map, so
the call came back without a namespace and Codex rejected it as an
unsupported call. Register the double-underscore spelling too (setdefault, so
a real tool of that name still wins).
2026-10-05 13:16:54 +02:00
Juan Canfield bcc39a1e42 serve: accept json_schema roots that are unions of object schemas
prepare_format refused every schema whose root was not literally "type":"object",
so a root anyOf/oneOf of object shapes - what apps written for llama.cpp's
json_schema send - got a 400, although every answer it allows is one JSON object.

_only_objects() accepts a root that can only be an object: "type":"object", an
anyOf/oneOf whose branches all qualify, an allOf with a qualifying member, or a
local $ref to one (a $ref cycle never qualifies). The "return exactly one JSON
object" directive and the object check without jsonschema stay true. A root that
also allows an array, string, number, boolean or null (including
"type":["object","null"] and a schema without a type) is still refused before the
engine loads.

Tests: serve/test_structured.py, unions accepted (a non-object answer is still
refused) and non-object roots refused: 10 OK with and without jsonschema
installed. test_server/security/lifecycle/detok/mcp/monitor/winjob: 214 OK.
docs/DETAILS.md: the root rule.
2026-10-05 13:16:53 +02:00
siddolo 773657cd1f serve: tolerate broken stdin pipes during engine cleanup 2026-10-05 13:16:53 +02:00
Evan a42a0c0b00 serve: say Connection: close on every response
The server is HTTP/1.0 and closes the connection after each response, but
never said so. A client that pools connections (.NET's SocketsHttpHandler)
then sometimes put its next request on the closing socket and got
'response ended prematurely' without the server ever reading it: 25 of
~1000 requests in one night from an agent app, each 1-24 ms after the
previous answer.
2026-10-05 13:16:53 +02:00
Trevin 38c9a4dce2 serve: a <tool_call> named in prose before the real call is content, not a malformed call
A reply such as "I will use the `<tool_call>` format now." followed by the call raised
ValueError("malformed tool call") in OutputParser.feed and ended the request: everything after the
first <tool_call> was taken as the call body. A call is the tag followed (after whitespace) by
<function=, as the chat template writes it; the tag with anything else after it is now content, and
it is held while streaming until its follower arrives, so streamed and whole output agree.

Found while porting tolerant tool-call recovery from a Qwen engine (ninfer --tolerant-tool-calls):
of its three recovery cases, Strata already handled values that quote the markup (#210) and prose
after the calls; this was the one that failed. Tests: ToolCallTagInProse (fails on main with 21
subtest errors, passes here); python -m unittest serve.test_server: 120 tests OK.
2026-10-05 13:16:53 +02:00
Amir Guindehi b3c63f7e0b serve: honour OpenAI tool_choice "required" and a named function
Without a grammar decoder a forced tool_choice was ignored, so clients
that need a call (an agent's first step, its "done" call) got text.
The server now writes the call's opening itself - <tool_call> and
<function= (with the name for a named choice) - and the model can only
go on with a call:

- without thinking, the opening ends the prompt;
- with thinking, it is written where the thinking ends, at a clean
  point, the way the budget's wrap-up is (continuing from the prefix
  the engine already holds);
- when reasoning_budget_tokens wraps up the thinking, it follows the
  wrap-up.

"auto" and no tool_choice are unchanged.  "none" offers no tools, as on
the Responses route.  An unknown name, a forced choice without tools
and other values are a 400 instead of being ignored; a forced choice
with MCP tools too.  The arguments are not constrained; a reply cut by
max tokens stays "length" without tool_calls, as before.

Maintainer: unknown tool_choice values are logged and act as auto (no 400), the flat {type:function,name} shape, Anthropic any/tool/none mapped and passed to /v1/messages, tests (#790). Note: tool_choice none now offers no tools on both routes.
2026-10-05 13:16:53 +02:00
Niko1221 da170f8ae7 serve: /config and /load bodies are marked read, so the close does not wait for the drain (#594) 2026-10-05 13:16:53 +02:00
Guillaume PUTIER a8497cf157 serve: the unread body is dropped under a time limit only, so megabytes still get their answer
A body over 1 MiB was left unread, and its answer was reset on Windows. The limit is now 5 s for the whole body, read one socket read at a time: a body of any size gets its answer, and a client that sends a byte at a time is let go after the 5 s (read() waited for the whole piece, with a new timeout for each byte).
2026-10-05 13:16:53 +02:00
Guillaume PUTIER 612a4d450c serve: read the request body an answer left unread, so the close is not a reset
The server answers before reading the body in some cases (401, 403, /load, /unload, a method with no handler) and then closes. Closing on unread bytes makes Windows send a reset, and a client that sends its body after the headers (http.client, urllib, requests) gets WinError 10054 instead of the answer.

After an answer, the body no handler took is now read and dropped, up to 1 MiB and with a 5 s timeout. A larger or chunked body is left unread, as before.
2026-10-05 13:16:53 +02:00
Niko1221 0ad6e8ac54 serve: validate stop in Responses and count_tokens; tests for stop in --batch and after a thinking budget (#454) 2026-10-05 13:16:53 +02:00
Zuraiz Anjum e7c2edb857 serve: honor stop and stop_sequences, cut the answer before the stop string and stop the engine there 2026-10-05 13:16:53 +02:00
Pravesh Khatana d398d7c33f fix(serve): safely handle malformed or partial tool call arguments in history
Maintainer: one frontend.tool_arguments helper for both frontends, bad JSON, a list or a number is kept as {"arguments": raw}; tests (#510)
2026-10-05 13:16:53 +02:00
Niko1221 9cd3d00b6d serve: STRATA_KEEP_EMPTY_TURNS=1 restores rendering of empty assistant turns (#843)
#886 skips them by default (recommended on; the owner can flip it). Only prompts that carry an empty
assistant turn change.
2026-10-05 13:16:53 +02:00
Arthur031221andjramirez-uab ffbc39f4fb serve: skip completed empty assistant turns in chat history
Filter earlier assistant messages with no text, images or tool calls
before rendering the prompt. Keep the final message.

Co-authored-by: jramirez-uab <[email protected]>
Signed-off-by: Arthur031221 <[email protected]>
2026-10-05 13:16:53 +02:00
Niko1221andkossum 8d0bb44620 serve: a tool call inside the reasoning counts only for a declared tool (#804, strict form of #787)
With tools declared, a <tool_call> in the reasoning is held whole; a declared name becomes a tool call,
anything else (undeclared name, malformed, unfinished, cut by </think>) stays reasoning text. finish() never
makes a call from it. Without tools the parser is byte-identical. Tests: parser (split tags, undeclared,
no tools, unfinished), OpenAI and Anthropic finish reasons, Anthropic block order.

Co-authored-by: kossum <[email protected]>
2026-10-05 13:16:53 +02:00
Strata Contributor 0b30051cb1 serve: invalidate the engine after fatal verification timeouts
Maintainer: fatal lines checked before batch routing, 'an earlier window never finished' is fatal, alive() check in generate_batched, tests run on Windows (#748).
2026-10-05 13:16:53 +02:00
Niko1221 264e81265b serve: /v1/responses refuses a file image from another origin (#553); a bad data: URL or unreadable file is a 400 (from #582) 2026-10-05 13:16:53 +02:00
sergiywith 58dd26b9f2 serve: image sources - network paths refused, URLs capped at 32 MiB and fetched outside the FIFO, no local files for other sites' pages
Vision.load read whatever an image source named. A network path (\\host\share\x.png, //host/share/x.png,
\\?\UNC\host\..., \??\UNC\host\..., file:////host/share/x.png) made Windows connect to that host and sign in with the
user's NTLM credentials - os.path.isfile alone does it. Such paths are now refused before anything looks at them, and
so is file://host/share/x.png (that names \\host\share; the old code read it as the relative path host/share/x.png).
An http(s) image was read whole, with no cap, inside prepare()'s `with self.fifo`: a huge one filled the memory and a
slow one held every other request for as long as urlopen waited (60 s per read). Now it is read up to 32 MiB
(IMAGE_URL_MAX; a larger Content-Length is refused unread), downloaded before the FIFO is taken, and a URL that cannot
be read is a 400 instead of a dropped connection.

Other sites' pages: with no api_key (the default) _authorized() lets every request in, and /v1/chat/completions and
/v1/messages read the body as JSON whatever its Content-Type; only /settings, /v1/load, /v1/unload and the MCP tools
check the Content-Type and Origin (_own_page). So any web page open in the user's browser could POST a chat request as
text/plain - a CORS "simple" request, no preflight - that names a file on this computer (or a network path) as an
image, and the server read it. The page gets no answer to read (no CORS headers unless cors_origins lists it or "*"),
but the read, and a network path's sign-in, happened. Reproduced over HTTP: answered 200, the file handed to the
encoder. Now a request whose Origin is neither the server's own address nor in trusted_origins may send data: and
http(s) images only; a file path or file:// URL is a 400 that says so. Clients that send no Origin (CLI tools, SDKs,
agents), Strata's own page (it sends data: URLs) and trusted origins are unchanged. As for /settings and MCP, a
DNS-rebinding page, whose Origin matches its Host header, still counts as the server's own.

Tests: each network form is refused with os.path.isfile never called, and local files, file:// and data: URLs still
load; the cap with and without a Content-Length, and a 404; the URL is downloaded with the FIFO free; a foreign-Origin
text/plain request naming a file is a 400 on both APIs, while data: images and no-Origin, own-origin and
trusted-origin requests are answered.
2026-10-05 13:16:53 +02:00
Niko1221 f96392dce8 build: the Aurora decode kernels compile in a CUDA build (host-device constexpr helpers, block_q8_1 copies by memcpy, plain loads for the AMD-only non-temporal ones, no wmma_gemm symbol off HIP) 2026-10-05 13:13:46 +02:00
Niko1221 bd50ff7a0a docs: the PLE table formats the engine reads, and how far each is from the BF16 table
Row error on 4,000 random rows against the checkpoint's BF16 table (Q8_0 0.53%, FP8 2.64%, IQ4_NL 7.60%, matching the
numbers reported in #651), and teacher-forced KL on the Q2_0 model with each table.
2026-10-05 12:18:48 +02:00
Niko1221 a5ada869ae docs: INTEL_ARC says what ran on an Arc (#868 follow-up)
The 0.1.39 paragraph said nobody had run the 0.1.39 port on an Arc. Two Arc Pro B60 reports (#867, #870) did, with
the two sycl/ fixes now in 0.1.40 (#784 the compile fix, #866 the ring wait). Say that, and that an unpatched 0.1.39
port did not compile against its own engine sources.
2026-10-05 12:18:48 +02:00
LocalXPU 525017f443 docs: e221 is also an Arc Pro B60 id (seen on another B60 pair) 2026-10-05 12:18:48 +02:00
LocalXPU b70c9cbbfe docs: the host has 64 GB of RAM (62 GiB usable), not 62 GB 2026-10-05 12:18:48 +02:00
LocalXPU 7cd96e3eef docs, setup: Arc Pro B60 rows, B60 notes, PCI id e211
INTEL_ARC.md: "What has been run" rows for 2x and 1x Arc Pro B60, plus notes for the card: PCI id 8086:e211 (bmg-g21), setvars.sh
stopping at OCL_ICD_FILENAMES under `set -u`, running natively without Docker, and the layer-split startup warning that counts the
other card's layers.

sycl/setup_intel.py: the B60 table entry was e221, which the kernel's xe id list files under the BMG-G31 cards (0xE220-0xE223). Both
Arc Pro B60 cards measured here are 8086:e211, so setup named them "Intel GPU e211 (xe)" with a guessed VRAM size. e211 is added;
e221 stays, since there is no card here to say it is wrong. tools/test_setup_sycl.py checks the table.

COMMUNITY_BENCHMARKS.md and bench/results/2026-10-04-community-2x-arc-pro-b60/: the report, in the template's format, with the
server configs, engine logs and per-request timings.
2026-10-05 12:18:48 +02:00
LocalXPU a5682fea16 sycl: keep cudaStreamQuery's answer in the per-layer ring waits
The migration turned `q = cudaStreamQuery(cs)` into `DPCT_CHECK_ERROR(cs->ext_oneapi_empty())`. That macro yields 0 whenever
the call does not throw, whatever the queue holds. The guard `q != 1 && *seq < want` (verify.cpp, session.cpp) therefore
fired on any ring that took more than 2 ms and reported "never rang (graph finished)" while the graph was still running.

With every expert resident the host does not wait per layer (STRATA_VERIFY_NO_HOST), so the path measured on the B70 never
reached it. With host-mirrored experts the first layer whose GPU time passes 2 ms does: layer 15 of the Coder on one Arc Pro
B60, every time.

q is now 0 when the queue is empty and 1 while it is running, as the guard and the trace comment ("1 = still running") expect.
fixups.py gets the same rewrite (entry 8), so a fresh dpct run of session.cpp produces it too.

Measured on one Arc Pro B60 (4,042 of 12,288 Coder IQ1_M experts mirrored in RAM, 128 greedy tokens, AOT bmg-g21): before,
exit 1 at layer 15 in 5 of 5 tries; after, exit 0 in 7 of 7 runs, at 11.2-11.9 tok/s with coherent text.
2026-10-05 12:18:48 +02:00
sarashin 9661ecb882 sycl: follow #626 (ThreadAffinity) and #559 (NativeDense::load layer range) so v0.1.39 compiles
The sycl port went in as 5ffcce4 ("sycl: port 0.1.39"). Two engine-side changes
were merged into the release branch after it (4f5e6c8, f5410ae) and nothing in
sycl/ was updated for them, so the v0.1.39 tag does not compile:

- #626 (5a8b292) made the thread affinity a value: pin_current_thread()
  returns strata::kernels::cpu::ThreadAffinity and restore_thread_affinity()
  takes it. sycl/include/strata/core/session.hpp still stored a `long long`
  (no conversion exists, and it did not include the header that names the
  type); sycl/src/core/session.cpp still assigned the returned struct to it
  and passed the `long long` back.
- #559 (9461f5e) added the two layer-range arguments to NativeDense::load.
  The sycl out-of-line definition was still the 4-argument one and no longer
  matched the declaration in include/strata/core/native_dense.hpp.

Both are fixed by mirroring the CUDA sources: the same member type, the same
`outside()` predicate, and the same place it is applied in the tensor loop.

`pinned` now follows CUDA as well: it is pinned_core.valid, so a pin that
failed is not "restored". Nothing changes when the pin succeeds.

No caller passes layer_lo/layer_hi yet, so `outside()` is never true today:
this restores the build and does not change what the engine computes.

Measured here: Arch Linux, Intel oneAPI DPC++ 2026.0.0 + oneMKL 2026.0,
SPIR-V (JIT), cmake -S sycl -B build-sycl -G Ninja -DCMAKE_C_COMPILER=icx
-DCMAKE_CXX_COMPILER=icpx, then
`cmake --build build-sycl --target strata -- -k 0` -> 0 errors, links. The two
errors are a type and a declaration mismatch, so the compiler version does not
matter.

Not built here: the other targets (kernel parity tests, benches) and the AOT
path. Not run on an Arc in this change.
2026-10-05 12:18:48 +02:00
Constantin cb87a62e82 ple: read the n-gram table at full BF16 precision (#586)
The full checkpoint stores the table as BF16 (320-byte rows, 102.4 GB), the source of record; the engine gets it as
IQ4_NL (about 8% off per row) or FP8. A bfloat16 is the top half of a float32, so widening is a shift: exact for
every value, no rounding and no scale. One entry in the PLE format list (type BF16, self-describing: no scale, no
metadata) and bf16_dequant_row; the direct reader takes the 320-byte row like any other width, and
PLE_ROW_BYTES_MAX is 320.

ple_reader_test checks the widening is exact over the patterns a lossy path breaks on (subnormals, +-inf, both NaNs);
the generic every-format test covers a synthetic BF16 GGUF through both readers.

Not in this commit: the PR's rename of tools/ple_fp8_pack.py (nothing needs it) and any setup option. Whether a
table format other than IQ4_NL is worth offering is a quality question (see the measurement in the 0.1.40 notes).

Ported by the maintainer from constantindjonkam's PR #586.
2026-10-05 12:18:48 +02:00
saikiran-rs 16bdc7073d native experts: Q4_0 and Q4_1 GPU kernels, Q4_0 PLE table
A plain llama-quantize Q4_0 file of this model (bartowski's Qwen3.8-Flash-Next-Q4_0 and
Swift-1.5 Q4_0: gate/up Q4_0, down Q4_0 on 42 layers and Q4_1 on 6, a Q4_0 PLE table and
token embedding) was refused at start: no GPU kernels for Q4_0/Q4_1 experts, and the PLE
reader took only IQ4_NL, Q5_0 and FP8. Follows #222 (Q4 to Q6 quantizations).

- Q4_0: Fmt<2> with the codes centred before dp4a (q - 8 as signed bytes), the exact
  integer form ggml-cpu's q4_0 x q8_0 dot uses, rather than llama.cpp's CUDA chain
  (uncentred codes minus 8 x the q8_1 float sum): on a real Q4_0 expert the CUDA chain
  measured 1.4e-2 relative error against the float product, the centred form 5.3e-3.
- Q4_1: Fmt<3>, the Q5_1 chain without the fifth bit and the same min-term choice.
- dq_q4_0 / dq_q4_1 for the prompt path's dequant fallback; row bytes, is_iq and the
  GU/D/MMVQ format lists.
- PLE: Q4_0 rows (90 B, as IQ4_NL) through the same reader: one entry in the PLE format list (ple_format_test and
  ple_reader_test cover it).
- docs/UNSLOTH_Q4.md: a Q4_0 section with the measured run.

native_expert_parity --synthetic (now in the CMake matrix): q4_0/q4_0 CPU 1.29e-2, GPU
1.29e-2, CPU-GPU 1.1e-7; q4_0/q4_1 CPU-GPU 3.2e-4; GPU dequant bit-exact against
to_float. The existing pairs are unchanged. On bartowski's file (revision 928589f), layers
0 and 5 (Q4_1 down) and 20 and 47: CPU and GPU 1.1-1.3e-2, CPU-GPU 1.1e-7 (Q4_0 down) and
5e-4 to 1.1e-3 (Q4_1 down). Served on one RTX 3060 (all experts in RAM, 131K context):
24,461-token prompt 787 tok/s read, 24.0 tok/s out; 67,934 tokens 737 / 26.4, the hidden
fact found.

Ported onto the format table by the maintainer (the PLE part of the PR is the Q4_0 table entry).
2026-10-05 12:18:48 +02:00
Anonandksanislo 626a89bc1e ple: --ple-io ram faults the table in on up to 16 threads before mlock (#651)
mlock alone brings a cold file in one page at a time from one thread, ~0.47 GiB/s (about two minutes for a 54 GB
Q8_0 table); 16 threads reach ~2 GiB/s on anon761's machine. The pages are then resident and mlock only pins them.
When mlock fails, the pages stay faulted in (the message says they may be reclaimed) instead of being touched again
one by one.

ple_reader_test gets --make-table PATH FORMAT (a big synthetic table, with --rows) and --ram-time PATH (open mapped
and locked, print the seconds) to time it cold.

Ported by the maintainer from anon761's PR #651.

Co-authored-by: ksanislo <[email protected]>
2026-10-05 12:18:47 +02:00
Niko1221andCC-David-CC e79b8fc143 ple: check the table's size arithmetic before using it (#865)
PleTable::open compared rows x row_bytes against the file after the 64-bit product could already have wrapped, and
mapped the tensor before checking it fits. Now: refuse a row count that overflows rows x row_bytes and a data
section that starts past the end of the file, check offset and size without an addition that can wrap
(offset > have, need > have - offset), require a single-tensor shard to start at offset 0 and fill the file, and map
the table only after all of that. close() also resets the FP8 scale and the byte counter.

ple_reader_test --selftest writes tables that claim one row too many, one too few and a wrapping row count, for every
format, and checks both readers refuse each with a message and stay closed.

Checks taken from CC-David-CC's #865 (its opt-in Q8_0 table is #651's; the direct reader reads Q8_0, so the
experimental switch and the mapped-only limit are not needed).

Co-authored-by: CC-David-CC <[email protected]>
2026-10-05 12:18:47 +02:00
Anonandksanislo 74945954fe ple: read Q8_0 and Q5_1 n-gram tables (#651)
Ordinary GGUFs ship per_layer_token_embd.weight in other formats than IQ4_NL: Unsloth's UD-Q6_K_XL and
Swift-1.5 Q4_K_L as Q8_0 (170-byte rows, ~54 GB), a Q5_K_M finetune as Q5_1 (120-byte rows). The engine refused
both at start.

- dequantize_q5_1 in strata/artifact/dequant.hpp (ggml's dequantize_row_q5_1: unsigned 5-bit codes times d plus the
  block minimum m); Q8_0 rows use the existing dequantize_q8_0
- two entries in the PLE format list (the table-driven commit before this one): Q5_1 and Q8_0, on both readers;
  PLE_ROW_BYTES_MAX grows to 170
- tests: dequant_q5_1_test (synthetic blocks against ggml, no model, no GPU), dequant_bf16_test knows Q5_1,
  ple_q5_parity takes Q5_0, Q5_1 or Q8_0 tables and checks both the mapped and the direct reader

Ported onto the format table by the maintainer from anon761's PR #651 (the --ple-io ram fault-in is the next
commit). Quality of the Q8_0 table: ksanislo measured 0.53% error against the BF16 table, FP8 2.66%, IQ4_NL 7.59%.

Co-authored-by: ksanislo <[email protected]>
2026-10-05 12:18:47 +02:00
Niko1221 ce62f5058f ple: a table-driven PLE format (enum, row bytes and a dequant per type)
PleTable had one bool per format (q5_0, fp8) and an if-chain in decode(), open() and format(). Now one list,
ple_formats(), holds one entry per table type: its GGUF type name, the bytes of a 160-value row, whether it
carries a scale and its dequantizer. open(), format(), the row size, the error string and the row buffers all
read it, so the next formats (Q8_0, Q5_1, Q4_0, BF16) are one entry each.

No behaviour change: IQ4_NL, Q5_0 and FP8 decode with the same functions, and the "not IQ4_NL, Q5_0 or FP8 (I8)"
error text is built from the list and reads the same.

ple_reader_test --selftest now writes a PLE-only GGUF for every format in the list and checks both readers
(direct and mapped) against the format's own dequantizer, for single rows and a 16-row token gather.
2026-10-05 12:18:47 +02:00
Niko1221 e51fa6c362 prefill: STRATA_HCD_EXACT says once when it cannot take the kernel (no tuning table, or a solution other than 1176 / 1177), and hip_prefill_hcd_exact_parity checks the kernel against hipBLASLt
The kernel reproduces one hipBLASLt solution's summation order; the test compares both on the same inputs for T from 64
to 16384 (bitwise) and SKIPs without STRATA_HIPBLASLT_TUNING.
2026-10-05 11:27:31 +02:00
Niko1221 6bd7e930da merge fixes: the stray #endif of the two fused-expert dev_info blocks, the DONE line's newline escapes 2026-10-05 11:27:30 +02:00
Niko1221 9708b549a4 gfx1151: the exact (bitwise) Aurora switches are on by default on gfx1151 only (arch_defaults), the rounding-level ones stay opt-in
16 switches whose output was byte-identical to the switch off on Aurora (GDN head / PP / CONVL2 / NOY / SPLIT, QFUSE,
CVEC_FUSE, HCD_EXACT, PF_PAD, Q8 / Q6 packed, MMVF_ROWS, ATTN_LANECELL, EXPERT_V2, TSUM, LFUSE, PLE_BATCH) are set at
start-up when device 0 is gfx1151 and the user has not set them; STRATA_GFX1151_DEFAULTS=0 turns the table off.  The
GDN head kernels are AMD-only now (HIP builds; CUDA keeps its key-head kernel), and verify.cpp's namespace-scope env
reads became lazy so the table reaches them.
2026-10-05 11:15:33 +02:00
Niko1221 8a0755a1da core: device_free_bytes caches the unified-memory check per device (#409 review), not in a process-wide static 2026-10-05 11:10:11 +02:00
Niko1221 1bb3279d74 prefill: the gfx11 WMMA gates match the compiled arch list (no silent zeros on gfx1103 / gfx1152), cached per device
WmmaTraits::mma's #else returned its accumulator (zeros) for a gfx11 part outside the __gfx1100__..__gfx1151__
list; it traps now, and the runtime gates of the WMMA GEMM, the prompt attention, the block scorer and the HC
up-projection take exactly gfx1100 / 1101 / 1102 / 1150 / 1151 (strata/kernels/gfx_arch.hpp) so a gfx1103 or
gfx1152 falls back to hipBLASLt instead of launching code that is not there.  The gate is cached per device
(a process-wide static answered for the first GPU only; hipGetDeviceProperties on every call was the review's other
complaint).
2026-10-05 11:10:11 +02:00
Niko1221 cbe3fddc59 build: wmma_gemm.cu is added to strata_prefill only under STRATA_ENABLE_HIP (it includes hip_runtime.h; the CUDA build broke) 2026-10-05 11:10:10 +02:00
Niko1221 1fb37cf810 Merge f-140 into the Aurora port; verify: halo's STRATA_VERIFY_RESIDENT is 0.1.39's all-resident graph
0.1.39 already skips the host round trip when every expert is in VRAM (all_resident_, on by default, #871's
refresh_ar), so the port keeps that graph and adds only what halo built on top of it: the LFUSE gated combine.
2026-10-05 11:08:25 +02:00
Niko1221 bc6b6f87a9 Merge the Aurora gfx1151 branch (f-halo-int + HCD_EXACT + the expert bundle) onto 0.1.39
Merges f-halo-int (82cf9b8 + 56 commits: the gfx1151 target, WMMA prompt attention / GEMM / scorer, GDN recurrence,
fused gfx11 prompt experts, decode switches, drafting) with f-halo-int-S (STRATA_HCD_EXACT, 203ec5c) and
f-halo-int-W (table16, float4 combine, LDS alias + occupancy, d23d4e2).  Conflicts resolved against 0.1.39's own
all-resident verify graph, forked shared-expert stream, fused swiglu q8_1, PLE batch, GDN commit split and peer
prompt path; the gfx1151-only code stays gated (build fixes and the arch defaults follow in separate commits).
2026-10-05 11:07:15 +02:00
Niko1221 258532d667 test: the checkpoint split's allocation-failure test covers 1-3 stages and an incomplete checkpoint (#752) 2026-10-05 11:03:50 +02:00
Niko1221 604056878e serve: a Stop during the prompt read goes to the engine at once (#879 abort latency) 2026-10-05 11:03:50 +02:00
Niko1221 cfe09ab5f5 prefill: STRATA_TEST_PAGEABLE=1 forces the pageable fallbacks of Prefill::init (#828 test switch) 2026-10-05 11:03:50 +02:00
Niko1221 6f7f680529 verify: the all-resident graph runs only while every expert is in VRAM; a -1 raises a plan error flag (#871)
A prompt loan, a VRAM shrink or an adaptive swap marks experts -1 in the residency table.  The zero-doorbell graph
planned from the device table and returned silently on a -1, so the window ran a stale plan (!!!! at 100% residency).
refresh_ar() checks the host table before each window and runs the doorbell graph (its own captured variant) while any
expert is out; resident_plan also writes a mapped error flag the host checks after the window.
2026-10-05 11:03:50 +02:00
Niko1221 82bc5de632 generate: res_put syncs stream 0 (HIP has no cudaStreamLegacy) (#550) 2026-10-05 11:03:50 +02:00
sergiywith 53ab5f7161 generate: residency-table uploads wait for their own copy before the non-blocking streams read the table
Every upload of the expert residency table (host_res -> d_res, and each stage's) was a plain cudaMemcpy: a pageable
copy on the legacy stream, which may return before its DMA has landed, while the kernels that read the table run on
streams created cudaStreamNonBlocking, which do not wait for the legacy stream. A kernel enqueued right after could
read a table half old, half new: an expert computed by both the GPU and the CPU, or by neither. The ~100 KB copy
lands in microseconds, so this rarely fires, but nothing ordered it. The uploads now go through res_put(), which
waits for the copy on the current device's legacy stream only. Same values, same output.
2026-10-05 11:03:50 +02:00
Niko1221 b4405a0eaa serve: a split's stage-0 GPU profile line keeps its text (#848); later stages say which stage 2026-10-05 11:03:50 +02:00
Francesco Albano 43c8cfa9e2 setup: the low-RAM mode's resident variant on several GPUs (#642)
With an engine that keeps --resident-experts on a layer split, setup no longer
steers a low-RAM PC with two cards to one of them:

- at install, the low-RAM mode on several GPUs takes the resident variant by
  the same rule as on one card (what no card holds fits the RAM with
  LOW_RAM_HEADROOM_GB beside it), without the one-card question;
- at a start, a resident config on several GPUs keeps --resident-experts
  (split_mmap leaves it alone);
- a resident config started on a PC with two cards is offered both, "y" by
  default, as any other config.

It is gated on MIN_ENGINE >= RESIDENT_SPLIT_ENGINE (0.1.40 here, a guess at
the release that would carry the engine change), so until then setup behaves
as before and the golden configs are unchanged. Two tests run the new paths
with MIN_ENGINE patched; tools/test_setup_*.py pass (260 tests).
2026-10-05 11:03:50 +02:00
Francesco Albano fe9c10cad7 Resident RAM mode with a layer split
--resident-experts (the low-RAM mode's resident variant) ran as plain
--mmap-experts as soon as a layer split was set. It now keeps its RAM copy on
a split:

- the experts every stage's cache holds are left out of the RAM copy, not only
  CUDA0's;
- when the rest does not fit whole (#467), the copy keeps the hottest by the
  whole expert profile. Each stage only keeps its own layers' share of the
  profile, and ranked by CUDA0's share alone the copy held layers 0..K-1's
  experts and read every later layer's from the files (4.0 GiB in RAM instead
  of 21.2 on the PC below);
- an adaptive swap copies the evicted expert back into RAM from the cache of
  the card that owns its layer, on that card's stream. host_res holds slot
  numbers of whichever cache owns the layer: reading a later stage's slot out
  of CUDA0's cache put another expert's bytes in RAM, and after the first
  swaps the answers turned to garbage. (Latent until now: the guard kept the
  mode off a split.)
- the decode profile prints every stage's GPU profile, not only CUDA0's.

Remote expert caches (--expert-cache-remote) are still refused with it.

Swift 1.5 IQ3_XXS at 160K, q4_0 KV, RTX 4060 Ti (layers 0-19) + RTX 5080
(20-47), i9-14900KF, 32 GB of RAM, Windows 11, four greedy prompts, decode
tok/s (first round / fourth):
- 5080 alone, --resident-experts: 25 / 29
- split, --mmap-experts (what --resident-experts became): 32 / 64
- split, --resident-experts (22 GiB of experts locked in RAM): 71 / 69
With --pcie-frac 0 --adapt-every 0 the split's greedy output is the same as
--mmap-experts' (4/4 prompts). With adaptive swaps on, 33 varied requests at
temperature 0.6 (thinking on and off, five languages, code, each checked for
degenerate output) exchanged 81,783 experts with the two caches and gave no
degenerate answer.
2026-10-05 11:03:50 +02:00
Francesco Albano 5c4105c073 Layer split: --vram-reserve-later-mib, a separate reserve for the later cards
--vram-reserve-mib is every card's reserve, but the card that drives the
monitors needs more headroom than one that drives none: one value has to fit
the display card, and the other cards then keep that headroom for nothing.
--vram-reserve-later-mib N is the reserve of every card after the first
(default: --vram-reserve-mib's value), in the split search and in each later
card's cache sizing.

RTX 4060 Ti (no display, layers 0-19) + RTX 5080 (display, 20-47), Swift 1.5
IQ3_XXS at 160K: --vram-reserve-mib 1000 gives the 4060 Ti's cache 4551 slots;
--vram-reserve-mib 300 --vram-reserve-later-mib 1800 gives it 4867, and the
5080 keeps 1.3 GB free with everything loaded.
2026-10-05 11:03:49 +02:00
Niko1221andzengyishou 1ec615f585 serve: park_current's try covers the checkpoint split too (#752): a host OOM skips parking
Co-authored-by: zengyishou <[email protected]>
2026-10-05 11:03:49 +02:00
Strata W 528c1fb185 prefill: fused-expert exact wins (table16 via direct selector, float4 moe_combine, LDS alias + occupancy)
Bitwise-identical to e58d7fc (generated ids identical on UD-IQ4_XS, UD-Q4_K_XL, IQ3_S, IQ3_XXS at 8K/4K/64K; harness fused-output hash unchanged):
- table16: IQ4_NL / IQ4_XS decode through the direct-selector v_perm form (X5; exhaustive 2^32 check). -DSTRATA_W_NO_T16 restores the old form.
- moe_combine: four columns per thread with float4 loads, same fma order (X5); falls back to the scalar kernel if Dm / shared / bo are not 16-byte aligned. -DSTRATA_W_NO_COMB.
- native_w11_kernel: the H tile aliased onto the weight buffers (gate/up LDS 46.5 -> 30.2 KB), amdgpu_waves_per_eu(8), 4 blocks per WGP (X1), only for the types that do not spill under the 192-VGPR cap (gate/up IQ2_*, IQ3_*, IQ4_XS; down Q2_0, Q8_0, IQ4_NL). -DSTRATA_W_NO_OCC.
- X3 on1 (skip the second 16-row n tile of the down kernel) NOT included: no gain alone (-0.1%), and with the occupancy cap it makes IQ4_NL down spill 62 VGPRs and the whole bundle 2.3% slower.
2026-10-05 10:56:23 +02:00
Strata Contributor 1d78e57bd0 cache: preserve checkpoints when split allocation fails 2026-10-05 10:00:33 +02:00
sergiywith f6601bf83f #606: the fused SwiGLU q8_1 quantizers keep the block's scale and sum finite too
0.1.39 clamped two q8_1 activation quantizers (#606: an fp16 sum or scale past 65504 rounds to inf, the dot products
then read inf * 0 = NaN, and a NaN in the residual ends as one token repeated). Two more store the block unclamped:
- native_swiglu_quantize_q8_1_kernel (native_mmvq.cu), the shared expert's fused SwiGLU + q8_1, on by default
  (STRATA_FUSED_SWIGLU_Q81) in decode and the multi-token pass;
- native_gu_fused_kernel (iq_kernels.cu), the routed experts' fused SwiGLU + q8_1 (gfx906 builds, STRATA_EXP_MODE=8).
Both now go through q8_1_finite / q8_1_quant / q8_1_ds as their siblings do: every finite block is stored bit for bit
as before. iq_multi_parity's #606 check covers the shared expert's one (gate = 32, up = x / 32: its activations are x
exactly). rwkeyes found the first one (#606).
2026-10-05 10:00:29 +02:00
Niko1221 203ec5cdf7 prefill: STRATA_HCD_EXACT=1 - the HC down projection by a WMMA kernel with hipBLASLt solution 1176/1177 k order (StaggerU included), bitwise 2026-10-05 03:52:38 +00:00
Niko1221 e58d7fc849 tests: gdn_rec_head also compares the PP (variant 4) and two-column (variant 5) recurrence kernels, bitwise
T = 1, 7, 8, 9, 17, 100, 2048, 2051 (full and partial chunks), y, its FP16 bits and the final state: 0 values differ.
2026-10-04 20:26:01 +00:00
Niko1221 a4c30dc5c6 prefill: STRATA_GDN_PP=2 - the GDN recurrence with two columns per lane, bitwise
gdn_rec_quad_kernel's limit was shared memory: every wave re-read the 64 k / q floats of its row group per token
and the shuffles went through the same unit (probe: no k / q reads 9.8 ms, no shuffles 16.9 ms, of 21 ms).  A lane
now carries two columns (8 lanes x 2 columns x 4 row groups = 16 columns a wave, 64 a block, 96 blocks, 384 waves
in one round at 230 VGPRs): the two columns share the k / q reads, and each wave has two independent dependency
chains.  Per column the same arithmetic in the same order.  One 16K chunk-layer 25.4 -> 16.9 ms (gdn_probe14.hip,
bitwise vs the old kernel); 64K prompt 1232.4 -> 1267.6 tok/s (-1.47 s, interleaved, 2 runs), ids identical at 8K
and 64K.  STRATA_GDN_PP=1 is the one-column kernel with the register fixes only (-0.66 s).
2026-10-04 20:13:02 +00:00
Niko1221 2f510316ec prefill: STRATA_GDN_PP=1 - the GDN recurrence at 10 waves a SIMD, no state copies, bitwise
gdn_rec_quad_kernel needed 196 VGPRs = 7 waves a SIMD, but its 192 blocks of 4 waves need 9.6: a second round of
blocks ran after the first (half the heads took exactly half the time).  Cause: the 32 state-row addresses of the
first loads were CSE'd with the final stores and kept live across the whole walk (64 VGPRs); the stores' lane offset
now goes through an empty asm, so the addresses are made again - 133 VGPRs.  A full chunk's four tokens also run
with the state alternating between two register sets (the update writes the other one), which drops the 32
register copies the compiler made after each update (131 VALU a token instead of ~178).  The same arithmetic in
the same order.  One 16K chunk-layer 25.4 -> 20.5 ms (gdn_probe12.hip, bitwise vs the old kernel); 64K prompt
1233.7 -> 1249.0 tok/s, -0.66 s; engine output ids identical at 8K and 64K.
2026-10-04 19:23:07 +00:00
Niko1221 9668e32400 prefill: STRATA_GDN_CONVL2=1 (conv + q/k L2 norm in one kernel) and STRATA_GDN_NOY=1 (no dead FP32 write), bitwise
STRATA_GDN_CONVL2: gdn_conv_tiled_kernel with gdn_l2_kernel folded in (a block's 128 threads are one head's channels):
the tile's conv loop verbatim, then the sum of squares spelled out as the compiler built the l2 kernel (first xor step
an fma on the partner's rounded square, then adds), the four partials in the same order, the same v * rsqrtf(ss+eps).
16K chunk, per layer: 9.13 ms -> 6.95 ms.  A first version keeping the values in registers differed by 1 ulp in the
silu (different code shape); this one keeps the tiled loop as is.

STRATA_GDN_NOY: the norm kernel does not store the FP32 y nothing reads (403 MB per 16K chunk and layer); the FP16
value is made with v_fma_mixlo_f16, the instruction the compiler used next to the store (otherwise a mul and a
convert round twice and 1 ulp of the FP16 results differ).

Engine ids match the unchanged binary at 8K (acd9c8328408).
2026-10-04 17:38:17 +00:00
Niko1221 ebfebd23e2 Merge branch 'f-halo-int-a' into f-halo-int 2026-10-04 15:32:04 +00:00
Niko1221 04e1e11afb HIP: grouped decode experts for UD-Q4_K_XL (Q4_K/Q5_K gate/up, Q5_1/Q8_0 down), bitwise, opt-in STRATA_EXPERT_V2K=1
S26 structure (4 rows per warp, activations in LDS, fused SwiGLU+q8, optional TSUM) over S27<TY>::load/apply splits of the existing vec_dot functions.
2026-10-04 15:31:16 +00:00
Niko1221 9d9338dd1b Merge f-halo-int (7440806) into the stream A branch 2026-10-04 14:40:32 +00:00
Niko1221 d385870f77 prefill: gfx11 native fused experts - sign-table decode and a flat weight buffer (down kernel 18% faster), bitwise
native_w11_kernel: the sign bytes of the IQ2 / IQ3 grids come from a shared-memory table of byte masks
((g ^ m) + c per 4 bytes; no zero byte in any grid) instead of the compare / subtract emulation; the decoded
weight stages are one flat shared buffer addressed through a pointer, which changes the code the compiler makes
for the down kernel (7.5 -> 6.2 ms per 128-expert launch, IQ3_S / IQ4_NL, 16384 tokens).  One layer of 16384
tokens, fused experts: IQ2_S 83.8 -> 76.3 ms, IQ2_XXS 74.4 -> 68.9, IQ3_S 78.5 -> 73.8, IQ3_XXS 77.6 -> 71.8.
Outputs are bit for bit the same (the test now prints a hash of the fused output in pair order).
2026-10-04 14:39:57 +00:00
Niko1221 609ce5a645 qsa_prompt_attn_parity: print a hash of the new kernel output bits 2026-10-04 14:33:01 +00:00
Niko1221 48994ee7a4 qsa_prompt_attn_parity: probe modes (QA_SAME, QA_DUMP) for the K/V sharing question 2026-10-04 14:27:56 +00:00
Niko1221 7440806987 prefill: STRATA_PF_FUSED_KQ=1 - the fused native-expert path takes UD-Q4_K_XL (gfx11): gate/up Q4_K / Q5_K, down Q5_1 / Q8_0
The formats carry a minimum, so the activation blocks' spare bytes now hold the int8 code sums per 32 values (written by
every path, read by none else). Layers MMQ does not cover on HIP (Q4_K) join the fused layout through MmqPlan::fo.
Opt-in (default output bit-identical). Test pairs plus an int8-rounded model check; QA_SAME probe in the attention harness.
2026-10-04 14:16:58 +00:00
Niko1221 a1641e9f77 setup: a tip (not a change) for images on a 12 GB card: --vram-reserve-mib 1000 if a request stalls
With the image encoder on the GPU, the 700 MiB reserve can leave ~200 MiB free on a 12 GB card (UD-IQ4_XS
end-to-end check on an RTX 5070). Setup prints a one-line recommendation; the written config is unchanged.
2026-10-04 14:16:36 +02:00
Niko1221 91b0f53659 setup: Unsloth's UD-IQ4_XS is a regular choice (no longer experimental); UD-Q4_K_XL stays experimental
- "experimental" is per model now: MODELS["UD-Q4_K_XL"] keeps it, the unsloth family and UD-IQ4_XS drop it. The
  first menu lists the family without [experimental], with a one-line about (UD-IQ4_XS: a 94 GB download; under
  ~80 GB of RAM part of its experts are read from the SSD). Its size menu lists UD-IQ4_XS first (the default) and
  UD-Q4_K_XL second; an experimental size always sorts last. --model names are unchanged.
- UD-IQ4_XS: no EXPERIMENTAL warning, --check verdict without it. Images are asked (off by default), per model: the
  engine's image path has no restriction for this pack, which uses the original model's image encoder; not yet run
  with images. UD-Q4_K_XL keeps images off.
- MCP: the fallback tables mirror setup's (per-model experimental/vision), sizes in setup's order, per-size
  "experimental" and "images", the vision check per model.
- Docs: README and its six translations, MODELS, UNSLOTH_Q4, AI_SETUP, MCP_SERVER.
- Tests: the menus, the default, --model by name, images, --check, the pack/tokenizer paths; the golden configs
  are unchanged.
2026-10-04 13:24:29 +02:00
Niko1221 11212e08f8 docs: README refined + six translations 2026-10-04 13:17:54 +02:00
Niko1221 f5410ae2be Merge branch 'f-139b-par' into f-139-rel
# Conflicts:
#	src/core/verify.cpp
#	src/program/generate.cpp
2026-10-04 10:14:03 +02:00
Niko1221 4f5e6c841d Merge branch 'f-139b-spd' into f-139-rel
# Conflicts:
#	src/core/expert_source.cpp
#	src/kernels/cuda/iq_kernels.cu
2026-10-04 10:12:55 +02:00
Niko1221 ad33b80748 Merge branch 'f-139b-arc' into f-139-rel 2026-10-04 10:12:13 +02:00
Niko1221 bd34d0d87e Merge branch 'f-139b-old' into f-139-rel
# Conflicts:
#	setup.py
2026-10-04 10:12:13 +02:00
Niko1221 0918cba0a5 Merge branch 'f-139b-cpu' into f-139-rel 2026-10-04 10:11:54 +02:00
Niko1221 56501a38db #583: the byte-budget ring only where it gains; short prompts keep 0.1.39's ring
- a prompt that fits 0.1.39's auto chunk keeps 0.1.39's ring (Prefill::set_ring_budget's small_max): 4K prompts
  were 1-17% slower with the smaller ring (Coder -15%, IQ3_S -5%, IQ3_XXS -2%; 5 interleaved pairs each);
- ring slots are given up for a bigger chunk only where 0.1.39's rule held the chunk under 6144 (ring_cap_for);
  from 6144 on the ring keeps its 0.1.39 size (the Coder 6144/384 -> 7936/199 was -12% at 32K);
- the unpinned arm's cap stays 96 (the byte budget made it ~49 on IQ3_S);
- the scan sets its own ring budget instead of set_ring_override, so a layer split's 96-slot override (#340) is no
  longer clobbered by the scan.
RTX 5070 vs STRATA_RING_BYTES=0: 4K -0.7..+1.1% (bit-identical); 32K IQ3_XXS +18.5% (cache 1500) / +9.4%, Coder
+3.1%, IQ3_S +0.2%.
2026-10-04 10:10:54 +02:00
Niko1221 65a48f0d57 prefill: STRATA_PF_PAD with a weight that cannot be padded (an i-quant dense tensor) - X read at its stride
The padded activation of ssm_out / attn_output was handed to Gemm::native, whose padded-weight path needs a
strided dequant; the GSQ-RCO IQ3_XXS model has IQ3_S ssm_out tensors (no strided dequant for the i-quants), so
the engine exited at the first 64K chunk ("a padded X needs STRATA_PF_PAD's path"). Now such a weight is
dequantized unpadded and strata_pf_gemm_f16_ld reads X at its stride: the same kernel and products as with
PF_PAD off, the same bits.
2026-10-04 09:24:45 +02:00
Niko1221 39cd7fbef4 setup: the CUDA 12 engine's driver floor per OS (Windows 527.41 -> 528, Linux 525); the wheel pins match the 12.9.1 toolkit 2026-10-04 08:01:18 +02:00
Niko1221 bcd3603e3c #583 default on (owner): STRATA_RING_BYTES=0 opts out; DETAILS.md with the measured quality
Changes default output on long prompts of native packs against 0.1.39 (expected; gate notes in the S40 report).
2026-10-04 07:58:15 +02:00
Niko1221 18d853ab4c setup: --remote-expert-opt recommended for 2+ GPU configs (#578)
Added where a config goes to several GPUs (setup --gpus / a multi-GPU install, start --gpus, "use both" at
start). Single-GPU configs are not touched. Opt-out: setup --no-remote-expert-opt, or "remote_expert_opt": false
in the config (a user key, kept on re-runs). The engine uses it only with a helper cache (--expert-cache-device1..3),
so a layer split runs as before. tools/test_setup_remote_opt.py; the 2x16 GB golden configs gain the flag.
2026-10-04 07:57:23 +02:00
Niko1221 5eecc5dee6 prefill: STRATA_PF_HCDOWN=1 - the HC read's down and inject projections as one WMMA GEMM over a padded xn16
The hyper-connection read ran two hipBLASLt BF16 GEMMs over the same T x 10240 xn16: down (N 320, 6.78 ms per
16K-token half, 15.8 TFLOPS - the 4 KB-multiple row stride) and inject (N 4, 1.81 ms). strata_pf_hcdown_bf16 does
both in one 128 x 128 BK-64 WMMA GEMM: weight rows [w_down; w_inject] read from the two tensors, the epilogue
splitting lo (T x 320) and inj (T x 4), so xn16 is read once; with the flag, xn16 is written with token stride
10240 + 64 (gr_norm_rs / gr_write_norm_rs / gr_write_cvec_norm_rs take an ldx; unchanged and bitwise when off).
s23/hcdown_probe.hip, 16K tokens: 3.60 / 3.77 ms for both (unpadded 5.75).

Opt-in, on chunks of STRATA_PF_SWITCH_MIN_T+ tokens. FP32 accumulation in another k order than hipBLASLt:
rounding-level. Aurora, c-best3 v3.2: 64K timing hc read 7234 / 7253 -> 6439 / 6175 ms; prompt 8K 1048 -> 1075 /
1036, 64K 1053 / 1056 -> 1067 / 1068 tok/s. Teacher-forced KL (8192-token prefix, 2001 positions) vs the default,
next to the accepted MMQ-vs-fused pair: offset 0 0.162 (mmq 0.158), 30000 0.110 (0.126), 70000 0.031 (0.033);
ledger {32,17,130}, 64K retrieval 3/3.
2026-10-04 06:17:29 +02:00
Niko1221 2bb11b52a6 hip_compat: cudaFuncAttributePreferredSharedMemoryCarveout (#646's fused_gr carveout on HIP) 2026-10-04 04:53:45 +02:00
Niko1221 6448f0f7ad prefill: STRATA_CVEC_FUSE=1 - a steered layer's write, control vector and next norm in one pass over R, bitwise
With the speed-projection control vector on, every steered layer's FFN write-back took three passes over the
T x 10240 FP32 residual (gr_write, cvec_apply, the next half's gr_norm_rs) instead of the one gr_write_norm_rs of
the other layers. gr_write_cvec_norm_rs does the three in one: gr_write's arithmetic, cvec_kernel's dot order and
two-level reduction, gr_norm_rs's sum order and block_sum - the same bits. STRATA_CVEC_FUSE_CHECK=N runs the
three-kernel path on a copy of R on the first N fused writes and compares R, the row scales and the BF16 image
(Aurora, 8K prompt, layers 4-11: all identical). cvec_tables() hands out the current device's vector tables.

c-best3 v3.1 on Aurora, one 64K prompt with STRATA_PREFILL_TIMING (x2): hc read + combine 13.0 / 13.1 ->
10.8 / 11.2 s, GPU timeline 64.6 / 64.9 -> 60.6 / 63.0 s; benches interleaved, same ids: 8K prompt
971.5 / 1019.9 -> 998.8 / 1045.1, 64K 1025.3 / 1012.8 -> 1039.2 / 1014.4 tok/s.
2026-10-04 04:50:20 +02:00
Niko1221 002f64da50 docs: STRATA_RING_BYTES=1 (#583, opt-in) with its RTX 5070 numbers and quality check 2026-10-04 04:41:35 +02:00
Gopi 8fef4f1ff2 serve (auto): the chunk and the ring are one budget, and the ring is the better buy
`--prefill auto` walked a fixed list of chunk sizes - 32768, 16384, 8192,
6144, ... - and took the first that fitted, with the ring a fixed 384 slots
taken off the top before the chunk was ever considered.  Both halves of
that were wrong on a rig like this one.

The list is coarse exactly where it matters.  `bytes_needed` is a sum of
(T x positive constant) terms plus a max of such sums, so it rises
monotonically with T, and so does every test the scan applies - which makes
the largest chunk that fits a bisection on the 256-token grid the prompt
path already works on.  Seven probes against the list's ten, at one
`bytes_needed` each.  It matters because this rig affords ~8,700 tokens and
was handed 8192; 8704 is not on the list.

The order was wrong because chunk and ring spend the same borrowed VRAM,
and a ring slot is worth far more than a chunk token.  Measured here (2x
RTX 3060 + 2x RTX 5060, CUDA3 lending at its 90% cap, 120K prompt): 8960
tokens with the 17-slot ring that leaves reads at 963 tok/s, 8192/130 at
1,008, 7168 with the ring full at its 199-slot byte budget at 1,000, 5632/199
at 915.  A ring slot is worth ~0.53 tok/s and a chunk token ~0.05, so the 69
slots between a full ring and 8192's 130 are worth more than the 512 chunk
tokens they cost - and once the ring IS full, a smaller chunk buys nothing.
So: the largest chunk that still leaves the ring full, and only a rig where
no chunk can afford one falls back to the old rule with a kRingMin floor.

The room is counted in BYTES, not slots.  A ring slot is max_blob, but a
cache slot holds its own layer's blob - 2.15 MiB against a 2.54 MiB max_blob
here.  In slots the ring looked 18% cheaper than it is, a chunk whose ring
fitted only after that discount was refused outright, and the scan stopped a
step short.  `bytes_from_slots` is the inverse of the existing
`slots_from_bytes`, and `cache_slots_for` factors the latter out for the
serve path's per-participant version.  Both inverses clamp at k <= 0: the
lend budget is `min(slots - 128, pct * slots / 100)` and goes negative on a
cache under 128 slots, where `slots - k` is off_[slots] - the end of the
prefix sum, so that cache lends 0 bytes rather than reading past its offsets.

Upstream's per-participant `fits`/`fits_one` and the #448 diagnostic are kept:
the ring room is taken over the smallest participant, `alone` is the chunk
CUDA0 alone would read in, and the small-card warning is unchanged.

Verified on the rig: the scan picks 7680/199 against the old rule's 8960/17,
1018.8 and 1021.1 tok/s on two cold 120K prompts against 963.1 - +5.9%.
Q8_0 picks 5632/101, its 506 MiB budget over a 5,222,400 B blob.

0.1.39b (Niko1221): behind STRATA_RING_BYTES=1 with the byte-budget ring; the default keeps 0.1.39's chunk list
(plan_lend and the serve scan), its log line gains the ring. The INFO fields (the Monitor commit) are not taken.
2026-10-04 04:07:03 +02:00
Niko1221 20f471be73 prefill: the STRATA_PF_GEMM 128 x 256 kernel with a 64-k LDS tile, bitwise (STRATA_PF_BK64=0 keeps BK 32)
With global loads removed, the BK 32 double-buffered kernel still stopped at 37-39 TFLOPS of the ~50 WMMA peak:
the K loop itself (fragment reads, one barrier per 32 k) was the limiter. pfg::kernel_bk64 stages a 64-k tile in
one LDS buffer (55 KB) from 12 named registers with 2 barriers per tile, half the loop trips. Every accumulator
takes the same WMMAs in the same k order: the same bits (s23/gemm_probe11.hip, memcmp vs the BK 32 code).

gfx1151, M 16384, both operands padded (2 runs): N 2560 K 6144 38.0 -> 41.3 TFLOPS, N 12288 K 2560 38.9 -> 40.9,
N 10240 K 2560 40.3 -> 40.4. Also probed and rejected (same bits, slower): A rows read under the previous row's
WMMAs (36.7-37.9; 8-16 B spills), half-wave 16 B reads + v_permlanex16 (31.7-32.4), both (32.8-33.5).

Used for N >= 1024 and K % 64 == 0. c-best3 v3 on Aurora, BK 32 -> BK 64, interleaved, same ids: prompt
8K 959.8 / 947.8 -> 968.0 / 1001.9, 64K 1007.9 / 1004.0 -> 1028.0 / 1025.4 tok/s.
2026-10-04 03:55:08 +02:00
Niko1221 0c4d1fef09 #583 on 0.1.39b: the ring's byte budget and the loan's corrected count opt-in (STRATA_RING_BYTES=1)
Default: 0.1.39's 384/1024-slot ring and bytes_needed count, so the default loan and output stay as they were.
The auto chunk scan (the PR's second commit) is not taken.
2026-10-04 03:53:44 +02:00
Niko1221 e0446f394c #465 setup: recommend "parallel" only where the experts mostly fit in VRAM
On a card whose experts mostly run on the CPU the slots cost speed per request (RTX 5070, Q2_0: 11-24 %), so setup
now recommends slots only when the expert cache (every card of a split counted) still holds half of the model's
experts beside them (Q2_0: 24 GB and up, or a split); elsewhere it stays at one at a time and says "parallel N
reduces waiting for several users but costs about 10-25% speed per request on this card". --parallel N is
honoured as asked, as before. BATCHING.md: the table with the change against one at a time.
2026-10-04 03:36:22 +02:00
Niko1221 2cc21100b4 #465 serve/test_parallel: the first request decodes long enough to overlap the others on a busy PC 2026-10-04 03:34:23 +02:00
Niko1221 1c219eb984 #465 docs: the final build's RTX 5070 numbers; the turn-checkpoint exactness check 2026-10-04 03:14:23 +02:00
Niko1221 de19c046f0 Merge S26 f-halo-int (STRATA_LFUSE, b08cf3e) with S23 STRATA_PF_PAD (bedb808): c-best3 v3 2026-10-04 01:13:49 +00:00
Gopi 04b8d346a1 prefill: the streamed ring is a byte budget, so a native pack sets its own slot count
The ring was 384 slots - a number measured on Q2_0, where a slot is one
expert blob of 1,382,400 B, so 506 MiB.  A slot is a whole blob, so on a
pack with bigger blobs the same 384 slots are a different amount of
memory: 1,912 MiB on Q8_0, more than half of an 8 GB card's expert cache,
and what kept that card at a 1024-token chunk when its own buffers would
have fitted 6144.  Measured on the 4-way rig, one env var and nothing
else: chunk 1024 -> 6144, prefill 87 -> 402 tok/s.

So the budget is the constant and the slot count is derived from the
pack's max blob: 384 on Q2_0 (pinned) or 96 (not), exactly as before, and
the pack it was tuned on does not move.  The fused rule (1024 slots, #136)
is preserved the same way, and `ring_cap()` still bounds the result.  This
is also what lets the auto chunk scan treat "the ring is full" as a plain
byte comparison.

Also exports the three accessors the scan needs: bytes_needed_no_ring
(the chunk's own buffers, without the ring), ring_max_slots (the cap in
slots) and ring_slots_for (what the ring resolves to for a chunk, after
the override, the env var and the pinned-share rule - what `init` lays out
and what the INFO line reports).

And one fix on the way: `bytes_needed` counted `carve`'s buffers from
memory and got two wrong - it took `xn` unconditionally, though `carve`
takes it only under STRATA_GR_UNFUSED, and it never took `grs`.  Net
T*(D-HC)*4 bytes too many: 42 MB at a 1024-token chunk.  The direction is
safe - the prompt path was told it had less room than it did - but it
under-sizes every loan.
2026-10-04 03:05:40 +02:00
Niko1221 bedb808741 prefill: STRATA_PF_PAD=1 - the S23 prompt GEMM rows padded to stride K + 64, bitwise
A 4 KB-multiple row stride (K 2048 / 4096 / 6144 halves) camps on the memory channels: the gfx1151 WMMA prompt
GEMM ran ssm_out (N 2560, K 6144) at 19 TFLOPS against 31-32 for K 2560. Padding the rows by 64 halves (gemm_probe8,
M 16384): K 6144 19.1 -> 35.0 TFLOPS (W alone 29.0, X alone 23.7), K 2560 31.7 -> 36.6.

With STRATA_PF_GEMM=1 on chunks of STRATA_PF_SWITCH_MIN_T+ tokens: Gemm::native dequantizes the weight into the
scratch with stride K + 64 (dequant_f16_ld, non-i-quant types) and runs strata_pf_gemm_f16_ld; the FP16
activations of the two K 6144 projections (gdn_recurrence's y16 for ssm_out, gate_attn's out16 for attn_output)
are written with stride 6144 + 64. The same products in the same order: the same bits.

c-best3 v2 + STRATA_PF_PAD=1 (Aurora, interleaved, same generated ids): prompt 8K 954.2 / 930.7 -> 983.7 / 940.8,
64K 947.0 / 946.2 -> 974.8 / 1014.4 tok/s.
2026-10-04 03:00:48 +02:00
Niko1221 b08cf3e160 verify: fewer launches around the shared expert and the KV append, bitwise (opt-in STRATA_LFUSE=1)
Per MoE layer of a verify window (2-8 rows, resident combine path):
- the shared expert's scalar gate (a 1-row BF16 GEMV, one latency-bound
  workgroup) rides as one more block of the router GEMV launch
  (bf16_gemv_fp32_mmvf_multi_aux; the rows kernel's per-output code is the
  multi kernel's - checked bitwise for 2-8 rows, with and without TSUM)
- its sigmoid + row scale move into the combine (combine<true, true>: the same
  sigmoid expression, the product rounded on its own with contraction off in
  that block only, then added as before)
- shared gate and up projections in one launch (native_mmvq_pair: blocks
  n_out.. take the second matrix; Q8_0, exact multi layout, not packed)
Per attention layer: the window's int8 KV appends in one launch
(kv_append_q8_steps, blockIdx.z = token x K/V; distinct cells).
-4 launches per MoE layer, -(n-1) per attention layer; STRATA_LFUSE_GATE=0 /
STRATA_LFUSE_PAIR=0 turn the gate / pair parts off.

Engine (gfx1151, UD-IQ4_XS, c-best3 + EXPERT_V2 + Q8_PACKED + TSUM, S25's 18
prompts, same binary): 51.29 -> 50.31 ms per verify window, 54.33 -> 55.12
tok/s; 59K prompts 54.19 -> 53.17 ms, 42.97 -> 43.79 tok/s; all outputs identical.
2026-10-04 00:41:01 +00:00
Niko1221 b4ad373266 #465 engine: INFO slot_cache=0|1 beside batch_slots (the server sends a lone slot request back to the solo path only when the slots keep their conversations) 2026-10-04 02:38:22 +02:00
Niko1221 038430ff20 #465 a request left alone in a slot goes back to the solo path; docs: BATCHING.md for one GPU, measured on the RTX 5070
server: a request decoding in a slot whose neighbours finished (no other slot busy, nobody waiting, at least 32
tokens allowed) is BSTOPped and continued on the solo path with its MTP drafts - the engine copies the slot's
sessions back (INFO slot_cache=1; at most twice per request; STRATA_PARALLEL_SOLO=0 keeps it in the slot).
engine: INFO batch_slots=N slot_cache=0|1.
tools/batch_interleave_test.py: the back-to-solo path, and a next turn from a slot's turn checkpoint (a client
that drops the reply's thinking).
docs: "parallel": N, what a slot costs and what setup recommends, the server's handling (interleaved prompt reads,
BYIELD, slot conversation cache, back to solo), exactness and its settings, the RTX 5070 measurements (the slots
buy waiting time, not speed, on a 12 GB card), the protocol; DETAILS / README / AI_SETUP mention the option.
2026-10-04 02:38:16 +02:00
Niko1221 a184ac914e docs: Older CPUs (experimental) - what setup does on a CPU without AVX2, what was measured
INSTALL.md gets the section (the build setup compiles, what differs, the forced-path numbers from a
Ryzen 5 7600 + RTX 5070, what is untested); the CPU rows of INSTALL.md / DETAILS.md and AI_SETUP.md
point to it.
2026-10-04 02:13:51 +02:00
Niko1221 b6b7a87d84 prefill: STRATA_PF_SWITCH_MIN_T=N - the S23 rounding-level prompt switches only on chunks of N+ tokens
STRATA_HC_UPMIX, STRATA_PA_FAST and STRATA_PF_GEMM change the prompt path's rounding; on short prompts their time
gain is negligible but they change the generated text.  With N set, chunks shorter than N keep the default
arithmetic (and outputs) while long prompts keep the gain.  Unset or 0: every chunk, as before.

gfx1151, c-best3 + STRATA_PF_SWITCH_MIN_T=4096: S25's 18 prompts (1.0-1.9K tokens) give outputs identical to
c-best2 v2 on 18 of 18 (49.28 tok/s; c-best3 without the gate 48.83 / 48.67, other texts).
2026-10-03 23:45:54 +00:00
Niko1221 94e4b623c0 #465 tools: batch_interleave_test.py (a prompt read beside decoding slots, BYIELD, a next turn from its slot); batch_test.py on Windows
batch_test.py: the engine log in the temp folder, the CUDA DLLs on PATH, ASCII output, --mt-min (empty: the
engine's default kernels, for the invariance check without the exact settings).  server: /metrics live.waiting
and live.outside_slots instead of a guessed count.
2026-10-04 01:32:46 +02:00
野生の男 5a8b292417 cpu: preserve full thread affinity on Windows and Linux (#626)
Windows: pool workers pin with SetThreadGroupAffinity (the processor group was dropped: a 3990X's 63 workers
collapsed to 32 group-local masks); the host thread selects a CPU Set and restores the previous selection.
Linux: the complete, dynamically sized affinity mask is kept and restored (CPU IDs past 63).
pool_affinity_test (Windows) and pool_affinity_linux_test. Squashed from the PR's 8 commits (net diff).
2026-10-04 01:29:24 +02:00
Niko1221 d0f2900027 #465 setup: --parallel N, and the count it recommends for the card
The slots' sessions may take a fifth of the expert cache (~VRAM less 5 GB), up to 4: 2 on 12 GB, 3 on 16 GB, 4
from 24 GB, none below. Without --parallel setup only says it once; with it the config gets "parallel": N and a
count above the recommendation is kept with a note.
2026-10-04 01:18:02 +02:00
Niko1221 3afe0e5092 #465 server: "parallel": N, slots in /metrics, one status per request, a long prompt gives way to a short one
- "parallel": N in the run config passes --batch N (a value the engine cannot use is said and passed on: the
  engine warns and adjusts); the server uses the slot count the engine reports (INFO batch_slots)
- every running request keeps its own status, rate window and engine figures (history rows are their own);
  /metrics live.slots shows each slot (idle with the tokens it holds, reading, decoding with tok/s),
  /v1/status concurrency.serving says N
- a conversation's next turn goes to the slot that holds its start, a new one to an empty or the least recently
  used slot; a slot left at a stop token keeps what it holds
- a long prompt read (solo or an admission) gives way (BYIELD) to a waiting request with a prompt under half as
  long, at most twice; the part read waits in a reserved slot and the request goes on once the other is in
- the engine start and POST /v1/vram are serialized against parallel requests
- serve/test_parallel.py: a scripted engine behind the real StrataEngine and Service
2026-10-04 01:18:02 +02:00
Niko1221 cab62c933f #465 engine: batch slots for one GPU - warn instead of refuse, windows over the active slots, slot conversation cache, prompts read beside decoding slots, BYIELD
- --slots N is the same as --batch N; a count the engine cannot run (no --serve, 1, more than 8, a split on one
  GPU, sessions that do not fit, --batch-groups that do not divide) is a warning and fewer slots or none, never a
  refusal; INFO says batch_slots=N when slots run
- a batch window runs over the active slots only (Verifier::run_slot_rows, graphs per row list): an idle slot is
  not written, so it keeps the conversation it served
- a request whose prompt starts with what an idle slot holds (all of it, or its turn checkpoint) continues from
  the slot's sessions instead of reading the history again
- with slots, a prompt is read one prompt chunk at a time (the same chunks as one run) and the slots decode
  between two chunks for half as long as the chunk took (STRATA_BATCH_DECODE_SHARE)
- BYIELD <slot>: the prompt being read stops at its next chunk boundary, the part read is copied into the slot,
  YIELDED <slot> <tokens> + DONE cancel; the same request sent again goes on from there with the same chunks
  and checkpoints (#656's cooperative preemption, a slot as the park)

Default (no --batch) unchanged.
2026-10-04 01:18:02 +02:00
Niko1221 005f7c7185 gfx906 build on 0.1.39: the segmented expert cache (#533) is CUDA-only there too; pinned.cu's std::max beside windows.h
PR #638 was cut from 0.1.38. 0.1.39's segmented expert cache (#533) keeps its cuMem* code out of HIP builds through
STRATA_USE_HIP, which the gfx906 compat build does not define, so it included <cuda.h>. Its virtual-memory blocks are
now behind STRATA_EC_NO_VMM (STRATA_USE_HIP or STRATA_HIP_GFX906); the CUDA and RDNA preprocessor output is unchanged.
(std::max) keeps windows.h's max macro out of two Windows-only lines (found by a Windows gfx906 compile check).
2026-10-04 01:01:09 +02:00
Niko1221 75c9fc6baa HIP: STRATA_TSUM also spreads the expert down rows' items evenly over the lanes, bitwise
s26_down_l_kernel (STRATA_EXPERT_V2): a warp's 4 rows have 40 (block, half)
items each; lane-strided per row, lanes 0-7 took 2 items of every row (8
loads) and lanes 8-31 one (4). Under STRATA_TSUM=1 the 160 items are spread
5 per lane (item p = 32 i + lane is row p / 40), all 5 loads issued before the
dots. A lane's items of a row are then exactly those of the per-row layout's
lane (l - 40 q) mod 32, in the same order, and an xor butterfly gives the same
bits under any rotation of the lanes (each level's partner differs by +-2^j,
which is +2^j modulo 2^(j+1)): every output is bitwise the same (ws3 harness,
memcmp, T 1-3: 1.09 / 1.11 / 1.12x for gate/up + down with TSUM, vs 1.03 / 1.05
/ 1.06x with the butterfly alone). The same spread for gate/up (80 items x 4
rows, 10 per lane in 1-3 load groups) was 0.6-0.8x and is not used.
2026-10-03 22:59:47 +00:00
Niko1221 2b115071ed docs/INTEL_ARC.md: the experimental Intel Arc engine - what you need, the build, what is tested and what is not 2026-10-04 00:50:48 +02:00
Niko1221 bd8371adcd prefill gemm: STRATA_BF16_TC=2, a test mode that runs the FP16 path on any card (gemm_bf16_parity on sm_80+) 2026-10-04 00:49:02 +02:00
Niko1221 2a1c54e7da HIP: several warp sums as one transposed butterfly, bitwise (opt-in STRATA_TSUM=1)
A warp that ends with P independent warp sums (P tokens of a row, or rows x
tokens) used P xor butterflies of 5 shuffles each. s26_tsum.cuh does them in
one transposed butterfly: at offset 16 a lane keeps half of its values and adds
the partner's copy of that half, at 8 half again, ... then plain xor steps.
Every level adds the same pair of values the butterfly adds (fp add commutes),
so each sum is bitwise the same; P - 1 + (5 - log2 P) moves instead of 5 P, as
DPP row_xmask / permlanex16 on AMD (__shfl_xor_sync elsewhere).

Applied under STRATA_TSUM=1 to the decode kernels that end in several sums:
- HC read (STRATA_HC_Q8): gr_down_q8 / gr_up_q8 (ws4 harness, every output
  equal, T 1-4: 1.00 / 1.03 / 1.03 / 1.15x per read)
- STRATA_EXPERT_V2 gate/up and down (ws3 harness, memcmp, T 1-3:
  1.03 / 1.05 / 1.06x)
- native_mmvq_multi_kernel (exact layout) and the Q8_0 / Q6_K packed kernels
- bf16_f32_mmvf_rows_kernel (STRATA_MMVF_ROWS), both reduction stages

Engine (gfx1151, UD-IQ4_XS, c-best3 + EXPERT_V2 + Q8_PACKED, S25's 18
prompts): 54.21 -> 52.10 ms per verify window, 51.31 -> 53.73 tok/s, all 18
outputs identical.
2026-10-03 22:47:42 +00:00
Niko1221 3984194646 #646: the single-matrix mmvq does not stage the IQ grids (10-20% slower on the RTX 5070 at 3-8 columns)
The grouped expert kernels keep the staging (they gain). STRATA_IQ_STAGE_GRID_MMVQ=1 stages mmvq too; the
results are bitwise the same either way.
2026-10-04 00:36:02 +02:00
Niko1221 5ff6ae7530 setup: --backend sycl tests; Windows points at Linux (setup_intel reads sysfs, which WSL has not) 2026-10-04 00:34:13 +02:00
Niko1221 1330ed56d4 #646 on 0.1.39b: the layer split and the CPU path as before, the resident plan for 8-token windows
- layer split: commit stays synchronous on a split (set_commit_async(!multi_gpu), the `|| next_ != nullptr`),
  no pre-staging of the next stage's inputs, kDrafterMib 1000 - the split's sizing and order as in 0.1.39
  (untested here: one GPU);
- the CPU expert kernels keep cpu_avx512_ok() (F/BW/VL/VNNI/VBMI): #646's AVX-512BW-only check would send a
  CPU without VNNI/VBMI to kernels that use them;
- resident_plan_kernel: one thread per window entry up to 128 (64 lost a 7- or 8-token window's last entries
  on the all-resident path);
- the host keeps zeroing the GPU's rows under STRATA_VERIFY_DEVICE_PLAN=1 (copy_or_zero_from_mapped copies
  every row there).
2026-10-04 00:22:59 +02:00
Niko1221 de231f52d2 sycl: strata-sycl.sh passes ONEAPI_DEVICE_SELECTOR into the container
The image pins level_zero:0, so a two-card layer split could not see the second
Arc (#423, tmking01). Set ONEAPI_DEVICE_SELECTOR=level_zero:* for it.
2026-10-04 00:08:16 +02:00
tmking01 f420ee2dd1 sycl: stage_room reads the free VRAM (a layer split's later GPUs had none)
dpct left the DPCT1106 note but dropped cudaMemGetInfo in generate.cpp's
stage_room, so every later stage of --layer-split sized its expert cache from
0 bytes free and the second card crashed with 'expert cache: no room'.
Reported with the fix by tmking01 in #423 (2x Arc Pro B70); also a fixups.py
entry so a re-migration keeps it.
2026-10-04 00:08:16 +02:00
Niko1221 5ffcce4382 sycl: port 0.1.39 (re-migration with dpct 2025.3, 3-way merge per docs/INTEL.md)
The SYCL port of PR #423 tracked 0.1.38; 13 of its migrated copies were behind
0.1.39's sources. Re-migrated 0.1.38 and 0.1.39 with sycl/tools/migrate.sh,
normalized, merged with sycl/tools/merge_upstream.py:

- clean merges: expert_cache, expert_source, native_dense, pinned, elementwise,
  kv_stream, iq_multi_parity, prefill, verify.hpp; q8_1_finite.hpp new (#606)
- verify.cpp: the #649 trace kept with the port's queue handling
  (STRATA_VERIFY_TRACE; the HIP-only coherent/doorbell switches stay HIP-only)
- generate.cpp: the port's --prefill-borrow beside --vram-elastic/--vram-segment-mib
- iq_kernels / native_mmvq: the port's kernels kept, #606's finite q8_1 scale
  and sum applied by hand (dpct's conflicts there were kernel-name hashes)
- expert_cache: --vram-elastic (#533) is CUDA-only on the port too (no driver
  VMM on Level Zero through dpct); it reports so instead of failing to build
- version 0.1.39

Compiled here with icpx 2026.1.1 (SPIR-V, no Intel GPU on this PC): strata
builds. Not run on an Arc.
2026-10-04 00:08:15 +02:00
Niko1221 335f742228 setup: the offer to share a model across two cards checks the model's own engine (CUDA 12 or 13) 2026-10-03 23:46:27 +02:00
Niko1221 7990455358 docs: Older GPUs (experimental) - the support matrix, the CUDA 12 engine and how to opt in
docs/OLDER_GPUS.md: Pascal / Volta through the CUDA 12 engine (#395 #600 #540 #655), RTX 20's STRATA_BF16_TC opt-in,
AMD gfx1031 (#524), gfx1012 (#442) and gfx906 (#638, #677) with the reporters' numbers; README, AI_SETUP, AMD_HIP and
NVIDIA_V100 point to it.
2026-10-03 23:44:14 +02:00
Niko1221 7c5a71adf7 router_dot_parity: the router lookahead's AVX2 and AVX1 dots against a double reference
Random BF16 rows of the router's shape [512 x 2560], 1..8 tokens: both within 3.3e-7 of the double
sums on a Ryzen 5 7600 (0.53 ms and 0.50 ms per layer for 4 tokens). Two ctest entries, the second with
STRATA_FORCE_ISA=avx (the AVX-only CPU's path). Test program only.
2026-10-03 23:44:03 +02:00
Niko1221 6234f26783 setup: older NVIDIA GPUs through a second, experimental CUDA 12 engine; --cuda 12|13 (#395 #627 #540 #600 #601)
CUDA 13 dropped Pascal and Volta. A model whose GPUs include one (its oldest card decides: one engine runs per model)
now runs the experimental CUDA 12 engine in engine-cuda12/ - the ready-made strata-windows-x64-cuda12.zip with NVIDIA's
CUDA 12 pip libraries, or compiled here with a CUDA 12.x toolkit (Linux; STRATA_NVCC picks one, #601) - and setup says
why. engine/ and every model on it stay as they were.
- the cards are an opt-in: naming one (--gpu / --gpus), --cuda 12, STRATA_EXPERIMENTAL_SM60=1, or a PC with no newer
  NVIDIA card and no supported AMD card; a PC with a newer card keeps recommending it
- --cuda 12|13 (or STRATA_CUDA) overrides the choice and is kept, with a warning where it cannot work (recommend,
  never force); --cuda 12 also runs with a driver older than 580 (525+), which the stop now mentions
- at a start, a Pascal / Volta card added to a CUDA 13 model moves that model's config to the CUDA 12 engine
- updates look at both engine folders; a compiled CUDA 12 engine builds in build-cuda12/
- an RTX 50 card in a CUDA 12 engine is a warning (CUDA 12.8+ builds it; #220 crashed with 12.8), no longer a stop
The setup golden test (every recommended config on five PCs) is unchanged; tools/test_setup_older_gpus.py covers the rest.
2026-10-03 23:42:23 +02:00
Niko1221 b8dbdfe12a older CPUs (experimental): STRATA_ISA_FLOOR=avx|none, and setup compiles it instead of stopping (#394 #595 #623)
- CMake: STRATA_ISA_FLOOR (empty by default) builds ggml-cpu for AVX (Sandy/Ivy Bridge) or SSE4.2
  (Nehalem/Westmere) instead of the build host or AVX2; every other ggml ISA option off. Strata's own
  AVX2/AVX-512 kernels stay in the binary behind their CPU checks. Excludes STRATA_PORTABLE. The ggml
  block follows the Strata_Dirigo fork's (rwkeyes).
- STRATA_FORCE_ISA=avx2|avx|sse caps the engine's CPU probes, so the older-CPU paths run on any PC
  (how this was tested here: no old CPU). cpu_sse42_ok(), isa_floor_build().
- The engine: a normal build still refuses a CPU without AVX2, now pointing at the experimental build;
  a floor build checks its own floor (AVX, or SSE4.2 + POPCNT) and warns that it is experimental and
  slow (or, on an AVX2 CPU, that the normal build is faster).
- setup: a CPU without AVX2 warns ("experimental, slow") and compiles the engine on the PC with the
  floor it has, instead of failing (#595's idea); the prebuilt AVX2 engine is not used there. Recorded
  in BUILD.json; a build folder for another floor is configured afresh. STRATA_ISA_FLOOR=avx|none asks
  for it on any PC. Windows + AMD has no source build: a clear stop. The MCP server's recommendation
  notes it instead of refusing.
- tools/test_setup_oldcpu.py.

Default build: nothing changes (no new CMake definitions, the probes answer as before without the env).
2026-10-03 23:35:52 +02:00
Niko1221 f4dc113ee1 iq_avx2: STRATA_IQ256_GATHER=0 keeps the scalar grid assembly (parse the value) 2026-10-03 23:34:41 +02:00
Yannick Loth 0736f05d8a iq: gather the AVX2 codebook from the grid table (STRATA_IQ256_GATHER)
The two IQ3 gate/up formats decode each 32-value half with eight scalar loads
assembled by _mm256_set_epi32.  A scratch build that substitutes a constant for
the grid vector shows that assembly is ~half the single-core kernel (IQ3_XXS
248 -> 130 us, IQ3_S 357 -> 140 us), and the two formats are ~58% of the
gate/up lookup work on the Swift 1.5 IQ3_XXS pack.

Add an opt-in AVX2 gather for IQ3_XXS (iq3xxs_grid) and IQ3_S (iq3s_grid),
the mirror of the AVX-512 kernels' STRATA_IQ_GATHER.  On the i7-12850HX
(Alder Lake, no AVX-512) it is bit-identical - a direct scalar-vs-gather output
dump matches for all five gate/up formats, native_expert_parity stays green -
and 1.32-1.34x on the two formats isolated, +1.0% serve end to end (on >= off in
5 of 5 interleaved pairs).  The pool is flat in the deterministic --stats (the
15-worker pool is not decode-bound), so it is a per-core win that compounds.

Default off, like the AVX-512 one: AVX2 gather throughput is microarchitecture-
dependent.  IQ2_XXS / IQ2_XS / IQ2_S use 64-bit grids, where an AVX2 i64 gather
measured a wash, and are unchanged.  The AVX-512 path is untouched.
2026-10-03 23:34:26 +02:00
Anon 8ca4e160c2 pinned: back the Linux expert arena with transparent huge pages
Without a hugetlb pool the Linux arena fell back to a plain anonymous
mapping with 4 KB pages. The CPU expert pool streams whole experts (about
3 MB each for the 4-5 bit GGUFs) out of that arena, so every expert costs
~750 TLB misses.

Map the fallback 2 MiB-aligned and madvise(MADV_HUGEPAGE), so THP in
"madvise" mode (the common distro default) backs it. STRATA_NO_LARGEPAGES=1
keeps 4 KB pages, as on the hugetlb path; the log note says which one it got.
2026-10-03 23:34:13 +02:00
Anon 4175cbcb5b prefill: a layer split's idle card streams a share of a one-chunk prompt's experts
A prompt that fits one chunk runs a layer split's stages one after the other,
so while one card reads its layers the other idles. --peer-device already has
the mechanism for this (PeerPrefill's peer streaming: a share of the experts
the primary streams goes over the peer's own PCIe link and is computed there),
but it needs P2P and is refused with --layer-split.

This makes PeerPrefill usable as a stream-only peer between the stages:

- set_stage_helper: each stage's prompt path gets the next stage's (the last
  one the first's); a stream-only PeerPrefill holds no experts (peer == null),
  so every use of the peer tier is guarded
- per prompt, bind_stage_helper points it at the idle stage's own lent prompt
  buffers (mixed, Xq, GU, H, Hq, Dm, ring, MMQ context): no VRAM of its own
- without P2P the activations, the row table, the group bounds and the result
  rows go through mapped host memory, read by copy kernels on the device that
  needs them. Copy-engine uploads queued behind the ring's expert blobs (the
  grouping tables' reason for mapped memory), which cost ~20 ms per layer and
  ate the whole gain; cudaMemcpyPeerAsync without P2P is staged by the driver
- only for one-chunk prompts on the MMQ path (not the fused kernels, not with
  --peer-device), with a share that falls with the chunk: min(0.45,
  0.5 - T/16384), off below 0.3 (~3.3K tokens) - measured, below
- STRATA_PREFILL_HELP=0 turns it off, STRATA_PREFILL_HELP_FRAC fixes the share

2x RTX 3090 (no P2P), UD-Q4_K_XL, layer split auto, 262K context,
--adapt-swaps 0, prompt tok/s without / with: 1.1K 496 / 723, 1.5K 674 / 833,
2K 878 / 1128, 2.5K 1017 / 1296, 3K 1260 / 1440, 4K 1605 / 1607, 8K 2215 /
2221; decode unchanged. The output is repeatable (same prompt, same answer)
but not bit-identical to STRATA_PREFILL_HELP=0's: the helped rows are
computed in another MMQ grouping.

0.1.39b (Niko1221): opt-in (STRATA_PREFILL_HELP=1), since the helped rows round differently from the default;
merged with #598 (run_impl / next_run_).
2026-10-03 23:34:07 +02:00
JeanP00l dc0f2f7916 bench: community report, 2x AMD Instinct MI50 (gfx906), Coder IQ1_M, 4K to 128K prompt tokens 2026-10-03 23:33:55 +02:00
David ff12cbe2b9 hip: retain native wave synchronization on HIP 7 2026-10-03 23:33:46 +02:00
David e9a5f8d2b8 hip: preserve Q2_0 signed zero on gfx1012 with legacy HIP 2026-10-03 23:33:46 +02:00
David e3e30eb131 hip: add experimental gfx1012 support and legacy BLAS compatibility 2026-10-03 23:33:45 +02:00
Niko1221 9d638ffed6 gfx906 build (PR #638 follow-up): mrope.hpp's HIP include only in the gfx906 build; tests.list dropped
The RDNA backend (STRATA_ENABLE_HIP) compiles mrope.hpp as before; tests.list was a local test runner's list, not
part of the build.
2026-10-03 23:33:16 +02:00
Danny Werner c3f2a5e63b refill: improve multi-GPU processing 2026-10-03 23:33:12 +02:00
zhedang 5cc53cddbc core: optimize remote expert helper decode
Add default-off cache coordination, helper-side weighted reduction and CPU activation quantization on demand. Allow helper cache capacities to be sized automatically at startup.

Port the saved v2.2 implementation onto upstream 0.1.38 without changing the separate peer tier. Document the helper-only scope and current validation limits.
2026-10-03 23:33:07 +02:00
JeanP00l 0afba54b4c fused_gr: the gfx906 fast norm/up launches only in the gfx906 build (CUDA and RDNA did not compile) 2026-10-03 23:33:00 +02:00
JeanP00l c330ec76cf docs: gfx906 verify-window routing in the kernel table 2026-10-03 23:33:00 +02:00
JeanP00l b18278ce7e gfx906: route the verify window's tokens in one BF16 projection + one top-k (bitwise the per-token calls)
The Coder's router is 256 experts, which the native 512 x 10 router does not take, so a verify window routed each
token with its own projection and top-k. moe_route_window does the window in one multi-column BF16 projection
(bf16_gemv_fp32_mmvf_cols over the existing multi-row kernel) and one n-token top-k; each token's route is bitwise
what moe_route gives it (route_window_parity, new ctest). gfx906 build only, so the CUDA and RDNA paths are
unchanged; STRATA_ROUTE_PER_TOKEN=1 restores the per-token calls.

2x MI50, Coder IQ1_M, 32K, greedy 1,500-token request: verify window 55.5 -> 52.5 ms, generated text identical.
2026-10-03 23:33:00 +02:00
JeanP00l 6b8b54963b gfx906: K-quant/Q5_1/Q8_0 experts take the CUDA layout; gr_down K-split opt-in; gfx906-aware ctest
- native_expert_grouped: the AMD layouts handle the IQ packs' gate/up and down types only; Unsloth's Q4_K / Q5_K
  gate/up and Q5_1 / Q8_0 down now take the CUDA layout instead of exiting (native_grouped_parity found it).
- fused_gr_read_multi: the K-split gr_down (fixed-order finish) sums in another order than the single-token
  fused_gr_read, so it broke gr_parity's multi == single contract; it is now opt-in (STRATA_GR_SPLIT=1). The
  latency-hidden norm/up (same sums, same order) run in the default read (STRATA_GR_FAST=0: off).
- mmvq_multi_parity: on gfx906 the wave64 MMVQ is the same exact kernel for every column count, so the negative
  control has nothing to find; a second ctest entry runs it on the CUDA layout (STRATA_MMVQ_WAVE=0), where it has
  power.
- kv_hybrid_parity: the tensor-core prompt attention refuses on gfx906 as on the RDNA backend.

ctest on 2x MI50 (gfx906): 34 of 34 pass (iq_parity and ple_parity need fixture files and are not counted).
2026-10-03 23:33:00 +02:00
JeanP00l 8e8e641245 docs: gfx906 (Instinct MI50 / MI60, Radeon VII) build, kernels and measurements in AMD_HIP.md 2026-10-03 23:33:00 +02:00
JeanP00l 9ff290b493 hip: AMD gfx906 (Instinct MI50 / MI60, Radeon VII; wave64) as an opt-in build, STRATA_HIP_GFX906=ON
The HIP backend (STRATA_ENABLE_HIP) is wave32 RDNA only, and the engine refuses a wave64 card. This adds a
separate opt-in build for gfx906: the CUDA sources compiled as HIP through a small compat layer, with a CUDA warp
as a logical half of the 64-lane wavefront. With the option off nothing changes for CUDA or the RDNA backend;
every new code path is under STRATA_HIP_GFX906.

Build: -DSTRATA_HIP_GFX906=ON -DCMAKE_HIP_ARCHITECTURES=gfx906 (implies STRATA_ENABLE_CUDA's targets, refuses
STRATA_ENABLE_HIP). The CUDA runtime/cuBLAS names come from include/strata/platform/hip_compat/ (first on the
include path), CUDA::cudart / CUDA::cublas become aliases of hip::host / roc::hipblas, every .cu (and the ggml MMQ
sources, with GGML_USE_HIP) is compiled as HIP. The native kernels' --use_fast_math (an nvcc flag) is not passed.

Correctness fixes found on the way (each one changed results or hung, not only speed):
- __fmul_rn / __fadd_rn / __fsub_rn contracted into FMA under HIP; they no longer do (as on NVIDIA) - the
  elementwise and quantize_act parity tests pass bitwise;
- the device check of the gfx906 build reads the card's gcnArchName (the wave32 check is the RDNA backend's);
- ggml MMQ got NVIDIA compute capability 9.0 for gfx906 and hung the prompt path; it gets the AMD arch code;
- __byte_perm is a scratch-memory array in HIP: the IQ4 table lookup uses llama.cpp's v_perm_b32 sequence
  (agent-request decode 29.9 -> 39.2 tok/s on 2x MI50);
- the stage profiler's wall clock runs at 25 MHz on gfx906, not 100 MHz;
- a CUDA toolkit-mismatch check that reads CUDART_VERSION is skipped (no CUDART_VERSION under HIP);
- gdn_rec_parity (cp.async, CUDA occupancy API) is not built for gfx906.

wave64 kernels (gfx906 only; the CUDA layout stays one env switch away for A/B, every one bitwise-checked):
- grouped native experts, STRATA_EXP_MODE=7 (default): gfx906 has no packed byte SIMD, so __vcmpne4/__vsub4
  became ~12 word ops each; signs are now dp4a(g ^ m, u) - dp4a(m, u) (exact in integers), grids and the group's
  activations sit in LDS, one weight load serves every token of the group. Same k-to-lane order, so the output is
  bitwise the old layout's (native_expert_bench, real GGUF rows). Verify window 60.0 -> 51.3 ms.
  STRATA_EXP_MODE=2 is the previous layout;
- MMVQ: one wavefront per row with a 64-lane butterfly, no LDS/barrier, same kernel for 1..8 columns
  (+2.3% decode; STRATA_MMVQ_WAVE=0: CUDA layout);
- router top-10 in one wavefront (register argmax, no block barriers), bit-identical (router_top10_parity);
- gr_down_multi split along K (8 rows x 5 slices of 2048 per block, fixed-order finish) (+2.9%;
  STRATA_GR_SPLIT=0: old);
- hyper-connection read: norm with its loads in flight and xn in registers, up with 8 lanes per row
  (51.3 -> 50.2 ms per window; STRATA_GR_FAST=0: old);
- the QSA prompt-attention tensor-core/WMMA kernels are not used on gfx906 (the FP32 kernel runs).

Benches (not ctest; they need a model shard): native_expert_bench (one expert layout against another, bitwise,
with timings) and fused_gr_bench (the fast hyper-connection kernels against the old ones).
2026-10-03 23:33:00 +02:00
rwkeyes 51a60af92a router lookahead: an AVX1 dot and a plain fallback for CPUs without AVX2 (Strata_Dirigo)
The routing-aware prefetch's router dot (bf16_rows_dot_multi) lives in kq_avx2.cpp, so an AVX-only
CPU started fine and died on the first request (SIGILL in vpmovzxwd on a Xeon E5-2687W). It now
takes the AVX2 kernel where the CPU has AVX2, kq_avx1.cpp's AVX dot (mul + add, 128-bit integer
widening) where it has AVX, and the same sums in plain C++ below that. cpu_avx1_ok() probes AVX +
OSXSAVE + the YMM state. An estimate only (which experts to prefetch). A CPU with AVX2 runs exactly
what it ran before.

From rwkeyes' Strata_Dirigo fork (MIT; 0d00a66, e0754d3), with MSVC's /arch:AVX added and
__builtin_memcpy replaced by std::memcpy for MSVC.
2026-10-03 23:31:16 +02:00
Niko1221 bbb0650993 QSA attention: PR #540's kernel below sm_75 in the experimental build only
#540's attention kernel (bit-exact, +7% prompt on a V100) uses about twice the registers and also runs decode, so it
is not taken for every card: the kernel the ready-made engine runs is restored as it was, and #540's version lives
beside it as attn_chunk_kernel_pre75, compiled only with -DSTRATA_EXPERIMENTAL_SM60=ON and launched on a card below
sm_75 (per device; STRATA_ATTN_PRE75=0 is the A/B arm).  The launches pass cap/stride explicitly (the same 0, 0 as
the defaults) so either kernel can be picked through one pointer.
2026-10-03 23:30:33 +02:00
Niko1221 89351a799d Merge PR #559 (blange48, crazyaimachine): batch slots, pipelined layer split, parking with a split
Conflicts with 0.1.39: --trim-stage-weights is now the same switch as STRATA_STAGE_TRIM=1 (PR #639's
implementation, already in 0.1.39); the #533 VRAM command is taken between batch windows only when no slot
is decoding.
2026-10-03 23:29:40 +02:00
Károly Sárdi 00e56870b4 perf(volta): address review - keep BF16X2 remainder GEMMs on cuBLAS, keep Inf, share sq with spt, atomic cc cache 2026-10-03 23:29:14 +02:00
Károly Sárdi 6a4b1265c6 perf(qsa): cut the attention kernel's shuffles and q shared-memory traffic, bit-exact 2026-10-03 23:29:12 +02:00
Niko1221 ef18ede418 cmake: STRATA_ENABLE_SYCL, the experimental Intel Arc engine (sycl/, off by default) 2026-10-03 23:29:11 +02:00
Niko1221 f13b869b6b Volta prompt attention and the Pascal BF16 path: compiled into the experimental build only (PR #600, #395 follow-up)
STRATA_EXPERIMENTAL_SM60 now reaches every target (add_compile_definitions). prompt_attn_v70_kernel with its launcher,
and Gemm::bf16's fp32 path for Pascal, exist only under it: the ready-made engine (sm_75+) loads no extra kernels for
them, while the experimental build's sm_60/61/70 cards get them.
2026-10-03 23:29:00 +02:00
4EverBuilder 3f32e4b66a native experts without AVX2: Q2_0 layers on ggml-cpu, every AVX2 kernel gated (#595)
A native pack's Q2_0 layers (most IQ packs' down projections) ran on Strata's own Q2_0 kernels, which
are AVX2 at least. q2_native_kernels() keeps them there when the CPU has AVX2 and otherwise hands the
layer to ggml-cpu's Q2_0 vec_dot like every other native type (the pool, the dispatcher's activation
quantizer and the parity test). STRATA_KQ256's gate/up kernel needs AVX2 too. native_expert_parity
skips the AVX2 checks on a CPU without AVX2. No change on a CPU with AVX2.

(The engine part of #595; its setup and run-script parts are not in this commit.)
2026-10-03 23:28:19 +02:00
Klaus Friedel 174ce924de docs: point the BF16 note at #540 (the BF16-via-FP16 PR #593 was closed in its favor) 2026-10-03 23:28:14 +02:00
Klaus Friedel 5e1926070c bench: distribution check of the Volta prompt attention (teacher-forced KL, controls)
Old path against new kernel on 8.5K / 33K / 99K-token chats, 617 scored positions each, with two controls that change only the rounding
order (BF16 GEMMs without the FP16 detour, another prefill chunk), reruns of both paths (bit-identical), and the kernel's own error on the
model's data (relative 4.4e-7 mean, 4.8e-6 worst row over ~5 M rows).
2026-10-03 23:28:14 +02:00
Klaus Friedel de9a78eed4 docs: NVIDIA_V100.md and the measurements of the Volta prompt attention
The experimental sm_70 build (STRATA_EXPERIMENTAL_SM60, #236) had no page. NVIDIA_V100.md says how to build it, which kernel each
part of the prompt path uses on Volta and what the prompt attention kernel was measured at.

bench/results/2026-10-03-v100-prompt-attn: prompt speed with and without the kernel (7K / 28K / 114K tokens), the nsys share of the
attention before and after, the parity numbers, needle recall (15 of 15 with either path) and the greedy-output comparison.
2026-10-03 23:28:14 +02:00
Klaus Friedel 649fc7fcad qsa_prompt_attn: tensor-core kernel for Volta (sm_70, mma.m8n8k4)
On sm_70 qsa_prompt_attn_batch refused the device and the prompt path fell
back to the decode kernel (FP32 FMAs, one query at a time): 19-25% of the GPU
time of a 32K prompt on a V100.

prompt_attn_v70_kernel is the v1 kernel's structure with the two matrix
products on m8n8k4 (FP16 in, FP32 accumulate): q.k with one dim group (64 dims,
= one int8 scale group) per warp and 8 cells per quad-pair, p.v with 16 dims per
quad-pair. q and p keep their hi + lo FP16 split, the four dim groups' partials
are added in a fixed order (deterministic). Int8, FP16 and K8V4 KV are handled;
Q4_0 KV (mode 4, sm_80+ only upstream) keeps the old kernel. The fragment layout
was measured on a V100 and matches turbomind's SM70_MMA_884.

qsa_prompt_attn_parity (V100): error against FP64 ~5e-6 (output scale ~3.6),
int8 3.0x and fp16 1.3x faster than the FP32 kernel per 2048-query chunk. The
test now skips its Q4_0 cases below sm_80 instead of exiting 2 there.
End to end, 32K prompt, one V100, greedy output identical:
26 s -> 22 s on current main (STRATA_PROMPT_ATTN_OLD=1 is the old path).
2026-10-03 23:28:14 +02:00
456950beec prefill gemm below sm_80: Volta on the FP16 path by default, Turing opt-in, Pascal through fp32 (#655 #540 #395)
PR #655's FP16 tensor-core path for Gemm::bf16, adapted so the ready-made engine stays byte-identical:
- default on for compute capability 7.0-7.4 only (Volta; the experimental STRATA_EXPERIMENTAL_SM60 build), off for
  7.5 (RTX 20): STRATA_BF16_TC=1 opts in, =0 turns it off on any 7.x card
- from #540: finite values beyond FP16's range clamp to +-65504; a beta = 1 product (the BF16X2 remainder, in
  FP16's subnormal band) keeps cuBLAS; the compute capability is cached per device (a layer split can mix cards)
- from #395: Pascal (6.x; cuBLAS has no BF16 GEMM there) widens both operands to fp32 by an exact shift and runs
  cublasSgemm with the same fp32 accumulator, tiled over T in the instance's own buffers
sm_80 and newer, and HIP, run the same cuBLAS / hipBLAS call as before.

Co-Authored-By: Károly Sárdi <[email protected]>
Co-Authored-By: Rafal R@V Prasal <[email protected]>
2026-10-03 23:28:09 +02:00
Demetree Kallergis 0f476b4553 native experts: gate the AVX2 multi-token kernels on cpu_avx2_ok() (#394)
native_gu_rows() tested cpu_avx512_ok() before the AVX-512 kernel but not cpu_avx2_ok() before the
AVX2 one, and native_down_rows() had the same asymmetry for its two multi-token kernels (kq256 and
the IQ4_NL one). On a CPU without AVX2 a verify window of two or more tokens took an /arch:AVX2 path
and died with 0xC000001D. With the gates it falls through to ggml-cpu's vec_dot, which covers every
native type for any nt. A CPU with AVX2 takes exactly the paths it took before.

(Cherry-picked from #394's 0083bb7 without its generate.cpp part; the startup gate is reworked for the
opt-in STRATA_ISA_FLOOR build in a later commit.)
2026-10-03 23:27:51 +02:00
Niko1221 d072203bf9 iq_avx2: the IQ2 sign table at compile time (no static constructor in an AVX2 file)
#391 removed MSVC's BMI2 shlx from the table's constructor; GCC still vectorised the same loop into
AVX2 (vpbroadcastb) and ran it before main() on an AVX-only Xeon E5 (found by rwkeyes' Strata_Dirigo
fork, 6dd37a2, which made it constexpr). constexpr here as well, deriving ksigns_iq2xs[i] (the 7 bits
plus an even-parity bit) so the constant expression does not read a non-constexpr array. Same 128
values; the file now has no runtime initializer.
2026-10-03 23:27:37 +02:00
Stuart Chapin 200c35a8e9 fix(cuda,decode): resolve sm_120 IQ3_S generic-pointer fault and restore 100% bit-exactness with main 2026-10-03 23:27:36 +02:00
Stuart Chapin a36be1db29 perf(cuda,decode): zero-doorbell verify graph, sub-warp expert packing, shared-mem staging, and batched PLE/MTP 2026-10-03 23:27:36 +02:00
Niko1221 241dcab7ac setup: --backend sycl, the Intel Arc engine (experimental, built from source; sycl/setup_intel.py) 2026-10-03 23:27:21 +02:00
Demetree Kallergis 30d2b5f07b iq_avx2: build the IQ2 sign table without a variable shift
A namespace-scope static initializer shifted a byte into place with << (8 * k), which is a
variable shift.  MSVC compiling this file with /arch:AVX2 emits BMI2 shlx for that - it assumes
anything with AVX2 also has BMI2, true from Haswell on and false of everything before it.

Because the table is static, the constructor runs before main(), so this faulted at PROCESS START:
strata.exe exited 0xC000001D with no output at all, not even for --help.  One shlx in the whole
linked binary was enough to make the engine unstartable on any pre-Haswell CPU under MSVC.

Storing the byte directly is the same 64-bit value on the little-endian targets this file is for,
and leaves no variable shift for the compiler to widen.

Found by building the engine for sm_61 on a Sandy Bridge-E (Xeon E5-2680) with
STRATA_EXPERIMENTAL_SM60=ON, which 0.1.31 added (#236).  Verified by disassembly: no shlx/shrx/sarx/
mulx/andn/bzhi/pext/pdep anywhere in strata.exe afterwards, and --help now runs.

This is independent of any AVX1 work - it is a plain startup crash on the CPU this was built on.

(cherry picked from commit 3fcaf03840)
2026-10-03 23:27:07 +02:00
Rafa b34cf81417 BF16 tensor-core path: default on for all of compute capability 7.x (Volta too)
Volta has FP16 tensor cores and no BF16 ones as well, so cuBLAS takes the same SIMT path for BF16 products there.
Suggested in review. Not measured on sm_70; STRATA_BF16_TC=0 turns it off.
2026-10-03 23:27:03 +02:00
Rafa 4dbc4c8b82 sm_75: run the prompt path's BF16 products on the FP16 tensor cores
Turing has no BF16 tensor cores, so cublasGemmEx on CUDA_R_16BF inputs falls back to a SIMT fp32 kernel
(magma_sgemmEx). On an RTX 2080 Ti that was the largest kernel of the prompt path, 20 % of a 4K prompt:
the hyper-connection down / up projections, the router and indexer rows, PLE key / value.

Gemm::bf16 now converts the weight and the activations (in row slices, into the instance's own scratch)
BF16 -> FP16, which is exact for every value inside FP16's range, and runs the existing FP16 GEMM (fp32
accumulate) on the tensor cores. Single-row products keep cuBLAS's GEMV. STRATA_BF16_TC=0/1 overrides;
the default is on for sm_75 only, so other cards run exactly what they ran.

New test gemm_bf16_parity: Gemm::bf16 against cuBLAS's BF16 product over the prompt path's shapes,
within fp32 rounding (worst relative difference 1.7e-5 on sm_75; 0 with the path off).

Qwen3.8-Flash-Next Q2_0, RTX 2080 Ti, i7-6700: prefill 877 / 1134 / 1153 / 1116 / 1009 t/s at
4K / 16K / 32K / 64K / 128K -> 1020 / 1337 / 1366 / 1312 / 1166.
2026-10-03 23:27:03 +02:00
Niko1221 37769d3aa1 setup: gfx1031 (RX 6700 XT) wording and a test (PR #524 follow-up) 2026-10-03 23:26:57 +02:00
Matt 94db2c877d forgot one spot to add in setup.py 2026-10-03 23:26:24 +02:00
Matt c198d8239a Added gfx1031 experimental support 2026-10-03 23:26:24 +02:00
Niko1221 088937b978 Merge PR #423 (maxfridbe): Intel Arc SYCL port of the engine, experimental 2026-10-03 23:26:15 +02:00
maxfridbe 63024cd848 sycl: the stream-all prompt walk by default when the VRAM holds >90% of the experts
It hung on the B70 until the stager/PLE event-wait fixes; it runs since and reads
Coder prompts faster (40K 1,106 -> 1,160, 128K 897 -> 920, 128K k8v4 1,006 ->
1,041, 256K 760 -> 780 tok/s; same output). It copies every non-resident expert,
so with a big host tier it loses (IQ2_XS, a quarter in the RAM mirror: 2,184
tokens ~560 -> 254 tok/s): generate.cpp hands the non-resident share to the
prompt path, which walks only below 10%. STRATA_PREFILL_STREAM_ALL=1/0 forces it.

Docs: the 40K prompt breakdown, and why the cluster kernels and Q4_0 XMX prompt
attention are not worth porting here; the 2K "regression" was session variance
(old and new builds A/B'd: 784-799 tok/s both).

Tested on the B70: Coder 2,184-token and 40K, IQ2_XS 19- and 2,184-token
outputs identical; IQ2_XS 562 tok/s (stream-all off by its share), Coder 40K
1,160 tok/s.
2026-10-03 16:32:22 -05:00
Chanyeong Lim 586367cb00 qsa_select: the top-k past the register kernel's reach on 1,024 threads with a histogram per warp (CUDA) - 9-12x at 262K-524K cells, a 243K-token prompt +26% on an RTX 3060
On CUDA the register kernel holds 33,792 blocks (~135K cells). Past it qsa_block_topk took the original kernel:
256 threads, each reading its own stretch of the scores on all six passes, one shared histogram updated with
atomics. The dispatch follows the capacity (--max-context), so with a context past ~135K that was every prompt
batch and every decode window on a card without the sm_75 active-bound dispatch (#512), whatever the prompt's
length, and on sm_75 every prompt batch past 33,792 blocks and every decode window.

block_topk_wide_kernel is the register kernel's layout (1,024 threads, a histogram per warp, warp scans) with the
keys read from memory:
- the four radix passes: thread t reads blocks t, t + 1024, ... - a histogram has no order, so a warp reads 32
  neighbours at a time;
- the count and the output: warp w holds `per` rows of 32 consecutive blocks, and the cells are written in the
  order (warp, row, lane); a row without a selected block is skipped.
The selection rule is the original kernel's (radix threshold, ties to the lowest index, cells ascending): identical
ids. One launch per call, no scratch memory, no capacity limit.

Dispatch (CUDA; HIP is unchanged and does not compile the kernel): where the blocks do not fit the registers the
new kernel, except a call that names fewer than 4,608 blocks (a prompt batch below ~18K cells), which keeps the
original kernel: its fixed cost is lower there. A decode window (no block count) takes the new kernel at any
context. The register kernel's range, the sm_75 active-bound dispatch and the sm_90+ cluster path are unchanged.
STRATA_TOPK_OLD=1 keeps the original kernel, as before.

qsa_topk_parity (new, with the kernel parity tests): the dispatched top-k against qsa_block_topk_ref on both sides
of the register kernel's reach, at short contexts under a long capacity and up to 524,288 cells, called as decode
and as the prompt path call it, with continuous scores, 64 score levels and equal scores.

RTX 3060 12 GB (sm_86), 256 queries with their block count under a 262,144-cell capacity (524,288 for the last
two), original -> dispatched:
  16K cells    0.199 -> 0.199 ms (the original kernel)
  32K          0.845 -> 0.328
  131K         4.70  -> 0.97
  262K        16.09  -> 1.71
  393K        26.02  -> 2.49
  524K        37.53  -> 3.24
4 queries without a count (a decode window): 0.031 -> 0.028 ms at 8K, 0.176 -> 0.083 at 131K, 0.309 -> 0.127 at
262K.

IQ3_XXS on that card (--resident-experts, --max-context 262144, --kv int8 --kv-resident 32768),
tools/needle_bench.py, STRATA_TOPK_OLD=1 against the default: tok/s of the prompt, and the prompt path's selection
phase (STRATA_PREFILL_TIMING):
  16,471 tokens    1004.5, 1016.2 ->  989.0, 1013.6       195 ->    195 ms
  31,970           1043.3, 1055.5 -> 1060.1, 1060.5       900 ->    731
  61,333            932.9         -> 1013.8             4,061 ->  2,428
  122,755           904.7,  904.2 ->  992.7,  989.6    20,019 ->  9,034
  185,729           819.7         ->  954.7            50,055 -> 20,761
  243,176           743.3         ->  933.7            96,326 -> 35,544
The needles are found in every run.
2026-10-03 23:25:56 +02:00
maxfridbe b7760573ec sycl: port upstream 0.1.38
3-way merge from the port's "main + PRs" migration to dpct of upstream 0.1.38
(prefill.cpp re-merged with the histogram diff: upstream's peer-device and fused
restructure kept, the port's edits carried over - the stager's GGUF job, the
stream-all gate, the fp16 NaN checks; generate.cpp: the pipelined profile fill
beside upstream's prefetching serial fill; mtp/verify: the SYCL host mapping).

- the PRs' header forks dropped: upstream has them now
- stubs: --peer-device (peer_experts.cpp; open refuses) and the fused int8 prompt
  kernels (moe_fused_stub.cpp; MMQ is not built here)
- off on SYCL: the sm_90 cluster greedy sampler and QSA top-k (fixups.py)
- fused_gr: dpct's undeduced kernel names filled in (fixups.py)
- STRATA_GDN_KEYHEAD stays opt-in on the port (upstream's gate is NVIDIA SM counts)
- version 0.1.38

Tested on the B70: build clean; native_grouped, iq_multi, gr, qsa, kv_hybrid,
quantize_act parity pass, qsa_prompt_attn's int8/fp16 pass (its new Q4_0
tensor-core cases are refused: not in the port); Coder short/long, IQ2_XS, 40K
outputs identical; 128K int8 KV streaming 892 / 66.8 tok/s; GR_DOWN_MAX4 neutral,
GDN_KEYHEAD 8% slower (stays off).
2026-10-03 15:13:06 -05:00
maxfridbe 733590721d Merge upstream main (0.1.38) into b70 2026-10-03 14:39:37 -05:00
benoit lange dbbc0d600e Layer split comment: KV streaming and images do run across a split
Reported on 2 x TITAN RTX (split 25, KV streaming, GPU image encoder, parking, --batch 4 --batch-groups 2).
2026-10-03 20:54:02 +02:00
Niko1221 73e71f40e0 Engine 0.1.39: the #577 file-tier regression fixed, the OpenAI Responses API (#451), #606 #620 #458 #533, PR batch; setup requires it 2026-10-03 20:05:44 +02:00
Niko1221 5fc49bdcac layer split trim: opt-in on HIP too (STRATA_STAGE_TRIM=1, PR #639)
The trim was on by default in the HIP builds. It now waits, as on CUDA, for the PR author's re-run of the release
branch on his cards; the default flips after that. --layer-split auto and one GPU were never affected.
2026-10-03 20:05:31 +02:00
Niko1221 8ac4b945a0 Merge branch 'f-139-big' into f-139-rel
# Conflicts:
#	serve/server.py
#	setup.py
#	src/program/generate.cpp
2026-10-03 20:05:05 +02:00
Niko1221 3ed9dafa1e Merge branch 'f-139-prs' into f-139-rel
# Conflicts:
#	setup.py
#	src/core/expert_source.cpp
2026-10-03 20:04:42 +02:00
Niko1221 46a4ef5cb2 Merge branch 'f-139-resp' into f-139-rel
# Conflicts:
#	serve/server.py
2026-10-03 20:04:17 +02:00
Niko1221 92ca0c7fbd Merge branch 'f-139-ux' into f-139-rel
# Conflicts:
#	docs/DETAILS.md
#	serve/server.py
2026-10-03 20:03:53 +02:00
Niko1221 ed3bd791ff Merge branch 'f-139-eng' into f-139-rel 2026-10-03 20:03:37 +02:00
Niko1221 19ff212d1c serve: a checkpoint that fails on the GPU sync says the GPU stopped responding (#613)
"saving a conversation checkpoint failed" was the only text when the checkpoint's
device sync failed - a GPU hang that Windows then resets (VIDEO_ENGINE_TIMEOUT), not a
checkpoint problem. The error now names it: "...: the GPU stopped responding before it
(<error>) - a GPU hang; on Windows the driver is then reset". Error text only.
2026-10-03 19:36:12 +02:00
Niko1221 fd5d665225 tools: conversation_restore_speed.py, decode after a conversation-cache restore vs live (#528)
Two private engines, the same conversation: the baseline keeps it live, the candidate
parks it (an unrelated request in between, a re-rendering client, or two long
conversations taking turns) and restores it. Each turn's greedy tokens must match and
its decode speed must be within --tolerance (15%) of the live turn's. Pure logic
tested without a GPU (tools/test_conversation_restore_speed.py).

#528 did not reproduce on the RTX 5070 with it: Q2_0 37K tokens (--kv-resident 16384)
and IQ3_XXS 50-75K tokens (--kv-resident 32768) decoded at the live turns' speed after
a restore, with the same tokens.
2026-10-03 19:29:26 +02:00
Niko1221 c3c034745b prefill: step diagnosis and a HIP host-DMA switch for the gfx1201 prompt stalls (#579 #613 #541)
- The per-layer wait for the router ids names itself in a stall report ("waiting for
  the GPU (attention, router) at layer"): a GPU stall reads apart from a host one.
- STRATA_PF_STEP_SYNC=1 (opt-in): the compute and copy streams are waited for after the
  K/V staging, the K/V append and each layer; a step over 250 ms is logged with its
  layer and chunk, and a stall names the step.
- STRATA_KV_HOST_DMA=1 (HIP only, opt-in): with KV streaming the prompt path's append
  writes the staging pool and the resident slots only, and one DMA copies the chunk's
  blocks to the host copy - no kernel writes host memory over PCIe. Same bytes for
  every reader (the staged first block is complete; past the chunk nothing is read
  before a later append writes it).

Q2_0 on the 5070: the same tokens with STRATA_PF_STEP_SYNC=1 as without (and as 0.1.38).
2026-10-03 19:12:21 +02:00
Niko1221 27db7cae1d verify: opt-in handshake trace for the gfx1030 timeouts, HIP A/B switches (#649)
STRATA_VERIFY_TRACE=1 records each verify window's handshake on the host (window
start, launch, each layer's ring and service, the final sync, a timeout, the release
and how long the GPU took to drain after it) with the seq / flag / A / B words, and
GPU breadcrumbs: the profiler's stage stamps per layer and token group, written to
mapped memory so they read while the GPU hangs. A timeout prints them before and
after the release; the serve watchdog's stall report (Verifier::diag) prints them too.

HIP only, opt-in, for the reporter's A/B: STRATA_VERIFY_COHERENT=1 allocates the
handshake words and rows with hipHostMallocCoherent; STRATA_DOORBELL_STORE=1 has the
GPU store each step's ring (known at capture) instead of read-modify-writing it over
PCIe. CUDA builds and the default path are unchanged (Q2_0 on the 5070: the same 96
tokens with and without the trace as 0.1.38; a forced stall dumps the breadcrumbs up
to the withheld flag).
2026-10-03 19:12:20 +02:00
Niko1221 fc38595c65 setup: recommend the hybrid worker count only with more E-cores than P-cores (#642)
docs/AMD_HIP.md's gfx1030 report measured an i7-13700KF (8P + 8E) at 38-42 tok/s with
all 15 workers against 36 with 8, so a CPU with no more E-cores than P-cores keeps the
engine's own count; the E-heavy chips the fork measured (i9-14900KF: 15 of 23 faster)
get the recommendation.
2026-10-03 19:12:20 +02:00
Niko1221 89bad9a4ec Hot VRAM resize, opt-in: a segmented expert cache, VRAM <reserve>, POST /v1/vram (#533)
--vram-elastic (the config's "vram_elastic": true) allocates the expert cache as one
reserved address range backed by physical segments (CUDA virtual memory management,
512 MiB each, --vram-segment-mib), so every slot keeps its address. Between
requests, the engine command `VRAM <reserve_mib>` gives the last segments back to
the driver until that much VRAM is free (their experts become CPU misses, the prompt
path's loan moves down and its chunk shrinks to fit), or maps them again and puts
the same experts back when more is free. `VRAM` alone: the start's reserve. The
server's POST /v1/vram {"reserve_mib": N | null} sends it after a running request,
keeps it for an engine that is unloaded, and /v1/status shows the cache's size.
Never automatic. One NVIDIA GPU only (no layer split, helper caches, --peer-device
or the resident low-RAM mode); HIP refuses the flag.

RTX 5070, Q2_0 (4.8 GiB cache): reserve 6000 -> 4.3 GiB freed in 78 ms, decode
44 -> 33 tok/s; grown back in 92 ms, the answers token for token the ones before.
Without the flag the cache is the one cudaMalloc it was (same answers with and
without the flag until a VRAM command).
2026-10-03 18:52:00 +02:00
Niko1221 1b3eac7f8a serve tests: the long fixture answer alternates two tokens (one repeated token is now ended at 256, #606) 2026-10-03 18:50:36 +02:00
Niko1221 0b48acea33 docs, setup help: --draft-vocab fr and its measured acceptance (#597)
IQ3_XXS on the RTX 5070, temperature 0, 256 tokens, 8 French prompts (topics outside the corpus), 2 English and 2 code
prompts, arms alternating, 2 passes each: drafts accepted in French 0.505 (en) / 0.507 (cjk) -> 0.597 (fr), higher on
all 8 prompts and in each pass; English 0.610 -> 0.629, code 0.772 -> 0.779. Decode speed was not measurable here
(builds ran beside it); the reporter measured 141 -> 158 tok/s in French on an RTX 5090.
2026-10-03 18:45:50 +02:00
Niko1221 a20a5d480e strata_mcp: UD-IQ4_XS in the built-in model table, as in setup.py (#621) 2026-10-03 18:40:42 +02:00
Niko1221 4e413b344e File tier: the #577 re-check's log line on Windows only (the unbuffered reads exist there alone) 2026-10-03 18:37:11 +02:00
Niko1221 5b735eccb2 setup: Unsloth's UD-IQ4_XS as an experimental choice (#621)
UD-IQ4_XS sits between IQ3_S and UD-Q4_K_XL: IQ3_S gate/up experts (IQ4_XS in one layer) with IQ4_NL downs (Q8_0 in
five layers), 59.5 GB of them, and UD-Q4_K_XL's dense side. The engine's kernels already take these formats; it was
packed (iq_pack.py --compat-bf16) and run on the Strix Halo, not yet on NVIDIA.

- MODELS["UD-IQ4_XS"] in the unsloth family: three shards pinned at the same revision 38bb39e with their sizes and
  SHA-256 (the Hub's LFS pointers), the RAM budget like UD-Q4_K_XL (budget, one GPU, no images, --compat-bf16 pack,
  no experts.bin), engine 0.1.38 or newer (the fused-layout fix for packs not every layer of which is covered).
- A model can have its own shard pattern and count (model_file / model_shards); budget_model() tells which Unsloth
  model a config runs, for the #498 multi-GPU messages and RAM need.
- The AMD question (#429) stays for UD-Q4_K_XL only (nvidia_only): UD-IQ4_XS's formats have AMD prompt kernels.
- --gguf-dir accepts UD-IQ4_XS files (#444's list says so).
- UNSLOTH_Q4.md: its files, what setup does, what is known (Strix Halo), and the BF16 rounding of the hyper-connection
  projections that every --compat-bf16 pack has (not changed here). MODELS.md: a paragraph.
- test_setup_unsloth: pins, budget, a mocked install, the engine check, no AMD question, the config read back.

UD-Q4_K_XL's install, its tests and every other model's config are unchanged.
2026-10-03 18:36:44 +02:00
Niko1221 8cd360707c web: the Model settings card's Save is the primary button (#564) 2026-10-03 18:35:47 +02:00
Niko1221andDavid 0703ec90e0 serve: the OpenAI Responses API, POST /v1/responses (#451)
Stateless, on the chat path: a Responses request becomes the chat template's
messages, tools and kwargs, runs through Service.run, and its reasoning, text
and tool calls come back as output items and the official typed SSE events
(response.created ... response.completed / incomplete / failed).

- input as a string or items (messages, reasoning, function_call,
  function_call_output, custom tool calls); instructions and leading developer
  messages make one system message; tool results are put in call order
- function, namespace (Codex's MCP/agent tools) and custom tools; hosted tools
  are left out with a log line
- reasoning.effort -> reasoning_effort, max_output_tokens, text.format
  json_schema/json_object through the structured output path
- reasoning returned as reasoning_text (and as opaque encrypted_content when
  asked) and replayed into the prompt, so Codex's next turn reuses the cache
- errors in the Responses format; same API key, Host and Origin checks as /v1
- a response.in_progress event every 15 s while a long prompt is read
  (Codex's idle timeout ignores SSE comments)
- docs: DETAILS.md section with a Codex config.toml

Based on #630 by CC-David-CC (the event assembler, namespace tools, call-id
ordering of results), without its opt-in flag, replay key and crypto
dependency, strict-function and JSON-format refusals, or the second
summary generation pass. Tested with Codex CLI 0.160.0 and openai 2.15.0.

Co-authored-by: David <[email protected]>
2026-10-03 18:35:35 +02:00
Niko1221 4546bf7c03 web: a Model settings view for documented run config keys (#564)
The About tab's Model settings card reads GET /config and saves through
POST /config: the sampling defaults, reasoning_budget_tokens,
fit_max_tokens, anthropic_thinking, effort_position, aliases,
idle_unload_s, lazy_load, engine_silence_s, api_monitor, open_browser
and --vram-reserve-mib (serve/runconfig.py). Every value is checked
first (one bad value changes nothing), only the named keys change, every
other key of strata-<model>.json stays as it is (as setup run again
keeps them, #629), the earlier file is kept as .bak, and the change is
used from the next start. POST takes JSON from Strata's own page only,
like /settings, and the API key when one is set; the network, key, MCP
and program keys are not editable there.
2026-10-03 18:35:02 +02:00
Niko1221 0b1c763a75 Docs: the five reading errors #604 found (the sixth, the n-gram table's unbuffered reads, is in #605's commit)
- MODELS.md: the RAM rule is the experts + ~10 GB (setup's arena_gb), not shard 1 + 10 GB; the sizes per model.
- DETAILS.md: prompts are read in chunks of up to 8,192 tokens (32,768 opt-in), not 2,048; Q2_0's AVX-512 pack is
  ~40 GB on disk = 34 GB of experts plus the dense weights.
- README: the NVIDIA speed table says which engine measured which row (Q2_0 0.1.36, the others 0.1.26).
- expert_cache.hpp: the comment that the cache "does not yet compute anything" is gone.
2026-10-03 18:32:16 +02:00
Niko1221 13d0e2f4a3 SECURITY.md: how to report privately, and what the server exposes (#544)
Private reports through GitHub's private vulnerability reporting; the
server's protections as of 0.1.38 (127.0.0.1 by default, the API key,
the Host and Origin checks, CORS, MCP tools and the request monitor
opt-in), with DETAILS.md for every setting. README links it.
2026-10-03 18:31:56 +02:00
Niko1221 a9fe9236bf web: a Conversation cache card in the Monitor tab (#596)
/metrics gains "conversation_cache": the parked conversations, their
bytes, parks/restores/evictions and the last switch, read from the
engine's own log lines ("conversation cache: parked/restored ...") from
the start of its current run on; the budget and slots from its INFO line;
and the prompt tokens reused in the last request and since the start.
The card shows the parked slots and memory when --conversation-cache-mib
is on, the reuse lines always, and how to turn parking on when it is off.
2026-10-03 18:31:20 +02:00
Niko1221 a74c61f608 Document the decode window profiler (STRATA_VERIFY_PROFILE + STRATA_DECODE_TIMING); --gpu-stages points to it on a native pack (#610)
--gpu-stages replays per-layer graphs, which a native (IQ) pack does not capture, and refused with "not captured
with the split". The serve path already times a native window's stages: STRATA_DECODE_TIMING=1 prints the
per-request decode split and STRATA_VERIFY_PROFILE=1 adds the GPU stages. DETAILS.md now says how to read them, and
--gpu-stages on a native pack says to use them.
2026-10-03 18:31:07 +02:00
Niko1221 b591a45bd7 Hit rate: say the PCIe share beside it (#588)
The decode hit rate is the VRAM share of the experts the pool looked up; the routed experts the GPU reads over PCIe
(--pcie-frac) or another GPU computes are in neither count, so raising --pcie-frac raised the "hit rate" while the
decode got slower. Its meaning stays; now that share is said beside it:

- engine: DriveState::offload_entries counts those entries; the serve line adds "; N more read by the GPU over
  PCIe or from another GPU (X% of all M routed)", and the DONE line a 16th field (an older server ignores it).
- server: /metrics' requests get "pcie_share" (None from an older engine), the console's done line "(+X% of the
  routed experts over PCIe)", and the Monitor's column is "VRAM hit rate" with "+X% PCIe" after it.
- DETAILS.md says what each means.

No number changes; tokens are unchanged.
2026-10-03 18:27:35 +02:00
Niko1221 29181ca203 docs: the layer split's per-card dense weights (PR #639), STRATA_ARENA_MMAP (PR #640), make_profile --reorder (#587) 2026-10-03 18:27:29 +02:00
Niko1221 c9dbd8603c Windows Pascal/Volta source build: link the shared CUDA runtime only (#585)
CMake links CUDA code with cudart_static by default and the targets also link CUDA::cudart (cudart.lib); MSVC with
CUDA 12.x (the STRATA_EXPERIMENTAL_SM60 build for sm_60/sm_70) then fails with LNK1169. That build (MSVC +
STRATA_EXPERIMENTAL_SM60, no CMAKE_CUDA_RUNTIME_LIBRARY given) now sets CMAKE_CUDA_RUNTIME_LIBRARY Shared, the
reporter's verified fix. The ready-made engine and every other build are unchanged. INSTALL.md: where github.com
cannot be reached, third_party/llama.cpp at the pinned commit can be put there by hand.
2026-10-03 18:26:04 +02:00
Niko1221 9eceb375ab serve + engine: opt-in "effort_position": "end" keeps the cached conversation when the effort changes (#458)
The effort's instruction is the first thing the template renders, so a
request that only changes reasoning_effort (or turns thinking off) read
the whole prompt again. With "effort_position": "end" in the run config
the server renders every prompt's start as the default effort's and puts
a low/medium effort in a short system turn right before the answer
(thinking off: just the template's empty thinking block); the rendering
is template-agnostic (history + turn + the generation prompt).

Engine: --tail-role-token ID (default -1, off) moves the turn checkpoint
in front of such a trailing turn, so it holds the conversation and not the
effort text; INFO reports tail_role_token. The server passes the id of
"system" only when the engine binary knows the flag, and says so when it
does not. Without the key nothing changes: the same prompt ids, no flag.
2026-10-03 18:26:01 +02:00
Niko1221 1d789a14c0 STRATA_ARENA_MMAP: write experts.bin only when the drive has room (PR #640 follow-up)
The first mapped start writes the whole arena (25 GB for the Coder) next to the pack. A drive without that much free
space filled up before the write failed. Now the start checks the free space first (the arena plus 2 GiB to spare);
without it, it says so and keeps the arena in RAM for this start. Linux opt-in only; nothing changes without the env.
2026-10-03 18:25:56 +02:00
Niko1221 f1281f7fd7 layer split trim: on by default in the HIP builds, opt-in on CUDA (PR #639 follow-up)
The trim was measured on 2x MI50 (gfx906) only; nobody has run it on NVIDIA multi-GPU, where CUDA-only paths could
still read another stage's dense weights on a card that no longer holds them. The HIP builds trim with explicit split
points as the PR does (STRATA_STAGE_TRIM=0 keeps the full copies); the CUDA build keeps the full copies unless
STRATA_STAGE_TRIM=1. --layer-split auto and one GPU are unchanged everywhere.
2026-10-03 18:25:56 +02:00
Niko1221 64b8d5dd31 setup: STRATA_NVCC picks the CUDA toolkit; CUDA_HOME is looked at; glibc 2.43 + CUDA 12.9 and gcc 15 documented (#601)
find_nvcc takes the newest toolkit it finds, so with CUDA 12.8 and 12.9 installed, 12.9 was always used - and 12.9's
math headers do not compile with glibc 2.43 (Ubuntu 26.04). STRATA_NVCC=<nvcc> is now the only one considered (a
warning when the file is missing, or when it is too new for the Pascal/Volta build). CUDA_HOME is a candidate like
CUDA_PATH. TROUBLESHOOTING.md: the two build errors and what to do (g++-14 for gcc > 14; CUDA 12.8 or 13.x for glibc
2.43). Without STRATA_NVCC nothing changes.
2026-10-03 18:25:30 +02:00
Niko1221 16a6d77ed4 The expert arena checks the host RAM before it is allocated; the RAM probe reads cgroup v1 too (#633)
The pinned expert arena (the default tier) was allocated without looking at the RAM: on Linux the anonymous mapping
succeeds whatever the host has, and a container whose memory limit is below the arena was killed by the OOM killer
part-way through the load, without a message.

- detail::host_available_memory: the file tier's probe (MemAvailable lowered to the tightest cgroup v2 limit's room),
  now with its files as parameters (tested on fake trees), cgroup v1's memory controller (memory.limit_in_bytes -
  memory.usage_in_bytes), and no cgroup line at all meaning MemAvailable alone (it was "cannot determine", which
  refused a --resident-budget-gib on a v1 host). It also returns the tightest hard limit itself.
- ArenaExpertSource::open, after the size check and before the allocation: a hard cgroup limit below the arena is
  refused with both numbers (a certain OOM kill); less RAM available than the arena is a warning with the numbers
  and what runs with less (--mmap-experts with --resident-budget-gib), and the load goes on. Not for a shared arena.
- file_expert_source_test: v2 limit / max / malformed / missing, v1 limit / unlimited / not mounted, no cgroup.
2026-10-03 18:24:31 +02:00
Niko1221 0d6e03fa0b docs: AMD_HIP.md - a calibration run by hand on Linux HIP is kept for its card (#566) 2026-10-03 18:24:06 +02:00
Niko1221 935ac87a54 --ple-io direct on a rotational disk: warn at start, setup keeps the table in RAM, the stall report counts disk waits (#605)
On a 7200 RPM disk the default --ple-io direct's random reads of the n-gram table stalled prompts past the 60 s
watchdog, and the stall report looked like any other engine stall.

- Engine (Linux): at start with --ple-io direct, the table's disk is looked up in sysfs (queue/rotational); on a
  rotational one it warns and recommends --ple-io ram or an SSD (not on WSL, whose virtual disk says rotational).
- Stall report (Linux): the engine's threads in state D and their wchan ("threads waiting on the disk (state D): 16
  of 35 (blk_io_schedule x16)"), with what that means.
- Setup (Linux): a model on a rotational disk gets --ple-io ram when the RAM holds the table beside the model,
  otherwise a warning that recommends an SSD. Nothing changes on an SSD.
- DETAILS.md: --ple-io direct is for SSDs (it reads unbuffered, not through the OS cache), and a troubleshooting row.
2026-10-03 18:22:16 +02:00
Niko1221 c16f31f850 serve: a literal <think> / </think> in a message is encoded as text (#537)
The tokenizer matches <think> and </think> as their special tokens even
in plain text (type 4, as llama.cpp does), so a user quoting "</think>"
handed the model a real end-of-reasoning token and the answer came back
empty. Before the template is rendered the tags in message text (user,
tool, system, assistant history, tool call arguments, tool descriptions)
are swapped for private-use marks; after it, those spans are encoded as
ordinary text (Tokenizer.encode's new plain= spans), the template's own
markers stay special. An assistant turn that opens with its own
<think>...</think> block keeps that block. A prompt without the tags is
encoded exactly as before; count_tokens uses the same path.
2026-10-03 18:21:55 +02:00
Niko1221 19dbffde75 setup: a calibration on Linux HIP names the AMD card and is reused for it (#566)
hardware_key, the settings file's key for a saved calibration, read the cards with nvidia-smi's list: on an AMD PC
every card was "?|0GB" (two different cards shared one calibration), and on a PC with an NVIDIA card too a HIP index
named that NVIDIA card or stopped setup ("there is no GPU N"). A HIP config's cards now come from amd_gpus, in HIP's
numbering, with the architecture in the name (an RX 7900 XTX and an RX 7900 XT are both gfx1100; a card without a
product name is known by its arch). Setup reuses a saved calibration on Linux HIP as on NVIDIA (setup_calibration);
Windows HIP keeps the defaults for now. The tuning is still offered on NVIDIA only - a `./setup.sh --calibrate` on
HIP runs it by hand, and each control is verified on HIP before setup offers it.

The NVIDIA key and the settings file's format are unchanged. Tests: tools/test_setup_amd.py CalibrationKey (7).
2026-10-03 18:20:33 +02:00
Niko1221 5c50fbbcf2 setup: --draft-vocab fr - the English/code subset plus the tokens of French text (#597)
French answers drafted poorly with the shipped subsets: 23.6% of the token occurrences of French text fall outside
draft_vocab_en.bin, and the draft head cannot propose those (no subset adds the accented words and word pieces).

- tools/draft_vocab.py: a coverage mode. --corpus FILE... adds to the base the most frequent tokens of the corpus that
  together cover --coverage (default 0.99) of its occurrences, and prints the share outside the base and the new list.
- data/draft_vocab_fr.bin: draft_vocab_en.bin plus 5,686 tokens (46,211 ids), from 10 French Wikipedia articles
  (France, Paris, Napoleon Ier, Langue francaise, Union europeenne, Litterature francaise, Cuisine francaise,
  Economie de la France, Revolution francaise, Seconde Guerre mondiale; 1.24 M characters, 326,926 tokens) at 0.99:
    python tools/draft_vocab.py --gguf <IQ3_XXS shard 1> --base data/draft_vocab_en.bin --corpus <the articles> \
        --coverage 0.99 --out data/draft_vocab_fr.bin
  Outside the list on that corpus: 0.74% (23.65% with en).
- setup.py: "fr" in DRAFT_VOCABS / --draft-vocab (~151 MiB head on IQ3_S, between en and cyrillic). The sha256 check
  knows it as a shipped subset, so a later --draft-vocab cjk/en replaces it and a subset made by hand stays.
- tests: tools/test_draft_vocab.py (the coverage mode), tools/test_setup_draft_vocab.py (fr replaces a shipped subset
  and back, keeps the en ids first in their order, its MiB estimate).

The default subset (cjk) is unchanged.
2026-10-03 18:19:49 +02:00
Niko1221 bb162e2edf serve: end a reply that repeats one token 256 times in a row (#606)
A broken state (or a model in a loop) can answer one token forever: #606 streamed 36,689 tokens of "!" for four
minutes, because a request without max_tokens gets the whole remaining context. The server now ends such a reply
at 256 identical tokens in a row with finish "length" and a line in its window saying what to do if it repeats on
a new request. "repeat_stop_tokens": N in strata-<model>.json sets the run (0 = off). Nothing changes for a reply
without such a run.
2026-10-03 18:18:49 +02:00
Niko1221 2b726ba683 q8_1 activations: keep the block's fp16 scale and sum finite (#606)
Both q8_1 activation quantizers (iq_kernels.cu q8_1_store, native_mmvq.cu native_quantize_q8_1_kernel) stored the
sum of a block's 32 raw activations as fp16: past 65504 (one massive-activation dimension is enough) it rounded to
inf, and d = amax / 127 did past amax = 8.3M. The dot products then read inf * 0 = NaN, and a NaN in the residual
answers one token forever (ggml-org/llama.cpp#23606 is the same defect).

Now both are clamped to the largest finite half (and the values to the int8 range they then exceed). A block that
was finite before is stored bit for bit as before - values in (65504, 65520) round to 65504 anyway, and a finite
block's |x / d| is at most 127 - so the default output only changes where a block overflowed (and was NaN). A NaN
input stays NaN, so STRATA_DBG_NAN still finds it.

iq_multi_parity checks both quantizers against the 0.1.38 formula on a host transcription: every finite block as
before, and three overflowing blocks (sum 96,000, sum -69,984, amax 2e7) stored finite.
2026-10-03 18:18:49 +02:00
Niko1221andHardin22 ad0df801ae setup: recommend P-cores + half the E-cores as CPU expert workers on hybrid CPUs (#642)
On a hybrid CPU (Intel 12th gen+, AMD Zen 5 + Zen 5c) setup writes --pool-workers
N into the run config: the performance cores but the host loop's one, plus half
of the efficiency cores. An E-core runs the expert kernels ~2.2x slower and each
layer waits for its slowest part; Hardin22 measured 15 workers at 165 / 116 tok/s
against 106 / 84 with all 23 on an i9-14900KF (#642). A recommendation only: the
line is in the config, a saved calibration's measured count wins, and a CPU whose
cores are all alike gets the same config as before.

The engine's pool, with every core allowed (the default affinity), now orders the
P-cores first on a hybrid CPU, so a smaller pool runs on the P-cores and the first
E-cores rather than on whatever the OS numbered first (from Hardin22's fork).
Non-hybrid CPUs: unchanged.

Co-Authored-By: Hardin22 <[email protected]>
2026-10-03 18:17:18 +02:00
Niko1221 021f544c60 setup: --vision-tokens N, the most image tokens a picture becomes (#625)
Kept in the run config's vision.max_tokens (the server already passes it
to the encoder); a setup run again keeps it for the same encoder device.
More than the default is allowed with a note on the encode time. Without
the flag the config is as before. DETAILS.md: vision.mmproj can point to
a Q8_0 mmproj of this model.
2026-10-03 18:15:55 +02:00
benoit lange 2871ff4b68 Parking with a layer split: the draft ring with the last stage, on its GPU; guards; trim log
- The draft layer's K/V lives on the last stage's GPU (the drafter is loaded there); its save, ring restore and
  verification now run with that stage's image under that device, instead of with stage 0's image on GPU 0, where
  the ring restore kernel ran against another GPU's memory (seen in Niko1221/Strata#653, which places it the same way).
- Parking with a layer split on one GPU (--split-device 0) is refused at start: untested.
- The whole-session validate refuses an image with stage images; clearer message for stage parts in live.
- --trim-stage-weights says which layers each GPU loads, and fails when index.txt cannot be read.
- conversation_snapshot_test: the whole-session refusal; parking_test.py runs with STRATA_SNAPSHOT_VERIFY=1.
2026-10-03 18:14:59 +02:00
Yannick Loth 90d3251790 make_profile: --reorder so a trace can rank ahead of a complete base
tools/make_profile.py builds the ranking as the base's order, then the
trace's pairs, then the fill. The base is only appended to, so --base can
never move a pair the base already ranks - and the shipped
data/expert-profile.bin ranks all 24,576 pairs, which makes a trace a
no-op:

  wrote ...: 24576 ranked pairs (24576 from the base, 0 from the traces, ...)

So the documented way to seed a profile from --dump-routing (rank the
pairs your workload routes most) silently did nothing with the shipped
base; only --no-base changed anything, and that drops the base's ranking
entirely.

Add --reorder: rank the trace's pairs first (most frequent first), then
let the base fill the rest, then the fill. The default is unchanged. The
ranking moves into a rank_profile() so it can be tested without a model;
tools/test_make_profile.py covers the no-op, --reorder, --no-base, the
frequency/tie order and an end-to-end run over a complete base. On this
host's coding trace the same command now puts 5,808 trace pairs first.
2026-10-03 18:14:52 +02:00
Niko1221 9b6515b37c setup: --no-browser / "open_browser": false keeps the chat page from opening (#609, #631)
--no-browser (on a start or at setup) saves "open_browser": false in the
model's run config; start() and run-<model>.bat/.sh then leave --open
out, and the server ignores --open when the config says so (a start
script written earlier still has it). --browser undoes it. Without the
flag the config, the command and the script are as before.
2026-10-03 18:14:39 +02:00
Niko1221 35c2bf9d9d adaptive swaps: gather the pin spans only when they are pinned (PR #640 follow-up)
The adaptive swap loops called srcp->blob() for every swap to collect the spans pin_blobs locks, on every build -
pin_blobs is a no-op except on Linux AMD with STRATA_ARENA_MMAP=1. blob() is not free: it counts reads and the file
tier (--mmap-experts) may assemble the blob, a second time for the copy. pin_blobs_on() now guards the gathering, so
CUDA and the runs without STRATA_ARENA_MMAP do exactly what 0.1.38 did.
2026-10-03 18:14:32 +02:00
Niko1221 5fc2afa9ce layer_split: check it before the start, accept a JSON list, say the format with an example (#644)
"layer_split" is the first layer of each later GPU ("24,36,42" for 4 GPUs), not a count of layers per card. A
value such as "24,16,12,12" failed the engine's check after the start began, and a JSON list reached the engine as
"[24, 16, 12, 12]".

- server.py layer_split_value: "auto" (default), a comma string or a JSON list of one rising number per GPU after the
  first, from 2; anything else stops the start with the format and an example for that many GPUs.
- The engine's message says the same, with the value it got.
- MULTI_GPU.md and setup's --layer-split help say it.
2026-10-03 18:14:23 +02:00
JeanP00l 6149efd3a4 STRATA_ARENA_MMAP=1: the expert arena as a read-only mapped file (Linux), for small-RAM machines
The host expert arena is normally read into pinned (locked) RAM. On a machine whose GPUs already hold most
experts, that locks memory the CPU never reads: with the Coder (25 GB arena) on 2x 16 GB GPUs and 32 GB of RAM,
~1 GB stayed available at 128K context, the kernel swapped, and a multi-turn checkpoint took 25-80 s.

With STRATA_ARENA_MMAP=1 (opt-in, Linux; off by default, nothing changes without it):

- the first start writes the arena to the pack's experts.bin (padded by one blob so a whole-slot copy may start at
  any expert); later starts map it read-only, not locked, not pinned. The page cache keeps what the CPU pool and
  the prompt path read and gives the rest back under pressure; a dropped page is re-read from the file, so no
  result depends on what is resident. The GPUs get no mapped alias of it: run with --pcie-frac 0;
- after the VRAM caches are filled, the pages of experts a GPU holds are handed back (MADV_DONTNEED,
  STRATA_ARENA_RELEASE=0 keeps them) and the rest are prefetched (MADV_WILLNEED); an adaptive swap releases the
  expert that went to VRAM and prefetches the one that came back;
- HIP: ROCclr copies a pageable source of 1 MiB or more by locking its pages in place and keeps them locked, which
  undid every release. The engine raises GPU_PINNED_MIN_XFER_SIZE (an explicit setting wins) so such copies
  stage through ROCclr's own buffers, and locks an adaptive swap's source pages itself only until the copy lands
  (the page ranges are merged first: a copy from a range only part of which is registered fails);
- STRATA_RSS_TRACE=1 prints the process's RssFile at the startup steps (madvise reports success on locked pages
  and frees nothing; RssFile is the honest check).

The existing --mmap-experts refuses native packs (the Coder); this path is for them.

Measured on 2x AMD Instinct MI50 16 GB + 32 GB DDR4 (gfx906 port, Coder IQ1_M, 128K context, layer split):
RAM available while serving ~1 GB -> 25 GB; multi-turn re-read of a checkpoint 25-80 s -> <= 3.2 s; decode
unchanged (49.06 vs 49.16 ms per verify window). Not measured on NVIDIA (pin_blobs is a no-op there).
2026-10-03 18:14:12 +02:00
Niko1221 464ca57d7f layer split trim: CUDA0 keeps every layer's router with --mmap-experts (PR #639 follow-up)
The file tier's routing-aware prefetch (RouterLookahead) copies all layers' ffn_gate_inp.weight from CUDA0's arena.
With CUDA0 trimmed to its own layers it found them missing and turned itself off ("the routers are not BF16 in the
arena"). CUDA0 now keeps the routers (~2.5 MiB a layer) when --mmap-experts is on; the other stages and the runs
without --mmap-experts trim as before.
2026-10-03 18:14:12 +02:00
JeanP00l d95805c61a layer split: with explicit split points each GPU loads only its own layers' dense weights
Without this every stage of a layer split keeps a full copy of the dense weights (~3.4 GB for the Coder),
although it only ever reads its own layers. That VRAM goes to the expert cache instead.

- the canonical arena of each GPU skips the `blk.N.*` tensors of layers outside its range (PLE tensors stay
  everywhere), read from the pack's index.txt;
- NativeDense::set_layer_range limits the native projections the next `load` uploads the same way;
- only with explicit split points (`--layer-split 27`); `auto` and a single GPU are unchanged;
  STRATA_STAGE_TRIM=0 keeps the full copies;
- one log line per GPU says what it loads, and a later stage logs its free VRAM before the cache is sized.

Measured on 2x AMD Instinct MI50 16 GB (gfx906 port, Coder IQ1_M, 128K context, --layer-split 27):
experts held in VRAM 8,819 -> 10,626 of 12,288, VRAM hit rate 95% -> 98%, decode on a 17K-token agent prompt
39.2 -> 41.7 tok/s. The trimmed tensors are never read by that GPU.
2026-10-03 18:13:54 +02:00
Niko1221 e294e0109b setup: running it again keeps the run config's keys it does not write (#629)
A re-run for an installed model (another --context, say) rewrote
strata-<model>.json from scratch and dropped the user's sampling,
mcp_servers, mcp and other blocks. Setup now carries over every key it
does not write (and env/vision entries of the user's own, such as a Q8_0
mmproj), keeps the earlier file as strata-<model>.json.bak and says what
it kept and which hand-added engine options it did not. A copy set up
like an earlier install carries them over from that install's config.
A first install writes the same config as before.
2026-10-03 18:13:28 +02:00
Niko1221 502c7296c9 Load the native head and the logits before the expert arena; name the free VRAM when they fail (#620)
The native head's cudaMalloc ran after the expert arena had registered ~45 GiB of host pages. WDDM then refused it
on a 16 GB card with the desktop on the iGPU ("native head upload: out of memory" with GiBs free) - the drafter is
loaded before the arena for the same reason. Now the head and the logits buffer load right after the drafter, still
before the expert cache is sized, so the slots are the same. The head's, the drafter's and a split stage's head
failures print "(N MiB of M MiB VRAM free on this GPU)".

setup: a context of 64K or more whose KV streaming does not fit the RAM test now says so (it was silent, and a
regenerated config lost --kv-resident without a word).
2026-10-03 18:12:58 +02:00
David b6d60f01b8 serve: read the /load and /unload body before replying (#630)
The server replied to /load and /unload without reading the request body; on
Windows, closing a socket with unread data sends a TCP reset, so the client saw
a connection reset instead of the answer. Read the (bounded) body first.

Taken from #630 by CC-David-CC.
2026-10-03 18:12:54 +02:00
Niko1221 d161e25ff6 File tier: decide unbuffered reads from the expert bytes it reads, again once the RAM copy is built (#577)
0.1.38 made the choice before the resident set existed, from the budget asked for, against every shard's bytes
(dense weights and the PLE table included). On a 96 GB PC with UD-Q4_K_XL (budget 72 GiB, 48.94 GiB really
resident) that read 83.0 - 72 - 4 = 7 GiB of room against 103.7 GiB of files, so every refill after a prompt read
the drive: prompts 15-40% slower than 0.1.34.

- platform::file_cache_keeps(avail, arena, read): the decision, unit-tested in platform_memory_test with the
  reporter's numbers and the 32/64 GB PCs of #357/#362.
- set_unbuffered: the arena is at most every expert's bytes, and the cache has to keep only the experts outside it.
- recheck_unbuffered, after pin_cache_complement: the same decision from the RAM the copy really holds and the
  expert bytes outside it; switches either way (startup, nothing reading) and logs the numbers.
- The 32 and 64 GB PCs still read unbuffered (the profile fill and the copy too, as before).

Same tokens either way: only how the same bytes are read changes.
2026-10-03 18:12:53 +02:00
Niko1221 b92b78b092 serve: a malformed "tools" value is a 400, not a dropped connection (#592)
openai_to_messages / anthropic_to_messages check that tools is a list of
named tool objects (a JSON-string list is decoded, as for messages) and
raise ValueError otherwise; the MCP name set skips non-objects too.
2026-10-03 18:09:27 +02:00
Niko1221 99fe8b2437 serve: restart() keeps 0.1.38's close() (PR #637 follow-up)
0.1.38's close() already ends the old engine and waits for it (QUIT, terminate, kill, 20 s each) and raises
EngineStuck when it cannot. The PR's second kill and 120 s wait, after which a new engine was started next to one
still alive, is left out; the start retry and the last known context stay.
2026-10-03 18:09:15 +02:00
JeanP00l 67f4dc72bf serve: restart a dead engine for real - wait for the old process, retry the start, keep the last known context
Seen in long agent sessions (Claude Code, many turns at ~20K tokens): when the engine was ended mid-request (the
60 s watchdog), restart() started the new engine while the old process still held its VRAM. The new one ran out
of memory and exited before READY, `max_context` stayed 0, and from then on every request failed with
"400 ... exceeds the context (0)" until the server was restarted by hand.

- restart() ends the old process first (close(); kill and wait if it is stuck), so its GPU memory is free;
- a start that exits before READY is tried again, 3 times, RESTART_RETRY_S (15 s) apart; `starting` is set
  meanwhile, so a request gets the 503 "starting" of #344;
- `known_ctx` keeps the last context the engine reported: after a restart that failed for good, a request is
  checked against it and reaches run(), which starts the engine again, instead of a 400 about context 0.

Two tests in RestartWindow (both fail without this change): a start that fails once is retried and the engine
comes up; a request after a failed restart gets 200, not a 400. `python -m unittest serve.test_server`: 120 OK.
2026-10-03 18:07:54 +02:00
Niko1221 59a7e22fc2 HIP: the grouped decode experts, IQ3_S gate/up + IQ4_NL down, faster and bitwise (opt-in STRATA_EXPERT_V2=1)
native_expert_grouped for the UD-IQ4_XS shapes (n_embd 2560, n_ff 640): s26_gu_l_kernel / s26_down_l_kernel keep
every row's lane-strided k order, Split<TY>::apply expression and warp_sum, so every output is bitwise the old one's;
a warp interleaves 4 rows (more loads in flight), the chunk's activation q8_1 rows are read from LDS, and for IQ3_S
the 512-entry grid table too (the same values); SwiGLU and its q8_1 run as one launch (contraction off in the
quantizer). Other formats / shapes keep native_gu_multi_kernel / native_down_multi_kernel.

gfx1151 harness (S26 ws3: real expert blobs, 32 experts x 4 layers = 298 MB, decode-style windows planned as
resident_plan does, memcmp of every output, paired HIP events): one layer's experts T=1 140.3 -> 133.3 us, T=2
225.1 -> 204.1, T=3 300.2 -> 265.9 (166 -> 175-185 GB/s). Tried and rejected: non-temporal loads (no gain), whole
rows staged in LDS (0.6-0.8x: occupancy), 8 rows per warp for down.
Engine (UD-IQ4_XS, c-best3 env + the switch, same binary, S25's 18 prompts): outputs 18/18 identical; 56.6 / 57.0
-> 55.65 / 55.27 (and 55.61 with the fused SwiGLU q8_1) ms per verify window, 48.6-48.9 -> 50.3 tok/s;
59K prompts 2/2 identical, 58.65 -> 56.77 / 56.66 ms per window, 39.70 -> 41.01 / 41.09 tok/s.
2026-10-03 15:33:07 +00:00
benoit lange af7918f02d Parking with a layer split: the draft ring once, every stage's K/V reused, checkpoints moved not copied
- conversation_snapshot_*(..., const QsaState* draft): nullptr saves, validates and restores an image without the
  draft layer's K/V. The later stages park that way; the draft ring is saved once, with the first stage's image.
- ConversationKvReuse::stages / ConversationCache::retain(.., stage_kv): every stage's restored K/V is retained, so
  its next park copies only what changed, as the first stage's already did.
- conversation_checkpoints_split / _merge: the checkpoints are moved into their stage parts for the capture and
  back afterwards (and on restore), instead of copied.
- Tests: conversation_cache_test (split/merge round trip without copies, refused misalignments, per-stage reuse),
  conversation_snapshot_test (draft-less images: estimate, validation both ways, A/B/A exactness, incremental reuse).
2026-10-03 17:03:02 +02:00
benoit lange 953203be43 Tests and docs: parking with a layer split, tools/parking_test.py, a Testing section
- tools/parking_test.py: a follow-up decodes the same tokens whether its conversation stayed live or came back
  from the parking cache (every stage's image with a layer split). 4-GPU split, IQ3_S: 3,786 and 9,276-token
  conversations restored in 42 / 51 ms, follow-ups identical; without parking the same follow-ups took 3.4 / 6.8 s.
- tools/batch_test.py: --keys to send sampling keys (sampled rows in batch windows).
- docs/BATCHING.md: parking together with batching, the Testing section; docs/DETAILS.md: parking now works with
  --layer-split.
2026-10-03 16:11:57 +02:00
crazyaimachineandbenoit lange 06125d2e20 Conversation parking with --layer-split
park_current snapshotted stage 0 only, so a split rejected parking. A parked conversation now holds one image per
later stage (SavedConversation::stage_images, captured from each stage's session on its own GPU); a split
checkpoint is cut into its stage-0 part and its stage parts while parking and put back together on restore; every
stage image is validated before anything is overwritten; the guard is removed.

Patch posted on #559 by crazyaimachine (written by their coding agent), tested on 2 GPUs there and on a 4-GPU
split here.

Co-authored-by: benoit lange <[email protected]>
2026-10-03 16:11:44 +02:00
Niko1221 db43f526d0 Merge S23 f-halo (STRATA_HC_UPMIX, STRATA_PA_FAST, STRATA_PF_GEMM prompt switches) into f-halo-int 2026-10-03 11:12:41 +00:00
Niko1221 f2afdfc244 Merge branch 's25-tps2' into f-halo-int 2026-10-03 08:20:18 +00:00
Niko1221 22abb92dff GDN decode step and activation quantizes: bitwise faster paths (STRATA_GDN_SPLIT=1, opt-in STRATA_QFUSE=1)
GDN step (verify_kernels.cu, S25's STRATA_GDN_SPLIT=1 split, handed to S26):
- the commit's replay writes no outputs (t_out_begin = MT): y_dummy_ was never read; the state is unchanged;
- the commit runs gdn_state_replay_kernel: S25's column split (4 blocks of 32 columns per head) with gate, beta and the
  v column of every row prefetched and the next row's k / q loaded while the current one computes;
- the window keeps the old kernel for one row (the split did not pay there) and runs the split for 2+ rows with
  gdn_out_norm_kernel rewritten in the old kernel's code shape: S25's 128-thread norm differed from the old kernel by
  1 ulp in ~7% of the outputs (405 of 6144 at T=1); the S x RG version is bitwise equal.
gfx1151 harness (h_v 48, 36 layers rotating, paired, every layer memcmp-equal): commit 44.1 -> 39.1 us at 1 row,
50.7 -> 41.8 at 3, 60.8 -> 46.1 at 6; window 23.8 -> 23.2 us at 2 rows, 30.1 -> 26.7 at 4.

STRATA_QFUSE=1: q8_1 images written by their producers instead of a separate native_quantize_q8_1 launch:
- the GDN output norm (both window kernels) quantizes its outputs (warp = one 32-column q8_1 block), contraction
  off in the quantizer so fma(a, b, shfl) cannot round the first sum differently (that made ds.sum differ by 1 ulp);
- the hyper-connection read (gr_up_multi_kernel, gr_up_q8_kernel): the second of the two 16-column blocks of each
  32-column group (a per-caller counter, reset by that block) reads the 32 `mixed` values back and quantizes them -
  attention side into xq_, FFN side into nat_xq_; fused_gr_read_multi returns whether it wrote them (the v3 read
  does not). gr_parity: new check, T 1..8, direct and graph replays, q8_1 bytes equal to native_quantize_q8_1's.
Harness: GDN step + quantize 23.1 -> 20.5 us (1 row), 26.4 -> 23.3 (2), 32.6 -> 27.0 (4), q8_1 bytes equal.

Engine (UD-IQ4_XS, c-best2 + the switch, S25's 18 prompts, 256 new tokens): 18/18 identical in every run;
c-best2 49.46 / 49.44 tok/s, + STRATA_GDN_SPLIT=1 50.13 / 50.23 / 49.99, + STRATA_QFUSE=1 50.10 / 49.98 / 49.95.
2026-10-03 08:19:26 +00:00
Niko1221 4c00d2e7a3 prefill: opt-in STRATA_PF_GEMM=1 - a gfx11 WMMA GEMM for the FP16 prompt projections
strata_pf_gemm_f16 (wmma_gemm.cu), tried in Gemm::f16 before hipBLASLt for T >= 64, N >= 512, K % 32 == 0, beta
0 / 1: block 128 x 256 (128 x 128 below N 1024), BK 32, 8 waves of 64 x 64, LDS double buffer with the next stage
prefetched into named registers, grouped tile order (8 row tiles sweep all column tiles, so the weights stream
from DRAM once per group).  FP32 accumulation, another K order than hipBLASLt: rounding-level.

gfx1151, M 16384 (TFLOPS, tuned hipBLASLt in brackets): 12288 x 2560 33.0 (27.4), 10240 x 2560 31.9 (26.8), 6144 x
2560 31.1 (25.9), 2560 x 2560 30.1 (24.9), 640 x 2560 30.2 (25.3), 2560 x 6144 19.4 (19.1); the register-only WMMA
ceiling is ~50.  Engine 8K: gdn 1122 / 1112 -> 1083 / 1071 ms, qsa proj 813 / 716 -> 692 / 676, gdn out proj
753 -> 645 / 665.  Teacher-forced KL 0.099 / 0.028 on two text offsets (accepted pair: 0.117 / 0.030).  Off by
default.  With STRATA_HC_UPMIX + STRATA_PA_FAST, UD-IQ4_XS 64K prompt 872.8 / 880.6 -> 942.4 / 937.8 tok/s.
2026-10-03 07:32:53 +00:00
Niko1221 7aaf466d18 qsa: opt-in STRATA_PA_FAST=1 - the gfx11 prompt attention with single FP16 q and p
prompt_attn_wmma_kernel carries q and p as FP16 hi + lo pairs (two WMMAs each, FP32-level).  SPLIT = false drops
the lo halves: FP16 attention as the usual flash-attention kernels, half the matrix work.

gfx1151, real 64K selections (16383 queries x 2051 cells, one QSA layer): 138.7 -> 117.8 ms; rel RMS vs FP64
4.8e-7 -> 2.7e-4.  Engine 8K "qsa attn" 718 / 712 -> 589 / 590 ms.  Teacher-forced KL on three text offsets 0.153 /
0.087 / 0.027 (the accepted MMQ-vs-fused pair: 0.153 / 0.117 / 0.030).  Off by default.
2026-10-03 07:32:53 +00:00
Niko1221 31b2472a3f prefill: opt-in STRATA_HC_UPMIX=1 - the hyper-connection up projection with gr_mix_r as its epilogue (gfx11)
The read's up GEMM wrote `gated` (T x 10240 FP32: 671 MB per 16K chunk) for gr_mix_r to read back.  gr_upmix
computes a tile of 128 tokens x 16 columns for the 4 streams on the matrix cores (BF16 in, FP32 accumulate, the
block's 64 w_up rows staged in LDS once) and runs the mix in registers, in gr_mix_r's order.  The grid is ordered
column-tile fastest: the blocks in flight share one token tile, so the R reads of the epilogue stay on few pages
(token-tile fastest touched 512 rows x 40 KB per block: 28 ms instead of 3.7 at 8K - address translation on this
box goes through the IOMMU).  STRATA_HC_UPMIX_CHECK=N runs the default pair on the first N reads and prints the
difference.

gfx1151, UD-IQ4_XS: `mixed` vs the default rel RMS 1.2-3.6e-7 on every read of an 8K prompt; prompt-timing "hc
read" 1352 / 1313 -> 1080 / 1212 ms at 8K; 64K prompt 874.3 / 876.1 -> 902.7 / 903.0 tok/s.  Rounding-level (the K
order of the GEMM): teacher-forced KL on three text offsets 0.170 / 0.085 / 0.032 vs the accepted MMQ-vs-fused
pair's 0.153 / 0.117 / 0.030; ledger and 8K / 64K retrieval pass.  Off by default.
2026-10-03 07:32:53 +00:00
benoit lange db90f0b816 server: a client that stops reading early keeps the engine in step
With --batch, a consumer that left mid-answer (a client disconnect, a tool call or a stop string ending the
response) left the engine writing the abandoned answer's tokens, and the next request read them as its own:
it answered the previous question again. Now the solo request is STOPped and read to its DONE, an admission
to its BADM, and a slot is BSTOPped and freed only at its BDONE. STRATA_BATCH_TRACE=1 logs the control lines.
tools/early_close_test.py reproduces it (solo and with a second request running).
2026-10-03 08:04:53 +02:00
benoit lange 9461f5e3a3 Several conversations at once: batch slots, pipelined layer split, per-stage dense weights
The engine's --serve can now keep up to N conversations open (--batch N) and decode them together, one token
each per verify window; with a layer split, --batch-groups G pipelines the slot groups through the GPUs, and
--trim-stage-weights makes every GPU load only its own layers' dense weights (VRAM back to the expert cache).
The server runs concurrent requests in the slots. See docs/BATCHING.md.
2026-10-03 08:04:53 +02:00
Niko1221 48d10a4996 Prompt path: STRATA_PREFILL_DUMP_R_ALL=FILE, every position's final residual as BF16 (opt-in, for distillation data)
Appends [n][hc*n_embd] BF16 rows (round-to-nearest-even) in position order for every batched prompt chunk: the
input the MTP draft layer reads, for training it against this trunk. Off unless the variable is set.
2026-10-03 05:35:31 +00:00
Niko1221 d92c9feb78 Verify PLE block: the window's key and value projections at once (opt-in STRATA_PLE_BATCH=1, bit-identical)
Layer 1's PLE block ran its key (10240 x 2560) and value (2560 x 2560) GEMVs once per window row, reading ~40 MB of
weights per row. Both depend only on the row's n-gram embedding, so with the switch the group's rows go through
the multi-row forms of the same kernels (native MMVQ over n columns / bf16_gemv_fp32_mmvf_multi, each row's
arithmetic the single-row call's) and ple_block copies its row's results instead of recomputing them. The
history-dependent rest of the block stays row by row.
2026-10-03 05:10:15 +00:00
Niko1221 58729711d9 STRATA_HC_Q8=1: inject rows as the exact BF16, the final mixer from Q8_0 too
The GGUF's F32 inject rows hold BF16-exact values (conversions.json: "the values are BF16's"), so quantizing them
to Q8_0 only added error: the Q8_0 read now takes the pack's BF16 inject rows (STRATA_HC_Q8_INJECT=1 keeps the
Q8_0 copy). The final mixer before the head (output_hc_down/up, also BF16-rounded in the pack) now reads the
GGUF's Q8_0 values through the same multi read.
2026-10-03 04:11:11 +00:00
Niko1221 2f6c70f0d1 Merge S25 f-halo-tps (8 commits) into S26 f-halo-s26-ovh: f-halo-int
Conflicts: mtp.cpp (the draft head: S25 converts it with --mtp-q4 first, then STRATA_Q6_PACKED packs it only
while it is still Q6_K), native_dense.cpp (includes).
2026-10-03 03:47:13 +00:00
Niko1221 e3c3d6bade GDN verify step: each head's columns over 4 blocks (opt-in STRATA_GDN_SPLIT=1, bit-identical by construction)
gdn_step_norm_multi_kernel ran one 512-thread block per head - 32 blocks for a layer's 2 MB state, ~36 us per
launch at T=1 on gfx1151 (~60 GB/s) and +4 us per window row; it runs twice per GDN layer and window (the window
and the commit's replay). With the switch the recurrence runs on (head, 32-column) blocks with the same
(column, row group) threads and state rows, so every column's arithmetic is unchanged; the output norm, which
needs a head's 128 columns, follows in gdn_out_norm_kernel with the same warps and the same sum order.
2026-10-03 03:46:23 +00:00
Niko1221 5cf0079bcc HIP: the packed Q6_K heads (opt-in STRATA_Q6_PACKED=1), bitwise
The main output head (248320 x 2560) and the MTP draft head (its 106299-row subset) are Q6_K: 210-byte blocks, so
every int load is 2-byte aligned. STRATA_Q6_PACKED=1 builds a packed copy of each at load - the same bytes as ql /
qh / scales / d planes (+497 MiB, +213 MiB) - and native_q6_k_mmvq on a registered pointer runs
native_q6_k_packed_kernel: aligned non-temporal dword loads, 640 persistent workgroups, and the thread ownership,
q6_q8_dot_impl expression, accumulation order and reduction of native_q6_k_mmvq_kernel<false> /
native_mmvq_multi_kernel<Q6KTraits, NC, 4, 1>, so every output is bitwise equal (exact multi-column layout only).
STRATA_Q6P_SELFTEST=1 checks it at load (1-4 columns, memcmp) and times it paired; =2 also sweeps the grid.

gfx1151 load-time self-test (11 paired samples, medians): main head 1 column 2420 -> 2300 us, 2 columns 2563 ->
2455, 4 columns 2973 -> 2975 (no gain: not bandwidth-bound there); draft head 1 column 1319-1351 -> 946-961 us,
2 columns 1420-1459 -> 1064-1090, 4 columns 1629-1678 -> 1320-1365. Outputs bitwise equal. Grid 320-20480 flat.
2026-10-03 03:28:31 +00:00
Niko1221 be7889ed84 verify: a fully resident decode window without the host round trip (opt-in), and fewer quantize launches
STRATA_VERIFY_RESIDENT=1: when every expert of every layer is resident in the VRAM/UMA tier (checked once at init;
a full cache never evicts; one stage only), the window graph is recorded without the per-layer host step: no
doorbell_publish, no wait_flag_ge (3 per layer), no plan copy from mapped memory, no PCIe/CPU share (fetch_blobs,
rebase_ptrs, its empty grouped launches, copy_rows_from_mapped) and no moe_hit_add: the device plans each group
(resident_plan, the host's exact loop) and the combine reads the hit rows as 0.0f + hit (combine<true>), which is
what the zeroed part rows plus parts += hit gave. run() then skips the per-layer spin. Same tokens.

resident_plan: the plan in one block of 128 threads (entry i per thread; groups in first-occurrence order, entries
in increasing i, the same arrays) instead of one thread - 44 us -> a few us per call on gfx1151, 48 per window.
Used by STRATA_VERIFY_DEVICE_PLAN=1 too.

STRATA_VERIFY_QDEDUP=1: the experts' q8_1 image of the MoE input is made before the shared expert, whose gate/up
read it instead of quantizing the same rows again (quantize_q8_1_rows and native_quantize_q8_1 write the same
bytes); the shared expert's SwiGLU and its q8_1 run as one launch (native_swiglu_q8_1_kernel: the same expression,
then native_quantize_q8_1_kernel's block quantizer); the BF16 copy of the input is skipped when the shared expert's
native BF16 gate (which never reads it) is on. Same bytes, same tokens.

Aurora (gfx1151, UD-IQ4_XS, S23's c-u4 config, one binary, env-only arms): output ids identical in every run.
Per verify window (rocprofv3 trace, 8K prompt + 300 outputs, 114 windows): see aurora_s23.md (S26, overhead).
2026-10-03 03:28:31 +00:00
Niko1221 c637ed5a6e bf16 multi-row GEMV: 4 output rows per block (opt-in STRATA_MMVF_ROWS=1, bit-identical by construction)
The router (512 x 2560) and the indexer projections run bf16_f32_mmvf_multi_kernel: one block per output row, so
the window's T activation rows were read again by every block (+3.3 us per row per launch on gfx1151, ~0.2 ms per
window row). With the switch a block computes 4 output rows from one read of the activations; per output each
thread keeps the same pairs, FMA order and reductions.
2026-10-03 03:17:34 +00:00
Niko1221 8b30b1d587 Decode attention: the score phase one cell per thread (opt-in STRATA_ATTN_LANECELL=1, meant bit-identical)
attn_chunk_kernel scored a chunk's 64 cells warp by warp: each lane 8 of the 256 dimensions, then one warp_sum
per query head - 12 shuffle reductions per cell, which is what made the kernel ~53 us per layer at T=1 and
+32 us per window row on gfx1151 (it scales linearly with T). With the switch, thread t scores cell t % 64 for
3 of the 12 heads alone: the same 8-dimension partial expression per former lane, then lane 0's butterfly order
(a[l] += a[l + o], o = 16 .. 1), so each score has the same operations in the same order. Softmax, values and the
merge are unchanged.
2026-10-03 03:17:34 +00:00
Niko1221 348abafdd9 STRATA_HC_Q8=1: the F32 inject rows as Q8_0 too, so the Q8_0 read is taken
The read takes the Q8_0 kernels only when the inject rows have a Q8_0 copy as well, and the GGUF stores them as
F32: with only down/up loaded (0.62 GiB) every window still ran the BF16 read (Aurora: 18/18 outputs identical
to the default, verify 61.4 vs 60.9 ms). The inject rows (4 x 10240 per projection) are now quantized at load
with ggml's Q8_0 reference rounding.
2026-10-03 03:17:34 +00:00
Niko1221 fe6c5260ec Verify: the hyper-connection read from the GGUF's Q8_0 projections (opt-in STRATA_HC_Q8=1; S23's parked patch)
NativeDense keeps the six hc_* projections per layer as stored (Q8_0, 0.65 GiB) beside the pack's BF16 copy
(1.20 GiB, --compat-bf16's rounding); the verify window's fused_gr_read_multi then reads them with split-K
kernels: gr_down_q8 (10 row groups + the inject rows x 16 chunks of 640 columns, the norm folded in as
unscaled partials + per-chunk sums of squares) and gr_up_q8. Every other path keeps BF16. Another summation
order and the GGUF's own values: output-changing, so opt-in and quality-checked separately. Also the
STRATA_GR_V3=2 knob (the two-half v3 split where only 64 KiB of LDS is available). Taken over from S23
(aurora_s23/hc_q8_grv3s2.diff) unchanged.
2026-10-03 03:17:34 +00:00
Niko1221 2c697fdace --mtp-q4 all|proj|head: the projections and the draft head separately
On Strix Halo (UD-IQ4_XS, head Q6_K) the 4-bit head costs acceptance (tokens per step 2.81 -> 2.72 with both)
while the smaller 40.5K-token subset (--mtp-draft-vocab data/draft_vocab_en.bin) costs none, so the two 4-bit
copies are now separate choices.
2026-10-03 03:17:34 +00:00
Niko1221 5e0c43bacc --lookup-chain: the draft policy keeps only the chained tokens that pay
Measured on Strix Halo (UD-IQ4_XS, 1-2K contexts) a verify row costs ~9 ms on a ~61 ms window, so chaining
every 3+-token match (49% of chained drafts accepted) gave +6.4% tokens per step for +7% window time. The
policy now picks the number of chained tokens k with the best expected tokens per ms: the MTP window's
measured tokens + p_mtp (c + c^2 + .. + c^k) at the measured cost of the longer window, where p_mtp is the
product of the draft layer's own draft probabilities and c the chained drafts' acceptance by match length
(their own decayed counts, learned only from rounds that reached the chain). Unmeasured sizes are probed a
few times when p_mtp * c >= 0.6. STRATA_LOOKUP_CHAIN_FIXED=1 takes every proposal as before.
2026-10-03 03:17:34 +00:00
Niko1221 e35a061f1d MTP draft head: --mtp-q4 (4-bit projections and draft head) and --mtp-draft-vocab FILE
Both opt-in; drafts only, the verify window decides every token (18/18 prompts identical on IQ3_XXS).

- --mtp-q4: the draft layer's ten Q8_0 projections (fc_embedding/fc_hidden, q/k/v/o, the shared expert) and
  the draft head's subset rows are requantized to Q4_0 at load/bind with ggml's reference quantizer
  (native-experts builds). The prompt path's batched K/V pass keeps the Q8_0 originals.
- --mtp-draft-vocab FILE: the draft head's token subset from FILE instead of <mtp>/draft_vocab.bin
  (data/draft_vocab_en.bin: 40,525 tokens instead of 106,299).

RTX 5070, IQ3_XXS (head Q5_K), 18 prompts: draft ms per window 2.55 -> 2.23 (q4), 2.13 (en), 1.91 (both);
tokens per step 2.64 -> 2.63 / 2.67 / 2.57.
2026-10-03 03:17:34 +00:00
Niko1221 2312c83bfd Speculation: --lookup-chain (prompt lookup chained after the MTP drafts), --mtp-hnorm stream, draft sources
All opt-in; with none of them given the engine runs exactly as before.

- --lookup-chain K [--lookup-chain-min M]: after the MTP's drafts, the suffix drafter matches the context
  plus those drafts and appends up to K of the tokens that followed the match to the same verify window
  (the window grows to at most 8). Greedy verification keeps the output. Own counts: a stderr line per
  request and five more DONE fields when on.
- include/strata/spec/draft_source.hpp: a DraftSource interface (the request's own text is
  PromptLookupSource; other sources register in extra_draft_sources() and the longest match wins).
- --mtp-hnorm stream: the draft layer's pre_fc_norm_hidden as one RMS per hyper-connection stream
  (llama.cpp's qwen4exp MTP graph) instead of one over all four (vLLM's qwen4_exp MTP, the default).
  New kernel native_qsa_rms_norm_grouped; the batched prompt K/V pass follows the switch.
- Diagnostics: STRATA_MTP_FULL_HEAD=1 drafts over the whole vocabulary; STRATA_MTP_TOP2=1 counts how often
  the draft layer's runner-up is the token verify picked where a draft was rejected.
2026-10-03 03:17:34 +00:00
Niko1221 96f4065aae HIP: the packed Q8_0 decode layout (opt-in STRATA_Q8_PACKED=1), bitwise
A lossless load-time repack of the native dense Q8_0 matrices with 1024 <= n_in <= 4096 and n_out >= 2048 (on
UD-IQ4_XS: attn_qkv, attn_gate, attn_q; 84 matrices, +1.87 GiB): the same int8 values in a qs plane and the same
fp16 scales in a d plane, 34 bytes per 32 values as before. native_q8_0_mmvq finds a registered matrix by its
GGUF-layout pointer (that copy stays: the prompt GEMMs read it) and runs native_q8_0_packed_kernel: 640 persistent
workgroups; each thread owns the bytes of the exact layout (block tid/4 + 32 i, ints 2 (tid%4) and +1), reads them as
one aligned 8-byte run with streaming loads, and accumulates and reduces in the same order, so every output is
bitwise equal to native_small_mmvq_kernel / native_mmvq_multi_kernel (exact layout; with the upstream multi-column
layout the GGUF kernels run).

gfx1151, S26 standalone harness (8 real UD-IQ4_XS layers per shape rotating, paired HIP events, 15 samples, every
layer x 1-5 columns memcmp-equal): attn_qkv +10-12%, attn_gate +11-12%, attn_q +10-11% per call. 6144-wide rows
(ssm_out, attn_output) and rows < 2048 are not packed (slower in the engine / standalone).
Engine (UD-IQ4_XS, S23's c-u4 config, same binary, env only): output ids identical in all 10 runs; steady output
8K 40.06 vs 39.77 tok/s (3 runs each), 64K 30.94 vs 30.34 (2 each).
2026-10-03 01:26:09 +00:00
Niko1221 7e363dbebb prefill: the gfx11 fused prompt-expert grids at 2 blocks per WGP
HIP counts a gfx11 WGP (two CUs, which the WMMA prompt-expert kernels use as one in
the default WGP mode) as one multiprocessor, and the occupancy query answers 1 block
for these kernels where 2 run side by side - so every fused launch (native IQ and
Q2_0) ran a 20-block grid on gfx1151, 2 waves per SIMD.  wgp_blocks() doubles the
query's answer (STRATA_PF_OCC=N sets it, an experiment knob).

The same work items and arithmetic: parity passes, fused-vs-MMQ rel RMS unchanged,
and the engine's outputs are the same tokens.

gfx1151, one layer, 8192 tokens x top 10, IQ3_S / IQ4_NL: blocks per WGP 1: 60.7 ms,
2: 44.7, 3: 49.9, 4: 45.2.  Q2_0 (2048 tokens): 13.3 -> 11.4 ms.
Engine, UD-IQ4_XS (MTP + vision + speed projection): 64K prompt 819.8 / 823.9 ->
892.4 / 878.8 tok/s, 8K 825.5 / 820.8 -> 874.5 (the other 8K run overlapped a
download: 758); outputs identical (drafts 292/516 at 64K, 343/468 at 8K); ledger
{32,17,130}, 8K retrieval 3/3.
2026-10-03 00:33:19 +00:00
Niko1221 09817da397 Merge branch 'f-138-fixB' into f-138-prs 2026-10-03 02:21:36 +02:00
Niko1221 f3efd59298 Merge branch 'f-138-sec' into f-138-prs 2026-10-03 02:21:36 +02:00
Niko1221 59ba26ce13 Merge branch 'f-138-fixA' into f-138-prs 2026-10-03 02:21:36 +02:00
Niko1221 73984cffe3 serve: no Host check when an API key is set
A rebinding page cannot send the key, so with one configured the check only
broke tunnels and proxies that pass their own name on (cloudflared does).
Keyless setups keep it, with allowed_hosts; the 403 now also says that
setting an API key turns the check off.
2026-10-03 02:20:37 +02:00
Niko1221 f9e6576c5a docs: the Coder is a 32 GB fit, not the pick for general use
It keeps 256 of the 512 experts, chosen on code data, so it is weaker outside
code and in other languages; for general use, or when RAM allows, MODELS.md
now points to the full models.
2026-10-03 02:11:36 +02:00
Niko1221 ed0b19ccca serve: refuse cross-site browser requests without an API key
/unload and /load took a plain form POST from any site: they now take JSON
from Strata's own page only, like /settings (_own_page). Without an API key, a
POST to /v1/* that carries an Origin must come from Strata's own page, a page
on localhost or an allowed host name, an origin in trusted_origins or
cors_origins, or a non-web scheme (browser extensions, desktop apps), and then
send JSON; others (and Origin: null) get 403, so a web page can no longer burn
GPU time with a text/plain POST. Requests without an Origin (curl, the SDKs)
are unchanged; with an API key, the key decides.
2026-10-03 02:11:36 +02:00
Niko1221 76a794e145 serve: check the Host header on every request (DNS rebinding)
A web page of another site could point its own name at 127.0.0.1 and reach
the server as the same origin: without an API key it could read /status,
/metrics and /api/requests, change settings and run MCP tools. The server now
answers only Host names it knows: localhost (and *.localhost), any IP address
(rebinding needs a name), the bind address and, bound beyond this PC, the PC's
name, name.local, its LAN addresses and host.docker.internal; any port. No
Host header (HTTP/1.0) passes. "allowed_hosts" in the config and
STRATA_ALLOWED_HOSTS add names (".example.com" for a domain, "*" turns the
check off); trusted_origins' hosts count too. A refusal is a 403 naming the
setting and one log line.
2026-10-03 02:11:26 +02:00
Niko1221 0d61154360 #486: a weight arena that does not fit says how much VRAM was free
The weight arena is the first large VRAM allocation and its size does not depend on the context, so when it fails
something else holds the card (another program, an engine still exiting). The error now names the CUDA error and the
card's free and total VRAM at that moment; a layer split's stage says the same for its card, with the MiB it needed.
Error paths only.
2026-10-03 02:03:31 +02:00
Niko1221 6e20509477 setup: a start prints the settings it uses (#564)
One line under the start banner: the config's engine options without the model's file paths, and the
server's fields (host:port, an API key set or not, GPUs, draft subset, fit_max_tokens, thinking budget).
The key itself is never printed.
2026-10-03 01:58:25 +02:00
Niko1221 bd174c4671 docs: an OpenCode config example (#543)
The provider, the context and output limits, the thinking level as a default and as variants, and how
they relate to the context check, fit_max_tokens and reasoning_budget_tokens.
2026-10-03 01:57:19 +02:00
Niko1221 9ae6dbd2ce #542: MMQ's device facts from cudaDeviceGetAttribute; warn when libcudart is older than the headers
A CUDA 13 build that linked the system's CUDA 12 libcudart.so (a kit with a dangling libcudart.so symlink) read
cudaDeviceProp shifted: sharedMemPerBlockOptin came back as 1, #420's fits() then refused MMQ for every i-quant and
the prompts ran ~4x slower, with a log line printing "1 bytes of shared memory per block".

- ggml_cuda_info() (CUDA) reads cc, smpbo, smpb, nsm, warp size, integrated and cooperative launch with
  cudaDeviceGetAttribute, which is ABI-stable. A matched build reads the same values: the same MMQ choices, the
  same output.
- The engine warns at start when the loaded CUDA runtime's major version differs from the headers' it was compiled
  with, and says to rebuild against one toolkit (-DCUDAToolkit_ROOT).

HIP is unchanged.
2026-10-03 01:57:12 +02:00
Niko1221 94705a1463 decode_cluster_parity: wait for every upload before the graph replays and timings use it (#548, as #536)
Dev::put uploads with a pageable cudaMemcpy, which can return before its DMA lands, and the graph replays and the
timing cases run on a cudaStreamNonBlocking stream that does not wait for the legacy stream: the graph could read
the previous replay's logits (one argmax token off; 5 of 6 replays on an RTX 5060 Ti, now and then on a 5090).
Dev::put now synchronizes the device after its copy, which covers run_graph_case and bench(). Test only; no engine
code.
2026-10-03 01:57:12 +02:00
Niko1221 e685972a47 serve: log when a reply reaches max tokens still thinking, and what helps (#530)
A reply that ends with finish "length" inside the reasoning has no answer; the server log now says so
and names reasoning_budget_tokens (per request, or in the config for every request). Nothing the client
receives changes.
2026-10-03 01:56:16 +02:00
Niko1221 40ae2d1e80 #560 #516: an AMD card on a Linux desktop gets a recommended VRAM reserve (3072 MiB)
With the default 700 MiB reserve the expert cache fills an AMD card that also drives a KDE/Wayland desktop. When the
desktop then needs VRAM (the browser --open starts, a new app), amdgpu moves GPU memory to system RAM (GTT), which
the experts already fill: the OOM killer ends kwin_wayland / plasmashell (#560, R9700), or the compositor fails to pin
its framebuffer (#516, 7900 XTX). --vram-reserve-mib 3072 / 4000 fixed it in both reports.

A recommendation, nothing is changed: setup prints the tip on a Linux desktop session (WAYLAND_DISPLAY or DISPLAY) with
the HIP backend and no reserve given, and the server prints it after the start when the engine reports less than
2048 MiB of VRAM free (INFO vram_free_mib) and the reserve is under 3072 - before --open starts the browser.
INSTALL.md and AMD_HIP.md describe the symptom and the fix. No engine code.
2026-10-03 01:56:03 +02:00
Niko1221 2233e815d1 serve: the "exceeds the context" 400 says how to get past it (#545)
It names the largest max_tokens that fits and the existing "fit_max_tokens": true config switch.
The check itself is unchanged.
2026-10-03 01:55:36 +02:00
Niko1221 d295c45634 setup --update: skip a strata-*.json that is no model config instead of KeyError: 'args' (#549)
installed_configs() and update_install() keep only JSON objects with "exe" and "args"; any other
strata-*.json in the folder gets a one-line warning naming it.
2026-10-03 01:54:18 +02:00
Niko1221 e5d186398c decode: STRATA_ADAPT_NOWAIT=1, an A/B switch for #463's wait
The verify window waits for the adaptive tier's copies since #463; STRATA_ADAPT_NOWAIT=1 starts it as 0.1.37 did (the
non-blocking query), for timing that wait. Default unchanged.
2026-10-03 00:41:52 +02:00
Niko1221 2c9fe45edb prefill: the fused layout's smaller MoE buffers only when the native kernels cover EVERY layer
fused_layout() (STRATA_PF_FUSED=1) shrinks GU / H / Xq to the fused kernels' needs whenever
fused_ring() is true, and fused_ring() was true when ANY layer of a native pack was covered. A pack
with an uncovered layer - Unsloth UD-IQ4_XS: 5 layers with Q8_0 down projections - then ran MMQ for
those layers at the full chunk in buffers sized for stream_all_min() - 1 tokens: on gfx1151 an 8K
prompt answered "!!!!..." and a 64K prompt hung (--prefill 2048: an illegal memory access). Such a
pack now keeps MMQ's buffers; its covered layers still take the fused kernels. UD-IQ4_XS 8K
retrieval after the fix: 3/3 correct, 837.9 prompt tok/s. (The CUDA path shares this code.)
2026-10-03 00:38:10 +02:00
Niko1221 55b9f8346f prefill: the fused layout's smaller MoE buffers only when the native kernels cover EVERY layer
fused_layout() (STRATA_PF_FUSED=1) shrinks GU / H / Xq to the fused kernels' needs whenever
fused_ring() is true, and fused_ring() was true when ANY layer of a native pack was covered. A pack
with an uncovered layer - Unsloth UD-IQ4_XS: 5 layers with Q8_0 down projections - then ran MMQ for
those layers at the full chunk in buffers sized for stream_all_min() - 1 tokens: on gfx1151 an 8K
prompt answered "!!!!..." and a 64K prompt hung (--prefill 2048: an illegal memory access). Such a
pack now keeps MMQ's buffers; its covered layers still take the fused kernels. UD-IQ4_XS 8K
retrieval after the fix: 3/3 correct, 837.9 prompt tok/s. (The CUDA path shares this code.)
2026-10-02 22:27:33 +00:00
Niko1221 69f4d94801 prefill: the resident lookup in the streamed walk indexes by the model's expert count (#531 follow-up)
#531's peer-aware lookup indexed the residency table with the 512-expert constant NE instead of the model's own
count. The Coder has 256 experts per layer, so from its second layer a resident expert was looked up in the wrong row,
and a prompt long enough for the streamed walk stopped with "an expert is neither resident, streamed nor on the peer"
(found by the 57K real-use check). The 512-expert models index the same row as before.
2026-10-02 23:47:59 +02:00
Niko1221 aa5754fa06 hip: gfx1151 hipBLASLt table - the prompt GEMM shapes at --prefill 16384 too (T 16383 / 16384)
30 more rows from tools/hip/tune_hipblaslt.cpp on Aurora (90 in all). IQ3_XXS, 64K prompt, the
gfx11 fused experts: --prefill 16384 with them 849.2 / 847.0 tok/s vs 8192 803.1 / 824.0 / 829.3.
2026-10-02 21:31:01 +00:00
Niko1221 cb5cfb7a09 Engine 0.1.38: faster prompts (#372 #374 #413 #452), Q5_0 experts on the GPU (#473), IQ4_XS on AVX-2 (#415), unbuffered loads on Windows (#357 #362), --peer-device (#531), a 6 GB card starts (#496), PR batch; setup requires it 2026-10-02 22:54:11 +02:00
Niko1221 c2beb7106e #496: the engine chooses a small card's reserve; setup only gives the tip
Setup no longer writes a fixed 300 MiB reserve for cards under 8 GB: the engine's own rule (lower the reserve only as
far as the smallest working cache needs, down to 300) chooses better, and a fixed 300 left an emulated small card with
5 MiB free. Setup keeps the tip (an 8K context, --draft-vocab en). When the engine lowered the reserve and the card ends
below the 256 MiB LOW line, it prints one warning (requests may stall; close other programs that use the GPU, or lower
--max-context) instead of advising a larger reserve, which would leave the cache no room.
2026-10-02 22:53:55 +02:00
Niko1221 74d81c22c1 hip_compat: the peer-access calls (#531 follow-up)
peer_experts.cpp calls cudaDeviceCanAccessPeer, cudaDeviceEnablePeerAccess and cudaMemcpyPeerAsync and tests
cudaErrorPeerAccessAlreadyEnabled; the HIP shim had none of them, so the Windows HIP build stopped there. Mapped to
their hip* names.
2026-10-02 22:44:26 +02:00
Niko1221 e68b8d1445 A 6 GB card starts with a small expert cache, or says what is short (#496)
On an RTX 3060 Laptop (6 GB) the weights, the KV cache and the draft layer left 0.29 GiB, the default 700 MiB reserve
and the draft head took it, the expert cache got 0 slots and the verify window refused to start.

- setup: a single card under 8 GB (nvidia-smi below 7.5 GB; an 8 GB card lists 7.99) gets --vram-reserve-mib 300
  unless one is given (images on the GPU keep theirs), marked in the config as setup's own choice so a later setup
  decides again. It prints what frees more VRAM if the start still stops: an 8K context, --draft-vocab en, other
  programs closed. The draft layer stays (the server needs --mtp and --spec). 8 GB and larger cards: the same config
  (golden test).
- engine: a cache too small to lend the prompt path a 256-token chunk (its buffers plus the 128-slot floor; one slot
  without --prefill) makes the prompt path allocate its own on top. When the default reserve leaves less than that,
  the reserve shrinks to what leaves exactly that cache, down to 300 MiB (what comes after the cache is paid from
  the reserve: at 300 an emulated small card ended with 5 MiB free, LOW by the serve check). With no slot at all the start stops with how many
  MiB are short, what the session and the draft head take, and the options. A start whose cache could lend that
  chunk is sized as before. Checked with a VRAM ballast on the 5070 (IQ3_XXS, 32K): 258 slots needed, 0.71 GiB free
  -> "about 333 MiB more", and with --vram-reserve-mib 700 given, "733 MiB more" plus the reserve tip.
- verify's refusal points at that line.
2026-10-02 22:44:25 +02:00
Niko1221 004b15cd4d core: #409 unified-memory free-memory accounting (device_free_bytes), its integrated-GPU sizing part
From PR #409 (af404df), only device_free_bytes(): on an integrated GPU (cudaDevAttrIntegrated, on HIP
hipDeviceAttributeIntegrated; the Ryzen AI Max 8060S) the expert cache sizing and checks count
/proc/meminfo MemAvailable less STRATA_UMA_HEADROOM_GIB (6) when that is more than cudaMemGetInfo:
the page cache of experts read from the GGUF in place gives way to a device allocation. The PR's
aarch64 / DGX Spark CPU parts are not taken.
2026-10-02 20:13:42 +00:00
Niko1221 41c89b1708 prefill: #313 RDNA3 WMMA dense GEMMs (opt-in STRATA_WMMA_GEMM=1), its GEMM part, on gfx1151 too
From PR #313 (1e42cf3): src/prefill/wmma_gemm.cu/.h, the Gemm::f16/bf16 hooks before hipBLASLt, the
build macro STRATA_WMMA_GFX11 and its parity test; not its prompt attention (STRATA_HIP_WMMA covers it).
Fix: the intrinsics guard named only gfx1100/1101/1102 while the runtime gate takes any gfx11, so on
gfx1150/gfx1151 mma() compiled to "return c" (silently wrong); it now names gfx1150/gfx1151 too.
hip_prefill_wmma_gemm_parity on gfx1151: 3520 cases pass (f16 max_abs 2.4e-7, bf16 0).
2026-10-02 20:12:38 +00:00
sergiywith b3096357c1 Prompt path: an MMQ group's experts gathered in one launch, after one wait, released by one event
In the streamed walk every expert put a cross-stream wait (its copy) and an event record (its ring slot back) on the
compute stream around a ~3 us gather. Under WDDM each pair left ~10 us of GPU idle even when the copy had long
landed: an nsys trace of a 32K prompt showed 226 ms of idle between back-to-back gathers while the host was 3-11 ms
ahead of the GPU. Now a group of 16 is gathered by one launch (copy16_group_kernel) after one wait on its last
streamed copy - the copy stream is in order - and one event releases all of its ring slots: the issuer waits on
used[used_of[slot]]. A ring entry the routing skipped inside an open group first gathers what the group holds so
far, so no more than a group's entries are ever held back from the issuer. The same bytes in the same group slots.
STRATA_PREFILL_GROUP_GATHER=0: one at a time, as before.

IQ2_XS, RTX 5090, 262K context: 32K prompt -8.6%, 8K -10%, 2K -12.6%; first-token logits bit-identical at 2K, 8K,
16K and 32K and with a 96-slot ring.
2026-10-02 20:10:40 +00:00
Niko1221 4cca9043e0 HIP: the native packs' fused prompt experts on gfx11 matrix cores (opt-in STRATA_PF_FUSED=1)
native_w11_kernel: moe_fused_iq.cu's decode (load_unit / convert: IQ2_XXS IQ2_XS IQ2_S IQ3_XXS IQ3_S
IQ4_XS gate/up, Q2_0 IQ4_NL down) into double-buffered LDS, v_wmma_i32_16x16x16_iu8 from a MAGIC C
operand (the CUDA kernel's arithmetic), 128 weight rows x 64-row tile per item, 8 waves of 2x2 tiles.
hip_prefill_fused_iq (tests/cuda/prefill_fused_iq_test.cpp) on gfx1151: every pair passes against the
FP32 reference (= MMQ's error) and MMQ (rel RMS 3e-5..3e-4); one layer, IQ3_XXS / IQ4_NL: 2048 tokens
31.1 -> 22.6 ms, 8192 tokens 67.2 -> 62.0 ms (MMQ path -> fused).
2026-10-02 20:10:40 +00:00
Niko1221 6037aee3b5 fused_gr: STRATA_GR_DOWN_MAX4 read once (#443 follow-up)
The switch was read with getenv on every launch_multi call, which runs per layer when decode is not captured in a
graph. It is now read once, like the engine's other STRATA_* switches.
2026-10-02 22:05:43 +02:00
David 276908261a kernels: opt-in small-window GR down projection (STRATA_GR_DOWN_MAX4)
STRATA_GR_DOWN_MAX4=1: launches of at most four tokens run the GR down-projection kernels (plain, split and staged)
with per-thread storage for four tokens instead of kFusedGrMaxT, keeping the block dimensions, the tile width, the
accumulation order and the plain/split/staged choice: the same bits. Off by default. RTX PRO 6000 Blackwell, IQ3_S,
MTP 4, 64K: decode +2.1% (code) / +2.4% (prose) with identical output tokens.

From #443; its one-warp MMVQ experiment (STRATA_MMVQ_WARP1, not bitwise), the roofline benches and the benchmark
evidence files are left out.
2026-10-02 22:05:33 +02:00
Niko1221 60768eb41e prefill: with --peer-device the fused experts stay off even when the peer declines the prompt path (#531 follow-up)
fused_ring() turns the fused ring sizing off for any --peer-device session (core::peer_portable), but the layer's
fused choice tested the peer's prompt-path state (m.pp), which is null when set_peer declines (no P2P, the buffers do
not fit, --peer-prefill-rows 0). Both now follow the flag, so a peer session's prompt path is MMQ with the MMQ ring
and buffers it was sized for. Without --peer-device nothing changes.
2026-10-02 22:05:04 +02:00
Andy 5743d8dc35 docs: the refused --peer-device combinations 2026-10-02 22:04:42 +02:00
Andy f6304c713c peer tier: refuse --peer-device with --layer-split or --expert-cache-device1..3 (both would use the same second card); --help lines for the --peer-* flags 2026-10-02 22:04:42 +02:00
Andy 58f852f100 multi-GPU: a second GPU as an opt-in expert-cache tier (--peer-device N)
A second visible CUDA GPU (N >= 1) holds an adaptive expert cache beside
CUDA0's, filled with the ranked pairs the primary does not hold.  Activations
and result rows cross NVLink or another P2P path; the peer also computes its
experts' rows for prompt chunks (MMQ; the fused path is not combined yet).
Knobs: --peer-device N, --peer-reserve-mib, --peer-slots, --peer-adapt-swaps,
--peer-prefill-rows; sizing stays manual until #216's buffer lending lands.
Default output unchanged: without the flag byte-identical to v0.1.36, with it
byte-identical under the exactness gate.  cudaHostAllocPortable only with a
peer.  docs/SECOND_GPU.md documents the flags and refused combinations.
Measured on 2x RTX 3090 + NVLink, IQ3_S: prefill +15/+25/+25 %, decode +19/+14/+16 %.
2026-10-02 22:04:42 +02:00
Abhinand B b827a47dbd HIP: run the MTP prompt pass per group by default
E-9 (Prefill::draft_kv) declines when the drafter's KV is a ring, which it is
with KV streaming (--kv-resident), so every chunk falls back to the E-4 pass in
MtpDrafter::prefill. On gfx1201 / ROCm 7.2.4 that queue (a graph launch and
four device copies per group, ~2,000 groups per 8192-token chunk, one sync)
sometimes never completes: the prompt hangs in hipGraphLaunch or the final sync
until the watchdog ends the engine.

HIP builds now use the per-group loop unless STRATA_MTP_PREFILL_SYNC=0; CUDA is
unchanged. The variable now reads its value (any value, 0 included, used to
select the old loop).

R9700, full IQ3_XXS, --kv-resident 32768, 131K context, mixed load: 0.1.31
hung in round 1 on 2 of 2 tries; this change ran 30 of 30 rounds clean with no
measurable prompt cost.
2026-10-02 22:03:36 +02:00
efeisot 68c573cee8 AMD: ship the gfx1200 hipBLASLt table, with the with/without measurements
The table #256 left out (489623c): tools/hip/gfx1200-hipblaslt-100202.txt, 67
rows calibrated on the RX 9060 XT with tools/hip/tune_hipblaslt (system ROCm
7.2, hipBLASLt 1.2.2). Same binary, prompt speed with the table vs plain
hipBLAS, two runs each, Coder IQ1_M greedy MTP, STRATA_PREFILL_MMQ=1:

| prompt | table | plain hipBLAS | gain |
| 2,374  | 597-599 | 396-398 | 1.50x |
| 65,045 | 754-757 | 380     | 1.99x |
| 130,091| 719     | 363-370 | 1.98x |

docs/AMD_HIP.md: the community-validated section carries the numbers; ctest
37/37 (without ple_parity and platform_memory_test).

Continues #256.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <[email protected]>
2026-10-02 22:03:36 +02:00
Abhinand B cd20588fa0 tools/hip: gfx1201 hipBLASLt table for hipBLASLt 1.2.2 (ROCm 7.2.4)
Calibrated on a Radeon AI PRO R9700 with tune_hipblaslt (24 of the gfx1100
table's 26 shapes). Setup only picks it when the card is gfx1201 and the
installed hipBLASLt is exactly 100202.

With that hipBLASLt the plain hipBLAS path is far off: on the full GSQ-RCO
IQ3_XXS (KV streaming, engine 0.1.31) a fresh 32K prompt reads at 1,177 tok/s
with the table against 638 without it, and a 7K prompt at 1,164 against 656
(median of 4 warm runs per arm, arms alternated); decode is unchanged.
hip_prefill_hipblaslt_gemm passes with it. docs/AMD_HIP.md notes that the
1.4.1 result (0-3%) does not carry over to 1.2.2.
2026-10-02 22:03:11 +02:00
Yannick Loth 6c90b67e85 pinned: honor STRATA_NO_LARGEPAGES on Linux; name the hugetlb pool shortfall
STRATA_NO_LARGEPAGES is documented as a same-run A/B switch for the large-page path, but reserve() only read it in the Windows branch; on Linux the MAP_HUGETLB path ignored it, so the switch silently did nothing. Honor it there too.

The failure message also said "no hugetlb pool configured?" even when a pool exists but is smaller than the mapping: MAP_HUGETLB is all-or-nothing, so a 34 GiB pool cannot serve a 40 GiB arena and the whole mapping falls back to 4 KiB pages. Print the needed 2 MiB page count against vm.nr_hugepages (the Windows branch already names its byte count and error codes).
2026-10-02 22:02:51 +02:00
sergiywith 49728cea44 File tier: a pack's experts.bin is read unbuffered too (Windows)
setup's low-RAM packs have an experts.bin, and with it 0.1.31's tier mapped it: on an emulated 32 GB PC the mapped
reads took the RAM the budget was sized for, and available RAM fell below 1 GB (#286, measured yesterday).

- set_unbuffered also takes experts.bin (paths_ is the one file); read_direct reads one window per blob (a blob is
  contiguous there) and merges near ones as for the GGUF.
- blob() hands out the stage buffers for any unbuffered source (staged()), so prefetch, begin_layer and transient
  work as with the GGUF in place; the mapped experts.bin path is unchanged otherwise.

IQ2_XS pack with experts.bin, emulated 32 GB PC + 16 GB GPU, 16 GiB budget, 8K prompt + 256 tokens, two runs:
decode 100.2 / 100.6 tok/s, done at 17.2 / 15.5 s, the prompt path's host copies 2.1 s (the GGUF in place: 84-89
tok/s, 21.5-22.1 s, 4.3 s). Greedy tokens identical unbuffered, through the cache and on 0.1.31.
2026-10-02 22:02:39 +02:00
sergiywith 8fe1a9b109 File tier: read the GGUF in place unbuffered when the file cache cannot keep it beside the RAM budget (Windows; #286 ported into 0.1.31's tier)
With --resident-budget-gib on a PC whose RAM cannot hold the expert files beside the budget, every expert outside
the budget comes from the drive anyway. Through the mapped GGUF that costs twice:
- the page faults are small requests on the critical path (the prompt path's stager, the profile fill);
- the pages they bring in take the RAM the budget was sized for. On an emulated 32 GB PC, the 16 GiB budget was
  clamped to 11.65 GiB after the profile fill.

- FileExpertSource::set_unbuffered: chosen by experts_unbuffered (#357) with the budget as the RAM it keeps: whenever
  the files could not be kept beside it, cached now or not - a partly cached file's mapped pages would still land in
  the working set (seen on an emulated 64 GB PC: the budget shrank, then RAM ran out). Each shard is opened
  FILE_FLAG_NO_BUFFERING | OVERLAPPED.
- copy_from_files, the decode prefetch and the complement copy read every role window of a batch at once, then
  copy it into place.
- Windows that are less than 1 MiB apart merge into requests of up to 32 MiB. NTFS runs a file's unbuffered reads
  one at a time while the file is mapped anywhere, and the engine always maps the shards (token embedding, PLE).
  Measured on a PCIe 5 drive at queue depth 48: 512 KiB reads give 10.4 GB/s on an unmapped file and 3.4 GB/s on a
  mapped one; 8 MiB reads give 8.6 GB/s.
- The profile fill reads its pairs in batches of 64, the next batch while this one is copied into the slots.
- warms() is false when unbuffered. A PrefetchVirtualMemory of the mapping would read the experts through the cache,
  a second time.
- Otherwise nothing changes: the mapped path stays for a keepable set, for no budget, and off Windows.
  STRATA_UNBUFFERED_LOAD=1/0 forces the choice.

Greedy tokens are identical with the reads unbuffered, through the cache, and on 0.1.31.
2026-10-02 22:02:39 +02:00
sergiywith e55b9676d7 load_experts_gguf: the header declares the new parameter
The definition gained a defaulted parameter while the header kept the four-parameter declaration. The engine's
caller is in the same file, so it built, but tests/core/expert_layout_test.cpp calls it through the header and
failed to link (LNK2019, unresolved load_experts_gguf). The default now lives in the declaration;
expert_layout_test passes.
2026-10-02 22:02:39 +02:00
sergiywith 9aae61f76d Start: read the expert arena unbuffered when the file cache cannot help (Windows; part 1 of #285)
A buffered read copies every expert through the file cache. That pays off only when the cache can keep the files
for the next start. On a PC whose RAM cannot hold them beside the arena (a 64 GB PC with IQ2_XS: 24 GiB left for
36.5 GiB of files), every start reads the drive anyway, and the copy is pure cost.

- experts_unbuffered() (pinned.cu): timed random 64 KiB reads tell whether the files are in the cache already
  (a cached read takes ~10 us, the drive ~80). Unbuffered is chosen only when they are not and the RAM left beside
  the arena could not keep them either. A warm restart that 0.1.31 serves from the cache stays on its FILE* path.
  STRATA_UNBUFFERED_LOAD=1/0 forces the choice; the log names the reader and why.
- load_experts_gguf: each chunk's 4 KiB-aligned window is read with FILE_FLAG_NO_BUFFERING into an aligned buffer and
  scattered into the blobs, with a handle per role file as expert_gguf_file() resolves it (split shards). 16 readers.
- load_experts_direct (pinned.cu): a pack's experts.bin ranges are read unbuffered straight into the arena. When the
  ranges are not 4 KiB-aligned, it falls back to load_experts_ranges.

IQ2_XS without experts.bin, RTX 5090, emulated 64 GB PC (a locked-pages RAM ballast leaves 58 GiB), two rounds:

| | first start: arena / exit | restart: arena / exit |
|---|---|---|
| 0.1.31 | 22.1-25.2 s / 28.2-31.0 s | 12.5-16.0 s / 17.5-20.8 s |
| this | 18.3-20.2 s / 23.1-25.4 s | 6.0-6.1 s / 9.8-9.9 s |

With 128 GB the probe finds the files cached (15 of 16 reads) and the buffered path runs as before. Greedy tokens are
identical unbuffered, buffered and on 0.1.31 main.
2026-10-02 22:02:38 +02:00
sergiywith c791d32934 Adaptive tier: --adapt-decay
--adapt-decay F sets the factor the routing counts are multiplied by after each adaptation (0.7, as before; the same
float, so the default is bit for bit 0.1.37's). #477's routing heat is added before the decay, as before.

From #407; its --adapt-tuned (opt-in re-ranking every 2 rounds, 192 swaps, x0.92 for caches holding 20-60% of the
experts) is left out of this release.
2026-10-02 22:02:16 +02:00
Niko1221 e4ed23fc17 IQ4_XS's AVX-2 kernel on AVX-2 CPUs only; native_expert_parity skips the AVX-512 check it has no kernel for (#415 follow-up)
- The engine's `avx2` switch is on for AVX-512 CPUs too, so the widened gate sent an AVX-512 CPU's IQ4_XS gate/up rows
  to the new AVX-2 kernel instead of ggml-cpu: other rounding on CPUs that #415 did not mean to change. A format with
  only an AVX-2 kernel now takes it on CPUs without AVX-512; everything else is dispatched as before.
- native_expert_parity ran its AVX-512 check for IQ4_XS on an AVX-512 CPU: iq512_rows has no case for it, so the
  rows stayed zero and the check failed. Each check runs only for the formats its kernel implements; the AVX-2 one
  runs on AVX-512 CPUs too, so this PC tests the new kernel.
2026-10-02 22:01:46 +02:00
pipeob0 3ce93f90fe IQ4_XS expert rows on the AVX-2 path: the multi-token kernel this format never had
IQ4_XS (23) was missing from iq256_supported, so on an AVX-2-only CPU its gate/up expert rows
fell back to ggml's per-token vec_dot while every other i-quant format got the multi-token
kernel that decodes the weights once for the whole verify window.

Fmt32<23> reuses the 16-value codebook IQ4_NL already has. Each of the eight 32-value sub-blocks
carries its own 6-bit scale (two nibbles of scales_l plus two bits of scales_h), used signed as
(ls - 32): the scale folds into the int16 operand of madd_epi16 instead of becoming a float
multiply per sub-block, and the codebook sign is carried the way iq4nl_rows does it (|w| as the
unsigned maddubs operand, w's sign applied to the activation).

The gate in native_expert.cpp and in native_expert_parity cannot be iq512_supported alone:
IQ4_XS has an AVX-2 kernel and no AVX-512 one, so on an AVX-512 CPU the widened gate must still
pick each kernel only for the formats it implements - falling through an empty switch would
leave ff unwritten rather than falling back to ggml-cpu. Widening the parity gate is what makes
the format tested at all: with iq512_supported alone the tool skipped it on every CPU.
2026-10-02 22:01:22 +02:00
Niko1221 96b32999b3 decode: #463 cleanup - one wait in apply_pending, the serve call site indented, shorter comments
The cherry-picked change kept the old `if (wait) cudaEventSynchronize` above its own (a second, no-op wait), and its
serve-mode call site sat four columns left of its block. The same code otherwise.
2026-10-02 22:00:54 +02:00
Constantin 504579da12 fix: --dump-logits must not promise rows it will never write
A native pack leaves the per-token loop at `if (native_pack) { spec_pos = pos;
break; }`, before the site that dumps a row per position.  The header was
written at open anyway, so the file claimed 64 or 66 rows and contained none -
and a reader that trusted it reported "0 differing positions" from a file with
no positions in it, which is the one answer that looks like a pass.

The header is now written with the FIRST row.  A run that dumps nothing leaves
an empty file, which is what actually happened, and a reader can treat size
zero as "this mode never dumps" instead of as agreement.

Verified on the native pack: the file is now 0 bytes where it was 8.  The
non-native path is unchanged apart from WHEN the header lands; it was not
exercised here because no non-native model is set up on this machine.

(cherry picked from commit b87d7dcfe9a0754c0a2b8b9776b7f2ec8980b6a1)
2026-10-02 22:00:24 +02:00
Constantin 63b4bf0c1e decode: wait for an adaptive expert swap before reading the residency table
Greedy decode was not reproducible on this box. Repeated identical requests
diverged from about the 28th generated character, and the drafter, the expert
routing and the first verify window were all byte-stable, which left the
adaptive tier as the only thing left that could move a result.

It is. `apply_pending(false)` polls the swap's event with a NON-BLOCKING
cudaEventQuery, so whether the experts an adapt round just copied in were
resident for the next window depended on whether their PCIe copies had landed.
Resident runs the GPU kernel; non-resident is computed on the CPU, and on a
machine without AVX-512 those two kernels round differently enough to move a
top logit by 0.26 - measured at the window right after the swap was issued.
From there the trajectory is a different one, permanently.

Waiting is the fix. The copies were issued during the previous window's
drafting, so the wait is short, and in exchange the residency table is a
function of what was actually copied rather than of how fast the disk was.

With the default --adapt-every 4 left in place, five runs are now byte-identical
across all 24 verify windows and emit the identical 40-token stream; before the
fix three of five agreed and two forked at window 16. --adapt-every 0 (frozen
placement) was already deterministic, which is what identified the tier.

The STRATA_TRACE_ADAPT lines added with the probe are env-gated and off by
default: they report whether a round considered, skipped, or swapped, and
whether the previous round's copies had landed.

No cost measurement is claimed here: this says the trajectory is a function of
the inputs again, not what the wait does to decode throughput.

(cherry picked from commit 1e3888a73b69a332585056af5b86643ff8367242)
2026-10-02 22:00:24 +02:00
BlueKingMuch e7a5fd30d5 experts: the verify window's PCIe call launches for the groups it has; SwiGLU and q8_1 in one pass (bitwise)
native_expert_grouped launched a block row per possible group (cap = window tokens x 10) for gate/up and down,
and SwiGLU and the q8_1 quantization as two kernels over all cap entries.  The verify window's PCIe call has no
group at all at pcie_frac 0 and usually none otherwise, yet every layer paid ~17k blocks that started only to
return plus two passes over entries that are not its own.

- gate/up and down stride over the groups (rows y, y + gridDim.y, ...); the PCIe call runs 4 block rows
  (kPcieGroupRows), the VRAM call keeps one per possible group.  Each group's rows are computed by the same warp
  code in the same order, so the results do not depend on the grid.
- SwiGLU + q8_1 in one kernel over the call's own entries [grp_start[0], grp_start[n]); the product is rounded on
  its own (__fmul_rn; on HIP a plain product under contract(off)) before the block sum, as when it went through
  memory, and the quantizer body is quantize_q8_1_kernel's (factored out, its PTX unchanged).
- STRATA_GROUPED_V1=1 keeps the old launches for A/B timing; native_grouped_parity checks old vs new bitwise
  (every gate/up x down format, 0..cap groups, entries from 0 and past 0, grid_groups 1..4 and > cap).
2026-10-02 22:00:09 +02:00
Niko1221 f2c220f560 qsa_topk_active_parity checks the active-bound dispatch on any CUDA card (#512 follow-up)
The engine takes the bound on Turing only, so on other cards the test compared the capacity rule with itself.
STRATA_TOPK_ACTIVE_ANY=1 (set by the test) takes the Turing dispatch on any card; the kernels are the same on every
architecture. The CMake block moves above the qsa_select_bench comment it had split.
2026-10-02 21:59:49 +02:00
imanu86andCodex 94329dd801 prefill: use active QSA top-k bounds on Turing with large KV capacity
With --max-context 262144 the QSA score rows have a stride of 65538 blocks; a prefill batch at 131K actual context
fits the register top-k kernel's 33792-block limit, but CUDA dispatch tested the allocated capacity and chose the
reference kernel. The supplied active_blocks bound is now used on sm_75 only; other CUDA cards keep the capacity
rule, HIP its own policy, and decode (no bound) is unchanged. STRATA_TOPK_CAPACITY_GUARD restores the capacity rule.
qsa_topk_active_parity: 16 cases at stride 65538, selected ids bitwise.

Squashed from #512 (its commit and its merge of upstream 0.1.36).

Co-Authored-By: Codex <[email protected]>
2026-10-02 21:59:27 +02:00
Rhonstin 98bb94d752 PLE: lift the stale Q5_0 + --ple-io direct refusal (#296)
PleReader's row_bytes has been a runtime parameter since the FP8 table
(160 B rows) needed it -- not 90-specific anywhere in the actual read/
cache/job-building code (RowCache, Job/Use, the straddle-length formula
in issue()). ngram.cpp's "Q5_0 PLE requires --ple-io mmap" refusal
predates that generalization (or was just never revisited): FP8's 160 B
rows already go through PleIo::Direct with no such gate.

ple_reader_test --selftest now runs its full synthetic suite (decode-
shaped tickets, page-straddling rows, dedup/edges, bulk, two in-flight
tickets, fault injection, keep-alive -- both threaded and caller-thread
modes) at row_bytes=110 as well as the production default 90, before
touching the refusal. Both: OK.

ple_reader_test --gguf against the real OrcaRouter Q4_K_M shard (the
same one from the Q5_0 kernel PR): direct vs mmap over 312 real PLE
tickets -- bit-identical, and direct is ~8.6x faster (461 vs 3959 us/
token) on this SSD, matching the ~2-2.6ms/token mmap cost the original
"sixteen serial page faults" comment in gather() measured for the
IQ4_NL table.

End to end on the running model (engine 0.1.32, RTX 3090): same text/
math/vision outputs as --ple-io mmap (deterministic sampling), with a
consistent decode speedup (~9-12% across three real generations) and
image-prompt PLE throughput up from not practical to measure to 185
tok/s -- the full per-token win is smaller than the isolated 8.6x since
PLE is one part of a token's cost, not all of it.
2026-10-02 21:59:03 +02:00
Rhonstin df52f530be native experts: Q5_0 GPU kernel (#222)
is_iq()/the GU/D/MMVQ format lists had Q4_K, Q5_K, Q5_1 and Q8_0 already,
but not Q5_0 -- a plain `llama-quantize` "_M"/"_S" tier GGUF (not Unsloth's
dynamic method) commonly puts Q5_0 on down-projections, sometimes gate/up
too, and native_expert_supported() refused those layers outright ("this
engine has no GPU kernels for").

vec_dot_q5_0_q8_1/dq_q5_0 port vecdotq.cuh's integer chain and the
dequantizer verbatim (symmetric format, so -- unlike Q5_1 -- there's no
min-term rounding choice to make). Fmt<6> plus the row-bytes/is_iq/
dq_dispatch entries follow the existing Q5_1 (type 7) pattern.

native_expert_parity --synthetic q4_K/q5_0 and q5_0/q8_0 (both now in the
CMake test matrix): 0 failures, GPU dequant bit-exact against to_float,
gate/up and down rows bit-exact against ggml's own vec_dot. q5_0/q5_0
(Q5_0 in both roles) is left out of the matrix -- stacking the same
lower-precision format on both roles pushes the GPU path to ~3.6% rel
error against the float reference, just over this test's 3% threshold;
that's compounded quantization noise (CPU rel error is the same ~1.25%
baseline as q5_0/q8_0), not a kernel correctness issue, and no quantizer
I've seen actually picks Q5_0 for both roles of the same expert.

Verified end to end on a real model: a community Q4_K_M GGUF (gate/up
Q4_K, down Q5_0 on several layers) that previously failed at layer 6
now loads and serves correctly on an RTX 3090 (engine 0.1.32).
2026-10-02 21:59:03 +02:00
BlueKingMuch 4e69f97477 prefill: DeltaNet recurrence with the three value heads of a key head in one thread (1.44x), output norm without its dead FP32 store (1.5x); same bits
gdn_rec_cols_pipe_kernel is bound by shared memory, not by arithmetic: every thread of a warp needs the same
32 q and k values per token (the k twice), and a warp receives one such broadcast value per clock. The new
kernel runs column c of the three value heads that share a key head (head % 16) in one thread, so every q/k
value it loads feeds three heads and the token's k row is loaded into registers once for both of its uses.
Its inputs come in blocks of 8 tokens, copied to shared memory by cp.async while the block before computes,
and a token needs 2 __syncthreads instead of 5. 64 blocks instead of 192. Per value head and column the same
arithmetic in the same order: gdn_rec_parity checks output, state and FP16 output bit for bit (T from 1 to
4099) and times it: 18.8 -> 13.0 ms per layer at 32768 tokens.

The output norm stored the normalized value in FP32 as well, which nothing reads (the out projection takes
the FP16 copy): 4.65 -> 3.05 ms per layer at 32768 tokens.

Together 845 -> 579 ms per 32768-token block over the 36 DeltaNet layers; in the engine +2.3 % prefill
tokens/s on 32000-token prompts and +2.2 % on 64000-token prompts, the same greedy answers. Measured on 0.1.32
on a 4080 SUPER (80 SMs); on 0.1.31 the same change gave 1.42x, 1.51x and +2.1 % / +2.0 %. CUDA sm_80+
(cp.async) on a card that holds all 64 blocks at once; otherwise, on Turing and with STRATA_GDN_KEYHEAD=0 the
kernel as before.

Squashed from #413 (5 commits: the kernel, gdn_rec_parity and its --bench SM bands; the 48-63 SM exception
added and taken back).
2026-10-02 21:58:46 +02:00
Niko1221 482e22b7cd qsa_prompt_attn: Q4_0 mode 4 on sm_80+ only (#452 follow-up)
On Turing mode 4 would run as pairs of m16n8k8 MMAs, which no parity run has checked yet; RTX 20 cards keep the old
kernel for --kv q4_0 until one does.
2026-10-02 21:58:21 +02:00
Chen Bao eb0803af78 qsa_prompt_attn: Q4_0 K and V on tensor cores (mode 4) - long prompts with --kv q4_0 no longer take the old kernel
The tensor-core prompt attention (D-1) refused Q4_0 pools, so --kv q4_0 read every prompt through the FP32 per-query
kernel. Mode 4 is mode 1 (int8) with a scale per 32 values: each q4_0 block's 16 code bytes become 32 exact int8
codes (code - 8) at gather, its fp16 scale goes to the per-group scales, which are applied in FP32 as int8's are
(q.k per 32-dim group; p.v folds each group's scale into p, two groups per warp). The p.v fold is bounded by the
chunk's largest |scale|: q4_0 scales are signed (ggml's d = max / -8). The caller's rotation of q and of the output
is unchanged. STRATA_PROMPT_ATTN_Q4=0: the old kernel (A/B).

qsa_prompt_attn_parity gets Q4_0 cases with signed scales spread over two decades, as a pool holds them (32K and
1.5K contexts), against FP64 and the old kernel.
2026-10-02 21:57:55 +02:00
Chen Bao b7639e8c90 prefill: the draft layer's batched K/V for a ring too (KV streaming), and STRATA_DRAFT_TIMING
With KV streaming (--kv-resident) the MTP drafter's K/V is a ring of its window (kv_mode 2: page p in slot p % n_slots
over a host copy), and draft_kv refused it, so every prompt chunk fell back to the drafter's own pass - one graph per
few rows. The batched path takes the ring with its own page table and host copy (as a streamed main layer appends);
the cells it writes are those the window can still reach, which the ring holds, and one batch never spans more than
the ring's slots, so no two cells of a batch share a slot. STRATA_MTP_BATCH_RING=0: the drafter's own pass (A/B).
STRATA_DRAFT_TIMING=1 (debug): the pass's time, synced.
2026-10-02 21:57:16 +02:00
sergiywith 6a5902832c Prompt path: a stager buffer's first job of a generation waits for the previous DMA from it
Stager::work waited for a buffer's DMA only from the generation's kRing-th job on (j >= kRing); a generation's first
kRing jobs wrote their buffers straight away. The previous generation's last DMAs from those buffers are only
known to be done where something else waits for them: the routing sync before a staged layer's start(), or the
sync at the end of a chunk with an MTP drafter or stages. A stream_all chunk that ends without one (no --mtp), or a
ring entry the routing skipped (its copy is never waited for), leaves a window where the next chunk's first jobs
overwrite a pinned buffer a DMA may still read. The event is now waited for on every job; an event never recorded,
or already complete, returns at once.

IQ2_XS with --mmap-experts --resident-budget-gib 16 (12,144 of 48,668 streamed experts through the stager): the
same tokens on a 32K prompt, prefill 6,491 vs 6,546 ms.
2026-10-02 21:57:12 +02:00
sergiywith 067c9362c8 ple_land: the rows' upload, its event and the wait before a refill are checked
From an audit: the upload of a chunk's rows, the event recorded after it and the wait on the other buffer's event
before the SSD thread refills it were unchecked, so a failed record or wait let the thread write a buffer an
upload might still read. A failure now ends the chunk with the CUDA error.
2026-10-02 21:56:59 +02:00
sergiywith a34078ab2f Prompt path: the first chunk's n-gram (PLE) rows read beside layer 0, 256 at a time
Layer 1 adds the per-layer embedding to every token of a chunk, so its rows must be in. A later chunk's rows were
already read on a thread during the chunk before; the first chunk's were read synchronously before layer 0, so the
GPU idled while the SSD read them (an nsys trace: ~245 ms of a single-chunk 32K prompt). Now the first chunk's
gather starts on a thread too and lands just before layer 1 (ple_land), which also starts the next chunk's.

The reads themselves went 64 at a time: a 32K prompt is 512,720 rows in 213,358 4 KiB reads, ~620K IOPS at queue
depth 64. --ple-inflight now defaults to 256, where the drive saturates (1024 is no faster). Decode reads 16 rows a
token and is unchanged. The same rows: the same results.

IQ2_XS, RTX 5090: a 32K prompt 5986 / 6013 -> 5843 / 5808 ms, 8K 1714 -> 1624 ms; first-token logits bit-identical.
2026-10-02 21:56:59 +02:00
sergiywith e8de49ebc1 Prompt path: an MMQ group's experts gathered in one launch, after one wait, released by one event
In the streamed walk every expert put a cross-stream wait (its copy) and an event record (its ring slot back) on the
compute stream around a ~3 us gather. Under WDDM each pair left ~10 us of GPU idle even when the copy had long
landed: an nsys trace of a 32K prompt showed 226 ms of idle between back-to-back gathers while the host was 3-11 ms
ahead of the GPU. Now a group of 16 is gathered by one launch (copy16_group_kernel) after one wait on its last
streamed copy - the copy stream is in order - and one event releases all of its ring slots: the issuer waits on
used[used_of[slot]]. A ring entry the routing skipped inside an open group first gathers what the group holds so
far, so no more than a group's entries are ever held back from the issuer. The same bytes in the same group slots.
STRATA_PREFILL_GROUP_GATHER=0: one at a time, as before.

IQ2_XS, RTX 5090, 262K context: 32K prompt -8.6%, 8K -10%, 2K -12.6%; first-token logits bit-identical at 2K, 8K,
16K and 32K and with a 96-slot ring.
2026-10-02 21:56:43 +02:00
maxfridbe 835d30b186 sycl: OpenAI logprobs on /v1/chat/completions (engine LP lines + server_intel)
- engine (serve mode): GEN key logprobs=K (0..20) writes "LP logprob id:lp ..."
  after each "T id", from the verify window's head logits (Verifier::copy_logits;
  before temperature, penalties and sampling); absent key, no LP lines
- server_intel.py: pairs LP lines with their tokens (StrataEngine._pump), passes
  logprobs/top_logprobs to the engine, and fills OpenAI's choices[].logprobs
  (content / reasoning_content) in streamed chunks and the collected reply; the
  stop token is not listed. serve/ itself is unchanged.

Tested: a fake engine on hardac (streamed, not streamed, without logprobs,
stop token excluded); on the B70 with the IQ2_XS: same answer with and without,
"Paris" -0.0019 with top-1 equal to the chosen token, no measurable time cost.
2026-10-02 14:35:20 -05:00
Niko1221 5b8c84e7da HIP: the fused Q2_0 prompt experts on gfx11 matrix cores (opt-in STRATA_PF_FUSED=1)
expert_w11_kernel: moe_fused.cu's design (GPU grouping, experts read in place, gate/up + SwiGLU +
int8 H, then down) on v_wmma_i32_16x16x16_iu8. A work item = 128 weight rows x a 64-row tile, 8
waves of 2x2 16x16 tiles; operands straight from global one block ahead, weight scales in LDS.
The activations take gfx11's K order (act_pos); per 32-value half the integer dot is exact and the
epilogue is the CUDA kernel's. hip_prefill_fused_moe (tests/cuda/prefill_fused_moe_test.cpp) on
gfx1151: vs FP32 reference rel RMS 1.070e-2 (= MMQ's), vs MMQ 3.0e-5; one 2048-token layer 23.2 ms
(MMQ path) -> 11.3 ms. The native packs' fused kernels stay CUDA-only (stubs on HIP).
2026-10-02 19:21:35 +00:00
Niko1221 a138f63067 prefill: the GDN recurrence with four lanes per column (no barrier per token) + a grid-stride norm
Replaces the per-head kernel of the previous commit (VGPR-bound, spilled). Same column-split grid
as gdn_rec_cols_pipe_kernel (4 x 32-column blocks per head), but lane g of a column's four holds
exactly the old thread's row group g; kv / o partials meet through wave shuffles and are added in
the old order, so no __syncthreads per token; q/k/v/gate/beta staged 4 tokens at a time (~10 KB
LDS: all 192 blocks resident). The output norm runs the old kernel's body over a grid-stride walk
(T x 48 blocks of 128 threads before). tests/hip/gdn_rec_head.cpp: y, y16 and state bitwise equal
to the old kernels for T 1..2051 (variant 3 = new recurrence + old norm, a diagnostic); 2048 tokens
9.8 -> 4.1 ms on gfx1151 at the test's 600-880 MHz.
2026-10-02 19:21:35 +00:00
Niko1221 9a42723283 prefill: the GDN recurrence per head, a lane pair per column, the output norm fused (same bits)
One block per value head; each column's 128 state rows in the registers of two lanes of one wave
(the 32-row group partials swapped within the wave and added in the old order); q/k/v/gate/beta
staged in LDS 8 tokens at a time with the next chunk prefetched; the RMS norm + gate of
gdn_out_norm_kernel fused per chunk. tests/hip/gdn_rec_head.cpp: y, y16 and the state bitwise
equal to the column-split + norm kernels for T 1..2051; 2048 tokens 9.8 -> 6.7 ms on gfx1151
(at the 600-880 MHz the GPU's DPM runs this test at). STRATA_GDN_HEAD=0 keeps the old kernels.
2026-10-02 19:21:35 +00:00
Niko1221 92dde2f72e HIP: the WMMA QSA block scorer (STRATA_SELECT_WMMA=1) on gfx11 (RDNA3 / RDNA3.5) too
gfx11's bf16 WMMA layout: 16 k per lane, C rows 2i + lane/16. On gfx1151 (qsa_select_bench, 131624
capacity): ctx 32768 x 2048 queries scores 14.2 -> 3.5 ms (4.1x), selections identical 2047/2048;
ctx 65536 x 8192 queries 110.1 -> 25.9 ms (4.3x), identical 8192/8192. Still opt-in, as on gfx12.
2026-10-02 19:21:35 +00:00
Niko1221 41dbcdff32 hip: hipBLASLt tuning table for gfx1151 (Strix Halo, ROCm 7.14.1 / hipBLASLt 100401)
All 15 prompt GEMM shapes of Qwen3.8-Flash-Next at chunks 2048 and 8192 (T = 2047/2048/8191/8192),
tuned on Aurora (Ryzen AI Max+ 395) with tools/hip/tune_hipblaslt.cpp.
2026-10-02 18:13:09 +00:00
maxfridbeandsergqwer, constantindjonkam, architectds, BlueKingMuch (upstream PR authors) fd3214f52e sycl: port open upstream PRs #385 #463 #453 #374 #363 #407 #413 onto 0.1.35
One dpct run of upstream main + the seven PRs, 3-way merged into the files they
touch (sycl/tools/merge_upstream.py); their header changes are forked into
sycl/include until upstream merges them.

- #385 stager waits for a buffer's previous DMA on every job (port: polled seq)
- #463 decode waits for an adaptive swap before reading residency
- #453 drafter's batched K/V on the KV-streaming ring
- #374 first chunk's PLE rows read beside layer 0; port fixes: the next read
  starts at c0 + T (the port's first chunk is shorter), and the upload is
  marked by a polled sequence number instead of a host event wait, which
  deadlocked prompts past ~4K tokens under the Level Zero v2 adapter
- #363 group stride + fused SwiGLU/q8_1 for the PCIe expert call, re-applied
  to the port's lane kernels (fp contract off, as upstream's HIP form)
- #407 --adapt-tuned (opt-in), #413 key-head DeltaNet recurrence (opt-in via
  STRATA_GDN_KEYHEAD=1: 8% slower on the B70; its NVIDIA gate and SM-holding
  parity bench not ported)

Tested on the B70: native_grouped_parity, iq_multi, gr, qsa, kv_hybrid,
quantize_act, qsa_prompt_attn parity pass; Coder 19/2,184-token, IQ2_XS and
40K outputs identical to 0.1.33; Coder 2,184-token prompt 784 -> 825 tok/s;
128K int8 KV streaming 895 / 67.0 tok/s; IQ2_XS decode +1.7% (#363).

Co-authored-by: sergqwer, constantindjonkam, architectds, BlueKingMuch (upstream PR authors)
2026-10-02 13:12:58 -05:00
Niko1221 c6a0d4033b prefill: MMQ groups of a fully resident layer in row-count order (opt-in STRATA_MMQ_RESIDENT_SORT_NE=1)
Port of the Aurora experiment (mmq-resident-rowcount-sorting-v1, +13% 8K prompt on gfx1151 over
0.1.30 + Lt, identical output ids there): each 16-expert MMQ group's max_rows is close to its
experts' own row counts, so less tile padding. Host-only; slot/src/off rebuilt before the upload.
2026-10-02 18:00:02 +00:00
Niko1221 601b7765b6 HIP: the matrix-core prompt attention (STRATA_HIP_WMMA=1) on gfx11 (RDNA3 / RDNA3.5) too
gfx11's v_wmma_f32_16x16x16_f16 takes all 16 k per lane (lanes 16..31 repeat 0..15) and
returns C rows 2i + lane/16; the kernel loads its fragments in that layout. Opt-in as on gfx12.
2026-10-02 18:00:02 +00:00
Niko1221 6edf8bde75 HIP: admit gfx1151 (Strix Halo, RDNA3.5) as an experimental target, with sudot4 2026-10-02 17:41:28 +00:00
Niko1221 fc4edd2ca5 Engine 0.1.37: a silent engine is restarted (#481), Windows AMD counts the desktop's VRAM (#380 #377 #497), a steadier PCIe probe (#485), fixes #496 #495 #498 #505 #493; setup requires it 2026-10-02 19:26:00 +02:00
Niko1221 de896a8e96 Merge branch 'f-137-srv' into rel-0.1.37 2026-10-02 19:23:24 +02:00
Niko1221 b038240369 docs: Windows AMD's free-VRAM figure within the WDDM budget (#380) and the host-timed PCIe probe (#377) 2026-10-02 19:22:46 +02:00
Niko1221 9abc623f2c PCIe probe (#485): best of four timed bursts, a continuous share, the samples logged
The probe timed one 1 GiB burst; an x16 PCIe 4 laptop (RTX A3000) read 18.5, 6.9 and 5.8 GB/s
in three starts, and the low reading set pcie_frac (0.12-0.15 where calibrate.py found 0.35).
The same 1 GiB is now four bursts of 256 MiB, each timed on its own (events between them on
the stream; on Windows HIP the host clock, #377), and the fastest is the link's figure: a
disturbance only ever slows a copy, while the median would still follow one lasting through
half the bursts. The probe copies no more than before.

The share was base above 20 GB/s and base * bw / 26 below (19.9 GB/s -> 0.42, 20.0 -> 0.55;
4.0 -> 0.08, 3.9 -> 0). It is now base * min(1, bw / 20): continuous, unchanged from 20 GB/s
up (an x16 PCIe 4/5 link reads ~26-28 GB/s, so the default stays 0.55 there), in proportion to
the link below, so the link's time on its share stays about what the x16 share costs. The rule
is one function for CUDA0 and the layer split's stages.

The log names every burst: "PCIe probe: 28.9 GB/s host->device (best of 28.9 28.9 28.9 28.9)"
(the RTX 5070 here; pcie_frac 0.55 as before).
Noted, not changed: a given --pcie-frac is every stage's share and skips the stages' probes.
2026-10-02 19:22:45 +02:00
Niko1221 3c38c22649 setup: --vram-reserve-mib N, and INSTALL.md documents it (#493)
The engine already leaves --vram-reserve-mib MiB of VRAM free (default 700). INSTALL.md now says what it does, its
default, and how to set it (the flag, or "--vram-reserve-mib", "2048" in the config's args). Setup's new flag writes
it into the config only when given (one value: it replaces the images' own 700, with a note when it is less than the
GPU image encoder needs); on a start of an installed model it is saved into that model's args, and a new copy set up
from an earlier install keeps it. The default config is unchanged (golden test). Tests in test_setup_choices.py.
2026-10-02 18:52:23 +02:00
Niko1221 18b9c18454 setup: UD-Q4_K_XL across GPUs without the RAM budget when the RAM holds it; no budget on a --gpus start (#498)
The engine refuses --resident-budget-gib with a layer split, so setup always dropped UD-Q4_K_XL to one GPU. With RAM
>= the GGUF size + UNSLOTH_RAM_LEFT_GB (~135 GB) and 2+ usable cards, setup now asks (one GPU stays the default and
--yes keeps it; an explicit --gpus is honoured; an explicit --resident-budget-gib keeps one GPU) and the split writes
"gpu": [..], "layer_split": "auto" without the budget: all the experts loaded into RAM at start, the files through the
OS file cache (the config #498 measured: 2x RTX 3090, 31 -> 64-78 tok/s). Latent bug: START-HERE --gpus 0,1 (or the
start-time offer, or a hand-edited config) on a UD-Q4 config kept the budget and the engine exited with code 2; the
split now drops it, or setup stops before saving when the RAM is too small. docs/UNSLOTH_Q4.md says so. Tests in
tools/test_setup_unsloth.py; the golden configs are unchanged.
2026-10-02 18:50:12 +02:00
Niko1221 b317c34698 setup: honour HF_ENDPOINT, and say where the model files go (#495)
hf() takes the host from HF_ENDPOINT (default huggingface.co, a trailing slash dropped); the pinned revisions, the
fallback to main and the SHA-256 checks are unchanged. tools/mtp_fetch.py reads the MTP tensors from the same host.
Step 5 prints the folder setup expects the model files in and how to use files downloaded by hand (that folder with
their original names, or --gguf-dir), and the mirror when one is set. INSTALL.md says the same. Tests: the endpoint
in hf()/hf_unpinned()/mtp_fetch, and step 5's words over a mocked install. The golden configs are unchanged.
2026-10-02 18:46:07 +02:00
Niko1221 455fc8a794 serve: the start narrator says what happens to the experts with --mmap-experts (#505)
The server window said "loading the experts into RAM (about N GB)" whatever the flags. Now: --mmap-experts maps them
from the model files (the OS file cache reads them, nothing is loaded up front; its "experts via mmap" line triggers
the message when the model has no PLE line), --resident-experts copies the ones the GPU does not hold, and
--resident-budget-gib N copies up to N GiB. setup's start banner says "maps" for the plain mapped mode too. Tests:
the words per flag set, and the narrator over a mapped and an arena log.
2026-10-02 18:44:19 +02:00
Niko1221 3af82092d6 serve: the engine-exited-before-READY error shows this start's last 20 log lines (#496)
Every start failure, not only the draft-head case (#474), now carries the engine's own reason: the last 20 lines
this start wrote to the engine log (never an earlier start's). The failed start also closes its pipes and its
handle on the log. Tests: the tail itself, and a fake engine that exits with a reason in its log.
2026-10-02 18:42:56 +02:00
Niko1221 a9e9eb2ae1 serve: end an engine that lost step with the server instead of waiting forever (#481)
A request whose engine prints nothing for engine_silence_s (default 300 s; while a prompt is read, a chunk may take
3x the previous one's time, the first up to its tokens at 50 tok/s more) ends with EngineSilent (an EngineDied): the
engine is killed and the next request starts it again. The STOP drain, under the request FIFO, is no longer an
untimed wait. "engine_silence_s": 0 keeps the old behaviour. Tests: unit (silence, PP chunks, first chunk, STOP
never acknowledged, 0, config) and over HTTP with a fake engine process (non-stream, stream, stop token).
2026-10-02 18:42:20 +02:00
BlueKingMuch 5a7f0860e7 HIP: count the desktop's VRAM on Windows (WDDM budget, STRATA_WDDM_BUDGET)
On Windows, hipMemGetInfo (ROCclr's PAL backend) reports the card's size
minus this process's own allocations; what the desktop and other
programs hold on the card is not subtracted. On a card that also drives
the desktop the engine counts the ~930 MiB those hold as free, and
--expert-cache auto fills the card past what Windows lets the process
keep in VRAM: WDDM moves part of it out to system RAM. On an RX 6800
(HIP SDK 7.2) with setup's configuration: a 9.83 GiB cache, the card at
16132 of its 16368 MiB, 929 MiB more of the engine in system RAM than
with this change, 30.1-31.0 tok/s decode. On a 0.1.30 build,
--vram-reserve-mib 1500 left the card as full (16037 MiB), since the
reserve is taken from the same figure.

Windows gives every process a video memory budget that does account
for the others (DXGI QueryVideoMemoryInfo). On that card it is 799 MiB
below the card's size while the process is small and about 1.8 GiB
below once it holds 11 GiB; allocations past it still succeed.
cudaMemGetInfo, which the HIP shim maps to hipMemGetInfo, now lowers
hipMemGetInfo's free figure by what the budget withholds (the card's
size minus the budget), on Windows only. What is sized from it then
stays within the budget: --expert-cache auto sizes the cache from it,
and the existing check after the slots are written shrinks it ("only
8 MiB free once the slots are written ... shrinking"): an 8.05 GiB
cache, the card at 15230 MiB, 40.6-41.5 tok/s.
Lowering HIP's own figure, instead of taking the budget minus DXGI's
usage, keeps memory the HIP runtime has freed but still caches counted
as free, as HIP counts it.

dxgi.dll is loaded at run time, so nothing new is linked; the adapter
is found by the device's LUID. Without dxgi.dll, the adapter or a
budget below the card's size, hipMemGetInfo's figure stands. The first
query logs the budget once. STRATA_WDDM_BUDGET=0 turns it off. CUDA
and Linux builds are unchanged.
2026-10-02 18:38:53 +02:00
BlueKingMuch e52051dc71 HIP: time the PCIe probe on the host on Windows
The PCIe probe sets the share of the missed experts the GPU reads over
the link (--pcie-frac): the native default 0.55 from 20 GB/s up, less
on a slower link (#44). On Windows HIP it timed its copies with events
that do not bracket them there: an RX 6800 read between 3,348 and
25,999 GB/s in 24 engine starts, so every link kept the x16 share. A
standalone copy of the probe on that card: its events measure 0.13 ms
for the 1 GiB, the host clock 43 ms (25.1 GB/s).

On Windows HIP the probe now times the same copies on the host, between
two synchronizes (1 GiB, tens of milliseconds): the same RX 6800 on
PCIe 4.0 x16 reads 27.2 GB/s in every run, which keeps 0.55 there. On
a PCIe 4.0 x8 or 3.0 x16 link the share now shrinks as #44 intended.
CUDA and Linux keep the events.
2026-10-02 18:38:35 +02:00
Niko1221 82cf9b83c8 docs: the cluster decode kernels run on sm_90+ (RTX 50), not RTX 40 2026-10-02 18:24:22 +02:00
Niko1221 2aa6ace036 docs: 0.1.36's speed (fused Q2_0 prompt experts, cluster decode kernels) and their switches 2026-10-02 18:24:15 +02:00
maxfridbe 05c90db586 sycl: port upstream 0.1.35 (re-migration of its changed engine files)
device, expert_source, native_head, prefill gemm, prefill.cpp, generate.cpp
merged from dpct of 8554b6b and 5b734e4 with sycl/tools/merge_upstream.py (the
3-way merge restricted to files upstream changed, dpct kernel-name hashes
canonicalized to the port's). Version 0.1.35.
2026-10-02 09:36:13 -05:00
Niko1221 fc21e54214 Merge the 0.1.36 speed work: fused Q2_0 prompt experts on by default (STRATA_PF_FUSED=0 off), the native IQ packs' fused kernels opt-in (=1), cluster decode kernels; the fused test waits for its uploads
The ring rule: 1024 slots for the Q2_0 pack's fused experts (P3), 512 for native packs with fused layers.
Quality (teacher-forced vs the FP16 path, Q2_0): fused as close as MMQ at 8K, closer at 32K (phaseA-tests s18-tf).
2026-10-02 16:31:42 +02:00
Niko1221 9d37a3ad5f Merge branch 'f-136-fused' into rel-0.1.36 2026-10-02 16:30:40 +02:00
maxfridbe e26ea97e09 Merge upstream main (0.1.35) into b70 2026-10-02 09:28:29 -05:00
Niko1221 60445b58c0 #136: the fused int8 prompt experts for the native IQ packs (gate/up IQ2_XXS IQ2_XS IQ2_S IQ3_XXS IQ3_S IQ4_XS, down Q2_0 IQ4_NL; opt-in STRATA_PF_FUSED=1)
src/prefill/moe_fused_iq.cu: the Q2_0 path's design (moe_fused.cu: the grouping on the GPU, a pointer per expert -
cache slot or ring slot, no gather -, SwiGLU and H's int8 rounding in the gate/up epilogue) for the raw GGUF blobs of
the native packs.  The load stage decodes the i-quant blocks to int8 in shared memory (llama.cpp's codebooks and sign
tables, held in shared memory; a 32-value sub-block per thread per 64 values of K, read one stage ahead with 16-bit
loads and two 256-value blocks ahead into L2), with each sub-block's scale (per 16 values for IQ2_XS / IQ2_S, which
multiply at m16n8k16).  The activations are int8 per 32 values in natural order (quantize_act_native); fragments by
ldmatrix; the magic bias 1.5 * 2^23 enters as the mma's C, so a dot becomes a float with one add.  A work item is 256
weight rows x 64 routed rows, or 128 x 128 when the experts have 56-112 rows each (STRATA_PF_FUSED_TILE=64|128).

Wiring (prefill.cpp): a native layer takes these kernels when both its formats are covered, else MMQ (IQ1_M keeps the
FP16 path); the 512-slot ring of the fused path now also for a native pack with such layers.  sm_75, HIP and the
default (no variable) are unchanged: on IQ2_XS, IQ3_XXS and IQ3_S the default output is 0.1.35's (256/256 greedy
tokens, 4K and 32K).

tests/cuda/prefill_fused_iq_test (exit 77 below sm_80), RTX 5070, 256 tokens x 64 experts against a double-precision
reference from ggml's to_float, rel RMS / worst row - MMQ and fused equal to four digits: IQ2_S/Q2_0 1.489e-2 /
2.93e-2 (fused vs MMQ 2.6e-4), IQ2_XXS/Q2_0 1.464e-2 / 2.96e-2 (1.9e-4), IQ2_XS/IQ4_NL 1.465e-2 / 2.41e-2 (3.5e-5),
IQ3_XXS/IQ4_NL 1.458e-2 / 2.73e-2 (1.6e-4), IQ3_S/IQ4_NL 1.470e-2 / 2.65e-2 (6.5e-5), IQ4_XS/Q2_0 1.446e-2 /
2.72e-2 (4.4e-5); both tile shapes.  One layer (512 experts, top 10), ms, MMQ path -> fused at 2048 / 3584 / 8192
tokens: IQ2_S 10.5 -> 5.2, 12.5 -> 9.3, 21.4 -> 17.5; IQ2_XXS 8.8 -> 4.2, 10.7 -> 7.6, 17.9 -> 13.6; IQ3_S 10.6 -> 5.6,
12.3 -> 8.8, 19.8 -> 18.4; IQ3_XXS 10.2 -> 5.1, 11.9 -> 8.3, 19.1 -> 16.5.  MMQ's products alone (no gathers) at
3584 / 8192: IQ2_S 8.9 / 17.9, IQ3_S 8.1 / 15.6: the kernels are about even with MMQ's, the gain is the path around them.
(The test syncs the device after its uploads: a cudaMemcpy from pageable memory on the legacy stream can still be
queued on Windows while a non-blocking stream runs - the grouping then read zeroed ids, every pair on expert 0.
prefill_fused_moe_test's timing part has the same pattern.)

End to end, RTX 5070, speed_135.py's settings, greedy, A (MMQ) / B (STRATA_PF_FUSED=1) alternating, 2 pairs, prompt
tok/s: IQ2_XS 4K 1,228 -> 1,378 (+12%; a cold first A run of 590 left out), 32K 2,107 -> 2,170 (+3.0%); IQ3_XXS 4K
1,001 -> 1,020 (+1.8%), 32K 1,745 -> 1,739 (-0.4%); IQ3_S 4K 927 -> 925 (-0.2%), 32K 1,382 -> 1,362 (-1.4%).  The IQ3
packs' prompts here wait on the host copies of their unpinned experts (IQ3_XXS 4K: 5,062 of 22,573 streamed, ~3.0 s
of 3.4 s), so faster kernels change little.  Each arm repeats itself (256/256; IQ3_XXS 32K B and IQ3_S 32K A split at
162 / 223, the decode's timing); A vs B greedy agreement, identical prefix of 256: IQ2_XS 204 / 88, IQ3_XXS 182 / 89,
IQ3_S 31 / 256.
2026-10-02 16:25:57 +02:00
Niko1221 d05d26e9c3 Decode on thread-block clusters (sm_90+): the QSA top-k and the greedy argmax, the same ids and tokens
- qsa_block_topk: calls of up to 16 queries (decode windows) run on a cluster of 8 CTAs per query
  (block_topk_cluster_kernel): keys in shared memory, digit histograms pushed through distributed shared memory,
  one cluster barrier per radix pass, a parallel digit search, cluster-wide offsets for the ordered emit. The
  threshold and the cut at it are the one-CTA kernels' (same tie rule, NaN keys 0). STRATA_QSA_CLUSTER=0: off.
  RTX 5070 per call: 21.9 -> 15.6 us at 32K, 58 -> 18 at 128K, 200 -> 22 at 262K.
- sample_tokens greedy without penalties: a cluster of 8 CTAs per row (sampler_greedy_cluster_kernel), four loads
  in flight per thread, results merged in CTA 0 (lowest index on ties, NaN never taken, 0 when none).
  STRATA_ARGMAX_MULTI=0: off. 39.6 -> 5.9 us per call at 248,320 logits.
- Both launch through cudaLaunchKernelEx with the cluster attribute (captured in the decode graphs) only where
  they run: CUDA, compute capability 9+ (STRATA_EMULATE_CC respected), the kernel's own PTX/SASS at sm_90+ (an
  older build's JIT copy is a trap), room for one cluster - checked once per device. HIP and sm_75/86/89 keep the
  one-CTA kernels.
- decode_cluster_parity (ctest; skips below sm_90): bitwise vs the one-CTA dispatch and the reference kernel over
  434 top-k cases (contexts 7..262,144, every tail weight, 1-16 queries, ties / NaN / +-inf / -0 / denormal / all
  NaN) and 216 argmax cases, plus a CUDA graph capturing both (first calls inside the capture); --bench timings.
2026-10-02 14:25:26 +02:00
Niko1221 34d4178952 #136: the fused experts take a 1024-slot streamed ring by default (two layers' experts)
With P3's smaller buffers the 1024-slot ring fits beside an 8192-token chunk at 32K (borrowed 3,153 of 3,690 slots,
under the 90% cap).  RTX 5070, Q2_0 (cfg-q2rel), --prefill auto, prompt tok/s at 512 / 1024 slots (2 alternating
pairs): 4K 1,512 / 1,605, 32K 2,485 / 2,660, 128K (KV streaming) 2,346 / 2,392 - there the chunk falls from 8192 to
6144 and is still faster.  Against MMQ (one more pair on this build): 4K 1,299 -> 1,609 (+23.9%), 32K 2,187 -> 2,656
(+21.5%), 128K 2,128 -> 2,454 (+15.3%).  The ring does not change the numbers (the same output as at 512 slots).
Without STRATA_PF_FUSED nothing changes (384 / 96 slots, cap 512).
2026-10-02 14:04:59 +02:00
Niko1221 30e5ba4a31 #136 P3: with the fused experts the prompt path's MoE buffers hold only what the fused kernels need
In a layout whose chunks run the fused experts (STRATA_PF_FUSED=1, the Q2_0 pack, a streamed chunk) GU holds the
grouping tables, H the int8 H rows and Xq the per-token int8 activations, and Hq nothing - instead of MMQ's FP32 GU / H
and per-slot q8_1 rows: ~100 KB a token less in the MoE set, which then no longer sets the shared region's size (the
GDN set does).  A last chunk below stream_all_min() still runs MMQ in the same buffers, so each keeps MMQ's size for
stream_all_min() - 1 tokens.  The ring may grow to 1024 slots with the fused experts (STRATA_PREFILL_RING; the default
stays 512).  Without STRATA_PF_FUSED nothing changes: the same buffers, ring cap (512) and events.

The fused walk now counts the experts it reads from the cache in experts_resident (it stayed 0): every resident expert
of the layer, routed or not - at a streamed chunk's size nearly all are.

RTX 5070, Q2_0 (cfg-q2rel), --prefill auto, 2 alternating pairs, prompt tok/s (borrowed slots):
  4K:   MMQ 1,305 (1621), fused 1,517 (1749), fused + P3 1,512 (1534), + 1024-slot ring 1,605 (2046)
  32K:  MMQ 2,177 (3071), fused 2,453 (3199), fused + P3 2,485 (2641), + 1024-slot ring 2,660 (3153)
  128K (--max-context 131072 --kv-resident 32768): MMQ 2,108 (chunk 8192), fused 2,140 (6144), fused + P3 2,346
        (8192), + 1024-slot ring 2,392 (6144)
A 16K chunk still does not fit the 12 GB card: at 8192 tokens the loan is 2,641 of 3,690 slots, ~2.1K of them per
8K tokens.
2026-10-02 13:43:19 +02:00
Niko1221 6f66917530 #136: the fused experts take a 512-slot streamed ring (a whole layer's experts) by default
The fused path launches on batches of a layer's streamed experts, so with the 384-slot ring a layer's last batch
waited for slots its own first batch frees.  With STRATA_PF_FUSED=1 (and the canonical Q2_0 layout) the pinned-RAM
ring is 512 slots; without it nothing changes (384 / 96 as before; STRATA_PREFILL_RING still overrides).

RTX 5070, Q2_0 (cfg-q2rel), greedy, 3 alternating pairs, prompt tok/s: 4K 1,275 -> 1,516 (+18.9%), 32K 2,176 ->
2,422 (+11.3%); at 384 slots the fused path gave +4-7% / +3%.  1024 slots: 4K +24-27%, but the 32K chunk falls
from 8192 to 6144 (+6%).  The default path's output is identical to 0.1.35's on both prompts.
2026-10-02 12:43:01 +02:00
Niko1221 47de4a4d83 #136: fused int8 tensor-core experts for the Q2_0 pack's prompt path, grouped on the GPU (opt-in STRATA_PF_FUSED=1)
Strata's own kernels (src/prefill/moe_fused.cu): the layer's input rounded to int8 once per token (a scale per 32
values), the (token, k) pairs grouped by expert on the GPU (counts, offsets, a 64-row tile list - no host sync),
then per batch of up to 128 experts one gate/up launch (mma.sync m16n8k32 s8, the 2-bit codes unpacked in
registers, Q2_0's offset folded into the activation blocks' sums, SwiGLU and H's int8 rounding in the epilogue)
and one down launch into the per-slot rows the existing combine reads.  Experts are read where they are (cache
slot or streamed ring slot, a pointer per expert): no gather.

Used only on the streamed walk (chunks from stream_all_min()) of the canonical Q2_0 layout on sm_80+ CUDA, with
STRATA_PF_FUSED=1; it reuses the MMQ buffers (Xq, H, GU).  Everything else - the default, native/IQ packs, small
chunks, sm_75, HIP - runs the MMQ path unchanged (the old block is only wrapped in the else branch).

tests/cuda/prefill_fused_moe_test (exit 77 below sm_80), RTX 5070: vs a double-precision reference, MMQ rel RMS
1.144e-2 (worst row 4.15e-2), fused 1.144e-2 (4.15e-2); fused vs MMQ 9.0e-5.  One layer at 2048 tokens x top 10
over 512 experts: MMQ path 11.12 ms, fused 3.13 ms.
2026-10-02 12:05:46 +02:00
Niko1221 30875ed297 Engine 0.1.36: a cancelled prompt logged as read so far (#471), the draft-head hint (#474), UPDATE.bat (#475), --expert-profile-save (#477); setup requires it 2026-10-02 11:17:13 +02:00
Niko1221 31da8f5dca Opt-in: keep what the expert cache learned across restarts (--expert-profile-save, #477)
`--expert-profile-save P` (--serve) writes the adaptive tier's learning as a profile in tools/make_profile.py's
format, byte for byte (read_expert_profile reads it back): every pair ranked - the experts resident in VRAM now
first, then the routing counted since the start (the decayed usage summed at each adapt step, before its decay),
then the profile the engine started from. On QUIT / stdin EOF and every --expert-profile-save-every minutes
(default 10, 0 = exit only) between requests, through <P>.tmp and a rename. Without the flag nothing is counted or
written: `heat` stays empty and every added loop is over it.

Server: "expert_profile_save" (and "expert_profile_save_every") in the config pass the flags, and the next start
begins from the saved file instead of the config's --expert-profile when its header matches that profile's
layers x experts. tests/core/expert_profile_save_test.cpp (CPU only) checks the order and the bytes.
2026-10-02 11:16:16 +02:00
Niko1221 4ba7c94d4d UPDATE.bat / update.sh: update Strata without starting the model (#475)
In a git clone they run `git pull --ff-only` (a zip copy is told to download the new zip), then `setup.py --update`:
what a plain start does to an install before it starts the model - the Python packages, the ready-made engine when
MIN_ENGINE is newer (a compiled one when its source changed), each model's config upgrades and its draft subset, the
Windows AMD runtime - and nothing else: no question, no model files, no start. Both scripts run from one parsed
block, since the pull can rewrite the running script. Documented in docs/INSTALL.md (Updating) and the README.
2026-10-02 11:06:51 +02:00
Niko1221 c472ff04c8 "The draft head does not fit" says what to change (#474)
Engine: when the MTP draft head's subset does not fit, it prints what the head needs, the VRAM free, and the smaller
shipped subsets (--draft-vocab cyrillic / en, their MiB from the head's real row size) with how to pick one
(START-HERE.bat / ./setup.sh --draft-vocab en, kept in the model's config). Text only, on the failure path.
Server: a start that ended that way carries the engine's hint (or the same advice for an older engine) in its
"the engine exited before it was ready" error. Setup: a card under 14 GB with the default subset gets a note
recommending --draft-vocab en; nothing is changed, an explicit or saved choice gets no note, and the golden
configs are unchanged.
2026-10-02 11:04:05 +02:00
Niko1221 512ae42f7c A prompt cancelled mid-read is logged and recorded with the tokens it read (#471)
The engine's `strata serve: prompt ...` line now says "= 0 reused + 12288 of 98179 read in ... (cancelled)" with the
rate from the tokens read, and DONE gets a 15th field: the prompt tokens actually read. The server's /metrics history
and totals count reused + read for a cancelled read (prompt_total keeps the whole prompt); an older engine's DONE line
(no such field) is read as before.
2026-10-02 11:01:07 +02:00
maxfridbe cbe442bfbb sycl: pipeline the expert cache's profile fill (model load 3-4x faster)
The fill from the GGUF (--stream-experts) read each expert's three slices,
copied the blob and waited for the copy before the next read: ~12,000-18,500
experts with neither the SSD nor PCIe kept busy. Now the slots are admitted
in profile order first (same placement), reads go in file order by up to 8
threads into page-locked batches of 64, and a batch's copies overlap the next
batch's reads. STRATA_FILL_SERIAL=1 keeps the serial fill.

Tested on the B70: cold page cache, Coder fill 23.4 GiB 76.2 s -> 18.8 s;
launch to first token Coder 82 s -> 26 s, IQ2_XS 120 s -> 41 s; outputs
identical to the serial fill.
2026-10-02 03:49:48 -05:00
Niko1221 5b734e427c Engine 0.1.35: Windows AMD uses its bundled HIP runtime (#468 #461), the low-RAM resident mode on Windows 32 GB PCs (#467), fixes #460 #459 #446 #447 #457 #448 #444; setup requires it 2026-10-02 09:44:21 +02:00
Niko1221 82d7e82926 Merge branch 'f-135-small' into rel-0.1.35 2026-10-02 09:41:57 +02:00
Niko1221 772c9330e9 Merge branch 'f-135-eng' into rel-0.1.35 2026-10-02 09:41:57 +02:00
Niko1221 6f8536aed1 docs: the Coder is weaker outside code, Chinese/CJK text included; the unpruned sizes for that (#438)
README and docs/MODELS.md said only "Weaker outside coding". #438 measured Chinese answers wrong or looping on the
Coder where English was fine; both now say plainly that this includes Chinese and other CJK text and point to the
sizes that keep every expert (Q2_0, IQ2_XS, IQ3_S).
2026-10-02 09:39:14 +02:00
Niko1221 6cc16bee09 setup (--gguf-dir): GGUFs Strata cannot run are named as such, with the --family/--model to use (#444)
With Unsloth's UD-IQ3_XXS or UD-Q2_K_XL in the folder, setup either said only "has no IQ3_XXS model file"
(--family unsloth --model IQ3_XXS) or took the UD-IQ3_XXS file for the GSQ-RCO IQ3_XXS by the size in its name.
Now:
- a chosen shard whose name is a quantization setup has no size for (UD-IQ3_XXS, UD-Q2_K_XL, a K-quant) stops
  with "<file> is UD-IQ3_XXS, a GGUF Strata cannot run" and what Strata runs: ISTA-DASLab's GSQ-RCO files (and
  Swift 1.5's and the Coder's) and Unsloth's UD-Q4_K_XL only;
- a folder without the chosen file but with other GGUFs lists the ones Strata cannot use and the --family/--model
  of the ones it can (an empty folder keeps check_shards' "missing");
- a size the family does not have names the families that do (--family qwen --model IQ3_XXS), and with
  --gguf-dir also what Strata runs.
2026-10-02 09:38:48 +02:00
Niko1221 95f2860231 /metrics: each request's speculative draft counts, and their sums in the totals (#457)
The server already read drafts_offered / drafts_accepted from the engine's DONE line but only returned them in a
response's timings (draft_n / draft_n_accepted). Each /metrics request entry now carries both (null when the
engine did not report them) and the totals keep their running sums since the server started, so a dashboard such
as llm-visuals can show the acceptance. Additive: no existing field changes.
2026-10-02 09:36:41 +02:00
Niko1221 22ee8d0e9a serve, setup: name the small split card that caps the prompt chunk; setup recommends the big card alone (#448)
- engine (layer splits only): when a stage's cache cannot fund the chunk CUDA0 alone would choose, a WARNING
  names it (CUDA index, name, cache slots, the slots the chunk borrows) and points at the helper cache
  (--expert-cache-device1, docs/SECOND_GPU.md).  The chunk choice itself is unchanged: fits() is split into
  fits_one() with the same tests; one GPU never reaches the new log.
- setup: a pair whose second card is under 12 GB beside a first card of 12 GB or more is still offered, but
  the first card alone is recommended (the default with --yes and Enter; offer_together asks "n" by default),
  with a note.  A named --gpus pair is kept.  Equal pairs (2x 8/16/24 GB) are unchanged.
- The automatic drop of the small card from an auto split is not done: stages load their weights before the
  boundary search and the exact prompt-buffer bytes need the sessions made after it.
2026-10-02 09:35:59 +02:00
Niko1221 0e4c3e8727 calibrate: the engine's arguments come from the server's engine_args; a failed tuning says why (#447)
tools/calibrate.py read any "gpu" list as a layer split and added --layer-split auto, so a one-card config with a
helper card for the expert tier ("gpu": [0] + --expert-cache-device1) was refused by the engine before it read a
weight, a "0,2" string never got its split, and split_skip_if_fits was ignored. The tuner now builds the arguments
with serve.server.engine_args, the same as a normal start.

When the tuning fails, setup prints the engine's own last error line from the log (only lines written during the
tuning), and says the failure again where it is not lost: before --calibrate starts the model, and in the
"All set." summary of an install that tuned.
2026-10-02 09:35:26 +02:00
Niko1221 cd49a498c8 setup (--backend hip): a system ROCm without the HIP development files falls back to the wheels (#446)
rocm_root took /opt/rocm when bin/hipcc and lib/libhipblas.so* were there and the version was 7.0 or newer. A
runtime-only ROCm 7 (no -dev packages) has both, and the engine's cmake configure then failed on the missing
hip-lang package. The system ROCm now also needs lib/cmake/hip-lang/hip-lang-config.cmake (lib, lib64 or the
multiarch lib folder, where CMake looks) and include/hip/hip_runtime.h; without them setup warns, naming what is
missing, and takes the TheRock wheels path, as it already does for a ROCm older than 7.0.
2026-10-02 09:33:17 +02:00
Niko1221 ce2d83b62d setup: an earlier config that does not parse is skipped, not a crash; configs are written atomically (#459)
A fresh copy of Strata set itself up like the newest strata-*.json of another Strata folder and crashed with
JSONDecodeError when that file was empty or cut off. previous_config now takes the newest one that parses as a JSON
object; each one that does not gets a one-line warning naming it, and with none the copy is set up as a fresh
install. Every place setup writes a run config now goes through write_config (a .tmp file, then os.replace), so a
setup stopped half-way no longer leaves an empty config behind.
2026-10-02 09:31:55 +02:00
Niko1221 42bc3dd9ad engine: the low-RAM resident mode engages on Windows 32 GB PCs (#467)
- Windows: the process working set is trimmed before the resident complement's RAM reading, so the experts
  the GPU cache pre-fill touched through the mapping count as available again (standby list); one line
  prints the reading before and after.
- --resident-experts (soft): when the whole complement does not fit, a second try keeps what fits, by
  profile rank, through the #403 budget path (RAM room minus the 256 MiB margin) instead of falling back
  to mmap entirely; a WARNING names it.  Same file bytes either way, so the answers are unchanged.
- Only the resident mode calls pin_cache_complement: the default and mmap paths are untouched.
2026-10-02 09:31:35 +02:00
Niko1221 a2edcb12f9 Windows AMD: the HIP runtime next to strata.exe, not an AMD driver's System32 copy (#468, #461)
Windows looks for an imported DLL in the exe's folder, then System32, then PATH (where the zip's rocm/bin is): a
driver that installs its own amdhip64_7.dll in System32 won, and the bundled rocBLAS/hipBLAS ran on that runtime - an
access violation on a W7900, hipErrorInvalidDeviceFunction on a 7900 XTX, on the first prompt. setup copies
amdhip64_7.dll and amd_comgr.dll from engine/rocm/bin next to the exes after the unzip, before the device probe and
on every start (so a 0.1.34 install is fixed too); package_windows.py ships them there; the engine and strata-device
log which runtime they loaded. rocBLAS/hipBLASLt stay in rocm/bin (their kernel libraries and .kpack are found from
there).
2026-10-02 09:31:18 +02:00
Niko1221 8896607268 serve: "messages" sent as a JSON string is decoded; a non-object entry is a 400 (#460)
openai_to_messages and anthropic_to_messages iterated req["messages"] directly, so a client that double-encodes
the array as a JSON string had its characters iterated and the request crashed on m.get. The new _object_list
decodes such a string and requires a list of objects; anything else raises ValueError("messages must be a list
of objects"), which the server answers with a 400. A message's tool_calls get the same guard.
2026-10-02 09:30:24 +02:00
maxfridbe f2f4121a70 sycl: read streamed experts from the right shard; fix IQ2_XS products (Swift 1.5 runs)
- gguf_expert_source: ExpertLayout::gguf_file is per layer and role
  (3 * layer + role) since upstream 0.1.31; the port indexed it by layer, so
  experts in shard 2 were read from shard 1 at shard-2 offsets (Swift 1.5:
  layers 13-47, NaN logits from layer 13). One fd per layer and role now.
- iq_kernels: vec_dot_iq2_xs and Split<17> took their 16-bit codes through
  a uint16_t* to an int2 (type punning the device compiler does not honour);
  by shifts now. iq_multi_parity checks IQ2_XS against a CPU decode from
  ggml's tables (iq2xs_host_tables.inc) and passes.
- prefill: STRATA_DBG_NAN=1 also reports the experts' fp16 GEMM inputs.

Tested on the B70: Swift 1.5 IQ2_XS answers correctly (48 tok/s raw, short
thinking); the original IQ2_XS output is unchanged (65109a, 58 tok/s).
2026-10-01 22:49:04 -05:00
maxfridbe 9ef7a73273 sycl: port upstream 0.1.33 (re-migration of its six engine files)
expert_cache.cpp, expert_source.cpp, fused_gr, qsa_prompt_attn, gr_parity and
generate.cpp merged from a fresh dpct of 2ca1b66 and 8554b6b; files that only
differed by dpct run-to-run noise left alone. Conflicts: --resident-cpu-experts
(upstream's resident_cpu_explicit kept with --stream-experts) and the prompt
attention's capability check (the port's XMX dispatch kept). Version 0.1.33.

Tested on the B70: build clean; gr_parity and qsa_prompt_attn_parity pass;
Coder short/long, IQ2_XS and the 40K prompt (borrowing) outputs identical,
78.3 / 75.7 / 58.0 / 68.9 tok/s. setup_intel.py --check and an install run, and
server_intel.py with the mock engine, against the new setup.py / server.py.
2026-10-01 20:26:24 -05:00
Niko1221 eb8bb8bcd9 README, MODELS: the AMD baseline - RX 9070 XT + Ryzen 9 3900X + 47 GB RAM (Q2_0, IQ2_XS, the Coder)
Measured with setup's own install and the README's speed method on the AMD box.
2026-10-02 03:08:05 +02:00
maxfridbe 5da3769523 Merge upstream main (0.1.33) into b70 2026-10-01 19:59:04 -05:00
maxfridbe b5793b7c5d sycl: fix the prompt-slot borrow hang (stager event wait under L0 v2); borrow above 32K again
The hang was in the streamed-expert prompt path, which borrowing is the only
way to reach on the Coder: the stager threads waited on the copy queue's
events to reuse their 16 page-locked buffers, and under the Level Zero v2
adapter that left another queue's barrier on the same event waiting forever
once the ring wrapped. The copy queue now writes a sequence number into
page-locked memory after each DMA and the stager polls it.

- prefill.cpp: Stager::issued_one / buffer_free; STRATA_PREFILL_SYNC=1 debug
  switch (wait and log after every phase)
- generate.cpp: borrowing is the default above a 32K context again

Tested on the B70: 40K prompt with borrowing 1,117-1,144 tok/s, decode 69
(output identical to the run without borrowing); 128K int8/q4_0/k8v4 decode
66.6/62.8/66.8 (from 59.5/53.4/54.4), 256K 55.9/51.7/52.2 (from
48.7/43.2/42.3); Coder and IQ2_XS 32K outputs unchanged.
2026-10-01 19:58:53 -05:00
Niko1221 43685766ae docs: byte-identical server repeats also need --pcie-frac 0 (#410, measured) 2026-10-02 00:59:21 +02:00
Niko1221 3997ca29fd docs (AI setup): AMD on Windows - the ready-made engine, the device check before the download 2026-10-02 00:55:01 +02:00
Niko1221 1867a8d6a1 README: pictures on AMD (Linux through the CPU, not on Windows yet) 2026-10-02 00:31:47 +02:00
Niko1221 dd23aa676c docs (AMD): Windows ships in 0.1.34 2026-10-02 00:30:46 +02:00
Niko1221 348ac7ef0e docs (AMD): the router's decode gain as measured by a user too (+1-4% over A/B/A/B), WMMA +29-34% with TheRock 7.10 (#432, jkuepker) 2026-10-02 00:30:25 +02:00
Niko1221 d5871c1af1 prefill: an MMQ product without a tile on some GPU takes the non-MMQ path instead of aborting (#420, qni-live)
llama.cpp's tile choice aborts the process ("J_best=0") when no tile size of a type fits the card's shared memory.
The plan now asks the same question for every visible GPU (the experts' gate+up and down shapes, the draft layer's
Q8_0 projections) and keeps a product with no tile on the existing FP16 path, saying which type, card and limits.
Where every product fits (all cards tested here), the plan is the same as before.
2026-10-02 00:28:48 +02:00
Niko1221 af53393b94 setup: UD-Q4_K_XL on AMD is asked before the download (#429); a resumed download needs room only for the rest (#425)
#429 (jkuepker): the HIP engine has no prompt kernels for its Q4_K/Q5_K experts and it has not been run on AMD -
--check says so, and setup asks (--model UD-Q4_K_XL --yes tries it). #425 (jctaborda): the finished shards and the
.part files already on the disk count against the download's size.
2026-10-02 00:27:13 +02:00
Niko1221 77668b2e3c serve: a request is cancelled within a second of its client hanging up (#430, #431, jkuepker)
A non-streamed request wrote nothing until its end, and a streamed one only a keep-alive per prompt chunk (the
first write after a hang-up usually still succeeds), so a dropped request kept the engine reading the whole prompt
or generating to max_tokens while the next request waited. A watcher per request checks the client's socket for EOF
every 0.5 s and cancels; the engine then stops at its next prompt chunk.
2026-10-02 00:24:20 +02:00
Niko1221 14dbd1be5f Engine 0.1.34: AMD on Windows (a ready-made HIP engine, #247 #325), an MCP server so an AI assistant can set Strata up (#133), a shorter README; setup requires it 2026-10-02 00:13:57 +02:00
Niko1221 3629d22c76 Merge branch 'f-133-docs' into rel-0.1.34
# Conflicts:
#	README.md
#	docs/AMD_HIP.md
#	setup.py
2026-10-02 00:09:58 +02:00
Niko1221 524b091daf Merge branch 'f-133-mcp' into rel-0.1.34 2026-10-02 00:09:12 +02:00
Niko1221 6edbe9d6ed Merge branch 'f-133-winamd' into rel-0.1.34
# Conflicts:
#	serve/test_server.py
2026-10-02 00:09:12 +02:00
maxfridbe fddee3a47d sycl: port upstream 0.1.32 (re-migration 3-way merge)
dpct of 6ac1a2c and 2ca1b66, normalized, kernel-name hashes canonicalized to
the port's, then git merge-file into sycl/: 49 files, 10 with real conflicts.

- verify: upstream's set_commit_async/wait_commit on the port's deferred
  commit (wait_commit = commit_finish); copy_logits on the queue
- fused_gr: upstream's split/staged read variants merged but unused by the
  port's read; their per-card self-test segfaults on the B70, so on SYCL it
  runs only with STRATA_HC_CHECK=1. The port's split-norm kernel renamed
  (upstream has one of the same name); two colliding kernel names renamed
- fixups.py: fused_gr's per-block local-memory query
- hand files: mtp.cpp, verify.cpp, ple_reader.cpp (keep-alive reads + trace)
- qsa_prompt_attn_parity turns on the XMX kernel it checks
- version 0.1.32

Tested on the B70: build clean; Coder (19 / 2,184-token prompts) and IQ2_XS
outputs identical to 0.1.31 at the same speed (78.1 / 75.7, 58.5 tok/s);
40K prompt 1,201 tok/s, decode 65.1; kv_hybrid, qsa_prompt_attn, qsa, gr,
kv_q4, kv_q8, rope, router, sampler, quantize_act parity pass.
2026-10-01 16:12:35 -05:00
Niko1221 8554b6bc53 hip_compat: cudaDevAttrComputeCapabilityMinor (#371's check, the HIP build) 2026-10-01 22:23:10 +02:00
maxfridbe c9fd9cd1d3 Merge upstream main (0.1.32) into b70; Intel code kept out of shared files
Every file outside sycl/ (and docs/INTEL.md) is now upstream's, byte for byte.
The Intel pieces that used to edit shared files move under sycl/ and wrap
upstream from outside:

- sycl/setup_intel.py: runs setup.py's main() with the GPU check, engine
  step, RAM rule and config writer swapped for the SYCL port's
- sycl/serve/server_intel.py: serve/server.py plus the Arc's Monitor
  readings (sycl/serve/xe_telemetry.py) and the optional model menu
  (sycl/serve/web/switcher.js)
- sycl/tools/gpustat.py (was tools/intel/), sycl/.gitignore; migrate.sh
  writes its compilation database outside the checkout
- removed: the llama.cpp engine path (serve/engine_llama.py), the README box

Engine sources in sycl/ still track 0.1.31; the 0.1.32 kernels are not
migrated yet.
2026-10-01 15:06:34 -05:00
maxfridbe 5b1acc00e4 sycl: parity tests wait like cudaMemcpy; drain the refill ring in long prompts
- fixups.py: default-queue memcpy/memset in the parity tests first waits for
  all device queues (cudaMemcpy's legacy-stream semantics), applied to every
  src/kernels/*_parity.cpp
- generate.cpp: the post-prompt refill loops sync the queued copies every 256
  entries so the ring cannot wrap over in-flight slots
- kv_hybrid_parity: enable STRATA_PROMPT_ATTN_XMX (step 5 needs the XMX path)

Tested on the B70: build clean; qsa_parity, gr_parity OK.
2026-10-01 14:56:20 -05:00
Niko1221 30a0f3269a Engine 0.1.33: a portable image encoder again (#411 #412), setup recommends instead of forcing (#406 #403 #364 #384), fixes #352 #365 #369 #371 #375 #393 #408 #414; setup requires it 2026-10-01 21:17:17 +02:00
Niko1221 decfc96c98 Merge branch 'f-133-choice' into rel-0.1.33 2026-10-01 21:12:04 +02:00
Niko1221 95ade2d5ee docs: the RAM rule recommends 128K, the low-RAM mode on several GPUs, --resident-budget-gib / --kv-streaming (#406 #403 #364 #384) 2026-10-01 21:03:56 +02:00
Niko1221 f0ee8ce54f setup: recommend, never force - longer contexts, more GPUs, a bigger RAM budget are kept with their risk (#406 #403 #364 #384)
The recommended answers stay the defaults, and --yes / Enter write the same config as before
(tools/test_setup_golden.py, five PCs x five sizes).  What a user asks for beyond the recommendation is kept and
its risk said:

- #406: the RAM rule for IQ3_XXS / IQ3_S (experts + KV + 24 GB) is part of the recommended context (the smaller of
  it and the GPU's rule), no longer a cap: an explicit --context, a pick in the list or the earlier install's
  context is kept with a note ("256K with IQ3_S needs ~78 GB of RAM by setup's estimate; this PC has 64. Kept as
  you chose ..."), and the list marks the sizes past it.  The low-RAM mode keeps its KV cache in VRAM, so there
  the context does not count against RAM.
- #364 #384: the low-RAM mode recommends one GPU (the resident variant has no layer split) and asks: 2 = all the
  chosen GPUs with the experts read through the OS file cache (--mmap-experts, layer_split auto; faster in both
  reports, RAM can fill up during long prompts).  An explicit --gpus (or the earlier install's cards) is kept;
  --yes keeps one GPU.  The GPUs' share counts every card.  The one-GPU text no longer sends users to --low-ram off.
  At start, --gpus on a --resident-experts config (and offer_together's "y", whose default is now n for such a
  config) switches it to --mmap-experts with a note instead of an engine refusal.
- S4: --resident-budget-gib N for UD-Q4_K_XL (default: the RAM less 24 GB, as before); more is kept with a note,
  and a given N is not lowered for KV streaming.
- confirm_risk(msg, explicit, yes): one helper for the stops a user may take on - asked with default n, and with
  --yes an explicit flag is the consent (--yes alone keeps the stop): UD-Q4_K_XL under 48 GB (--model), the RAM
  floor (--model), the paging question (--model, besides --low-ram off), a card under 8 GB named with --gpus.
- --kv-streaming on|off|auto (auto: the RAM test, as before); on past the RAM test with a note, never with k8v4 or
  under WSL.

The refusals that stay are the impossible ones: rope none past 262144, disk space, engine version, driver < 580,
no AVX2, a size outside the family.
2026-10-01 21:03:56 +02:00
Niko1221 7349d9112b engine: --resident-experts with a layer split runs as --mmap-experts with a warning (#364 #384)
The low-RAM mode's resident variant has no layer split yet, and the engine refused the pair.  When the residency
comes only from setup's soft --resident-experts (no --resident-cpu-experts, no --resident-budget-gib, no remote
caches), it now prints a WARNING - the experts the GPUs do not hold are read through the OS file cache and RAM may
fill up during long prompts - and continues exactly as --mmap-experts: the resident flags are cleared before
anything reads them, so the source, the placement and the per-stage caches are the mapped mode's (#364's hand-edited
config).  An explicit --resident-cpu-experts, a budget, or remote caches are still refused.

The explicit --expert-cache reduced under a layer split is now a WARNING that names --vram-reserve-mib.
2026-10-01 21:00:49 +02:00
Niko1221 152f7198b9 engine: a RAM budget clamped to the free RAM no longer fails its own safety check (#403)
FileExpertSource::pin_cache_complement read the available RAM twice: the budget was clamped to the first reading
(less the 4 GiB headroom) and the resident-memory check then failed it on a second reading a few MB lower, so a
64 GB PC with setup's --resident-budget-gib 40 could exit at start.  With a budget, the check now reuses the reading
the budget was sized from, and a clamped budget stops 256 MiB under the room.  An unclamped budget holds the same
experts as before (the lend region is off with a budget, so `budget` there is unused).

If the budget still cannot be kept (no RAM reading, an allocation that fails), generate.cpp warns and serves every
expert the GPU does not hold from the files through the OS file cache (--mmap-experts) instead of exiting; the
complement is left unbuilt on every failure path.
2026-10-01 21:00:48 +02:00
Niko1221 41e9ecb016 docs: byte-identical repeats through the server also need --prompt-cache 0 --adapt-swaps 0 (#410) 2026-10-01 20:53:18 +02:00
Niko1221 18a0ec2d47 tests: golden --yes / Enter configs on five PCs (#403 #406 #364 #384)
setup.main() with --yes, and with Enter for every question, on 64 GB + 32 GB, 32 GB + 2x24 GB, 47 GB + 2x16 GB,
96 GB + 16 GB and 128 GB + 24 GB, for the recommended size, Q2_0, IQ3_XXS, IQ3_S and UD-Q4_K_XL: the run config
recorded by this setup (tools/test_setup_golden.json), so the choices that follow cannot change the default.
2026-10-01 20:52:24 +02:00
sergiywith 17ebb94433 gr_parity: compare the split read (STRATA_GR_V3=1) within float rounding
With STRATA_GR_V3=1 "fused GR multi max-T=8 LDS launch and changing graph replay" failed: the test compares the
multi-token read with the single-token kernel bit for bit, and v3 sums `down` in another order (row group x stream
blocks). It also compared `lo`, the default kernels' workspace between down and up, which v3 keeps in shared
memory and never writes. Under v3 the test now checks R_out, rs, inject and mixed within 2e-6 of the largest
reference value and leaves `lo` out; without it, bit for bit as before. Passes both ways.
2026-10-01 20:51:59 +02:00
Niko1221 e878547256 fused_gr: STRATA_GR_V3=1 keeps the default read where it needs the two-half split (Turing; #375, kenh0u)
Opt-in path only; the default read is unchanged.
2026-10-01 20:51:54 +02:00
Niko1221 950c1199dd expert cache: --expert-cache-per-layer starts on native packs (#369, dag08)
open_sized seeded every layer's cursor at slot 0, so all layers wrote the same slots and the startup check failed;
the profile fill ended at the first full layer. Now each layer starts in its own range, a full layer skips only
its own pairs, and per-layer mode keeps slots of the largest blob (its ranges ignore the rank a sized slot was cut
for). The default (shared) cache is unchanged.
2026-10-01 20:51:16 +02:00
Niko1221 37fe5b5328 serve: the image encoder on its own GPU, "cuda_device" in the vision section (#408, Efs-O)
Opt-in; without it the encoder gets the engine's environment as before.
2026-10-01 20:49:41 +02:00
Niko1221 6aa51c24d8 qsa_prompt_attn: the tensor-core kernels need sm_75 - a V100 (sm_70) keeps the old kernel (#371)
The host check compared the major version only (>= 7) while the device code traps below sm_75, so an sm_70 card
took the m16n8k8 kernel and hit __trap(). sm_75 and newer: the same choice as before.
2026-10-01 20:47:40 +02:00
Niko1221 0c8b8dc4d3 tests: find_nvcc's test ignores a real CUDA toolkit on the host (#414) 2026-10-01 20:46:32 +02:00
Bortlesboat 36beee903b setup: stop on EOF instead of accepting prompt defaults 2026-10-01 20:46:19 +02:00
Niko1221 318d74d9d2 serve: a template refusal answers 400 (#365); the temporary image goes when the encoder's pipe fails (#352) 2026-10-01 20:46:18 +02:00
Niko1221 082d59640f docs (AMD): Windows - the ready-made HIP engine, what it needs, what is validated, how to report 2026-10-01 20:34:37 +02:00
26cc76347a setup: AMD on Windows - the ready-made HIP engine, chosen by itself without a usable NVIDIA card
START-HERE.bat on a Windows PC whose AMD Radeon is the card Strata can use now
sets it up like an NVIDIA one: no compiler, no ROCm install, only the AMD driver.

- Detection without any AMD software: the display adapters present
  (Win32_VideoController: name + PCI id) with each one's 64-bit VRAM size from
  the display-class registry (readable without admin; #247/#325's source),
  the arch by PCI device id, else by name. An integrated or older Radeon is
  listed and refused, as on Linux. The NVIDIA-or-AMD choice is the Linux one:
  AMD by itself when no NVIDIA card can be used, asked when both can.
- The engine: strata-windows-x64-hip.zip from the release (this version's,
  then the latest; --prebuilt for a local folder), unpacked into engine/ and
  checked for this card's arch and version >= 0.1.33; an older one is
  replaced on a later start like the NVIDIA zip. Without a published zip setup
  says how to make one (tools\hip\build_windows.bat + --prebuilt).
- Before the model download, the engine's own strata-device --list-devices
  (with its rocm/bin on PATH) must see the card - otherwise it stops and
  points to the AMD driver - and gives the card's HIP ordinal (#325: an
  integrated Radeon is HIP's device 0). From then on setup lists the AMD
  cards in HIP's order, so "gpu" in the config and --gpu N are HIP numbers.
- The config: backend hip, lib_dirs = engine\rocm\bin, the hipBLASLt table
  for the zip's hipBLASLt version (BUILD.json). Images on the CPU and
  several AMD cards (--gpus) stay Linux-only for now (said, not silent).
- Texts: setup's description and step 1 name NVIDIA or AMD; START-HERE.bat
  needs "an NVIDIA or AMD graphics driver"; the "AMD backend runs on Linux
  only" stop is gone.
- An installed HIP engine's BUILD.json ("gfx1201" archs) is no longer read as
  an NVIDIA one by get_prebuilt.

Linux is unchanged (KFD detection, TheRock wheels, compiled here).
Tests: tools/test_setup_amd.py WindowsDetection (mocked WMI/registry rows,
the list-devices parser on this PC's real output, the iGPU-first ordinal
match, the driver-missing stop, the zip install/refusals, the dispatch);
test_setup_choices' Linux CPU-encoder case pins WIN=False.

Co-authored-by: Dimitri Vasdekis <[email protected]>
Co-authored-by: isshin <[email protected]>
2026-10-01 20:34:03 +02:00
Niko1221 b8349a8144 tools/hip: build_windows.bat and package_windows.py - the ready-made Windows HIP engine zip
build_windows.bat builds strata.exe + strata-device.exe (and with `tests` every
HIP test) for gfx1100;gfx1101;gfx1102;gfx1200;gfx1201;gfx1030 with no admin
rights and no AMD GPU: ROCm 10.2.0a20260930 from AMD's TheRock wheels
(whl-next: rocm[libraries,devel,device-<arch>...], the version #325 ran on an
RX 9070 XT) in a private venv (.rocm-win, ~7 GB), ROCm's clang as host and HIP
compiler with MSVC's headers/linker from vcvars, STRATA_PORTABLE (AVX2 ggml).

package_windows.py makes dist/strata-windows-x64-hip.zip (524 MiB, 810 MiB
unpacked): strata.exe (61 MiB), strata-device.exe, BUILD.json (backend hip,
archs, ROCm and hipBLASLt versions, lib_dirs rocm/bin), rocm/bin with the DLLs
the programs import followed through ROCm (amdhip64_7, hipblas, rocblas,
rocsolver, libhipblaslt, libtensilelite-host, origami, rocm_kpack) + amd_comgr
(loaded by name) + the MSVC runtime, rocBLAS/hipBLASLt kernels for these archs,
rocBLAS's kpack device code (found at ../.kpack from rocblas.dll), licenses and
a NOTICE. The user needs only the AMD driver (the HIP runtime uses its
user-mode components).

Checked on this PC's Ryzen iGPU (gfx1036, a test build of the same tree): with
only the zip's rocm/bin on PATH, strata-device lists the card and
hipblasGemmEx BF16 -> FP32 (T=100) matches the CPU (max err 4.7e-7); ctest
52 of 56 pass, the 4 failures the same as #325's RX 9070 XT run (hip_handoff,
and ple_parity / expert_parity / pool_test without the pack fixture).
2026-10-01 20:33:37 +02:00
36c11637f5 HIP on Windows: the hipBLAS sticky error (Windows only) and the mapped embedding fallback (#247, #325)
- prefill gemm: on Windows hipBLAS can return success with the right BF16/FP16
  product and still leave hipErrorInvalidValue set (#247 on gfx1201: hc up once
  T >= 96, the router), which the next kernel check turns into an exit. That
  one stale error is cleared after a GEMM that succeeded; any other error
  still stops the engine. Only under __HIPCC__ && _WIN32: on Linux a stale
  hipErrorInvalidValue is a real error and keeps being reported (our review
  of #247). CUDA compiles a ((void) 0).
- native embedding (HIP builds): when the runtime refuses a device alias for
  the mapped table, the table goes into VRAM (as when it cannot be pinned)
  instead of failing the start; the pinned copy is freed so the destructor's
  one-of-two rule holds (#325's version leaked it and freed dev_owned_ twice).
  CUDA keeps the old code path.
- tests/hip/mapped_alias (#325): what a hipHostGetDevicePointer alias is on
  this stack. On Windows it is the host pointer itself, and a D2D copy into it
  does not land - hip_handoff's timeout there; kernels reading it work (the
  engine serves on Windows). Rewritten to read the kernel's output back with
  hipMemcpy (the PR's version dereferenced device memory on the host) and to
  try the kernel read in both cases. Diagnostic: exits 0, 77 without a device.

Co-authored-by: Dimitri Vasdekis <[email protected]>
Co-authored-by: isshin <[email protected]>
2026-10-01 20:20:09 +02:00
Niko1221andDimitri Vasdekis 51fdc43c80 strata-device --list-devices, and HIP's numbering for AMD cards on Windows (#325)
On Windows the AMD cards are found in the display-adapter order, but
HIP_VISIBLE_DEVICES counts the devices the HIP runtime enumerates, and an
integrated Radeon takes HIP's device 0 and pushes the discrete card to 1 - so
the engine was pointed at the iGPU, which the arch check then refuses (found
by dvasdekis on an RX 9070 XT + Ryzen iGPU).

- device_count() and device_summary(): enumerate without device_info's arch
  check (the cards this binary has no code for are part of the answer).
- strata-device --list-devices: every device the runtime enumerates, as
  "device N: <name>", then "arch gfx1201, 15.9 GiB, wave32" (CUDA: compute
  capability and VRAM), then "cannot run: <why>" for a card this binary
  cannot run. setup.py parses it (next commit).
- server.py hip_visible(): a one-card config's "hip_ordinal" (written by
  #325's branch) wins over "gpu"; a layer split keeps its list.

Checked on this PC's own Ryzen iGPU through TheRock's Windows HIP runtime:
"device 0: AMD Radeon(TM) Graphics / arch gfx1036, 28.1 GiB, wave32 / cannot
run: ... not an architecture this Strata engine was compiled for (...)".

Co-authored-by: Dimitri Vasdekis <[email protected]>
2026-10-01 20:19:56 +02:00
isshinandDimitri Vasdekis eecb32abf6 HIP on Windows: the build with ROCm's clang as the host compiler (#247, #325)
CMake refuses to mix cl.exe with Clang for HIP, so on Windows ROCm's clang++
compiles the host code too (targeting the MSVC ABI, with MSVC's headers and
linker from vcvars). The CUDA->HIP shim is force-included with /FI when the
host front end is MSVC-style (cl / clang-cl) and with -include otherwise, its
path in forward slashes; CMAKE_HIP_ARCHITECTURES may also be space-separated.
On Windows the shim keeps <windows.h>'s min/max macros out (NOMINMAX,
WIN32_LEAN_AND_MEAN).

Taken from jagsan-cyber's #247 as ported by dvasdekis in #325 (2373c75); the
arch lists and the arch check stay 0.1.32's. Built on this PC with ROCm
10.2.0a20260930 (TheRock wheels, the version #325 ran on an RX 9070 XT) for
gfx1100;gfx1101;gfx1102;gfx1200;gfx1201;gfx1030: strata.exe and all 253
targets with the tests. CUDA builds do not read these files.

Co-authored-by: Dimitri Vasdekis <[email protected]>
2026-10-01 20:19:37 +02:00
Niko1221 885e52052b tools/strata_mcp.py: an MCP server so an AI assistant can install, start, check and stop Strata (#133)
Claude Code, Claude Desktop, Cursor, VS Code, Codex ... add it over stdio (JSON-RPC 2.0, MCP 2025-06-18, also
2025-03-26 / 2024-11-05); standard library only, so it runs before setup made .venv. Eight tools: strata_status
(running server via /health, /v1/status, /status, /metrics; installed configs, engine, data folder; hardware and
setup's recommendation), strata_models, strata_install (setup --yes --no-start in the background, plan first and
confirm=true to start, progress / cancel on later calls), strata_start (the run script's command, waits for
/health), strata_stop (POST /unload, then ends the server it started), strata_logs, strata_benchmark,
strata_connect_info.

Every argument is checked against a schema and setup's own tables; the only path (data_dir) must be the data
folder, inside the Strata folder, or a new Strata* folder outside system folders. Processes are tracked by pid and
start time in .strata-mcp/, so only processes it started are ever ended; a Strata started elsewhere is only
unloaded. docs/MCP_SERVER.md has every client's config; docs/DETAILS.md links it. Tests use a fake setup and
server (Windows and Linux).
2026-10-01 20:18:07 +02:00
Niko1221 f938412499 docs: a short README for regular people; the details move to INSTALL, MODELS, TROUBLESHOOTING, HOW_IT_WORKS
README.md (279 -> ~180 lines): what it is, speed on an NVIDIA and an AMD baseline PC side by side (the AMD
numbers are TODO-AMD placeholders until the RX 9070 XT baseline is measured), what you need with NVIDIA and AMD
as equals, install by asking an AI assistant (docs/AI_SETUP.md, MCP server) or by hand, pick-by-RAM table,
using it, the four common problems, how it works with the two diagrams, Buy Me a Coffee button below the speed
table and at the end. Its anchors other pages use (#which-model-should-i-pick, #install, #using-it,
#something-went-wrong, #how-does-it-work) are kept.

Everything the README had moves, nothing dropped: docs/INSTALL.md (requirements, Windows, Linux, AMD cards,
several cards, Docker, updating, where things are stored, setup's questions incl. rope scaling / images /
speed projection, calibrate, all options), docs/MODELS.md (speed per size, sizes, will it fit, low-RAM, Coder,
Swift 1.5, Unsloth UD-Q4_K_XL, Orca), docs/TROUBLESHOOTING.md (the README's problems plus AMD ones),
docs/HOW_IT_WORKS.md (the longer explanation, credits, license). New docs/AI_SETUP.md (instructions for an AI
agent installing Strata for a user) and AGENTS.md. .github/FUNDING.yml (buy_me_a_coffee: strataengine).
AMD_HIP.md loses "Experimental" in its title and intro; DETAILS.md lists the AMD cards and points to the new pages.
2026-10-01 20:08:58 +02:00
Niko1221 0ad23b584d setup: the AMD backend is no longer called experimental in its messages
--backend's help, the NVIDIA-or-AMD question and the GPU line drop "experimental" (the Unsloth model, the
speed projection and the Pascal/Volta build keep it); the AMD choice says images run on the CPU (0.1.32)
instead of "no images". setup.sh's header comment likewise.
2026-10-01 20:08:58 +02:00
Niko1221 2ca1b6645f docs (AMD): images through the CPU encoder and the Monitor's AMD readings (0.1.32, #304 #301) 2026-10-01 18:45:09 +02:00
Niko1221 3f11e286b4 docs: #337's top-k dispatch is AMD-only 2026-10-01 18:45:00 +02:00
Niko1221 01ec3ac900 qsa_select (#337 follow-up): the top-k dispatch by active blocks on HIP only - CUDA keeps the capacity rule (the 64K prompts read 1-3% slower with it on an RTX 5070; #337 was measured on RDNA4) 2026-10-01 18:44:53 +02:00
maxfridbe fe95d59e25 docs/INTEL.md: lanes per row of the expert kernels measured per verify round (no difference) 2026-10-01 11:31:00 -05:00
maxfridbe 90ff5da28e sycl: refresh the port to upstream 0.1.31
Re-migrated (dpct of 0.1.29 and 0.1.31, 3-way merge per file): 45 files
changed upstream, 38 conflicts resolved; verify.cpp, mtp.cpp and the new
conversation_state.cpp ported by hand; 7 new upstream files.

Fixed on the way:
- the port's grouped expert kernels stay the default: upstream's new multi
  kernels (8 rows a group) ran on the port's 32-row grid and wrote a quarter
  of each expert (end-of-text output); STRATA_EXPERT_SPLIT=1 runs them with
  their own grid. Lanes per row now selectable (STRATA_GU/DOWN_LANES)
- dpct's unparenthesised __fadd_rn: the native QSA indexer's per-token
  pooled key (decode), the native QSA scores and the s2 activation rounding
  replaced instead of added - from the first migration; fixups.py fixed
- doorbell waits: fixups.py bounds upstream's new spin spelling again
- prompt-slot borrowing hangs since upstream's rework: off by default
- the Turing PTX branch in qsa_prompt_attn, dp4a.hpp's __nanosleep, the
  coupled-draft capture signature, a duplicate kernel name
- gr_parity: the single-token GR read runs the multi kernels (bitwise)
- qsa_parity: a cross-queue copy race in the test itself

Decode 78.2 / 75.7 tok/s (Coder), 58.6 / 64.2 (IQ2_XS); 128K-256K complete.
2026-10-01 11:05:32 -05:00
Niko1221 5a826638b4 qsa_select (#337 follow-up): the gfx12 WMMA block scorer is opt-in (STRATA_SELECT_WMMA=1) - it selects slightly differently from the warp kernel; the top-k dispatch by active blocks (the same ids) stays on; docs 2026-10-01 17:58:46 +02:00
bsorensen110 dd670cac36 hip: gfx12 (RDNA4) QSA select - WMMA block scorer, and a top-k dispatch that follows the prompt, not the capacity
Two changes to the prompt path's QSA selection (qsa_select.cu), measured on a Radeon AI PRO R9700 (gfx1201) with
--max-context 262144:

1. qsa_block_topk picked its register kernel by max_blocks, a CAPACITY (--max-context / 4 + 2). With a 262144-cell
   capacity every prompt, even a 4K one, took the slow reference top-k (up to ~10x slower at 128K+). The prompt path
   now passes the batch's active block count (the argument qsa_block_scores already takes); decode passes none and
   keeps the capacity rule and the original register width, so it is unchanged. On HIP the register kernel is
   instantiated for 66 blocks per thread (contexts up to 270,336 cells, the 262144 --max-context) and, below
   ~28K cells, where it measured 0.2-0.9x of the reference on gfx1201, the reference is kept. Same ids as the reference
   (checked 256/256 at every size).

2. qsa_block_scores_tc on gfx1200/gfx1201: block_scores_wmma_kernel on v_wmma_f32_16x16x16_bf16 (wave32). Each operand
   is split into three bf16 slices (hi / mid / lo are exact 8-bit mantissa slices of the fp32, so no scaling is
   needed) and the six products of order <= 2 are summed; the hi*hi chain keeps its own accumulator and the five
   corrections another, added once at the end (a single shared accumulator rounded the corrections at the big
   accumulator's ulp: 8e-7 of the score scale, failing the harness's gate at short context; split: 1.6e-7, the warp
   kernel's own error is of the same order). The tail block n_bid is the warp kernel's arithmetic. Like the TF32
   kernel it is not bitwise with the warp kernel (a near-tie can select differently). Gated at compile time
   (__gfx1200__/__gfx1201__) and run time (gcnArchName); other HIP targets keep the warp kernel; CUDA is unchanged.

qsa_select_bench now builds on HIP, takes the engine's capacity as a 4th argument, checks the scorer against an FP64
reference (gate: no worse than 4x the warp kernel's error, floored at 1e-6 of the score scale), exits non-zero on a
failed gate, and is registered with ctest (32K context under a 262144-cell capacity).

R9700, synthetic bench, 256 queries, capacity 262144: scores 0.81 -> 0.18 ms at 32K, 3.5 -> 0.65 ms at 131K, 6.8 ->
1.5 ms at 262K; top-k 3.9 -> 0.51 ms at 131K, 12.9 -> 1.3 ms at 262K. End to end (Swift 1.5 IQ3_XXS, --kv int8,
prefill timing, same binary with STRATA_SELECT_OLD=1 STRATA_TOPK_OLD=1 as the old arm): 107.7K-token prompt 79.5 s ->
59.5 s (1.34x; qsa select 23.3 s -> 3.4 s); 30.9K 1.02x; below 10K about 1.01x. ctest 44/44.
2026-10-01 17:58:17 +02:00
Rafael Grossi 7d15ef727b AMD HIP: RDNA2 gfx1030 (tested), gfx(1031, 1032) untested.
dp4a through the plain signed v_dot4_i32_i8 (RDNA2 has no sudot4).
setup knows the card and the gfx103X-all TheRock index.
docs carry a community report (RX 6900 XT 16 GB: complete build, 28/28
ctest, 38-42 tok/s decode at 131,072 context, 330-339 tok/s prefill)
2026-10-01 17:58:17 +02:00
bsorensen110 a8d57b1f00 hip: address review of the gfx1201 table: current docs, smoke-test wording
docs/AMD_HIP.md: the RDNA4 validation note still said there was no gfx1201 table and none was shipped; it now says
that holds for hipBLASLt 1.4.1 and points to the 1.5.0 table and its measured gain. The "Tuning table" text no longer
says the parity test "exits non-zero when the table does not fit". It describes what the test checks (architecture and
version through the loader, two of the 32 rows against hipBLASEx) and what it does not: a solution id the library
rejects falls back to hipBLASEx and the test still passes, so it says to read STRATA_HIPBLASLT_VERBOSE's
"fallbacks=" summary and to recalibrate for another 1.5.0 build.

tests/hip/prefill_hipblaslt_gemm.cpp: the header comment, the SKIP and missing-row messages and the case comment now
say it is a smoke test over two rows, and it prints "smoke test: 4 cases on 2 of the table's N rows" at the end.
Test behaviour and exit codes are unchanged.
2026-10-01 17:57:41 +02:00
Soren-ldandCopilot Autofix powered by AI cfe6021eb2 Update AMD HIP documentation for hipBLASLt 1.5.0
Clarify usage of hip_prefill_hipblaslt_gemm and tuning process for different 1.5.0 builds.

Co-authored-by: Copilot Autofix powered by AI <[email protected]>
2026-10-01 17:57:24 +02:00
bsorensen110 025602c2be hip: encode the BF16 fixtures of the hipBLASLt tuner and parity test with bf16_from_f32()
Both helpers built their BF16 inputs with hip_bfloat16(x).data. Compiled as host C++ (no __HIPCC__) the SDK's
hip_bfloat16 is a struct holding a uint16_t, and the conversion from a float is not the engine's round-to-nearest-even
BF16 encoding (kernels/bf16_bits.hpp has that one).

Observed effect on gfx1201 with ROCm 10.2.0a, parity test with the 100500 table: the T=37 beta=1 BF16 case printed
relative_l2=0 max_abs=0 with the old encoding and relative_l2=3.6e-07 max_abs=2.6e-06 with this one; the T=4096 BF16
case prints 0 either way, and the f16 cases are unchanged. I did not inspect the old encoder's bit patterns directly,
so the exact fault is inferred from that difference, not shown.

Use strata::kernels::bf16_from_f32() in both, so the BF16 rows of gfx1201-hipblaslt-100500.txt were calibrated on
intended inputs and anyone regenerating a table gets the same. No change to the engine or to the f16 path.
2026-10-01 17:57:24 +02:00
bsorensen110 dd088d3324 hip: hipBLASLt tuning table for gfx1201 (Radeon AI PRO R9700) with ROCm 10.2.0a nightly (hipBLASLt 1.5.0)
tools/hip/gfx1201-hipblaslt-100500.txt: 16 dense GEMM geometries (bf16 and f16) at T=4096 and T=8192, 32 rows,
calibrated on an R9700 with tune_hipblaslt (16 candidates per row, relative L2 <= 1e-4, max abs <= 1e-2, no padding
writes) against rocm-nightly-gfx120x-all 10.2.0a20260914, hipBLASLt 1.5.0 (version number 100500).

The engine refuses a table of another hipBLASLt version, so the existing gfx1201 table in #262 (100401, hipBLASLt
1.4.1) is not used on this ROCm; setup picks tools/hip/<arch>-hipblaslt-<version>.txt by the installed version, so both
can be shipped side by side. Compared with #262's 24 rows this table has the same 24 shapes (with solution ids chosen
for hipBLASLt 1.5.0: 13 of the 24 ids are the same) and 8 more, all bf16 (N=1/K=2560 at T=8192, N=4/K=10240, N=512/K=2560
at T=4096, N=2560/K=2560 at T=4096, and N=10240 with K=2560 and K=320 at T=4096/8192).

docs/AMD_HIP.md lists the shipped tables and how to check one.
2026-10-01 17:57:24 +02:00
Niko1221 99b3bde00a Engine 0.1.32: split prompts faster with the same output (#340), AMD router +12% decode (bit-identical), RDNA4 matrix-core prompt attention (opt-in), Unsloth UD-Q4_K_XL in setup (experimental) with 2.8x faster prompts, fixes #326 #327 #342 #344 #331, the PR batch; setup requires it 2026-10-01 15:25:30 +02:00
Niko1221 97712287fe serve (merge #333 + #344): the engine stays not-alive from the start of __init__ until READY - #333's lazy start set ended=False before READY, so a request could again plan with context 0 (RestartWindow test) 2026-10-01 15:17:14 +02:00
Niko1221 b0abdeb446 Merge branch 'f-132-pr' into rel-0.1.32
# Conflicts:
#	CMakeLists.txt
#	serve/server.py
#	src/program/generate.cpp
2026-10-01 15:10:33 +02:00
Niko1221 aebfd69a2f Merge branch 'f-132-amd' into rel-0.1.32 2026-10-01 15:09:45 +02:00
Niko1221 d9fe3019e0 Merge branch 'f-132-q4' into rel-0.1.32
# Conflicts:
#	setup.py
2026-10-01 15:09:45 +02:00
Niko1221 3b7162131d #278 follow-up: an Anthropic request that doesn't ask for thinking renders without it only with "anthropic_thinking": "on_request" in the config - the default thinks as 0.1.31 did (a client that never asks would otherwise lose the thinking on every turn); docs 2026-10-01 14:42:53 +02:00
Niko1221 e12ecf6ac8 #280 follow-up: the rope kernels without the table are 0.1.31's code exactly (template <bool TAB>)
With STRATA_ROPE_TABLE unset the table was skipped at run time, yet the compiled default kernels changed their
results: the model-level parity run (Swift IQ2_XS, tools/conversation_cache_parity.py, STRATA_STATE_HASH) gave the
same tokens but other GDN / indexer / K/V state hashes than 0.1.31's (bisected to #280). native_rope's apply,
the indexer's append / append_first / append_blocks and the prompt path's rope_kernel are templates on TAB now;
the host launches <false> whenever no table applies, and that instantiation has no table read at all. Checked:
the same tokens and every state hash as round 1 with the whole branch.
2026-10-01 14:34:20 +02:00
Niko1221 dadc9e781a #340: a split's own prompt buffers are opt-in (STRATA_SPLIT_OWN=1, or auto for the 12% rule) - the owner's choice: the default borrows as 0.1.31 did, with the concurrent refill, the 96-blob split ring and own buffers only on a card with free VRAM, so the split's output stays 0.1.31's (2K +27%, 16K +5%, decode unchanged on the R9700 + 9070 XT); docs 2026-10-01 14:30:39 +02:00
maxfridbe 2837e43650 PR hygiene: licenses for the vendored code, a generic Intel GPU sampler, no generated files
- sycl/include/dpct/LICENSE.TXT: the SYCLomatic helper headers' license
  (Apache-2.0 WITH LLVM-exception; their SPDX notices already name it)
- sycl/third_party/ggml/LICENSE: ggml's MIT notice beside the migrated copy
- tools/intel/gpustat.py + gpustat.service: the root sampler the Monitor
  tab reads load and VRAM from on xe (finds the card, sizes VRAM from its
  BAR; GPUSTAT_PCI / GPUSTAT_VRAM_MB override)
- dpct reports and .yaml sidecars removed and ignored
- docs/INTEL.md: no references to a private test rig; the sampler and the
  model_switcher setting documented
2026-10-01 07:15:36 -05:00
maxfridbe e533380d98 Merge upstream main (engine 0.1.31) into b70
Conflicts: setup.py (upstream's reworked low-RAM/paging/rope logic kept, the
Intel backends guarded out of the experts-in-RAM rules as before; meta, the
CUDA/HIP build stamp, only read where the resident variant uses it) and
serve/server.py (upstream's /load, /unload and idle-unload beside the port's
/switcher and request logging). The SYCL copies are refreshed next.
2026-10-01 07:11:17 -05:00
maxfridbe 6f12431d53 serve: Intel Arc readings in the Monitor tab; a model menu for hosts that swap models
- telemetry: on an Intel Arc (xe) the GPU readings come from a root
  sampler's /run/gpustat.json (load, VRAM: xe exposes them to root only)
  and sysfs (temperature, power, cap, the PCIe link the card trained at,
  capped by the slot). NVML stays first; nothing changes on NVIDIA.
- a run config may name a model_switcher RPC (one model at a time on a
  shared GPU): GET/POST /switcher report and request a swap, and the web
  app shows a Model menu with the models served on this port; it waits
  for /health to name the new model, then reloads. setup.py keeps the
  setting when it rewrites a config.
2026-10-01 06:55:20 -05:00
maxfridbe c2c6ccf431 docs/INTEL.md: the original Qwen3.8-Flash-Next IQ2_XS runs on the B70 (51-61 tok/s)
6,247 of its 24,576 experts live in the pinned host mirror (8.4 GiB) and
are read over PCIe by the device plan; RAM stays above 12 GB free.
2026-10-01 06:07:55 -05:00
Niko1221 e6a06be558 HIP (S6): STRATA_HIP_WMMA=1 also takes a 96-slot prompt expert ring (9070 XT 4K prompts 718 -> 1,211 tok/s with it); docs/AMD_HIP.md: the router and WMMA switches, with credit to PR #329's equal-speed kernel 2026-10-01 13:06:56 +02:00
maxfridbe 75d2c94d38 docs/INTEL.md: k8v4 long-context rows and the API figure on the current build
k8v4 (KV in VRAM, no streaming): 995 tok/s prompt / 65.8 decode at 128K,
804 / 51.2 at 256K with 994 experts served from the host mirror.
API: 48-72 tok/s on a short chat answer, prompt included.
2026-10-01 04:52:51 -05:00
Niko1221 c92c4540e3 #340: with the split's own prompt buffers (its rule, not --no-prefill-borrow) the boundary is searched as the borrowing configuration would; the reserve only shrinks the caches (STRATA_SPLIT_OWN_PLACE=reserve: the search sees it)
9070 XT + R9700: the reserve moved K 28 -> 32 and split decode 58.5 -> 54.8 tok/s; own buffers at K=28 decode 58.4.
2026-10-01 11:34:19 +02:00
Niko1221 bf7b181a2c prefill: the Q4_K / Q5_K / Q5_1 MMQ kernels are a build option (STRATA_MMQ_KQUANTS, off) - with every kernel loaded at start they took 1-3 expert slots from every model
The engine sets CUDA_MODULE_LOADING=EAGER (a kernel loaded mid-prompt found no VRAM), so the three extra mmq
instances (+24 MB of binary) were resident for every model: IQ3_S 2261 -> 2260 slots, Q2_0 3678 -> 3675 (S1's A/B,
IQ3_S story decode ~1.5% lower). Measured with the IQ3_S setup config against 0.1.31 (wt-131-r9 build-release):
- slots 2261 / free 5.25 GiB, the same as 0.1.31 again (2260 / 5.24 with the instances);
- engine threads the same (23 at READY, 25 after a request, 0.1.31 likewise): nothing new runs for a normal pack -
  the stager's 32 threads are only for a source with file-read blobs, the verify hook only with STRATA_LOGPOS;
- 5 alternating pairs, greedy story / code / third prompt: 0.1.31 39.5 / 44.7 / 32.0, this 40.3 / 45.2 / 33.3
  tok/s (story B >= A in 5 of 5).
The UD-Q4_K_XL prompt is SSD-bound with or without MMQ (29 s per 4K chunk either way), so the released engine keeps
FP16 products for it; prefill_mmq_kquant_test is built with the option.
2026-10-01 11:31:20 +02:00
maxfridbe c53fe2331d docs/INTEL.md: re-measured on the current build, long contexts included
Summary 77.9 tok/s (19-token prompt) / 74.2 after 2,184 tokens; long
contexts with setup's KV streaming: 66.1 tok/s decode after 128K, 54.1
after 256K (all experts in VRAM). The 'not re-measured' caveat is gone.
2026-10-01 04:23:15 -05:00
maxfridbe e6d5e03006 sycl: GR norm per (token, stream), aligned loads in the IQ3_XXS/IQ3_S/IQ2_S expert dots
- the GR norm ran one work-group per token; one per (token, stream) visits
  every element in the same order, so rs and xn are bitwise unchanged
  (gr_bench checksums equal), GR read 76.7 -> 71.4 us at 6 tokens
- the gate/up expert dots read their 2-byte-aligned weights as aligned
  4-byte loads (page-safe) instead of 16-bit pairs; same ints
- grids in local memory (STRATA_GRID_SLM=1) measured slower: off
Decode 77.9 tok/s (19-token prompt), output tokens unchanged.
2026-10-01 04:22:27 -05:00
Niko1221 560e4788a1 #290 follow-up: --bf16-embd's output buffer holds the 97 gathered rows, not only the 61-row table
The gather wrote 97 rows into a 61-row device buffer (and read them back into a 61-row vector); the next launch
reported the overrun as "iq_dequant_f32: invalid argument". The buffer is max(gathered, table) rows now.
2026-10-01 11:06:21 +02:00
maxfridbe 5273a1cfb7 docs/INTEL.md: planned item 9, the original IQ2_XS with the expert overflow in the host mirror 2026-10-01 04:01:03 -05:00
maxfridbe 223c9c3a01 sycl: IQ4_NL expert dots with the codebook in registers and aligned loads (decode 70.8 -> 76.1 tok/s)
The expert down projection (IQ4_NL in 39 of 48 layers) was the largest
expert kernel: ggml reads four uint32 of the codebook from global memory
per lookup and each weight int as two 16-bit loads. Register constants
and aligned 4-byte loads (the third only when unaligned, so page-safe)
produce the same ints: 80.8 -> 43.1 us per call, output tokens identical.
-DSTRATA_IQ4NL_FAST=0 restores ggml's path.
2026-10-01 03:38:25 -05:00
maxfridbe 69b4b98f1b docs/INTEL.md: current numbers up front (SYCL port 70.8 tok/s decode, 799 tok/s prompt)
The summary still described llama.cpp as the Intel engine at 23-25 tok/s.
It now compares NVIDIA, the SYCL port (setup's default once built) and
llama.cpp; the stale 'not ported'/'not done' items, setup's KV choice and
the served speed are corrected, and the long-context table is marked as
measured before the decode work.
2026-10-01 03:35:41 -05:00
Niko1221 0239cffde7 #296 follow-up: only the Q5_0 MMQ instance and case stay (Q4_K / Q5_1 come with S5's STRATA_MMQ_KQUANTS)
S5's branch (f-132-q4) compiles the Q4_K, Q5_K and Q5_1 MMQ instances on CUDA and enables them with the private
define STRATA_MMQ_KQUANTS; with both, moe_mmq.cu would have duplicate case labels. STRATA_ORCA_Q4KS_MMQ now adds only
q5_0 (OrcaRouter's Q5_0 expert downs; HIP included) - supported() and run() take Q5_0 under it.
2026-10-01 10:31:23 +02:00
sergiywith d11ea857df PLE: the n-gram table in FP8 E4M3, as Qwen ships it
The engine read the 51.2e9-value n-gram table only as IQ4_NL (ISTA-DASLab's shard 2, 90 B/row), which is 8.1% off the
checkpoint's own values per row (correlation 0.996-0.997 on rows from all 128 shards: same table, same order). The
checkpoint stores it as 128 shards of [2500012, 160] F8_E4M3 plus one weight_scale.

- tools/ple_fp8_pack.py copies those bytes, unchanged, into a one-tensor GGUF: per_layer_token_embd.weight
  [160, 320001536] as I8, with strata.ple.format = f8_e4m3 and strata.ple.scale. 51.2 GB, streamed.
- PleTable opens either format; the row size (90 / 160) and the decode (IQ4_NL codebook / an E4M3 table times the
  scale) follow the file. PleReader takes the row size at open; its cache sizes itself by it. GGUF reader: type I8.
- A PLE-only table (architecture strata-ple) is not added to the dense-projection sources.
- The start line names the table's format.
- ple_fp8_parity: rows through Direct, Mmap and gather_batch match torch's decode of the checkpoint bit for bit.

First-token KL of the IQ4_NL table against the FP8 one: 0.0009 (1K), 0.0013 (2K), 0.0002 (4K), 0.022 (32K); mean 0.0061, top-1 4/4.

Rebased onto 0.1.31 + #317 + #296 (Niko1221): one row size (`rb`) and one decoder in PleTable for the three table
formats - IQ4_NL, #296's Q5_0 (110 B rows, the mapped reader only, as #296 has it) and FP8 (160 B) - and #317's
SSD keep-alive picks its page inside the table at the table's own row size; 0.1.31's shard list for the dense
sources keeps the PLE-only exception; ple_fp8_parity builds with STRATA_BUILD_TESTS beside #296's checks. The
"PLE on" start line stays 0.1.31's.
2026-10-01 10:31:23 +02:00
Niko1221 2ba4504b71 prefill: UD-Q4_K_XL prompts 2.8x faster (16K: 57 -> 160 tok/s on an RTX 5070) - 32 stager threads and a 128-deep ring when the experts are read from the GGUF in place; MMQ for its Q4_K / Q5_K / Q5_1 experts
- The prompt path streams every expert once per 4K chunk; with the GGUF read in place ~35 GB of that comes from
  the SSD as page faults, and 4 copy threads with 16 blobs in flight read it at ~0.6 GB/s. When the expert source
  has transient (file-read) blobs the stager now defaults to 32 threads and a ring of 4 x threads (the env
  overrides stay); every other source keeps 4 / 16. Measured (4K chunk): 71 s -> 34 s (16/64) -> 29 s (32/128);
  16K prompt 273-282 s -> 99 s.
- moe_mmq: Q4_K, Q5_K and Q5_1 in supported() and the dispatcher, their mmq instances compiled for CUDA
  (STRATA_MMQ_KQUANTS; HIP unchanged). The dispatch follows eddoursul/Strata 7706c1b; main's prompt path already
  picks MMQ per layer. GPU time of the experts' products 4x lower (10 s -> 2.4 s per 4K chunk), not visible in
  the wall time on this PC (SSD-bound either way: 29 s with and without); after a 16K prompt the continuation
  agrees with llama.cpp at 92.2% (KL 0.029) against 90.2-90.6% (0.038) with the FP16 products. The other
  models' formats are not affected (their layers' types decide; none uses these three).
- tests/cuda/prefill_mmq_kquant_test: the four expert formats through MMQ against ggml's dequantized weights
  (synthetic, several experts per group, permuted rows, a zero row; rel. L2 <= 0.34%), and Q6_K stays uncovered.
2026-10-01 10:30:41 +02:00
maxfridbe 0012c9eb3f serve: log each request's client; SYCL wrapper without the image's health check
A disconnect in the log now names the client that closed it. The
strata-sycl-dev image inherits a health check on port 8080 (llama.cpp's)
that marked the serving container unhealthy forever.
2026-10-01 03:27:17 -05:00
Niko1221 d70df548ad #340: a layer split keeps 0.1.29's own prompt buffers (2048-token chunks, priced into the split search) when they are at most 12% of every card's VRAM; smaller cards keep borrowing (STRATA_SPLIT_OWN=1/0 forces)
Measured on 9070 XT + R9700 (Coder IQ1_M): 2K/4K/8K/16K prompts 1588/1771/1943/2006 tok/s (0.1.29 1568/1730/1870/1935,
0.1.31 993/1212/1350/1852). One GPU unchanged; --split-skip-if-fits keeps the loans.
2026-10-01 10:25:03 +02:00
Niko1221 b7bb142060 #340 prototype: STRATA_SPLIT_SMALL_MAX=M - a split request of at most M prompt tokens reads in the stages' own S-token chunks (nothing lent) 2026-10-01 10:04:08 +02:00
Niko1221 242248ceed setup: Unsloth UD-Q4_K_XL as an experimental choice (--family unsloth) - the four shards pinned at 38bb39e with their sizes and SHA-256, a RAM budget of the PC's RAM less 24 GB, packed with --compat-bf16, engine 0.1.32 or newer
- FAMILIES["unsloth"] (marked [experimental], not the default) and MODELS["UD-Q4_K_XL"] ("budget": True,
  48 GB of RAM or more); HF_REVISIONS pins unsloth/Qwen3.8-Flash-Next-GGUF; families may have more than two
  shards ("shards": 4).
- The download resumes as before; then verify_sha256 checks each shard's size and SHA-256 once (remembered in its
  finish mark; a wrong file is deleted so the next run downloads it again).
- resident_budget_gib: round(RAM) - 24 GiB (40 on 64 GB, the measured setting), at most the 71 GiB of experts, at
  least 8; a KV cache streamed to RAM (64K+) comes out of it. --resident-budget-gib replaces the low-RAM mode for
  this model (no experts.bin; --low-ram is ignored with a warning); one GPU, no images, no speed projection; 8K
  context recommended on GPUs under 14 GB; no --ple-gguf for a 4-shard file (the engine finds the PLE shard).
- The engine version is checked right after the engine step, before the 111 GB download.
- choices_from_config reads a size with a dash (strata-unsloth-ud-q4_k_xl.json).
- tools/test_setup_unsloth.py: pins, budget, SHA-256 handling, config round trip, and setup.main() end to end with
  every outside effect mocked (URLs, pack flags, engine args, old engine, too little RAM, two GPUs + images).
- README and docs/UNSLOTH_Q4.md / DETAILS.md describe it.

The model support itself follows eddoursul/Strata (PR #245).
2026-10-01 09:33:20 +02:00
Niko1221 796655c6ff docs: UD-Q4_K_XL against llama.cpp on the same GGUF - 99.0% argmax agreement on a code answer, 97.5% on a thinking answer, 90-91% after a 16K prompt, every difference where llama.cpp's own top two are close
Same token sequences through Strata (40 GiB budget, greedy, adaptation off, STRATA_LOGPOS_TOPK=20 on the verify
windows) and llama.cpp 3cf0325 (CPU, mmap, top 20 from llama_get_logits_ith): argmax agreement, top-5/10 overlap,
KL over the top 20, perplexity. Code 99.0% / thinking 97.5% (the fork, eddoursul/Strata: 98.2-99.3% / 95.6-95.8%);
after a 16K prompt 90.2% on Strata's greedy continuation and 91.2% on real text, the same real-text positions with
512 tokens of context 89.2% - so not a long-context loss: all positions with a top-1/top-2 gap of 0.5 or more agree
(and every code/thinking position from 0.2), perplexities within 3%.
2026-10-01 09:32:19 +02:00
Niko1221 88f4146c53 #340 prototype: a split's streamed ring is 96 slots when most experts are resident (STRATA_SPLIT_RING); STRATA_SPLIT_SMALL_OWN=S keeps an S-token chunk's buffers per lending stage for the session; --no-prefill-borrow on a split books the ring (it no longer starves the draft head)
One GPU: unchanged (all three rules are for layer splits only).
2026-10-01 09:22:58 +02:00
Niko1221 5fd4f2670f #296 follow-up: ple_q5_parity / q5_projection_parity build only with STRATA_BUILD_TESTS; the doc says what runs where
The two real-weight checks were added to every CUDA build with native experts (a full release build compiled them);
they are test programs. docs/ORCA_Q4_K_S.md: the build flag for them, and that 0.1.31's GPU expert kernels take
Q4_K gate/up with Q5_1 or Q8_0 downs (Q5_0 is not among them yet: the engine refuses such a pack at start, naming the layer).
2026-10-01 08:49:35 +02:00
Suoriks 75a39eef3a feat: support OrcaRouter Q4_K_S
Load three-shard Uncensored weights while preserving Q5_0 PLE rows
and Q4_K/Q5 expert bytes.

Add native CUDA and MMQ paths with real-weight parity checks.

Rebased onto 0.1.31 (Niko1221): 0.1.31 already loads each expert role from its own shard (the per-role shard column
of native_experts.txt, iq_pack.py, expert_source.cpp, native_expert_parity's multi-shard mode) and has its own
Q4_K/Q5_K/Q5_1/Q8_0 GPU expert decoders, so this PR's gguf_role_file / v4 manifest, its iq_pack.py and
test_iq_pack.py changes and its iq_kernels.cu decoders are dropped. Kept: Q5_1 in native_mmvq (type 7 through
0.1.31's iq_mmvq) and in the BF16 dequantizer, the Q5_0 PLE table (mapped reader), the Q4_K/Q5_0/Q5_1 MMQ
instances under the STRATA_ORCA_Q4KS_MMQ option (OFF), ple_q5_parity / q5_projection_parity and the doc.
2026-10-01 08:49:03 +02:00
Niko1221 cf3b351c19 #272 follow-up: --pool-affinity all (the pool's layout so far) is the default; auto and p-cores are opt-in
#272 made Auto the default, which on a hybrid CPU moves the workers (P-core primaries, then SMT siblings, then
E-cores) and cuts their number to P-cores - 1: a speed change nobody has measured here, on the machines most
users have. The default is All - the same cores in the same order as before on every CPU (Windows: the first
logical processor of each core; Linux: one allowed CPU per (package, core)), and the same worker count - in
Options, ExpertPool, physical_cores() and detect_cpu_topology(). --pool-affinity auto | p-cores opts in; the
hybrid line is printed only then. Usage text says so.
2026-10-01 08:47:56 +02:00
Pravesh Khatana 69743d3a5c feat(cpu): add hybrid architecture awareness and --pool-affinity for P/E-core CPUs
- Add detect_cpu_topology() for Windows (GetLogicalProcessorInformationEx) and Linux (/sys/devices/system/cpu/cpu*/cpu_capacity)
- Identify hybrid P/E-core topology and SMT sibling structures
- Prioritize primary P-cores for worker allocation, reserving core 0 for host thread
- Default pool_workers to (p_cores - 1) on hybrid CPUs when unspecified
- Add --pool-affinity auto|p-cores|all CLI option
- Maintain 100% backward compatibility on non-hybrid CPUs and default configs
2026-10-01 08:47:28 +02:00
Niko1221 029e10d9d9 #290 follow-up: a BF16-row parity test (native_expert_parity --bf16-embd)
iq_embed_rows (97 rows gathered out of order, with repeats) and iq_dequant_f32 on a random BF16 table, every value
compared bit for bit with the exact widening (bits << 16); embed_type_supported(30) / iq_supported(30) /
iq_row_bytes(30). ctest native_expert_parity_bf16_embd.
2026-10-01 08:46:48 +02:00
sergiywith 32727a7a94 Token embedding in BF16 from the checkpoint (--embd-gguf)
- tools/embd_bf16_pack.py copies embed_tokens (BF16, as the checkpoint ships it) into a one-tensor GGUF; only the
  safetensors shard that holds it is needed (3 GB for Qwen/Qwen3.8-Flash-Next).
- --embd-gguf PATH: NativeEmbed reads token_embd from that file; iq_embed_rows and iq_dequant_f32 decode BF16
  (embed_type_supported). Mapped host memory as before (1.2 GiB instead of 0.3 for IQ4_XS), no VRAM.

First-token KL of the GGUF's IQ4_XS embedding against the BF16 one: 0.0015 (1K), 0.0089 (2K; the top token changes), 0.0010 (4K), 0.037 (32K); mean 0.012, ~100x the run-to-run noise. On the NVFP4 fork, whose GGUF embedding is Q8_0, the same comparison gave 0.0025. Decode and prompt speed are unchanged (fork); the start takes ~0.2 s more.

Rebased onto 0.1.31 (Niko1221): NativeEmbed::load takes the shard list (one file for --embd-gguf) and checks the
model's architecture since 0.1.31 - the one-tensor file says "strata-embd", so only its tensor is checked there;
the Q4_K/Q5_K/Q5_1/Q8_0 decoders 0.1.31 added stay beside the BF16 one.
2026-10-01 08:46:48 +02:00
Niko1221 c81244d4e9 #293 follow-up: the drafter stores rotated INT8 K/V as INT8; the rotation is part of the snapshot format
- mtp.cpp record_forward: the `if (st_.kv_rot)` branch rotated K and V and then always appended with
  kv_append_q4_step - for INT8 + STRATA_KV_ROT=1 into Q4_0 pools the state does not have. The rotation and the
  append are separate now: rotate when kv_rot, then append in the state's own format (Q4_0, INT8, FP16).
- conversation_snapshot.cpp: rotated INT8 K/V is its own snapshot format (+16), so a conversation snapshot or prompt
  checkpoint taken with the rotation is refused by a state without it and the reverse ("incompatible K/V
  geometry"); without the rotation the format is unchanged. conversation_snapshot_test checks both directions.
- generate: says when STRATA_KV_ROT=1 applies; the q4_0 line's comment back.
2026-10-01 08:45:09 +02:00
sergiywith f133c655a8 KV: optional Hadamard rotation for int8 K/V (STRATA_KV_ROT=1); the drafter and the batched verify rotation-consistent
INT8 K and V can go through the Walsh-Hadamard rotation --kv q4_0 already uses (kv_q4.hpp): it spreads outlier
channels over the 64-value scale groups before quantization; the queries are rotated too (<Hq, Hk> = <q, k>) and the
output rotated back.

- QsaState::kv_rot: Q4_0 always, INT8 with STRATA_KV_ROT=1 (off by default: the same tokens as main).
- Every writer and reader follows it: decode, the verify window, the prompt path, the MTP drafter, and the drafter's
  batched prompt pass (Prefill::draft_kv) - which rotated only for Q4_0.
- verify.cpp: the batched window path (qb) never rotated its queries; it did not matter while Q4_0 was kept off it.

First-token KL to fp16 K/V, 4 prompts incl. 32K: NVFP4 pack 0.0066 -> 0.0051; IQ2_XS 0.0022 -> 0.0054. Hence opt-in.
2026-10-01 08:44:04 +02:00
Niko1221 0f461187d2 #280 follow-up: the float64 RoPE table is opt-in (STRATA_ROPE_TABLE=1); a freed session's table is forgotten
- The table's angles differ from the fast-math cosf/sinf ones in the last bits, so every output moves: off by
  default (the kernels compute the angle exactly as 0.1.31), STRATA_ROPE_TABLE=1 turns it on (replaces the PR's
  STRATA_ROPE_LEGACY A/B switch).
- The per-device registration was a raw pointer into the session's arena that outlived it: QsaState::owns_rope marks
  the state that built the table (not one that borrowed it with share_rope, like the MTP drafter's), and
  session_release() - to be called before a session's memory is freed - clears every device's entry pointing at
  it (rope_table_release). The latest session of a device now wins, instead of the longest table.
2026-10-01 08:43:38 +02:00
sergiywith 16a369b574 RoPE: every kernel reads the session's float64 angle table
The native decode/verify rope and the indexer's pooled keys computed pos * powf(...) with cosf/sinf under
--use_fast_math (0.0014 rad off at 32K, ~0.02 at 262K), the prompt path with precise float libm, and the float64
table the session builds was read only by the non-native path. rope_table_set registers that table per device
(mrope.hpp); rope_cs reads it, or computes in float64 past its end.

Measured on main with IQ2_XS: first-token KL of the old angles against the table 0.0045 on a 32K prompt (two runs of
main: 0 to 0.00013 on short prompts). On an NVFP4 pack: 0.0063 at 32K and at 125K. Speed unchanged.
STRATA_ROPE_LEGACY=1 brings the old float angles back for A/B.

Rebased onto 0.1.31 (Niko1221): 0.1.31's rope scaling (#84: linear / YaRN, rope_scaled_angle) is in every rope
kernel and in the session's table (build_rope_table with the RopeScaling), so a kernel reads the table only when it
was built with the scaling it was given, and otherwise - or past the table's end - computes the angle exactly as
0.1.31 does (no separate float64 device path); rope_table_set registers the scaling with the table.
2026-10-01 08:43:07 +02:00
Niko1221 5f02176997 verify: STRATA_LOGPOS_TOPK=K adds the K most likely tokens and their log-probabilities to the STRATA_LOGPOS rows
For a per-position comparison with another engine on the same tokens (argmax agreement, top-k overlap, KL on the
top K): docs/UNSLOTH_Q4.md compares UD-Q4_K_XL with llama.cpp this way.  Off unless the variable is set; the
eight existing columns are unchanged.
2026-10-01 08:42:54 +02:00
Niko1221 fc2eb78e0a conversation cache: a turn's parked copy supersedes the previous turn's, so a subagent no longer evicts its parent (#342)
Every request that does not continue the live session parks it, and put() never removed older copies of the
same conversation while make_room evicted oldest-first: a subagent's 9 successive turns (each re-rendering the
previous reply) parked 9 copies and pushed the parent conversation out of 4 slots. drop_superseded() now runs
before make_room (park_current) and in put(): an entry whose DEEPEST checkpoint the outgoing chain (or live
state) still holds - the same conversation a turn back, differing only in the stale reply tail - is dropped
(counted apart from evictions, logged). An entry without checkpoints, of the other steering mode, or whose
deepest checkpoint the outgoing chain lacks (another conversation sharing only the system-prompt root) is kept;
an oversized put drops nothing. The cache is opt-in (#189): with it off nothing runs. Tests in
conversation_cache_test (MAIN -> SUB x9 -> MAIN with 4 slots; the kept cases).
2026-10-01 08:42:33 +02:00
Niko1221 c03efab319 serve: AMD readings in the Monitor tab from Linux sysfs; free VRAM on HIP (#301)
With the AMD backend (config backend "hip") telemetry reads the amdgpu driver's sysfs files instead of NVML:
gpu_busy_percent, mem_info_vram_used/_total, and hwmon temp1_input, power1_average (or power1_input) and
power1_cap. The card is found as setup's amd_gpus() numbers it (KFD topology GPU nodes in order, CPU nodes
skipped, drm_render_minor -> /sys/class/drm/renderD<N>/device), which is HIP_VISIBLE_DEVICES' numbering; a
layer split sums/averages as on NVIDIA. Service.free_vram_mib (min_free_vram_mib) uses it on HIP. NVIDIA
paths unchanged. Test: AmdTelemetry (a fake sysfs tree, two cards and a CPU node). Not yet checked on a real
AMD box.
2026-10-01 08:41:14 +02:00
Niko1221 7d746a0887 #283 follow-up: STRATA_PREFILL_BF16X2 defaults to 0 (off) - the prompt path's numbers stay 0.1.31's
The second (remainder) GEMM changes what the prompt path computes, so it is opt-in: 2 = all but the
hyper-connection's projections, 1 = all. With 0 every lo pointer is null: no extra buffers in carve()/bytes_needed(),
the PLE batch size as before, and every kernel writes exactly the BF16 images it wrote before.
2026-10-01 08:40:29 +02:00
sergiywith a86bc853f3 Prompt path: BF16 projections get the activation's BF16 remainder too
The prompt path fed BF16-rounded activations (2^-9 relative) to the BF16-weight projections, where decode feeds FP32:
the router (a discrete top-10), the indexer (a discrete block selection), SSM alpha/beta, the shared-expert gate, the
PLE key/value and the hyper-connection. Each now takes x as hi + lo, both BF16 (lo = bf16(x - hi)), in two GEMMs
summed in FP32: ~16 mantissa bits, decode's FP32 x to within ~1e-5.

STRATA_PREFILL_BF16X2: 2 (default) all but the hyper-connection, 1 all, 0 off.

IQ2_XS, first-token KL to mode 1: short prompts main 0.0028/0.0069/0.0009, mode 2 0.0014/0.0024/0.0012; a 32K prompt
0.074 and 0.072 (the hyper-connection is what matters there).
2026-10-01 08:40:02 +02:00
Niko1221 da95ad29d8 #282 follow-up: chunks above 8192 are opt-in (--prefill auto:16384 / auto:32768, or STRATA_PREFILL_AUTO_MAX)
A bigger chunk reads a long prompt in a different order of chunks (other expert loans, other rounding of the
batched path), so it stays out of the default: plain --prefill auto picks from 8192 down exactly as 0.1.31 did (the
PR's "no chunk past the context" rule, which also moved the choice below 8192 for small contexts, now applies only
to the new sizes). auto:N (16384 or 32768) or STRATA_PREFILL_AUTO_MAX with auto sets the ceiling; o.prefill_chunk
starts at that ceiling for the buffer estimates. Both kAutoChunks lists - plan_lend and the serve path's per-stage
fits() - take the same sizes under the same rule.
2026-10-01 08:39:58 +02:00
sergiywith 1e5e84d919 prefill auto: chunks up to 32768 (was 8192)
Every chunk streams again each expert it routes to, so a long prompt read in 8192-token chunks crossed PCIe with
nearly all experts of every layer four times per 32K. The auto list now starts at 32768 and 16384, still bounded by
the lend rule and by --max-context; a request lends only what its prompt needs, so short prompts are unaffected.

IQ2_XS, RTX 5090, 64K context, a 32K prompt (3 runs each): 5,624 -> 6,465 tok/s, 40K -> 18K experts streamed.
NVFP4 pack at 262K: 3,535 -> 5,201 tok/s.
2026-10-01 08:39:27 +02:00
Niko1221 6280f653c8 #281 follow-up: the saturated FP16 SwiGLU product keeps a NaN a NaN
fmaxf(NaN, -65504) is -65504, so #281's clamp turned a NaN product into -65504 and the prompt path went on with a
plausible value where it used to show the NaN (STRATA_DBG_NAN and the NaN checks find it there). isnan(x) ? x :
clamp(x): only +-inf (and finite values from 65520 up, which rounded to inf) saturate; everything else is unchanged.
2026-10-01 08:38:59 +02:00
sergiywith c517862ce2 numerics: saturate the prompt path's FP16 SwiGLU products; log1pf in the unfused GDN gate
- prefill/kernels.cu: the SwiGLU products that feed the prompt path's FP16 down projection are clamped to FP16's
  range (+-65504) before rounding. A token with a massive activation otherwise becomes inf there and NaN after the
  GEMM, where decode's q8_1 path (range ~8e6) stays finite.
- native_gdn_preprocess.cu: the unfused gate softplus used logf(1 + expf(v)), which returns 0 for v below ~-16
  (1 + e^v rounds to 1); the fused kernels, gdn.cu and verify_kernels.cu already use log1pf(expf(v)). The two paths
  now agree.

On ordinary prompts nothing moves: first-token KL to main 0, 0.00013, 0 (the run-to-run noise).
2026-10-01 08:38:35 +02:00
BlueKingMuch 4da8bfcbf9 ple: keep the SSD awake while rows are read (STRATA_SSD_KEEPALIVE)
Some SSDs (here a WD_BLACK SN7100 on Windows 11) drop into a power state
after ~250 ms without a command and stall the next reads 50-150 ms; the
NVMe idle timeouts of Windows' power plan do not change it. In decode that
hits the first read after a pause: at the start of a request, or after a
few rounds whose rows all came from the row cache. --ple-io ram, which
avoids the reads altogether, is not available on Windows.

The reader's worker now reads one page of the table (a different one each
time) when no read has gone out for 100 ms, until 60 s after the last
issue; then the SSD may sleep until the next request re-arms it. A
keep-alive read counts when it completes and stays out of the row-read
counters and latencies; the "ple io" line adds "SSD kept awake by N reads
(slowest X ms)". A keep-alive read that fails, or cannot be submitted,
turns the keep-alive off instead of failing the reader.
STRATA_SSD_KEEPALIVE=0 turns it off, =50 shortens the period;
STRATA_SSD_KEEPALIVE_WINDOW sets the window in seconds. Only with the I/O
worker (the default), not with --ple-sync-submit or --ple-io mmap/ram.

The reader's statistics are now copied and reset under the worker's lock
(snapshot()), since the worker may be counting a keep-alive read. The
selftest checks the period, the window, the re-arm by a ticket the row
cache serves, that rows and read counters are untouched, and that the
caller-thread mode has none.

A scan on that PC (reads after pauses of every length): 0 of 211 bursts
stalled after pauses under 200 ms, 35 of 73 after 200 ms and more, 0 of 68
of those with the keep-alive on.
2026-10-01 08:38:27 +02:00
Niko1221 9d0b28df54 #315 follow-up: its variants and switch renamed (plain / split / staged, STRATA_HC_SPLIT) - no clash with STRATA_GR_V3
main already has an opt-in "v3" hyper-connection read (#186, STRATA_GR_V3=1, another summation order); #315's
"v2"/"v3" and STRATA_HC_V2 read as the same thing. Now: the plain read (0.1.31's default), split (the norm per
token and stream) and staged (split + the down projection's activations staged by cp.async), kHcPlain/kHcSplit/
kHcStaged, gr_norm_split_kernel / gr_down_staged_kernel, and STRATA_HC_SPLIT: unset or 2 = the newest the card's
check accepts, 1 = at most split, 0 = the plain read. The check compares against the plain read (launch_multi with
kHcPlain) and the single-token read, never against what STRATA_GR_V3 selects; with STRATA_GR_V3=1 that opt-in read
still runs first, unchanged.
2026-10-01 08:38:22 +02:00
Niko1221 d85ff9dfe9 serve: model aliases - the config's aliases in /v1/models and accepted as model names (#297)
`"aliases": [...]` (or a comma-separated string) in strata-<model>.json: /v1/models lists the model with an
`aliases` field and each alias as its own entry (`alias_of`), /props?model= accepts them, and a request naming
an alias is answered under that name (OpenAI, streamed or not, and Anthropic). Any other name is still served
under the model's own name, as before; without aliases the responses are unchanged. Documented in DETAILS.md.
Test: ModelAliases (serve/test_server.py).
2026-10-01 08:37:46 +02:00
Niko1221 469bdaf891 #340 prototype: a split stage with room for its prompt buffers keeps them as its own (no loan, nothing streamed or refilled for it); STRATA_SPLIT_OWN_BUFFERS=0: every stage borrows
One GPU: unchanged (the rule is for layer splits only; the single-cache loan is computed exactly as before).
2026-10-01 08:37:18 +02:00
BlueKingMuch 2cf197f894 hc: the multi-token hyper-connection read split finer, checked bit for bit on each card (STRATA_HC_V2)
The multi-token read (verify windows, the MTP drafter) keeps v1's
arithmetic exactly - every sum over the same elements in the same order -
and only splits the work differently:
- the norm (v2, v3): one block per token and stream instead of one per
  token. Each thread visits the elements of its stream in the order it did
  in v1, so every sum of squares and rs is v1's; R' * w_norm is recomputed
  and scaled once (the same two roundings as v1's store and in-place
  scale). On an RTX 4080 SUPER: 0.58 -> 0.23 ms per 4-token round.
- the down projection (v3): v1's rows per block and lane order, but the
  activations arrive by cp.async in half-stream tiles, two in flight, in a
  bank-conflict-free two-plane layout, and the next tile's weights load
  while the current one is used. A tile is 160 = 5 x 32 chunks, so a lane
  still accumulates its chunks lane + 32 q in ascending order. Before sm_80
  and on HIP the staging is a plain copy (the same bits).

Verifier::init runs fused_gr_check once per card: v1, v2, v3 and the
single-token read on random bf16 weights and inputs (1..8 tokens, with and
without the pending write), every output compared bit for bit; the newest
variant that agrees runs on that card and the log says which. A card that
has not been checked runs v1. STRATA_HC_V2=0 keeps v1, =2 stops at v2.
The down kernels carry as many tokens per launch as the card's shared
memory allows (v3: 10 KB per token), as v1 did.

Rebased onto 0.1.31 (Niko1221): v1 is 0.1.31's default read unchanged - the TILEV 1280/2560 down kernel (sm_75's
small tile), the pre-Volta capacity rule, STRATA_EMULATE_CC - moved into down_chunk()/launch_multi(); main's opt-in
STRATA_GR_V3 path (#186, another summation order) still comes first in fused_gr_read_multi, and the card's check
calls launch_multi(1) directly, so it compares against the default read whatever STRATA_GR_V3 says.
2026-10-01 08:36:04 +02:00
Niko1221 348d65da7b #340 prototype: a layer split refills every stage's prompt loan concurrently (queue all, then wait); STRATA_REFILL_SERIAL=1: stage after stage; STRATA_TRACE times the loan and the refill
One stage: refill_one exactly as before (single-GPU unchanged). The same copies into the same slots either way.
2026-10-01 08:35:57 +02:00
Niko1221 bd84d0bc6d #284 follow-up: wait for the async commit on an event, at every point that touches the session afterwards
The commit graph writes the GDN state and conv tail, the QSA indexer's tail/dead/pooled/block_pos and the PLE
history; with #284 it may still run when commit() returns. Verifier::commit records commit_done_ after it, and
Verifier::wait_commit() synchronizes that event (not the device; a no-op when nothing is pending, recursing into a
layer split's later stages). A layer split's first stage keeps the synchronous commit (next_ set).

Audited, and where the wait now is:
- the serve decode loop's end (end of turn, max tokens, STOP/cancel): wait before the live session, the state
  fingerprint (STRATA_STATE_HASH) and the DONE line - so the next request's park (conversation snapshot capture),
  restore, checkpoint restore and zeroing never see a running commit;
- the prompt read by verify windows (serve): wait at its end - the batched prompt path (other streams), prompt
  checkpoints (cudaDeviceSynchronize already) and snapshots may follow;
- the start of each serve request: an event wait replaces #284's cudaDeviceSynchronize (covers error paths);
- the end of a generate run: wait right after the decode loop, before the stats and the dumps (#284 synchronized
  only later, after the routing dump);
- unchanged and safe: the next window (same stream), the MTP draft (its own stream; reads the window's final rows
  and its own K/V, which commit does not write), the adaptive tier thread (expert slots and residency tables only),
  STRATA_LOGPOS / STRATA_DUMP_FIRST_LOGITS (read run()'s head logits after run() synchronized), QUIT and /unload
  (the Verifier destructor synchronizes its streams before freeing).
2026-10-01 08:34:33 +02:00
Niko1221 2282393234 setup --backend hip: --vision cpu builds and uses the CPU image encoder (#304)
Setup forced images off on the AMD backend. hip_vision() now takes --vision cpu: build_engine_hip builds
tools/vision without CUDA beside the HIP engine (build_vision_cpu, again when its source changes) and records
vision/vision_src in BUILD.json; the start config is the CPU encoder's, as on NVIDIA. --vision yes/gpu stay off
with a hint (no HIP encoder build yet); without --vision nothing changes. Test: tools/test_setup_choices.py.
2026-10-01 08:34:07 +02:00
sergiywith a1e4fb4c80 Verify: the commit graph no longer waits; it overlaps the MTP draft
The commit's cudaStreamSynchronize held the host ~0.45 ms a round. The next window follows it on the same stream and
the drafter (its own stream) reads only this window's final rows and its own K/V, so a single-GPU session
(Verifier::set_commit_async) returns at once. Whatever touches the session from another stream or the host afterwards
synchronizes the device: the start of each --serve request (checkpoint restore, zeroing, the prompt path) and the end
of a generate run; checkpoint saves already did. A layer split keeps the wait, as does STRATA_COMMIT_SYNC=1.

IQ2_XS, 400-token answers, 3 runs each: 128.6 -> 135.8 tok/s decode (+5.6%), the same tokens. NVFP4 pack +0.8%.
2026-10-01 08:33:05 +02:00
Niko1221 3b7a49a6fd setup: Pascal (6.x) and Volta (7.0) with STRATA_EXPERIMENTAL_SM60=1: the community build with CUDA 12.x (#295)
The engine/CMake part shipped in 0.1.31. Setup now admits compute capability 6.x and 7.0 only when
STRATA_EXPERIMENTAL_SM60=1 is set (gpu_problem; without it the message says so), compiles the engine with
-DSTRATA_EXPERIMENTAL_SM60=ON for cards below sm_75 (engine_defs), and takes the newest CUDA 12.x toolkit
(find_nvcc(below=(13, 0)); CUDA 13 cannot build sm_60/sm_70) - stopping with a hint when there is none, or
when an RTX 50 card (CUDA 13) shares the model with such a card. Without the variable nothing changes.
Test: tools/test_setup_choices.py (mocked toolkits and cards).
2026-10-01 08:32:49 +02:00
Niko1221 272c16c767 #332 follow-up: the API request monitor is opt-in ("api_monitor": true / --api-monitor), off by default
It keeps the last 100 requests' prompts, answers and reasoning in memory. Off (the default): begin_request() keeps
nothing, the streams are not wrapped, GET /api/requests and /api-monitor answer 404. Every record write goes through
_note(), which does nothing without a record (the PR's direct self.record[...] writes in the stream error paths
would have failed with the monitor off). A client disconnect in do_POST is marked and then re-raised, as the server
handled it before. The start line says when it is on (and that anyone can read the history without an API key).
test_monitor: turns it on; MonitorOff checks the default; Anthropic requests ask for thinking with "thinking" (#278).
2026-10-01 08:32:01 +02:00
Ricardo Ambrogi 24d011807c serve: add standalone API request monitor 2026-10-01 08:31:48 +02:00
Niko1221 5a18f83a13 setup --gguf-dir: the shard count from the -of-N part of the name, not two (#305)
--gguf-dir built exactly <model>-00001-of-00002.gguf and -00002-of-00002.gguf, so a model split or named
differently (-00001-of-00003, Unsloth's ...-00001-of-00004.gguf) was not found. gguf_dir_shards() takes the
published name when it is there (unchanged for the existing models), else the one first shard in the folder
whose name has the size in it, and names shards 1..N from it as the engine and iq_pack do. Help text updated.
Test: tools/test_setup_choices.py (2- and 4-shard names).
2026-10-01 08:31:13 +02:00
Niko1221 354212421e setup: the CPU image encoder when the ready-made encoder has no code for the card (#331)
The release zip's strata-vision has no sm_75 code (BUILD.json vision_archs 86/89/120), so on an RTX 20 card
setup fell back to compiling the encoder, which fails on most Windows PCs. prebuilt_vision() now chooses the
CPU encoder (the same program without --gpu) with a warning; --build still compiles a GPU one. The next release
zip should build strata-vision with 75-real as well. Test: tools/test_setup_choices.py.
2026-10-01 08:30:06 +02:00
Niko1221 abfb05cfbe native packs: a BF16 (--compat-bf16) PLE key stays in the arena and is not replaced by the GGUF key (#326)
Since 0.1.25 NativeDense treats an IQ3_XXS/IQ4_XS/Q8_0 GGUF key as native, so for a native pack the loader
skipped the pack's key row and then refused the BF16 row iq_pack --compat-bf16 writes for OrcaRouter's IQ3_XXS
key ("native dense: incompatible matrix blk.1.ple_key.weight"). NativeDense::keep_unquantized_ple_key reads the
key row's code_bits from index.txt (WeightTable::index_code_bits) and keeps an unquantized row in the arena;
NativeDense::load does not upload the GGUF key over it, and the PLE uses the BF16 key as before 0.1.25. A
quantized key row (Q2_0, UD-Q4_K_XL packs) is unchanged; the GSQ packs' GGUF keys are BF16 (not eligible), so
they never reach this path. The reporter's fallback (Gen4536). Test: native_dense_ple_key_test (synthetic GGUF
+ pack, CUDA).
2026-10-01 08:29:03 +02:00
Niko1221 75780af235 mtp_fetch: a range read needs 206 + its Content-Range; pinned per-tensor sha256, corrupt installs fetched again (#327)
A mirror that ignores the Range header answers 200 with the shard's start (its JSON header); cut to the asked
length it passed the size check and the manifest hashed the wrong bytes, so the drafter accepted nothing. get()
now requires HTTP 206 with the requested Content-Range. The 31 MTP tensors' sha256 at the pinned revision
(de4b8e4) ship in SHA256 (two independent fetches agree; 29 re-read from the revision, the two expert tensors'
first/last 16 MiB): a wrong tensor is fetched again once, then refused. An inventory read from another
repository/revision is read again and its tensors are kept only when they hash right. `mtp_fetch.py verify`
(offline, cached by size/mtime) finds a corrupt install; setup then fetches the bad tensors again and rebuilds
the draft layer. From PR #324: a refused engine archive no longer keeps its zip and .done mark.
Tests: tools/test_mtp_fetch.py (fake checkpoint behind a mocked urlopen, a mirror that ignores Range),
test_setup_pins (refused archive).
2026-10-01 08:28:45 +02:00
Niko1221 d3bf912ea0 #334 follow-up: jsonschema is an optional, lazily imported package (no new hard dependency)
- The rebase keeps 0.1.31's requirements.txt install in setup.py and the Dockerfile: jsonschema is not added.
- serve/structured.py imports jsonschema on the first json_schema request, not at server start (a server without it
  started fine before #334 and still does). json_object never needs it; json_schema without it is checked to be one
  JSON object, and the server window says once how to get full schema validation.
- test_structured: the two schema-violation tests skip without jsonschema; new tests for the object-only fallback
  and for "import serve.server" not importing jsonschema. docs/DETAILS.md says it is optional.
2026-10-01 08:27:57 +02:00
Ricardo Ambrogi c87a9cb0ce serve: validate JSON response formats before delivery 2026-10-01 08:27:08 +02:00
Niko1221 bd9a1bc126 #333 follow-up: the unload keeps its terminate/kill fallback; EngineStuck instead of a catch-all RuntimeError
- StrataEngine.close() (now also the unload and the restart): QUIT and EOF, then terminate, then kill, each with 20 s
  as the unload had (#333 went from QUIT straight to kill after 10 s; an engine unpinning tens of GB can need more).
  A process that outlives all three raises EngineStuck and stays owned.
- do_POST caught every RuntimeError as a 503 - EngineDied, GpuBusy and ModelBusy are RuntimeErrors too, and any other
  failure was turned into a vague 503. Only EngineStuck is caught now (also around POST /unload, and the idle-unload
  thread survives it); EngineDied keeps its own answer.
- test_lifecycle: terminate before kill, EngineStuck, an EngineDied on load answered as such.
2026-10-01 08:26:28 +02:00
Ricardo Ambrogi 7f3a091895 serve: add lazy startup and reliable Windows model cleanup 2026-10-01 08:24:02 +02:00
Niko1221 a8d5a16c35 #321 follow-up: CORS only on /v1/* for configured origins; no own-page bypass for proxy headers
- The Origin check of /settings and the MCP tools let any page through when the request carried X-Forwarded-For,
  CF-Ray or CF-Connecting-IP (headers every reverse proxy or tunnel adds), and compared hosts without their ports
  (a page on another local port passed): any web page could then change the shared settings or run MCP tools with the
  user's rights. Removed. The Origin must be this server's host:port, or an origin in the config's new
  "trusted_origins" (the web app behind a proxy or tunnel); a proxy header alone opens nothing.
- CORS is opt-in: "cors_origins" in the config (an origin, a list, or "*"). Only /v1/* answers with
  Access-Control-Allow-Origin (the origin itself, or "*"), never /settings, /unload or the app's files; the
  preflight echoes the headers asked for ("*" does not cover Authorization). OPTIONS is answered 204 either way.
- X-Accel-Buffering: no on SSE stays. origins_of() checks both lists at start (scheme://host[:port], no paths;
  "*" only for cors_origins). docs/DETAILS.md; tests for the bypasses, the trusted origin, CORS off/on, the header.
2026-10-01 08:23:27 +02:00
BlitzenCatsandGemini 392e32c46b serve: add CORS preflight (OPTIONS), reverse-proxy header support, and X-Accel-Buffering for SSE
- Implement do_OPTIONS (204 No Content) and add Access-Control-Allow-* headers to allow web-based clients (Open WebUI, LibreChat, browser extensions) to query endpoints.
- Update _own_page to recognize reverse proxies and tunnels (Cloudflare Tunnel, Tailscale Funnel, Nginx) via X-Forwarded-Host, CF-Ray, and forwarded headers, preventing 403 CSRF false-positives when serving remotely.
- Add X-Accel-Buffering: no to SSE streaming responses to prevent reverse proxies from buffering real-time token generation.
- Add unit tests in serve/test_server.py covering CORS preflight, CORS headers, and reverse proxy origin checks.

Co-authored-by: Gemini <[email protected]>
2026-10-01 08:22:10 +02:00
Niko1221 ca85ebdee2 #278 follow-up: an Anthropic request with its own reasoning_budget_tokens still thinks
"thinking" absent meant no thinking, also for a request that gives reasoning_budget_tokens (#123), which asks for
thinking with a cap (serve.test_server's test_anthropic_stream failed: no thinking at all). Such a request renders
as before. test_anthropic_thinks_only_when_asked pins the five cases.
2026-10-01 08:18:19 +02:00
Niko1221 40eaa123d4 serve: a restarting engine is not alive until READY; context 0 is a 503 "starting" (#344)
restart() set ended=False before __init__, which zeroes max_context and blocks until READY, so a request in that
window skipped load() and failed with a 400 "leaves no room to answer in the context (0)". The engine is now
marked alive by __init__ once READY; prepare() answers 503 "the engine is starting" when max_context <= 0. The
output thread is bound to its own process and queue, so a killed engine's thread no longer marks its successor
dead or writes into its queue. Tests: RestartWindow (a fake strata --serve with a held READY).
2026-10-01 08:17:54 +02:00
Developer 6cd29d9850 serve: keep retained K/V through the cache capacity gate
park_current dropped the retained K/V whenever can_fit failed and fell
back to a full snapshot capture. The gate duplicates what make_room
decides immediately after, with harsher arithmetic: the slot term fires
when make_room enforces the same cap, and the byte term compares the
with-reuse estimate against headroom that ignores the parked image
replacing the retained buffers. make_room already implements the
stated policy - pressure drops the optional retained storage before
evicting any parked conversation (the priority the cache tests pin).
With a full cache the fallback buys nothing: the fresh estimate forces
the same or more eviction, plus a whole-snapshot recapture instead of
the growth - hundreds of ms per park at ~100K tokens where one long
conversation round-trips while short-lived conversations keep the
cache full.

The with-reuse estimate stays uncapped: it counts the retained buffers'
capacity and directories, and put() charges that same true size, so a
capped figure would under-evict and overfill the budget.
2026-10-01 08:15:27 +02:00
Pravesh Khatana b0711943b2 feat(mtp): add --coupled-draft and --no-coupled-draft CLI options for coupled speculative sampling
- Add set_coupled_draft() and coupled_draft_state() in include/strata/core/coupled_draft.hpp
- Add --coupled-draft and --no-coupled-draft CLI options to src/program/generate.cpp
- Default option to STRATA_SPEC_COUPLED environment variable for full backward compatibility
- Update usage() help text with option descriptions
2026-10-01 08:15:27 +02:00
Hozák Martin 43cd140ecd bench: BF16 GEMV via Turing tensor cores on sm_75 - measured negative
Isolated benchmark (no inference-path changes) comparing the production
bf16_gemv warp kernel against an mma.sync.m16n8k8 tensor-core variant with
BF16->FP16 conversion, on the real decode GEMV shapes (n_in = 2560). Three
TC variants (W preconverted / inline conversion / fused output) and a full
k-split occupancy sweep; parity against an fp64 reference.

Result: the TC variant is 1.3-2.2x slower on every real shape even at its
best config - the warp kernel is already bandwidth-bound (374 GB/s) and a
single-token GEMV wastes 15/16 of the m16 MMA tile. Keeping the warp
kernel; the benchmark is checked in so this does not have to be measured
twice.
2026-10-01 08:15:27 +02:00
Zac Chen 4e1a7c5982 verify: profile columns stop wrapping (unsigned stamp deltas) and the hc-read second half stops overwriting the next layer's base stamp
kProfPer 32 -> 33: fused_gr_read_multi writes three stamps per half and the second
half's base was 30, so its up-stamp landed at slot 32 = (l+1)*32 + 0, the next layer's
stage-0 base.  Derived columns (gap/head/hc0) also wrapped to ~1.8e19 ns whenever a
slot was unstamped, printing ~1e14 ms per window.  A delta now counts only when both
stamps are nonzero and monotonic; the hc0 split replaces the single hc-read0 column
only when the split chain is complete.  Metrics-only: no computed model value changes.
Reason recorded in PORTING.md 19.
2026-10-01 08:15:27 +02:00
sergiywith 7f2c76e18d iq_pack: keep experts.bin only when its blobs match the GGUF
An existing experts.bin was kept whenever its size matched the layout. A different checkpoint with the same geometry
(a re-quantization or a fine-tune packed into the same folder) has the same size, so the engine silently served the
old experts with the new model's dense weights.

Before keeping the file, the first and last blobs of the first, middle and last layers are now compared with the
GGUF; a mismatch rewrites it. The check reads six blobs, so an unchanged pack is still reused at once.

Test: test_experts_bin_is_kept_only_with_this_ggufs_blobs packs two GGUFs of the same geometry into one folder (it
fails on the previous code).

Rebased onto 0.1.31 (Niko1221): 0.1.31 already refuses an experts.bin whose sidecar (experts.bin.src.json: shard
names and sizes, the hash of native_experts.txt) does not match, so the six-blob comparison runs only when the
sidecar says "reuse" - it catches the case the sidecar cannot (a re-quantized or fine-tuned checkpoint under the same
file names and sizes). It reads each of the six expert blobs on its own instead of concatenating the whole layer.
The test packs the second model under the first one's file name, so it reaches the new check.
2026-10-01 08:15:22 +02:00
Niko1221 d672a5f443 #287 follow-up: setup run again without --draft-vocab keeps the model's earlier choice
The full setup rewrites the model's config and refreshed the MTP folder's subset with `a.draft_vocab or "cjk"`, so
running it again without the flag put the CJK subset back over a cyrillic (or en) choice, and dropped draft_vocab from
the config. saved_draft_vocab() reads the choice the config holds; the flag still wins. tools/test_setup_draft_vocab.py.
2026-10-01 08:14:00 +02:00
sergiywith 79aa0bb11b setup: --draft-vocab cyrillic - the English/code subset plus the whole Cyrillic script
The shipped draft subsets hold 142 of the vocabulary's 18,580 Cyrillic tokens, so an answer in Ukrainian, Russian,
Bulgarian or Serbian drafted almost nothing. data/draft_vocab_cyrillic.bin is draft_vocab_en.bin plus every token
whose text is Cyrillic (58,963 ids), built with the repository's own tool:
  python tools/draft_vocab.py --gguf <IQ2_XS shard 1> --base data/draft_vocab_en.bin --add cyrillic

- tools/draft_vocab.py: a "cyrillic" script (U+0400-052F, 1C80-1C8F, 2DE0-2DFF, A640-A69F).
- setup.py: --draft-vocab cyrillic; docs/DETAILS.md.

On the NVFP4 fork: 1.4 -> 2.1 tokens per round, 83 -> 109 tok/s in Ukrainian answers, English unchanged.
2026-10-01 08:13:17 +02:00
sergiywith fcef1b0dbd strata-vision: --flash-attn on|off|auto; on the CPU no CUDA context, no warm-up, a thread per core
- --flash-attn on|off|auto (mtmd's flash_attn_type): flash attention keeps K and V in FP16. On the NVFP4 fork the
  vision tower's output was 11.2% off with it on the GPU; FP32 attention (CPU) 0.1%.
- On the CPU a CUDA build keeps the GPU unseen (CUDA_VISIBLE_DEVICES=-1 before the runtime starts): it otherwise
  opened a context there, 0.4-0.7 GB of VRAM the expert cache loses.
- On the CPU without --threads: one thread per core (mtmd's default is 4); no warm-up encode (~6 s of start).
- serve/server.py: relative exe/mmproj/model paths in the vision config are the config's cwd's, as the engine's are.
2026-10-01 08:12:47 +02:00
Niko1221 7f49b76680 #278 follow-up: the request-line follower starts once per log; its time field is prompt_read, not ttft
- StrataEngine.restart() runs __init__ again (after a crash, an idle unload's reload), which started one more
  STRATA_REQUEST_LINES follower each time and printed every request line once per restart: a follower is started
  once per log path (the log is opened for append, so the first follower keeps reading the same file).
- The field the follower printed as "ttft" is the engine's prompt read time (the new tokens only, without the queue,
  the template, the first decode step): it is named prompt_read.
2026-10-01 08:12:35 +02:00
sergiywith 4c2cd14f5f serve: /v1/messages/count_tokens, Anthropic thinking only when asked, STRATA_REQUEST_LINES, a relative exe
Found by running Claude Code against the server (claude -p, three tool turns) and by starting a config with a
relative engine path:

- POST /v1/messages/count_tokens answered 404; Claude Code asks it for its context figures. It now renders and
  tokenizes the request exactly as /v1/messages would, without running the model.
- A /v1/messages request with no "thinking" (and no effort) got the template's default, which thinks: Claude Code's
  helper calls (a ~60-token session title) came back with a thinking block and no text. Anthropic's thinking is
  opt-in, so such a request now renders with enable_thinking false. A config's reasoning_effort still applies;
  "thinking" set, or an effort, behave as before.
- STRATA_REQUEST_LINES=1: a thread follows the engine log and re-states each request's summary line on stdout, for
  supervisors that only see the server's stdout (a tray, llama-swap). Off by default.
- A relative "exe" in the config failed in Windows' CreateProcess (WinError 2): it is made absolute against the
  config's cwd, as the engine's cwd already is.

Tests: count_tokens equals the input_tokens /v1/messages reports for the same request; the request line pattern
parses the engine's summary. python -m unittest serve.test_server: 44 OK.
2026-10-01 08:12:11 +02:00
Niko1221 158e85bf43 #289 follow-up: a placeholder GPU name when the properties query fails; HIP builds compile (no device_code_error probe)
- generate.cpp: the startup line names "(an unnamed GPU)" when cudaGetDevice/cudaGetDeviceProperties fail (the
  error is cleared), and the "no code for" message uses the same name; a HIP build prints the gfx architecture
  instead of a CUDA compute capability.
- device.cu: device_code_error() returns "" on HIP - cudaFuncAttributes/cudaFuncGetAttributes have no mapping in
  hip_compat, and gpu_arch_problem() already stops a HIP run on an architecture the build lacks.
- fused_gr.cu: STRATA_EMULATE_CC also answers the two compute-capability queries there (small tile, the sm_70
  capacity rule), as the PR's description promises; with the variable unset nothing changes.
2026-10-01 08:11:39 +02:00
sergiywith a606e3a966 Start: name the GPU and stop at once when the build has no code for it; STRATA_EMULATE_CC for tests
- generate.cpp: before the expert arena loads, the engine names the card and its compute capability and checks that
  the build has code for it (device_code_error: cudaFuncGetAttributes on a kernel). A binary built for other GPUs
  used to fail at the first kernel, after the whole arena had loaded; now it stops in ~0.3 s and says why.
- include/strata/core/emulate.hpp: STRATA_EMULATE_CC=75|80|86|89 makes the host's device queries (compute
  capability, shared memory per block) answer as that generation, for a PTX build of it JIT-compiled on a newer
  card - ggml's MMQ config, the QSA kernels' choice, fused_gr's shared memory. Tests only.
- STRATA_QSA_WARP=1|select|attn: the pre-sm_80 QSA kernels on any card (A/B).
2026-10-01 08:11:23 +02:00
sergiywith aea6e45c64 diagnostics: STRATA_DUMP_FIRST_LOGITS writes the first generated token's logits
STRATA_DUMP_FIRST_LOGITS=<file>: the logits of the first window's first position (the token the prompt predicts),
n_vocab float32, written once per run. Two engine variants run on the same prompt then give a first-token KL
divergence: how far a prompt-path change moves the model's distribution, not only whether its top token changed.
On a layer split the last stage's verifier writes it.
2026-10-01 08:09:42 +02:00
Niko1221 cfb1866ec5 HIP (S6): router_top10.cu - drop a nested #if that left the HIP block unterminated 2026-10-01 08:07:46 +02:00
Niko1221 a2be1670bb HIP (S6): router_top10 without its serial parts on AMD, bitwise the same (default on HIP; STRATA_HIP_ROUTER_OLD=1: old)
On RDNA4 the router took 39 us per call in decode (16% of the decode GPU time): 512 dependent FP64 adds, ten
selection passes with 20 block barriers, a renormalisation re-reading its weights from global memory. The sum's only
use is inv = (float)(1.0 / sum): all terms are positive with the largest exactly 1, so the serial sum and a tree sum
are within 2^-43 of each other; when the bracket tree*(1 -+ 2^-40) maps to one float, that float is the serial sum's
(1/x and the cast are monotone), otherwise thread 0 runs the serial sum as before. The selection runs on wave 0 from
registers (the argmax with the lowest index on ties is unique), the renormalisation from registers in rank order.
hip_router_fast checks ids and weights bitwise against the portable kernel (65,536 rows with ties, near-ties, NaN
rows, the forced serial path; and 256 experts / k 8). CUDA builds unchanged (HIP-only code).
2026-10-01 07:24:19 +02:00
Niko1221 73ba449679 HIP (S6): RDNA4 matrix-core prompt attention for int8 KV, opt-in (STRATA_HIP_WMMA=1, gfx12 only)
The v2 tensor-core design with gfx12's v_wmma_f32_16x16x16_f16: one block per (query, KV head), wave w owns
dims [64w, 64w+64) (int8 scale group w), q and p split into FP16 hi + lo parts, int8 codes exact as FP16, scales in
FP32, the four groups' q.k partials added in a fixed order, online softmax over 32-cell chunks. Masked
(non-resident) cells get no weight, as in the decode kernel. FP32-level accuracy, not bitwise equal to the default
kernel, hence opt-in. hip_prompt_attn_wmma = qsa_prompt_attn_parity built for HIP (skips off gfx12).
NVIDIA builds unchanged (all new code is under __HIPCC__ / the HIP test section).
2026-10-01 06:44:23 +02:00
Niko1221 6ac1a2cc5e Engine 0.1.31: Unsloth UD-Q4_K_XL runs on a 64 GB PC (experimental: split GGUF, Q4_K/Q5_K/Q5_1/Q8_0 experts, RAM budget + SSD tier with routing prefetch), the low-RAM mode reads GGUF experts in place, Windows GGUF load 2x (#230), server status race (#266) and tokenizer (#268) fixes, truncated tool calls (#211/#231), AMD intrinsics (#262); setup requires it 2026-10-01 06:27:52 +02:00
maxfridbe 368ec61aac sycl: GR down projection sliced by columns (decode 65.5 -> 70.6 tok/s)
Each work-group owns a 128-column slice of all 324 rows, stages that
slice of xn once (<= 4 KB SLM) and streams the rows through it, 4 lanes
per row; a reduce kernel sums the 80 slice partials in a fixed order.
GR read 108.6 -> 76.5 us at 6 tokens. STRATA_GR_DOWN_SLICED=0 restores
the direct kernel.
2026-09-30 23:25:20 -05:00
maxfridbe 02013d01c8 sycl: wide Q8_0/IQ4_NL decode kernels, aligned Q6_K activation loads (decode 63.4 -> 65.6 tok/s)
Q8_0 and IQ4_NL blocks (34/18 bytes) are 2-byte aligned: the wide kernels
load them through load16_a2, now page-safe (the second chunk only when the
address is unaligned). Q8_0 4-6x, IQ4_NL 640->2560 4x. Q6_K's Q8_1 activation
int4 loads were 4-byte aligned: four int loads instead.
Output identical for 146 of 256 tokens, then a near-tie flips (summation
order); STRATA_MMVQ_WIDE_32=0 restores the old kernels.
2026-09-30 23:12:42 -05:00
maxfridbe 90aed054ff sycl: decode 54 -> 62.6 tok/s: parallel resident plan, untiled GR down, wide Q4_K/Q5_K/IQ4_XS
- resident_plan groups the entries with one thread per entry (thread 0
  alone took 73 us per layer); the plan is the host loop's exactly
- the GR down kernel reads xn from global memory instead of a 60 KB SLM
  tile per work-group (occupancy); outputs bitwise equal (gr_bench)
- 16-byte-load wide kernels for Q4_K, Q5_K and IQ4_XS (IQ4 codebook in
  registers): IQ4_XS 107 -> 323 GB/s, Q4_K/Q5_K 1.3-1.6x
Output tokens identical in every engine run.
2026-09-30 22:46:56 -05:00
maxfridbe cd83544431 sycl: aligned loads for the Q6_K decode kernel (decode 45 -> 54 tok/s); PLE gather trace
Q6_K blocks are 210 bytes, so the wide kernel's 16-byte ql/qh loads were
2-byte aligned and the B70 split them: 145 GB/s against 640 GB/s for the
same blocks at a 224-byte stride. load16_a2 does two aligned loads and a
shift; with it the wide kernel takes every Q6_K shape and up to 8 columns
(2.6-3.4x in q6k_align_bench). Output tokens identical.

Also a port copy of ple_reader.cpp with STRATA_PLE_TRACE=1, which showed
the 45/39 tok/s two-speed runs are one 226 ms PLE stall landing in either
the prompt or the first decode round (TTFT + decode is the same).
2026-09-30 21:43:56 -05:00
Niko1221 9195d989a4 Merge branch 'f-q4-on242' into r131-final 2026-10-01 03:11:54 +02:00
Niko1221 2903837bbe docs: Unsloth UD-Q4_K_XL manual import (docs/UNSLOTH_Q4.md); DETAILS: the mapped mode without experts.bin, --resident-budget-gib, the tier counters
- docs/UNSLOTH_Q4.md: what UD-Q4_K_XL is (Hugging Face revision 38bb39e, the four shards with sizes and SHA-256),
  disk/RAM/GPU needs (111.3 GB download, 1.4 GB pack, no experts.bin), the iq_pack.py command and why
  --compat-bf16, the numerical policy (native experts/embedding/head/projections/PLE; the converted small tensors
  listed in conversions.json), the MTP draft layer, a server config (--native shard 1, --ple-gguf found by name,
  --resident-budget-gib N with N = RAM minus 20-24 GB), measured speed on an RTX 5070 / 64 GB PC (7-8.5 tok/s at
  40 GiB; ~60 s to the first answer), the switches (STRATA_LOOKAHEAD=0, STRATA_KQ256=1, STRATA_PARTIAL_PIN=1,
  STRATA_FETCH_THREADS), scope and validation, credits (eddoursul #245, gopinath87607 #255, jagsan-cyber #247).
  Experimental, not in setup.
- docs/DETAILS.md: the mapped low-RAM mode reads a native pack's experts from the GGUF when it has no experts.bin
  (checked, identical answers on the Coder); --resident-budget-gib and the routing-aware prefetch; where the tier
  counters are (--stats, the server log, /metrics' ram_blobs / file_blobs / file_mb); a pointer from "Which model?".
2026-10-01 03:11:36 +02:00
Niko1221 0699e466ad Merge branch 'f-q4-on242' into r131-final 2026-10-01 03:03:40 +02:00
Niko1221 a74acb6dd2 CS-T: the partial pin of the RAM tier opt-in (STRATA_PARTIAL_PIN=1)
On the RTX 5070 / 64 GB PC the GPU computing a share of the misses over PCIe measured no faster than the CPU:
7.30 and 7.44 tok/s with 24 and 16 GiB of a 40 GiB budget registered, against 7.05-7.74 unpinned, and
registering costs startup time and driver memory.  The default budget mode is now locked-only; the routing-aware
prefetch (multi-run A/B: 6.93 -> 7.91 tok/s mean, identical answers) stays on with the GGUF in place.
2026-10-01 03:03:17 +02:00
mad9home 140a8730a3 Bench: RTX 3090 / dual RTX 3090 on EPYC 7453
Add preliminary native v0.1.26 results, raw run JSON, scrubbed guest hardware facts, and the local API harness. Prompt and memory topology limitations are documented.
2026-10-01 02:52:39 +02:00
Omar Al-Jadda b73e770212 docs: add RTX 5090 community benchmark results 2026-10-01 02:52:39 +02:00
Omar Al-Jadda e51da24c52 docs: add community benchmark submission guide 2026-10-01 02:52:39 +02:00
maxfridbe e7c42b62b9 sycl: SIMD16 variants of the decode mmvq kernels (opt-in STRATA_MMVQ_SG), mmvq_sg_bench
SIMD16 wins in isolation on IQ4_XS and short outputs, but no setting beats
the 32-lane default in the engine beyond noise; kept opt-in.
2026-09-30 19:52:32 -05:00
Niko1221 0dac2b9aa1 CS-T: routing-aware prefetch of the file tier - the next layer's router on this layer's MoE input warms its predicted experts' pages
- RouterLookahead: when the CPU pool starts layer l, a worker thread applies layer l+1's router (a BF16 host copy
  of ffn_gate_inp, 126 MB for 48 layers) to layer l's MoE input - the router's own input - for each token of the
  window, takes the top STRATA_LOOKAHEAD_K (default 10), drops the experts the GPU cache (host_res) or the RAM
  copy holds, and asks the source to warm the rest.  It never waits: a prediction still running makes the next
  one skip.  STRATA_LOOKAHEAD=0 is the A/B arm.
- ExpertSource::warm / warms(): FileExpertSource with the GGUF in place issues one PrefetchVirtualMemory for the
  predicted slices (madvise(WILLNEED) elsewhere).  Pages only: blob(), the experts computed and their bytes do not
  change (the same answers in every A/B run).  Every other source: no-op, and the predictor is not started.
- bf16_rows_dot_multi (kq_avx2.cpp, AVX2): the router read once for all tokens of the window.
- Stats: experts warmed, how many of the decode's file-tier reads had been warmed, the predictor's time and skips.

UD-Q4_K_XL at a 40 GiB budget (single-token-router version): ~48-54% of the file tier's reads had been warmed;
reading time 850-968 -> 630-730 ms per verify round; decode 5.31/6.60 tok/s off vs 7.08/6.79/6.91 on.
2026-10-01 02:30:24 +02:00
Niko1221 a37491ede4 tests (#264 follow-up): iq_parity skips (exit 3) when no fixture was generated, as its generator does; a partly missing set still fails; the open handle of a half-present fixture is closed 2026-10-01 02:27:40 +02:00
Andy aa0777f7aa decode: hc read v3 is opt-in (STRATA_GR_V3=1: another summation order); its shared memory is sized from the card's opt-in limit - one or two column halves, else the default kernels (Turing/HIP 64 KB fit with two; capability-based split as proposed by @Adamyno); the neutral knobs (DOWN_R2, UP_PF, KSPLIT) dropped (review) 2026-10-01 02:14:16 +02:00
Andy 784cdc5d08 decode: hyper-connection read in 2 kernels - norm folded into a stream-split down kernel (164 blocks), rs/lo/inject in up's prologue (STRATA_GR_V3=0 = old) 2026-10-01 02:14:16 +02:00
Niko1221 7d8fc8fd04 CS-T: the partial pin locks only what it does not register and ends at an expert boundary; the Q4_K/Q5_1/Q8_0 multi-token kernels opt-in (STRATA_KQ256=1)
- Locking the whole 40 GiB arena in the working set and then registering its prefix made the next device
  allocation fail (the prompt path's token id buffer); the registered prefix is page-locked by the driver
  already, so only the rest is locked now.  24 GiB registered out of a 40 GiB budget then starts and runs.
- The registered prefix ends at an expert boundary: a blob that began inside it and ran past it was taken as
  page-locked by cudaMemcpyAsync and refused (an adaptive refill failed, with 16 GiB registered).
- The prompt path's token id buffer error names the CUDA error.
- kq_avx2 multi-token kernels: bit-exact, but no faster in the engine (the rows phases stayed at 72 ms per
  verify round at a 40 GiB budget; a window's expert groups hold ~1.4 tokens and ggml's per-token calls find the
  weights in L1), so they are opt-in with STRATA_KQ256=1; native_expert_parity still checks them bit for bit.
2026-10-01 01:58:30 +02:00
maxfridbe 7becf121d6 sycl: pinned host mirror for experts missing from VRAM, read by the device plan
Experts without a VRAM slot are read once into pinned host memory and the
device-built verify plan points the expert kernels at them over PCIe. The
plan used to drop non-resident experts, so output with misses diverged.
Forced 1,879-expert miss: decode 2.6 -> 40.9 tok/s, output identical.
2026-09-30 18:54:06 -05:00
Niko1221 a88904e530 Revert #257 (AVX2 two-block Q2_0 unpack): bit-exact but not faster on an AVX2-only CPU (Ryzen 9 3900X: gate/up -2.6..-4.7% at 1 token, down -3..-5% at 2 tokens)
This reverts commit f121667.
2026-10-01 01:33:15 +02:00
Niko1221 9305322ff5 Merge branch 'f-131-amd' into r131-amd
# Conflicts:
#	src/core/pinned.cu
2026-10-01 01:33:10 +02:00
Niko1221 18ad40c0dc --split-skip-if-fits (opt-in): an auto split runs on the main card alone when it holds every profiled expert + KV
Before any later stage loads, split-auto checks whether CUDA0 alone holds every profiled expert pair plus the whole
session (KV of every layer), the drafter + head, the verify windows and the reserve; if so it clears the split (one
GPU) and logs why, else it logs how much of the profile CUDA0 would hold and keeps the split. Default behaviour is
unchanged: the engine flag is opt-in, and the server passes it only for a config with "split_skip_if_fits": true
(and a GPU list). Not with remote expert caches.

Measured on amdbox (Coder IQ1_M, --expert-cache auto --prefill auto, 128 greedy tokens, gpu [1, 0] = R9700 first,
2 starts per arm, warm = the second request of each size):
  | arm                          | 4K warm   | 16K warm  | decode    |
  | split (flag off)             | 1,244     | 1,897     | 50.5-53.0 |
  | --split-skip-if-fits (on)    | 1,776     | 1,791     | 59.7-61.8 |
  | R9700 alone                  | 1,787     | 1,801     | 59.9-61.3 |
The flag's run is the R9700-alone run (same tokens, all four requests); with the 9070 XT first it keeps the split
("would hold only 9.84 of the profile's 23.42 GiB"). On this pair the split still reads 16K prompts ~5% faster.
2026-10-01 01:31:22 +02:00
Niko1221 9f8fa9088e #253: the 8 GiB arena pin cap only under WDDM; STRATA_ARENA_PIN_GIB; the split's prompt chunk steps down
- The expert arena was pinned at most 8 GiB whenever a layer split (or remote experts) ran, on every OS - a
  Windows/WDDM workaround that cost a Linux 4090 + 3060 split two thirds of its prompt speed (#253,
  bettercallcaleb). The cap now applies only under WDDM (_WIN32, or WSL2 detected by /dev/dxg), for multi_gpu and
  expert_cache_remote alike. STRATA_ARENA_PIN_GIB overrides it on any OS: "0" pins the whole arena, N > 0 at most
  N GiB (arena_pin_cap_gib(), -1 when unset: the same name and meaning as the S2 branch's helper, file-local here).
- The split's prompt chunk no longer stops the start when its buffers do not fit: a prompt path without a loan
  first gets the largest chunk whose buffers (Prefill::bytes_needed) leave 512 MiB free on its device, and an init
  that still fails steps down one size (8192 -> 6144 -> ... -> 2048 -> 1536 -> 1024 -> 512): Prefill::reset() frees
  what the failed init made, the loans are re-priced, and the failed allocation's sticky error is consumed (else the
  next launch check reported "out of memory").
- pinned.cu: the capped note no longer says "for CUDA1".
- docs: MULTI_GPU.md, SECOND_GPU.md.

Measured on amdbox (Linux, R9700 + RX 9070 XT, gpu [1, 0], Coder IQ1_M, 128 greedy tokens; tok/s):
  | cache                  | arm          | 4K cold | 4K warm | 16K cold | 16K warm | decode    |
  | auto (holds ~all)      | 8 GiB cap    | 678     | 1,355   | 1,709    | 1,880    | 44.5-51.5 |
  |                        | whole arena  | 703     | 1,234   | 1,729    | 1,864    | 44.6-51.4 |
  | fixed 1500 on CUDA0    | 8 GiB cap    | 608     | 1,101   | 1,287    |          | 34.5-36.1 |
  |                        | whole arena  | 716     | 1,160   | 1,803    |          | 34.8-36.0 |
(2 starts per arm for auto, 5 for fixed.)  With most experts streamed the whole arena reads a 16K prompt 40%
faster; with every expert already on the cards the two are within noise except 4K warm (-9%: the pinned share
raises the auto lend to 90% and the streamed ring to 384 slots).  Identity: the fixed-cache arms gave the same
tokens in all 5 + 5 starts (4K, 16K, 4K again), and the auto arms 2 + 2.  The step-down was exercised on the
9070 XT with --expert-cache 3000 --no-prefill-borrow --prefill 8192 ("need 4528 MiB, 2910 MiB free: 2048-token
chunks"; with the init retry alone it went 8192 -> ... -> 2048, and 1536 ran all four requests).  Known, also on
main: that own-buffer configuration at 2048 makes hipBLAS pick hipBLASLt kernels whose code objects this ROCm 7.14
lacks (TensileLibrary_..._gfx1201-xnack+.co not found, "launchKernel failed") and the prompt hangs.  The WDDM side (Windows, WSL2) is unchanged and not re-measured here.
2026-10-01 01:31:22 +02:00
Niko1221 d484ec735f CS-T: the GGUF-in-place prefetch asks Windows for all of a layer's missed slices at once (PrefetchVirtualMemory)
The copies' page faults read a few clusters each; one PrefetchVirtualMemory call for every role slice about to
be copied lets the memory manager queue large reads at once, and the parallel copies then find the pages
resident or in flight.  Only the GGUF-in-place source's prefetch uses it; STRATA_FETCH_PVM=0 is the A/B arm.
2026-10-01 01:12:36 +02:00
Niko1221 f8525fa0b0 CS-T: the partial pin at most 24 GiB (STRATA_PARTIAL_PIN_GIB), the Q4_K/Q5_1/Q8_0 multi-token kernels from two tokens on
- Registering 30 GiB of a 40 GiB RAM tier left the driver unable to page-lock the prompt path's token id buffer
  afterwards (RTX 5070, WDDM: "prefill: the token id buffer"); the prefix is now capped at 24 GiB, the size a
  whole 24 GiB budget page-locks with, and STRATA_PARTIAL_PIN_GIB sets it.
- A verify window's expert groups hold ~1.4 tokens on average; one token goes to ggml's own dot (the same bits,
  without the multi-token kernel's per-token arrays).
2026-10-01 01:11:50 +02:00
Niko1221 4167bd17ac Merge branch 'f-q4-on242' into r131-q4
# Conflicts:
#	serve/server.py
#	src/core/expert_source.cpp
2026-10-01 01:01:04 +02:00
Niko1221 13b76cc5f8 Merge branch 'f-131-srv' into r131-q4 2026-10-01 01:00:27 +02:00
Niko1221 003ec62140 CS-T speed: the file tier fetched in parallel, PCIe planning without file reads, a partial pin of the RAM tier, bit-exact AVX2 multi-token kernels for Q4_K / Q5_1 / Q8_0 experts, decode-only tier stats
Where the 288 ms/token at a 40 GiB budget went (UD-Q4_K_XL, --stats): of the 945 ms CPU pool call per verify
round (3.46 tokens), 871 ms were the dispatch thread assembling missed experts from the mapped GGUF one after
another (~391 blobs, 1.3 GB per round, ~1.5 GB/s: page faults from the SSD); the kernels were 42 ms gate/up and
30 ms down.  At 24 GiB, 771 ms/round more went into the PCIe planning, which asked blob() - a file read with the
GGUF in place - of every miss just to learn it was not pinned.

- ExpertSource::prefetch: the dispatch hands the source the layer's missed experts before its jobs loop;
  FileExpertSource with the GGUF in place assembles them on STRATA_FETCH_THREADS threads (default 8) so the
  SSD sees a queue instead of one fault at a time.  A no-op for every other source.  Staging buffers being
  filled are never reused, and a blob asked while its fill runs waits for it.
- The PCIe planning asks pinned() before blob(): the same decisions and bytes for every source.
- --resident-budget-gib: when the driver refuses to page-lock the whole budget, the locked arena's hottest
  prefix (profile order) is registered with cudaHostRegister, as much as it takes (from the whole down in 2 GiB
  steps), so the GPU can read those misses over PCIe and the prompt path can DMA them; pinned() answers for
  that prefix only.  STRATA_PARTIAL_PIN=0 is the A/B arm.
- src/kernels/cpu/kq_avx2.cpp: ggml-cpu's AVX2 vec_dot for Q4_K x Q8_K, Q5_1 x Q8_1 and Q8_0 x Q8_0 with the
  token loop inside the block loop - the weight side decoded once per verify window, each token's integer chain
  and float operations exactly ggml's, so the results are ggml's to the bit for any group size (no #152 rule).
  native_gu_rows / native_down_rows use them for those types (only UD-Q4_K_XL has them); STRATA_NO_KQ256 is the
  A/B arm.  native_expert_parity checks them bit for bit against vec_dot for 1..8 tokens and times 4 tokens.
- Stats: the decode's file tier alone (blobs, MB, MB/round, reading ms/round and GB/s per thread) and the
  prompt path's copies separately.
2026-10-01 00:51:30 +02:00
Niko1221 f73b0e062a pinned (#243 follow-up): the shared-memory-budget cap on the sliced pin is opt-in (STRATA_ARENA_PIN_GIB=auto) - by default the arena pins as in 0.1.30; on this 64 GB PC the cap pinned 26 instead of 30 GiB and cost ~20% prompt speed and 2-4% IQ3_S decode 2026-10-01 00:49:49 +02:00
maxfridbe 21ccac1b01 setup/docs: KV streaming for the SYCL engine from 64K - 256K context decodes at 31 tok/s (from 4-5)
--kv-resident 32768 keeps the whole KV in pinned host memory and only the attended window in VRAM, so every
expert stays in VRAM at long contexts. B70, decode after the prompt: 128K int8 8.5 -> 38.7 tok/s, 128K q4_0
32.7 -> 35.3, 256K int8 3.7 -> 31.3, 256K q4_0 5.0 -> 31.5; the prompt pays 5-13%. setup.py now turns it on
from 64K for the SYCL engine (its RAM check counts only the KV copy and the engine, the experts being in VRAM)
and keeps INT8 KV, which is the faster of the two with streaming.
2026-09-30 17:41:04 -05:00
Niko1221 ebe52edd8b setup: AMD layer splits with --gpus (every chosen card a supported AMD arch; the engine compiled for each)
setup refused AMD GPU lists at install and at start ("NVIDIA only for now"), although the engine's layer split runs
on two AMD cards (0.1.30, from a hand-written config).
- amd_parse_gpus(): --gpus "1,0" (setup's HIP numbering, the first card the main one) or "all" (every supported
  card, the most VRAM first); every card must be in AMD_ARCHS, else a plain message with what can be used.
- install: --backend hip --gpus writes "gpu": [..] + "layer_split" like the NVIDIA path; build_engine_hip compiles
  for the set of the chosen cards' archs (CMAKE_HIP_ARCHITECTURES "gfx1100;gfx1201" already worked) and records
  it in BUILD.json; an engine whose archs cover the cards is not rebuilt; update_installed_engine keeps every arch.
- rocm_root(archs): cards of two families need a system ROCm (TheRock's wheels hold one family) - said plainly.
- start: --gpus on an AMD install is saved like on NVIDIA (refused when the engine has no code for a card);
  --gpus all finds the AMD cards on a PC without NVIDIA cards that can share.
- docs/AMD_HIP.md, README; tools/test_setup_amd.py: lists, "all", refusals, the one-family wheel rule, the arch set
  in the build and BUILD.json.
2026-10-01 00:35:39 +02:00
489623c7d3 AMD: gfx1101 (RX 7800 XT, #254 by jhohertz) and gfx1200 (RX 9060 XT, #256 by Efeisot) as community-validated cards
Cut down from #254 and #256 onto 0.1.30's AMD tables:
- setup.py: AMD_ARCHS / AMD_NAMES / ROCM_INDEXES / AMD_CARDS list gfx1101 (TheRock gfx110X-dgpu) and gfx1200
  (gfx120X-all); amd_gpus() takes the sysfs root so the detection can be tested.
- cmake/hip_backend.cmake: gfx1101 and gfx1200 build without the "not validated" warning (a status line names
  them community-validated); gfx1102 (#192: ctest only) keeps the warning.
- docs/AMD_HIP.md (Community-validated cards: the owners' setups, ctest and numbers) and README.
- tools/test_setup_amd.py: detection on a mocked KFD topology (every family, the CPU node, an iGPU and gfx1102
  listed as not supported, product-name fallbacks, the ROCm index per family).
Left out: the PRs' own cmake/device.cu arch checks (0.1.30's compiled_for covers them), the dp4a change (main has
it), math_constants.h, the bench JSONs, the launcher, and both hipBLASLt tables (neither PR measured the prompt speed
without its table).

Co-Authored-By: Joseph Hohertz <[email protected]>
Co-Authored-By: efeisot <[email protected]>
2026-10-01 00:35:39 +02:00
Niko1221andttio2tech 600d73070c HIP: __byte_perm as v_perm_b32 and SWAR __vsub4/__vsubss4/__vcmpne4 (from #262 by ttio2tech)
Cut down from #262 (ttio2tech): only the intrinsics and their test.
- HIP's __byte_perm indexes a byte array in private memory (scratch traffic in the IQ4_XS/Q2_0 table
  lookups); byte_perm() is the same selection (nibble & 7 of the pair {y:x}) in one v_perm_b32.
- __vsub4, __vsubss4 and __vcmpne4 work on all four byte lanes at once (Hacker's Delight 2-18) instead
  of a per-lane loop.
- tests/hip/intrinsics checks them on 1,024 random operands against host references (passes on gfx1201).
Left out: the arch/setup/device.cu parts (0.1.30 already builds and checks gfx1201; main's dp4a covers
gfx1100-1102/1200/1201) and the gfx1201 hipBLASLt table (none is shipped for gfx1201).

A/B vs main on amdbox (Coder IQ1_M, 128 greedy tokens): identity with a fixed cache (--expert-cache 1500
--prefill 2048), 5 + 5 starts per card, 4K / 16K / 4K again: the modal outputs are identical on the R9700
and on the RX 9070 XT (one start of 20 differed from its arm's mode, the known HIP start drift). Speed with
setup's settings (auto cache/chunk), 2 + 2 starts per card, tok/s:
  | card         | arm  | 4K cold | 4K warm | 16K cold | 16K warm | decode    |
  | R9700        | main | 1,027   | 1,792   | 1,695    | 1,812    | 46.0-52.2 |
  |              | #262 | 1,023   | 1,786   | 1,681    | 1,808    | 53.0-61.0 |
  | RX 9070 XT   | main | 781     | 1,018   | 1,421    | 1,517    | 32.7-41.4 |
  |              | #262 | 780     | 1,017   | 1,424    | 1,517    | 34.9-44.0 |
Decode +15% on the R9700, +5-7% on the 9070 XT; prompts unchanged.

Co-Authored-By: ttio2tech <[email protected]>
2026-10-01 00:35:39 +02:00
Niko1221 5865998af9 verify (#267 follow-up): the window's final wait stays a blocking sync - the cudaStreamQuery poll cost IQ3_S ~3% decode; the stall watchdog's release of every verifier's GPU waits is what keeps a spin kernel from outliving the engine 2026-10-01 00:26:23 +02:00
maxfridbe 29e379e0d2 setup: Strata's SYCL engine on Intel cards when it is built; sycl: clean exit in serve mode
setup.py gets a third backend, sycl: on an Intel Arc with build-sycl-aot/strata and the strata-sycl-dev image
present (or --intel-engine strata; --intel-engine llama keeps llama.cpp), it builds the native pack and the
MTP draft layer (reusing an mtp-q2_0.gguf that is already there), writes the engine's arguments with the
container's paths through sycl/serve/strata-sycl.sh, --stream-experts with a reserve that keeps every expert in
VRAM (1,024 MiB up to 32K, 2,048 MiB and 4,096-token chunks above), Q4_0 KV above 64K, and keeps the sampling
block of an earlier config. start() checks the model files through the config's sycl_root; upgrade_config
leaves the SYCL config alone (the wrapper has no version, which read as 0.1.12 and downgraded --prefill).
Tested on the B70: the Coder's config regenerated by setup serves at 38.9 / 30.3 tok/s (first turn / follow-up)
with all 12,288 experts in VRAM.

The serve loop used to abort at exit (139): the Verifier's destructor waited on its queue after the Level
Zero context had begun tearing down. The destructor is now exception-safe and serve mode exits directly once
its requests are done: exit 0.
2026-09-30 17:11:08 -05:00
maxfridbe 1807ab8f2c sycl: serve the port - strata-sycl.sh runs the engine in the oneAPI image as server.py's exe (36 tok/s sampled)
The Coder on the B70 now runs Strata's own engine behind serve/server.py --engine strata: the wrapper starts
build-sycl-aot/strata inside strata-sycl-dev with the serve pipes attached and the port's run-time switches set.
Through the OpenAI API with temperature 0.6 / top-p 0.95 / top-k 20 / repetition penalty 1.05: 36 tok/s decode
on a first turn, 33 on a follow-up (conversation cache reused), vs 24-26 for llama.cpp on the same card. The
expert reserve has to leave every expert in VRAM (--stream-experts has no host copy): 1,024 MiB at 32K context.
2026-09-30 16:15:45 -05:00
maxfridbe 6b5761d34a sycl: STRATA_DUMP_SEL (the prompt path's selected cells); INTEL.md - XMX v2 in the full matrix, selection overlap
The selection dump measured how much neighbouring prompt positions' QSA selections overlap at 80K tokens: the
union of 8 is 3.3x one selection (16: 5.1x), 12% shared by all 8, so a grouped-gather attention kernel would buy
at most 5-8 s of an 80K prompt. XMX v2 across the 128K/256K matrix: 23-33% slower prompts than the FP32 attention.
2026-09-30 16:02:40 -05:00
Niko1221 1e663cc70e CS-T: native packs read their experts from the GGUF shards in place (--mmap-experts without experts.bin), --resident-budget-gib N, per-tier counters
- FileExpertSource: a native pack without experts.bin, given the --native shard, maps every GGUF file
  native_experts.txt names (after check_experts_gguf) and assembles a blob [gate | up | down] from the
  three role slices when asked: into a small pool of buffers for blob() (a buffer is reused once its blob
  has not been asked for during 3 layers (begin_layer) or 256 assemblies), or straight into the caller's
  memory for copy_blob().  No 30-77 GB experts.bin on the disk.  With experts.bin present nothing changes.
- ExpertSource::transient / copy_blob: the prompt path's stager copies a transient blob itself (its queue
  holds a whole chunk's experts), everything else keeps using blob().
- --resident-budget-gib N (the resident mode with a budget): the experts the GPU cache does not hold are
  copied into RAM in expert-profile order while they fit N GiB (clamped to available RAM minus the
  headroom), the rest are read from the files; no lend region then.  Without the flag the resident mode
  and --mmap-experts are unchanged.
- Counters: blobs served from the RAM copy, from the files, and bytes read from the files; in the stats
  table ("expert tiers"), the serve log, and appended to DONE (RAM blobs, file blobs, file MB for the
  request), which serve/server.py puts into /metrics' request history (older DONE lines still parse).
- expert_layout_test: the GGUF-in-place source gives the loaded arena's bytes through blob() and
  copy_blob(), an assembled blob stays put while in use, and experts.bin still wins when present.
2026-09-30 22:51:03 +02:00
Niko1221 ee7c802664 iq_kernels: Q4_K / Q5_K / Q5_1 / Q8_0 native experts (Unsloth UD-Q4_K_XL), per-role format lists, native_expert_supported at startup, Q8_0 embedding and PLE key
- Dots: llama.cpp's vec_dot_q4_K / q5_K / q8_0_q8_1 transcribed (VDR 2), via eddoursul/Strata
  8029fa9 and #255 (gopinath87607, Q8_0), which agree.  Q5_1's min term multiplies the sum of the
  QUANTIZED activations (ggml-cpu's convention, as the fork does), not llama.cpp CUDA's ds.y.
- Dequantizers dq_q4_k / dq_q5_k / dq_q5_1 / dq_q8_0 (llama.cpp's formulas) for the prompt path's FP16
  fallback, f32 dumps and the Q8_0 embedding; iq_row_bytes / is_iq know the four types;
  iq_dequant_gu_f16 now refuses an unknown type instead of leaving its output unwritten.
- The grouped gate/up, down and iq_mmvq switches are generated from STRATA_GU_FMTS /
  STRATA_D_FMTS / STRATA_MMVQ_FMTS; the existing entries launch the same kernels as before.
- native_expert_supported(gu, d, n_embd, n_ff): generate checks every layer of a native pack right
  after expert_layout_load and refuses an unsupported pair by name before anything is allocated
  (it used to exit from inside the first verify window).
- Native PLE key: Q8_0 accepted (NativeDense, generate, ple.cu); native_mmvq already runs it.
- native_expert_parity: --synthetic GU/DOWN (random ggml-quantized blobs at 2560/640; port of the
  fork's mode), GPU dequant f32/f16 and embedding rows vs ggml to_float bit for bit, split models via
  GgufModel, --q5_1-min.  CTests: q4_K/q5_1, q4_K/q8_0, q5_K/q8_0, q8_0/q8_0, the Q5_1 min term, and
  q6_K refused.  RTX 5070: GPU and CPU within 1.25-1.37e-2 of the float reference for all three real
  pairs; every dequantized value identical; Q5_1 GPU vs ggml-cpu 7.5e-5 (vs 1.95e-2 for the ds.y
  variant); IQ3_XXS/IQ4_NL and IQ2_XS/Q2_0 unchanged.
- Not yet: #242's decode-once traits for the new types (they take the per-entry kernel; see
  phaseA-tests/s5_cs3_design.md), prompt MMQ for Q4_K/Q5_K/Q5_1, identity gates.
2026-09-30 22:31:09 +02:00
Niko1221 dc24332249 tests: --real modes for gguf_split_test and expert_layout_test (a real model's shards / a real pack's spans, headers only)
`gguf_split_test --real SHARD` opens a real model's shards (GgufModel), checks the architecture on the
metadata shard and prints where output / token_embd / the PLE table and key / layer 11's experts are.
`expert_layout_test --real PACK NATIVE_SHARD` checks a real pack's native_experts.txt against its model
(check_experts_gguf; no expert byte is read).  Both pass on the Q2_0, IQ3_XXS (v2), IQ3_S, Coder IQ1_M
and Swift IQ2_XS packs and models on the reference PC.
2026-09-30 22:30:11 +02:00
Niko1221 24bba1743b iq_pack: each tensor in the form the engine reads (FORM), exact F32->BF16 by default, PLE conv F32 -> F16 by the loader, conversions.json; the engine refuses a wide conv1d
- FORM (eddoursul/Strata's list of which tensor the engine reads as BF16, F16 or F32) decides the
  pack form; the conversion itself is upstream's bf16_bytes (gguf-py, finite check, round-to-nearest-
  even).  By default only lossless conversions happen: F32 whose values are exactly BF16 (low 16 bits
  zero; before, only the routers) and F16/BF16 widened to F32.  Rounding (inexact F32, Q8_0 hyper-
  connection / PLE value / output_hc, F16 -> BF16) still needs --compat-bf16.  NaN/Inf are refused
  even where the low bits are zero.
- A Q8_0 PLE key stays native (served from the GGUF, like Q2_0); other quantized keys take the BF16
  path as before.  (The engine's native PLE key learns Q8_0 in the formats change.)
- blk.1.ple_conv1d stored F32 (Q8_0 / UD-Q4_K_XL files) goes into dense.bin as index kind 3 and the
  loader narrows it to F16 (#255, gopinath87607), with or without --compat-bf16; a value beyond
  F16's range is refused.  generate refuses a pack whose conv1d is not F16 (#255's check, which also
  accepts the canonical Q2_0 pack's verbatim-F16 kind 0 - #255 as written refuses that pack).
- conversions.json (schema 1): the source shards' names and sizes, and per converted tensor its
  shard, source/destination type, method, exact flag, largest absolute error and source sha256.
  compat-bf16.json is written as before.  Refusals happen before anything is published.
- Byte identity: index.txt, native_experts.txt and dense.bin of Q2_0, IQ3_XXS, IQ3_S, Coder IQ1_M and
  Swift IQ2_XS are identical to main's packer (Swift's 96 exact F32 routers are now listed in
  conversions.json).
- Tests: exact F32->BF16 by default, inexact only with --compat-bf16 (error bound), NaN/+-Inf
  refused with and without the flag (previous pack untouched), conv1d kind 3 (bytes, record, F16
  kept, overflow refused), Q8_0 projections need the flag and are recorded, Q8_0 key native.
2026-09-30 22:30:11 +02:00
Niko1221 21844a3ebf iq_pack: per-role shards and data_start (v4 only for a split layer), split keys checked, experts.bin reused only with its source sidecar, atomic publication
- Each expert role is resolved in the shard that holds it and its offset is absolute in THAT shard
  (the first role's data_start was used for all three; #255, gopinath87607).  A layer whose roles
  are in different shards gets the per-role column `gate,up,down` and the file becomes v4; every
  other pack keeps the v3 header and bytes (checked on Q2_0, IQ3_XXS, IQ3_S, Coder IQ1_M, Swift
  IQ2_XS: index.txt, native_experts.txt and dense.bin identical to main's packer).
- The split keys are checked as the engine does (shard 1 has the metadata; split.count / split.no /
  split.tensors.count consistent).  The expert table is computed and checked before any file of
  the pack changes.
- experts.bin is written under a temporary name and gets experts.bin.src.json (the shards' names
  and sizes, the sha256 of native_experts.txt); it is reused only when that matches, never by size.
  An experts.bin of another source is refused without --experts-bin (the engine would read it).
- dense.bin and index.txt are published together after the old completion marker
  (native_experts.txt) is removed, so a stop part-way never mixes files of two runs.
- .absolute() stays (not .resolve()): symlinked HF snapshot names keep the split naming.
- Tests: a synthetic 4-shard GGUF (shard 1 metadata only, layer 1 split per role; offsets per
  shard, experts.bin byte for byte), v3 kept when nothing is split, missing shard, duplicate tensor,
  a shard of another split, truncated shard, wrong type (pack untouched), interrupted pack (experts
  and index), stale same-size experts.bin.  Idea of per-role names also in #247 (jagsan-cyber).
2026-09-30 22:30:11 +02:00
Niko1221 65a1111e3a Split GGUF artifacts: every shard found (a missing one is an error), tensors from their owning shard, per-role expert files (native_experts.txt v4)
Groundwork for Unsloth's UD-Q4_K_XL (4 shards: shard 1 metadata only, output/token_embd/PLE table in
shard 2, layer 11's down in shard 2 and its gate/up in shard 3).  Existing packs load unchanged.

- include/strata/artifact/gguf_split.hpp: gguf_split_paths (from eddoursul/Strata 8029fa9) finds the
  shards from any shard's name; a missing shard is an error naming it.  It replaces generate.cpp's
  model_shards(), which skipped a shard it could not open.
- gguf_reader.hpp: GgufModel (8029fa9) looks a tensor up across the shards and refuses a name in two
  shards; the split keys are validated as #255 (gopinath87607) does for the head: shard 1 carries the
  architecture, later shards declare split.count / split.no / split.tensors.count consistently, and the
  directories add up to split.tensors.count.  tensor_payload_bytes / in_bounds for payload checks.
- NativeHead::load / NativeEmbed::load take the shard list: the architecture from the metadata shard,
  the tensor from the shard that holds it; the embedding also checks its payload is in the file.
- generate: --native resolves all shards once (native_shards), the head from --native-head-gguf's
  family, the model keys from the metadata shard; --ple-gguf defaults to the shard that holds
  per_layer_token_embd.weight.
- native_experts.txt: the shard column may be per role, `gate,up,down` (#255's comma form; empty =
  the --native shard).  The reader accepts v2-v4 and refuses a higher version; an engine older than
  this one fails to open a "gate,up,down" file loudly.  Fixes the parse's own aliasing hazard
  (parts.assign(3, parts[0])).
- load_experts_gguf reads each role from its file, after check_experts_gguf proved every (file,
  offset) is that tensor, of the pack's type and dimensions, and inside its file.
- Tests (synthetic, no model, no GPU): gguf_split_test (4 shards, missing shard, duplicate, split keys,
  count, truncation); expert_layout_test (copies of the Q2_0/IQ2_XS/IQ3_XXS/IQ3_S/Coder/Swift packs'
  native_experts.txt parse field for field as before; v4 column; v5 / 4 / 2 names refused; the arena
  from split synthetic shards at 2560/640 with Q4_K/Q5_1 and Q5_K/Q8_0, every byte compared, and
  wrong offset / file / type / shape / truncated / missing shard refused).
2026-09-30 22:30:10 +02:00
Niko1221 7dc1fae80b mcp: a server that stops quotes its last log line reliably (the stdout reader waited no time for the stderr reader, so the reason was sometimes missing - the flaky test_a_server_that_fails_is_left_out) 2026-09-30 22:13:46 +02:00
Niko1221 c67c90fa03 Merge branch 'f-131-fix' into r131-fix 2026-09-30 22:03:31 +02:00
maxfridbe 3467cc9d4e sycl: XMX prompt attention v2 (1.5x v1, k8v4 parity complete), long-context x KV-type table
v2: 64-cell chunks, V packed two cells at a time as 32-byte stores, K^T as 4-byte pairs with INT8 converted on
the load, hi+lo Q in one accumulator per scale group, one accumulator update per chunk. qsa_prompt_attn_parity
passes in every mode and kv_hybrid_parity passes completely with it (its last step needs a tensor-core-class
prompt kernel). 13.4 ms per chunk vs v1's 18.7 and the FP32 fallback's 5.5: the attention is gather-bound, so
it stays opt-in (STRATA_PROMPT_ATTN_XMX=1, or =32 for 32-cell chunks).

INTEL.md: 128K and 256K prompts with int8, q4_0 and k8v4 KV on the B70. All complete; q4_0 keeps every expert
in VRAM at 128K (decode 32.7 tok/s after the prompt); at 256K all three evict experts and decode drops to 4-5.
2026-09-30 15:02:17 -05:00
maxfridbe 04e00c08c6 sycl: lend cache slots to the prompt path above a 32K context - 80,000 tokens at 1,062 tok/s, decode 35-40 after
Without borrowing, the VRAM reserve for the KV state and the chunk buffers evicts ~1,900 experts, the prompt
streams them (790 tok/s at 80,000 tokens) and decode after it runs at 2 tok/s. Borrowing lends ~940 slots and
refills them in ~1 s: 1,062 tok/s and 35-40 tok/s decode. It costs ~1 s per prompt at short contexts (2,184
tokens 610 vs 792 tok/s), so the default is by context: borrow above 32K. --prefill-borrow / --no-prefill-borrow
decide explicitly; layer splits keep their own buffers as before.
2026-09-30 14:25:02 -05:00
Niko1221 cd677f7414 Experimental Pascal/Volta build: admit sm_70, and the device check honours it (#236)
-DSTRATA_EXPERIMENTAL_SM60=ON now names Volta (sm_70) beside Pascal (sm_60)
and is a declared option; below sm_60 is refused even then.  The runtime check
in device_info refused anything below compute capability 7.5 even in that
build, so the flag produced an engine that could not start on the cards it was
built for: strata_core now gets STRATA_EXPERIMENTAL_SM60=1 with the flag and
the check admits 6.0 and up there.  The release engine is unchanged (7.5).

Checked here: configuring for 70-real without the flag still fails with the
7.5 message; with it (CUDA 12.6 - CUDA 13 no longer compiles compute_70, noted
in the comment) it configures and strata-device builds with the define.
2026-09-30 21:07:28 +02:00
maxfridbe 14e0c017bb sycl: refresh for upstream 0.1.28-0.1.29, fix the streamed-expert prompt path (stale ring pointers, stream-all hang)
- Re-migration merge of upstream 99b4097..0ea2fc3 (GDN recurrence pipelining, block scores read once per window,
  the GPU-wide sampler, the draft head's VRAM reserve, correctness fixes); verify.cpp/mtp.cpp ported by hand; two
  new fixups (a cudaStream_t cast in the sampler, a const sycl::free in native_head). Parity unchanged (19 of 21).
  B70: 2,184-token prompt 765 -> 792 tok/s, decode at that context 43.1 -> 45.2 tok/s, outputs identical.
- The prompt path's stream plan kept GgufExpertSource::blob() pointers for ~1,900 experts per chunk against a
  512-slot ring, so blobs were overwritten before they were copied (the first 80k measurement was partly wrong
  experts). The stager threads now read (layer, expert) themselves via GgufExpertSource::read_into.
- The stream-all walk hangs in its first large chunk on this card (copy engine stuck on a barrier, any ring size,
  either issuer; the old read path too). The port defaults to the per-layer routed-only walk (upstream e258e6e's
  STRATA_PREFILL_RING=8, included); STRATA_PREFILL_STREAM_ALL=1 restores it for debugging.
- The PLE reader copy keeps its 64-deep queue. 80,000 tokens now complete: 101 s = 790 tok/s.
2026-09-30 14:07:02 -05:00
Niko1221 e1f12eb852 Refuse a CPU without AVX2 at start, by name
Every CPU expert kernel is AVX2 at least (q2_avx2.cpp, iq_avx2.cpp; the
AVX-512 ones are chosen above them) and so is ggml-cpu in the release build,
but nothing checked for AVX2: a pre-Haswell CPU died of an illegal instruction.
cpu_avx2_ok() (AVX, AVX2, FMA, F16C and the OS's XSAVE state) is checked
before the pack's layout load, and the message names the CPU (cpu_name, the
CPUID brand string).  STRATA_FORCE_AVX2 is unaffected (it only answers
cpu_avx512_ok).
2026-09-30 21:04:53 +02:00
Niko1221 b9f426713a Stall report: name the prompt chunk and layer; mark a finished verify window (#251)
The #251 report stalled in "reading the prompt, from token 0" and printed the
previous request's verify window as if it were the stuck one.

- Verifier::diag says "(last window, not the current stage)" when the stage
  is not a verify window.
- The batched prompt read sets its stage per chunk (preparing, finishing) and
  per layer, with the chunk's first position (Progress::chunk, a third
  progress_at argument; every other call leaves it -1), so the stall report and
  the watchdog line read e.g. "reading the prompt (batched): layer 17 of the
  prompt chunk from token 8192".

Text only: nothing computed changes.
2026-09-30 21:03:36 +02:00
Niko1221 50b4fadb08 Verify window: bounded final wait; release the GPU's flag waits before the engine ends (#267)
A verify window the GPU never finished held the host in an unbounded
cudaStreamSynchronize, and the serve watchdog then aborted the process with
the window's spin kernel (wait_flag_ge / wait_flag_ge_or on a host-mapped
flag) still resident - on Windows the GPU was left "lost" until a power cycle.

- The final wait of Verifier::run polls cudaStreamQuery (the same wait while
  the window runs) and gives up after 20 s like the per-layer wait, through
  the existing error path.
- Verifier::release_gpu_waits writes UINT32_MAX into the mapped flags M/A/B
  (past every ring, so each spin kernel returns; wait_flag_ge_or returns on its
  flag too), then waits for the streams up to 5 s; the verifier refuses later
  windows.  Both timeouts run it before returning their error, and the serve
  watchdog and the expert pool's stall aborts run it (progress.hpp
  release_gpu_fn, every live verifier) before std::abort.
- Test hook: STRATA_TEST_VERIFY_STALL=N withholds the last layer's flag in the
  N-th window; unset it is never taken.

The normal path runs the same kernels in the same order.
2026-09-30 21:02:27 +02:00
Niko1221 00ec1d081d Windows: cap the sliced arena pin at the GPU's shared-memory budget (#243)
When cudaHostRegister refuses the whole expert arena, the sliced fallback
pinned layer after layer until the driver refused one (28 GiB on a 63 GB
single-GPU PC), and WDDM then refused every later device allocation
("native head upload: out of memory").  On Windows the sliced pass now stops
at the adapter's DXGI non-local budget - the process's current usage - 4 GiB
(IDXGIAdapter3::QueryVideoMemoryInfo for the CUDA device's LUID; dxgi.dll is
loaded at run time), or RAM/2 - 8 GiB when that query fails.  The arena line
names the cap and where it came from.

STRATA_ARENA_PIN_GIB: unset = the above; 0 = no cap (the old behaviour);
N > 0 = at most N GiB from the start.  arena_pin_cap_gib() (pinned.hpp)
reads it, -1 when unset, for the multi-GPU cap in generate.cpp as well.
A machine whose whole-arena registration succeeds is unchanged, and a
caller's cap (multi-GPU) still takes precedence.

This PC's whole registration fails too: IQ3_XXS now pins 24 GiB (32 slices;
budget 30.8 GiB - 2.0 in use - 4) instead of 28 GiB (36).
2026-09-30 21:02:17 +02:00
Niko1221 4b8db25763 load_experts_gguf reads with fread on a FILE* (#230)
The GGUF branch of the arena load (a native pack without experts.bin, the
normal install) read through std::ifstream, which MSVC splits into 4095-byte
freads - 0.02 GiB/s on the reporter's PC.  It now uses the same fopen/fread
with a 64-bit seek as load_experts_ranges (#89), with an RAII close.  Same
chunks, same bytes, same scatter.

Measured here (IQ3_XXS pack without experts.bin, RTX 5070, 64 GB): 1.49-1.60
GiB/s before, 3.17-3.25 GiB/s after (start 45-48 s -> 29-34 s); the generated
tokens are the same.
2026-09-30 21:02:08 +02:00
Niko1221 912a931f0f README: where things are stored (#226)
Chats (and the Chat tab's settings and API key) only in the browser's local storage (strata.* keys), the start
config strata-<model>.json and its siblings in the Strata folder, the model files in Strata-data next to it (or
--data-dir), and where that folder is remembered (%APPDATA%\Strata\settings.json, ~/.config/strata/settings.json).
2026-09-30 20:58:59 +02:00
Niko1221 8eff54c845 serve: an opt-in hard thinking budget, reasoning_budget_tokens (#123)
A request (OpenAI or Anthropic) may set "reasoning_budget_tokens": N, and "reasoning_budget_tokens" in
strata-<model>.json sets a default (a request's own value wins; 0 means no budget).  When the thinking reaches N
tokens - at a clean point, no tag held back and no character split across tokens - Service.run stops the engine,
feeds a short wrap-up line and </think> through the detokenizer and parser (the client sees it as the end of the
thinking; it counts as output), and generates again from prompt + what was generated + the wrap-up: a prefix of
what the engine's session already holds, so it continues from it.  With no room left to answer it ends with
"length" as before.  A bad value is a 400 before anything is sent (a bad config value refuses to start).  Off
by default: without the field and the key every request runs exactly as before (one engine pass).  Anthropic's
thinking.budget_tokens still only picks the level.  Documented in docs/DETAILS.md.

Tests (serve/test_server.py ThinkingBudget, a fake engine that continues after </think>): off by default, the
wrap-up and the continued prompt (the first prompt + the kept thinking + the wrap-up), the Anthropic stream, a
budget the thinking stays under, the config default and a request turning it off, thinking off, no room left,
bad values.
2026-09-30 20:58:59 +02:00
Niko1221 afc33c260e setup: reproducible installs - the checkout's own engine release, pinned Hugging Face revisions, pinned Python packages (#214)
- The ready-made engine: with the default --prebuilt, setup looks at releases/download/v<version>/ first (the
  version CMakeLists.txt says, source_version()) and falls back to releases/latest with a message when that
  release is not published (yet).  An explicit --prebuilt / STRATA_PREBUILT_URL is used as before; an
  installed engine new enough is kept without asking the network.
- Hugging Face: every model family's shards and vision encoder come from a fixed commit (HF_REVISIONS, the repos'
  `sha` on 2026-09-30), tools/mtp_fetch.py reads the BF16 checkpoint at its commit (STRATA_MTP_REVISION
  overrides).  A revision a repository no longer has falls back to its current files, with a message.  Files
  already downloaded keep their names and .done marks, so nothing is downloaded again.
- Python: requirements.txt pins the packages and their dependencies (numpy per Python range, 3.10+), used by
  setup's pip step and the Dockerfile.  A venv set up before this (bare names in .strata-pip.json) is left as it
  is; only packages it never had are installed, pinned.

Tests: tools/test_setup_pins.py (mocked network: the tag URL first, latest as the fallback, an installed engine
kept, a gone revision falling back to main in download() and mtp_fetch, the pip step for fresh, old and bumped
installs).
2026-09-30 20:58:44 +02:00
Niko1221 64f30121f4 qsa_prompt_attn (#270 follow-up): the m16n8k8 pair only for sm_75+ CUDA device code (AMD and pre-Turing builds keep the trap, which the host never reaches); Turing chosen per call from the current device instead of a process-wide flag (a split can mix Turing with newer cards) 2026-09-30 20:42:52 +02:00
kenh0u 48ecc6ac3d qsa_prompt_attn: the f16 tensor-core path runs on Turing (sm_75) as two m16n8k8 steps
m16n8k16 needs sm_80, but sm_75 has m16n8k8 with the same A/B/C register mapping, so
each k=16 step becomes two k=8 steps on the fragments as they are already laid out
(a[0]/a[1] with b[0], a[2]/a[3] with b[1]).  The sum now rounds twice, so the two paths
do not agree bit for bit.

cp.async does not exist before sm_80, so Turing takes the v1 kernel (launch<1>, same
accuracy, another summation order) instead of launch_i8; the capability probe now
accepts cc >= 7 and a device without cp.async sets g_turing.

Measured on a Quadro RTX 8000, CUDA 12.9, arch 75: qsa_prompt_attn_parity PASS
(FAILURES: 0; vs FP64 new 6.99e-06, old 2.37e-06, output scale 3.62); the int8 kernel
62.3 -> 19.6 ms per chunk (3.19x), fp16 65.0 -> 25.1 ms (2.59x).  Engine prefill on
three Turing cards: 9.7K-token prompt 1,050 -> 1,177 tok/s, 42K 1,124 -> 1,251 tok/s;
an 80K needle test answers correctly.
2026-09-30 20:42:23 +02:00
Guillaume PUTIER 45f93fc5ee iq_kernels: decode each IQ weight part once for every column and entry
iq_mmvq, native_gu_kernel and native_down_kernel called the format's dot once
per column (or group entry), re-reading the weight words and redoing the grid
lookups and sign unpacking each time. Each dot is now split into load (weight
side) and apply (activation side, same integer chain and float expression), as
native_mmvq.cu's multi-column traits are: the dense kernel takes 1, 2, 4 or 8
columns per pass (8 at a time past 8), the grouped ones 4 entries per pass
(~48 registers; the default verify window, --spec 4 with the split off, fits
in one pass).

Every column keeps the same calls, lane stride, summation order and warp_sum,
so results are bitwise equal to the old kernels, which STRATA_OLD_IQ_MMVQ=1 (or
iq_set_old_kernels) keeps for A/B timing.

Tests: iq_multi_parity (ctest, GPU, synthetic, no model) checks old vs new
bitwise for every format, ncols 1..8 and 11, groups of 0..11 entries; --bench
times both. iq_parity (real rows from tools/iq_fixture.py) now runs the dot for
1 to 8 columns and requires every column of a multi-column call to equal a
one-column call on it bitwise (exact layout, the default). native_expert_parity
runs the GPU expert with both the decode-once and the per-entry kernels on real
blobs and requires the same bits.
2026-09-30 20:41:56 +02:00
Niko1221 abde6fc8c9 s2_expert_grouped (#241 follow-up): the new chunk kernels' dp4a through STRATA_DP4A, so the sm_60 experimental build keeps its exact fallback 2026-09-30 20:41:26 +02:00
Guillaume PUTIER e155b07b9e kernels: faster grouped and per-hit Q2_0 expert kernels, bitwise identical
The grouped kernels (verify window, MTP layer) staged each entry's activations
as xs_q[k][c * 8 + j], an 8-way bank conflict on every read, and recomputed the
chunk sum hx with eight dp4a for every row. The per-hit kernels (token graph)
read each chunk with 44 byte loads.

New kernels, on by default:
- activations regrouped once per chunk so the codes expand with shift+mask
  and hx is summed once per chunk;
- grouped: word-major shared layout xs_w[j][k * NC + c] plus (dx, hx) pairs,
  conflict-free on the staging writes and the reads, two rows per warp;
- per hit: nine aligned word loads per activation chunk, uint2 code loads,
  16-bit scale loads, one warp per (gate, up) pair or pair of down rows.

s, hx and the float expression dw * dx * (float) (s - hx) are unchanged, so
every output matches the previous kernels bit for bit. STRATA_OLD_GROUPED=1
(or moe_grouped_select_old(1)) selects the previous kernels, and so does any
activation row, scratch or blob arena the wide loads cannot take.
STRATA_GROUPED_PAIR_MIN_HITS=N keeps the previous per-hit kernels below N hits
of capacity. moe_grouped_last_path() reports which kernels the last call ran.

The funnel shift that realigns an activation chunk is written as a 64-bit
shift instead of __funnelshift_r, which nothing else in the tree uses.

tests: s2_expert_grouped_parity runs every entry point with the previous
kernels then the new ones on synthetic Q2_0 blobs and Q8_0 activations, checks
the path taken, and requires output and scratch to match byte for byte, plus a
double-precision host reference. It covers the stride and arena fallbacks and
a 2-byte aligned activation row. --bench times previous against new. It
needs a GPU and is registered in ctest.
2026-09-30 20:41:08 +02:00
Niko1221 5a7190de4a setup: the low-RAM mode's one-GPU warning says why, with the RAM math; --low-ram off --yes installs (#250)
Low-RAM mode on a multi-GPU pick dropped to one GPU with only "the low-RAM mode runs on one GPU".  It now says
why: the experts plus ~10 GB for the rest (e.g. 43 + 10 = 53 GB) against this PC's RAM, or that --low-ram was
chosen; that the engine does not split layers in that mode (it refuses --resident-experts with a layer split);
and what keeps all the GPUs (more RAM, a smaller size, --low-ram off).

--low-ram off on a PC short of RAM asked "Install it anyway?" with the default n, so an unattended --yes
install always stopped although the user had turned the mode off explicitly.  With --low-ram off the default is
y (--yes installs, with a warning); with auto the question and its n default are as before (#125), and the stop
message names --low-ram off --yes.  The two blocks are functions now (low_ram_one_gpu_why, confirm_paging);
tests in tools/test_setup_lowram.py with mocked input.
2026-09-30 20:40:02 +02:00
Niko1221 c8e46e80b7 serve: a whole OpenAI answer leaves out a tool call whose arguments don't parse unless it ends in tool_calls (#211)
The follow-up to #231: openai_collect kept a call the output ended inside, with its truncated arguments, in
message.tool_calls (finish_reason "stop" or "length").  It now leaves out every call whose arguments are not
JSON when the finish reason is not "tool_calls" - what anthropic_collect does with such a tool_use block.  The
streamed answers are unchanged.  Tests: the cut call over both whole APIs (at the end of the turn and at the
token limit) and openai_collect directly.
2026-09-30 20:38:29 +02:00
Sunil Srivatsa 67d5ed4277 fix(serve): report a tool call cut off by the end of the output as unfinished
When the model's output ended inside a tool call whose name was already
streamed, finish() closed its JSON and emitted a tool_call event, and the
answer ended with finish_reason "tool_calls" / stop_reason "tool_use", so
clients ran the truncated arguments; an MCP call ran with empty arguments.

The call now stays unfinished: its JSON is not closed and no tool_call
follows its tool_start. Both APIs report "tool_calls" / "tool_use" only when
every streamed call completed, and the non-streamed Anthropic answer leaves
out a call whose input never closed.

Fixes #211
2026-09-30 20:37:57 +02:00
Niko1221 97362183ef tokenizer: a word longer than 64 symbols merges with a heap and a linked list, not a rescan per merge (#268)
_bpe rescanned every adjacent pair after each merge: O(n^2) on one long pre-token piece (a CJK run, a minified
blob).  With the pack's vocabulary a 2,000-character CJK run took 1.6 s and 8K characters tens of seconds;
_bpe_heap takes about 5 ms and 20 ms.  It pops the lowest rank, then the lowest position - the order the scan's
strict `<` picks - and skips pairs whose symbols have merged since they were pushed.  Words up to HEAP_MIN (64)
symbols run the existing scan unchanged.

Tests (serve/test_detok.py HeapBpe): the heap against the scan word by word and through encode (both
parse_special modes, heap forced on for every word and at the default threshold) over random text with CJK and
Hangul runs, conjoining jamo, combining marks, URLs, minified code and specials - with a synthetic vocabulary
(always) and the pack's (when there is one); an 8K-character CJK run round-trips in well under a second.
2026-09-30 20:37:45 +02:00
Niko1221 9556a8dcf4 tests (#264 follow-up): the fixture step skips (exit 3) instead of failing when the vendored gguf-py is absent; no unused SCALE_F16 2026-09-30 20:36:29 +02:00
Niko1221 64dcc59fae gemm (#240 follow-up): setup calls that failed before without a word are logged and survived as before (not fatal - hipBLAS can return not-supported), init_external names its failures too, the MiB stays in the scratch message; no unused resource_failure flag 2026-09-30 20:36:18 +02:00
Niko1221 50d2adaabd serve: a request settles its status, history and totals while it still holds the fifo (#266)
Service.run() recorded the finished request's history row and totals, set busy=False and dropped `tail` in a
finally that ran after `with self.fifo:` had released the lock.  A request waiting for the fifo could start in
that gap: the old request then recorded the NEW request's status as its own, cleared its busy flag and popped
its tail, and the new request crashed in _note (KeyError 'tail').  The block now runs inside the fifo (an
inner try/finally, which also sees the disconnect), and _note reads the tail defensively.  Test: a stream
aborted mid-answer while another request waits, with a fifo that lets the waiter run first on release.
2026-09-30 20:35:46 +02:00
Hozák Martin f121667826 q2_avx2: two-block 256-bit unpack for rows of 1-2 tokens (bit-exact)
Rows that serve 1 or 2 activations (the near-universal shape of routed
decode) read each weight block twice less often: one 256-bit shuffle
ladder covers two consecutive blocks (lanes are per-128-bit, so the
arithmetic is the SSE ladder run twice and the re-homed halves keep the
original byte order) -> the same madd lane mapping, bit-identical
results.  The SSE unpack stays for 3+ tokens: at four accumulators the
extra live unpack vectors spill registers and it measurably loses.
Measured on i7-8700K AVX2, qwen3.8 125B-MoE Q2_0 decode: +10% gate/up and
+5-7% down at 1 token/expert in the standalone harness
(ML-Experiments/bench5/q2_cpu_bench.cpp, bit-exact verified), and -7
ms/verify-window end to end (CPU pool waitCPU ~19 -> ~13 ms), GPU stages
and generation unchanged.
2026-09-30 20:35:28 +02:00
Hozák Martin 765fc13473 fused_gr: sm_75 down kernel with TILE=1280 staging, other archs unchanged
Turing (sm_75) opt-in shared memory is 64 KiB. With the old fixed
TILE=2560 staging the down kernel could hold at most 6 tokens
(2560*6*4 = 60 KiB), so 7+ token windows split into two launches and,
more importantly, a single 40 KiB tile at T=4 filled the SM so only
one block per SM fit next to the resident expert/attention work.

Specialize gr_down_multi_kernel on the per-token tile size:
- sm_75: TILE=1280 -> up to 8 tokens staged in one 40 KiB launch
  (kFusedGrMaxT=8 covered), and T-token tiles fit 1-3 blocks/SM
  depending on T, so concurrent hc lanes can overlap.
- every other arch keeps TILE=2560 exactly as before.

Per-lane weight chunk order within a tile stays strictly increasing
in (tile, chunk), so the accumulation order for every (expert, row)
is identical to the 2560 path and results are bitwise unchanged.

Measured on RTX 2070 (8700K host, engine 0.1.27, Qwen3.6 125B Q2_0,
29K context, temperature 0, identical benchmark): GDN hc0 down
2.73-2.80 -> 1.88-1.98 ms/window (-30%), QSA hc0 down 0.90-0.93 ->
0.62-0.65, up/norm kernels unchanged, GPU util 91.7 -> 93.5%,
decode tok/s slightly higher on average (within per-run noise;
window is CPU expert-scheduling bound).
2026-09-30 20:35:28 +02:00
Jakub Luwierski 2538ed7927 tests: make iq_parity reproducible from a fresh checkout (TODO 24)
The i-quant fixtures were never published, so iq_parity reported ten
"missing fixture" failures on any fresh tree.  tools/iq_fixture.py now
generates them deterministically (seeded rows/cols, RandomState) into
the BUILD directory: for each of the ten types it writes the raw block
bytes (sane fp16 scales at each layout's scale offsets, seeded index and
sub-scale bytes) plus the gguf-py dequantized reference - gguf-py is
dequant-only for the i-quants, so no quantizer is needed, and Q2_0 (the
repository's type 42) uses tools/gguf_writer.py's codec.  The kernel
type ids in the headers match the vendored gguf-py's enum one for one.
Dependencies: python3 with numpy and the vendored gguf-py - nothing is
pip-installed, and CMake probes the configured interpreter and .venv,
registering the tests only when a usable interpreter is found and
saying so otherwise.

CTest now runs iq_parity (previously built but never registered) with
the fixtures as an explicit CTest fixture: generation completes before
the test even under parallel execution, and a generation failure fails
the run.  The missing-fixture diagnostic names both candidate files and
the generating command; the nonzero exit is preserved.
2026-09-30 20:35:02 +02:00
lukmanfauzie 9726c926d6 gemm: name the cuBLAS/CUDA call that failed at init, and flag resource shortages
`Gemm::init` collapsed five distinct failures into three bare strings ("cublasCreate
failed", "workspace", "dequant scratch of N MiB"), so an init failure on a tight machine
could not be told apart from a driver or install problem without a debugger.

Each call is now checked through two small helpers that report the operation and the real
status - `cuBLAS status N` or `cudaGetErrorString` - and optionally set
`resource_failure` when the failure means the machine is out of room
(`CUBLAS_STATUS_ALLOC_FAILED`, `cudaErrorMemoryAllocation`).  A caller can then retry with
a smaller cache or prompt instead of treating a shortage as fatal.

The parameter is defaulted to nullptr, so every existing caller is source-compatible; the
upstream HIP/hipblaslt block is untouched.
2026-09-30 20:35:02 +02:00
Enky 5396360ef7 verify: STRATA_LOGPOS hook for per-position teacher-forced log-probabilities
Verifier::window_logprobs writes one line per row of the last verify window's
head: position, target, its log-probability, the top token and its
log-probability, a hit flag, the log-probability of STRATA_LOGPOS_EXTRA
(default 248046, <|im_end|>) and the target's log-probability renormalized
without that token. read_windows calls it before commit when
STRATA_LOGPOS=<path> is set; otherwise the only cost is one null check.
A layer split's earlier stage forwards to the stage that holds the head,
under OnDevice as commit() does.
2026-09-30 20:35:02 +02:00
Niko1221 a3037d5435 Engine 0.1.30: short prompts up to 28% faster (every expert streams from 1024-token chunks), the resident low-RAM variant, the multi-GPU session carve (#216), AMD RDNA4, idle unload (#208); opt-ins: rope scaling (#84), conversation cache (#189), STRATA_IQ_MT_MIN=1 (#152); setup requires it 2026-09-30 19:34:50 +02:00
Niko1221 1e213213e3 docs: the layer split on two AMD RDNA4 cards (identity with one card, checkpoints, speed; setup offers one AMD card) 2026-09-30 19:20:16 +02:00
Niko1221 8099fdb980 tests/hip: prefill_native_batch passes the indexer a RopeScaling (the #84 signature; plain rope over base 1e4 as before) - a HIP-only test the CUDA build never compiled 2026-09-30 19:18:41 +02:00
Niko1221 31ad962727 #152 as an opt-in (the owner's choice): STRATA_IQ_MT_MIN=1 makes CPU expert rounding independent of the drafting; the default stays 0.1.29's rule (IQ3_S decoded 1-3% slower with it on); docs; the width test runs the opt-in 2026-09-30 19:03:39 +02:00
maxfridbe d62ccc75ff Merge remote-tracking branch 'origin/main' into b70
# Conflicts:
#	setup.py
2026-09-30 11:35:14 -05:00
Niko1221 19a2dc169b tools: the cache-disabled gate compares every resolved setting except the engine version (release vs previous release) 2026-09-30 17:52:12 +02:00
Niko1221 fee66e89cc CPU experts: the multi-token kernels from one token on (#152): a token's expert rows round the same whatever its verify window held, so output no longer depends on the drafts; STRATA_IQ_MT_MIN=2 restores the old rule; native_expert_parity checks the width invariance bit for bit 2026-09-30 17:48:49 +02:00
Niko1221 59b8c45777 Merge f-rdna4 (AMD RDNA4 gfx1201, with doplxyz's patch) into rel-0.1.30
# Conflicts:
#	setup.py
2026-09-30 17:36:03 +02:00
Niko1221 dea2b5a3ec docs: RDNA4 (gfx1201) in AMD_HIP.md with the validation on the RX 9070 XT and R9700; how to calibrate a hipBLASLt table; README and setup's texts name the RDNA4 cards
AMD_HIP.md: the per-arch ROCm wheels, the system-ROCm rule, the table rule, the
arch list and the startup check; an RDNA4 section (ctest 42 pass / 1 skip /
2 non-GPU failures, the arch check, end-to-end 4K/16K numbers on both cards and
with setup's TheRock 7.10 wheels, the 9/9 server smoke on each card, why no
gfx1201 table is shipped, what is not validated); a Tuning table section with
the tune_hipblaslt command at the engine's shapes. setup's no-table message
points there.
2026-09-30 17:32:41 +02:00
Niko1221 70e24f43e3 doorbell_ring: a volatile store, so the host sees the ring on RDNA4 without a stream sync
On gfx1201 a plain store to mapped pinned memory stays in the GPU's L2 until the
stream is synchronized, so hip_handoff failed ("separate copy/ring timeout") on
both RX 9070 XT and R9700. A probe of the ring forms on both cards, graph and
stream launches, 100 rounds each: plain store 0/100 seen without a sync;
volatile store, plain store + trailing system fence, and a system-scope atomic
release store 100/100 (41-157 us), no stale payloads. The ring now uses the
volatile form doorbell_publish_kernel already uses. The ring kernel is the
--no-publish-kernel fallback; the default fused publish was already volatile.
2026-09-30 17:09:57 +02:00
Niko1221 4dcc8f5313 CMake: the D-1 prompt-attention parity tool is CUDA-only; the HIP build with tests configures again
qsa_prompt_attn_parity linked CUDA::cudart unconditionally, so
-DSTRATA_ENABLE_HIP=ON -DSTRATA_BUILD_TESTS=ON stopped at CMake's generate step
("CUDA::cudart ... target was not found"). The tool compares the tensor-core
kernel that HIP compiles out, so it is built with CUDA only.
2026-09-30 17:01:23 +02:00
Niko1221 862c5a4767 HIP: RDNA4 gfx1201 beside gfx1100; the startup check compares the card with the compiled archs; setup picks ROCm and the hipBLASLt table per arch
- CMake: CMAKE_HIP_ARCHITECTURES may list gfx1100 and gfx1201 (validated) and
  gfx1101 / gfx1102 / gfx1200 (build with a warning: same wave32, 64 KiB LDS and
  dot4, not run by us; #192, #176). The list reaches the code as STRATA_HIP_ARCHS.
- Runtime: the engine (every GPU a run uses) and strata-device compare the card's
  gcnArchName (up to the ':' feature suffix) with the compiled archs and require
  wave32, with a message naming the card, its arch and the build's archs, instead
  of a later "invalid device function".
- __dp4a uses __builtin_amdgcn_sudot4 (v_dot4_i32_iu8) on all five archs; the
  portable fallback stays for other compilers/targets.
- setup.py: AMD_ARCHS gfx1100 + gfx1201; TheRock's wheel index per GPU family
  (gfx110X-dgpu, gfx120X-all; the pinned 7.10.0a20251120 is on both), only that
  family's libraries on the path, reinstall when the family changes; a system
  ROCm older than 7.0 is passed over for the wheels; the engine is rebuilt when
  the chosen card's arch is not in its BUILD.json. The hipBLASLt table is
  tools/hip/<arch>-hipblaslt-<version>.txt for the card's arch AND the installed
  hipBLASLt (read from hipblaslt-version.h, 1.4.1 -> 100401), else none with a
  message; before, the highest-named table of the arch was taken whatever the
  installed version, which the engine then refused.
2026-09-30 16:57:59 +02:00
Niko1221 d263ec58f9 Conversation snapshots and checkpoints follow the session carve (#216): a session saves and restores only the layers it owns
conversation_session_sizes() gives one session's running-state sizes: the GDN bytes of its gdn_alloc
rows, the indexer tail/dead/block_pos per owned QSA state; an inconsistent carve is rejected.
Checkpoint save/validate/restore, the snapshot size estimate, capture, validation and restore iterate
the owned QSA ordinals [qsa_ord0, qsa_ord0 + qsa_alloc) instead of every model layer (the spare
pooled row is written back per owned layer only), and a parked snapshot records the carve it was
taken from (layer_lo, layer_hi): a restore into another range is refused before any write.

One GPU (the default full range: gdn_alloc = n_gdn_layers, qsa_ord0 = 0, qsa_alloc = n_qsa_layers)
saves and restores exactly the bytes it did before, in the same order. generate.cpp's
conv_state_sizes uses the same function. The tests' hand-built sessions carry the full-range carve,
and the host-only validation test checks the carved sizes and the rejections.
2026-09-30 16:57:11 +02:00
Niko1221 abbf12caf5 Merge f-189 (PR #189, the conversation snapshot core and RAM cache) into rel-0.1.30
Conflicts in generate.cpp:
- against #216's session carve: conv_state_sizes takes the session (the carve's signature) and scales
  the PR's whole-model GDN size to ss.gdn_alloc rows; checkpoint_save/checkpoint_restore are the PR's
  (conversation_state.cpp), which the next commit makes carve-aware.
- STATE_HASH: the per-GDN-layer line over ss.gdn_alloc (guarded for zero rows), the QSA loop over the
  owned ordinals [qsa_ord0, qsa_ord0 + qsa_alloc) with the PR's dead= and pooled_full= in it, and
  end_cell from ss.max_cells (the primary state's max_cells, and valid with no QSA layer).
- INFO: f-resram's arena_mib (resident bytes under --mmap-experts) and the PR's three
  conversation_cache_* fields.
The --conversation-cache-* options sit in the option parser's second chain (6fb466b); their value is
`number`, not `parsed`, which is that chain's flag.
2026-09-30 16:57:10 +02:00
Niko1221 840f01734e Merge f-resram into rel-0.1.30
# Conflicts:
#	src/program/generate.cpp
2026-09-30 16:54:12 +02:00
Niko1221 6fb466b7cb generate: the option parser's else-if chain in two statements (MSVC C1061: more than 128 nested blocks after the new options); the same order and effects 2026-09-30 16:53:53 +02:00
doplxyz ca574a27ad HIP: enable RDNA4 gfx1201 (RX 9070 / AI PRO R9700)
doplxyz's minimal patch from #178 (their commit 0c59582): CMake, the
runtime device check, the signed dot4 intrinsic and setup's AMD_ARCHS
accept gfx1201 beside gfx1100.
2026-09-30 16:52:13 +02:00
Niko1221 7a2948f9bb Merge f-coupled into rel-0.1.30 2026-09-30 16:51:52 +02:00
Niko1221 f9a31f391b setup: the resident low-RAM variant keeps its RAM copy pageable on ROCm (STRATA_RESIDENT_PIN=0 in the config's env) 2026-09-30 16:51:39 +02:00
Niko1221 12ebc67271 Merge f-84 into rel-0.1.30 2026-09-30 16:51:33 +02:00
Niko1221 5ac6d37e59 Low-RAM mode, resident variant: the experts the GPU does not hold stay in RAM (--resident-experts), chosen by setup
On a PC whose VRAM cache plus RAM can hold all experts but whose RAM alone cannot (e.g. 32 GB + a 24 GB GPU with
Q2_0 / IQ2_XS / the Coder), the plain low-RAM mode (--mmap-experts) reads the non-VRAM experts through the OS file
cache, which such a PC keeps giving back to the SSD. The resident variant copies exactly those experts from
experts.bin into RAM once at start:

- engine: --resident-experts = --mmap-experts --resident-cpu-experts, the copy page-locked when the driver allows
  (else locked in the working set), 4 GiB headroom, plain mmap with a warning when it does not fit. Built after the
  prompt path's lend plan: the lendable slots' experts are kept in RAM too, from the last slot down, as far as RAM
  allows. Adaptive swaps stay on: an evicted expert is copied back from its VRAM slot into the RAM place of the one
  that replaces it (exchange buffers, committed when the swap lands), so no swap reads the file.
- --resident-cpu-experts (the ROCm arm) no longer requires --adapt-every 0 and gets the lend region too; its copy
  stays pageable with 8 GiB headroom as before.
- the PCIe share is gated per source (pcie_layer): the arena answers as before; a page-locked resident copy answers
  for every layer. Same bits as --mmap-experts for the same placement with --pcie-frac 0 or STRATA_RESIDENT_PIN=0.
- INFO arena_mib reports the RAM the experts take in the mmap modes (the resident copy, or 0); the serve log and the
  CLI report the resident GiB, exchanges and blob reads from the file.
- setup: in the low-RAM mode, resident when RAM >= (experts minus the GPU's estimated share at this context, less the
  image encoder's room) + 10 GB; --low-ram resident|mmap forces a variant; needs engine 0.1.30 (else mmap).
- tests: lend-region choice and exchange bookkeeping (CPU only). Default (arena) path unchanged.
2026-09-30 16:51:04 +02:00
Niko1221 3b4230a182 Coupled draft sampling for the MTP drafter (STRATA_SPEC_COUPLED=1, off by default)
Under sampling the draft layer proposed its argmax. With STRATA_SPEC_COUPLED=1 a sampled request's drafts are
sampled with the target's own chain (top_k / top_p / min_p / temperature, penalties over the same history) and the
same Philox uniform the verify window draws for the row that checks the draft: counter = MTP cell + 1 (a draft at
cell p + a + j is checked by row j of the next window, counter p' + j). Verification is still exact-match against
the target's sample, so the output does not depend on the drafts; acceptance should rise.

- sampler.cu: coupled_stage / coupled_penalize / coupled_merge kernels (params, seed, counter and penalty ring from
  device memory, so they live in the drafter's CUDA graphs); the split part kernel reused unchanged; the tail
  (sampled_tail_warp) templated to also return the pick's probability. The five existing sampler kernels compile to
  identical SASS (sm_120).
- mtp.cpp: separate coupled round/step graphs (the argmax graphs are untouched and still used for greedy requests);
  subset-aware (sample over the draft head's subset, id <-> subset maps for the penalties); --spec-min-p gates on the
  draft's probability of its sampled token under the chain.
- generate.cpp: set_draft_sampling per request (serve and CLI), the penalty history base before each draft (serve).
- coupled_draft.hpp + coupled_draft_test.cpp: the counter / ring arithmetic and a host-only test (907k checks).

Switch off: no allocations, no new launches, the same graphs.
2026-09-30 16:46:51 +02:00
Niko1221 4240629dba docs: rope scaling is experimental and opt-in; the measured perplexity at 293K
DETAILS.md: what it does, that no flag means no change, the contributors' paired per-position NLL (yarn 2 -0.18 nats vs none and linear 2 at 293K, no separation at 2.7K/32K, needles not discriminating), the explicit-factor pass-through, fixed per run. The stale 'engine 0.1.18' references go; the setup's 384K/512K menu entries and the README say experimental.
2026-09-30 16:44:48 +02:00
Niko1221 eb77a8c145 rope: one validity rule for the resolved config; none passes the identity constants to every analytic site
rope_scaling_invalid() checks every value with std::isfinite first (a NaN passes every range comparison), factor >= 1, original context > 0, a finite positive freq_scale and mscale; the engine applies it to the resolved config (CLI + model file) and fails at startup with the reason, and native_rope, both native indexer appends and the prefill rope use the same rule instead of three hand-copied lists. RopeScaling::kernel_args() gives the analytic kernels their float constants and returns the identity (1, 0, 0, 0, 1) for none whatever the other knobs hold, as the table builder already ignored them: an unscaled run cannot pick up a stray --yarn-attn-factor on the native path only. none resets the knobs (with a note if some were given). The magnitude-correction note prints whenever mscale != 1, and only then (not for plain linear).
2026-09-30 16:44:48 +02:00
Niko1221 d4526cf156 qsa: the table indexer's spare rotates at position 0 like the native one (TODO 7)
indexer_key_append_kernel skipped the rotation at pos 0, which is only an identity while row 0 of the table is (1, 0). Under YaRN row 0 is (mscale, 0), so dead and pooled[0] stayed the only unscaled keys of a scaled cache and disagreed with the native indexer's spare. The rotation at angle 0 reduces to v * cos_tab[pair] on the rotated dims (the sine is 0 in every scaling), so no partner read and no barrier; unscaled it is v * 1.0f, bit for bit the old value. qsa_parity checks the table spare against the unscaled spare times row 0 (bit-exact), pooled[0] == dead, the native spare's factor, and that YaRN's mscale is observable there.
2026-09-30 16:44:48 +02:00
Niko1221 56c7cd2f80 STATE_HASH: pooled= keeps its 0.1.29 meaning (the completed indexer rows); the extent with the spare row is pooled_full=
pooled= hashes rows [0, L/4) of every QSA layer's idx_pooled again, as in 0.1.29 and earlier, so a
state hash from this engine compares with an older one field by field. The PR's extent (those rows plus
the spare row at L/4, which a conversation restore writes back) is pooled_full=; dead= stays. The
cache gates compare pooled and pooled_full; the cache-off gate against an older engine compares pooled
directly and needs pooled_full only as proof that the candidate is this build.

A failed checkpoint save/restore prints its reason to stderr (the ERR line has none). The cache
harness reads its files as UTF-8 (Windows' default code page stopped it at the tokenizer), and the
isolation gate passes absolute fixture paths (the engine runs in the config's cwd).
2026-09-30 16:43:28 +02:00
Niko1221 81bd596242 wip: version 0.1.30 2026-09-30 16:37:30 +02:00
Gopi 915f74fefb Multi-GPU: the session carve and the per-stage prompt loans
Two things a layer split was paying for and not using.

* THE SESSION CARVE.  A stage carved state for ALL 48 layers whatever slice it ran - every QSA KV pool at
  max_cells, every GDN recurrence - the whole-model-sized-buffer disease the chunked-QSA-prefill PR cured
  upstream.  `session_bytes`/`session_init` take [layer_lo, layer_hi), and a session now owns only that range:
  `qsa_states`/`gdn_state` keep GLOBAL ordinal indexing and simply hold fewer rows (`qsa_ord0`/`qsa_alloc`,
  `gdn_ord0`/`gdn_alloc`), per-layer consumers subtract `gdn_ord0`, and the model-level uses - the shared RoPE
  table, the prefill staging identity, the MTP rope borrow - read `qsa_states[qsa_primary()]`.  A range with no
  QSA layer still carves ONE primary state so those uses stay valid, and the default full range is
  byte-identical to the old carve.  On the 2x3060 + 2x5060 rig, CUDA1's [30, 48) session costs 0.93 GiB:
  7.83 GiB free before the carve, 6.90 GiB after (`session [30, 48) and the head`).

* PER-STAGE PROMPT LOANS.  `no_prefill_borrow = true` for split stages said "each stage's prompt path has its
  own buffers" - true, but that is a reason to give each stage its own LOAN, not to make every stage withhold a
  chunk-sized reserve from its cache for the whole session, and forced on it also collapsed `--prefill auto` to
  2048.  Each prompt path now borrows the tail of ITS OWN stage's cache (`PfPart`), so outside the prompt the
  whole cache is expert cache: `--prefill auto` is the largest chunk every participant can lend (8192 tokens
  here), a participant refills its loan into its own slots and marks only its own layers (a slot refilled into
  another cache, or another stage's rows marked resident, is silent and produces plausible tokens), and the
  chunk is the largest one EVERY participant can lend rather than one card's answer imposed on the others.
  A participant that cannot lend the buffers falls back to the prompt path's own, as a lone one always could;
  with a single participant the plan reduces to `plan_lend` exactly, so the single-GPU loan is unchanged from
  main - the percentage cap stays an AUTO-chunk rule (an explicit `--prefill` is the operator's number and a
  loan of it only has to leave the 128-slot floor).  The flat 1 GiB withheld from every stage after the first
  becomes what is actually held back after the weights, session and drafter exist: 96 MiB of verify windows,
  plus 1000 MiB of drafter and head on the ONE stage that carries them.  CUDA0 lends 2162 slots (3.98 GiB),
  CUDA1 1993 of its 2653 (3.97 GiB).

* REPORTING.  `expert_slots`/`expert_cache_mib` sum every tier: a 4-GPU 256K run reported CUDA0's cache alone
  (3327 experts) while the four cards held 13310, so the Monitor tab was wrong by 4x for every multi-GPU
  config.  `expert_slots_primary`/`expert_cache_primary_mib` keep the old figure.  The helper ranks'
  ms_begin/ms_wait are cumulative since boot and were printed next to per-request deltas; they take deltas now.
  KV-streaming stats iterate the session's OWNED ordinals.

* REFUSALS.  `--gpu-only-full` and `--gpu-stages` replay every layer through CUDA0's session, which a split
  carves to CUDA0's range, so they are refused with a layer split rather than answering about another stage's
  state; the token-graph hit path is disabled under a split (such a graph cannot span stages); and the sessions
  are allocated AFTER the split search, because the search prices each placement by what that range's session
  will cost on that device (`session_bytes` is pure arithmetic).
2026-09-30 16:37:18 +02:00
Go 4f5d0860d7 docs: limit shared arena backing to dev shm 2026-09-30 16:36:33 +02:00
Daehun 80f83268d4 core: add guarded shared expert arena backing
Rebase the shared-arena primitive onto 0.1.26, bind backing files to a pack fingerprint with a small header, and document tmpfs/hugetlbfs placement.
2026-09-30 16:36:32 +02:00
ruibeikaa e200e08f54 Pascal (sm_60): bring the engine up on compute capability 6.0
Two gates stand between this engine and a 6.0 card, plus one attribute the card does
not honour.  None of them needs the kernels rewritten:

* `CMakeLists.txt` refuses to configure below sm_75;
* `__dp4a` (6.1+) appears 29 times in the i-quant kernels (`native_mmvq.cu`,
  `s2_expert_grouped.cu`, `iq_kernels.cu`) and `__nanosleep` (7.0+) in the three
  doorbell waits (`elementwise.cu`, `verify_kernels.cu`);
* the Turing port sizes `fused_gr_read_multi`'s slice from
  `cudaDevAttrMaxSharedMemoryPerBlockOptin`, which on an sm_60 answers 65536 - a card
  whose launch validator enforces the 49152 B per-block limit instead.  The capacity
  comes out 6 tokens and every 6- or 8-token window fails the launch with
  "invalid argument".

## The changes

* **`include/strata/kernels/dp4a.hpp` (new)** - `STRATA_DP4A` and `strata_spin_pause()`.
  The dp4a fallback is llama.cpp's own (`ggml/src/ggml-cuda/common.cuh`): both operands
  read as SIGNED bytes, accumulated into int32 - which is what `__dp4a` does for exactly
  these call sites, the kernels here being transcribed from `vecdotq.cuh`/`mmvq.cu`.  The
  fallback is bit-exact, not approximate; the nanosleep sites only pace single-thread
  doorbell waits, so on sm_6x the loop spins.  Both are `__CUDA_ARCH__` selections, so a
  HIP build takes neither: its `__dp4a` and `__nanosleep` are `hip_compat`'s own.
* **`CMakeLists.txt`** - `-DSTRATA_EXPERIMENTAL_SM60=ON` relaxes the architecture gate,
  and the refusal message names it.  The UTF-8 BOM stays.
* **`fused_gr.cu`** - below sm_70 the slice capacity comes from
  `cudaDevAttrMaxSharedMemoryPerBlock` (49152 B -> 4 tokens) instead of the opt-in.  The
  Turing port's slicing, its no-opt-in fallback and the HIP expression are unchanged.

On sm_70 and newer this is a no-op: the opt-in is honoured there, so the capacity is the
value it already was, and `STRATA_DP4A` and `strata_spin_pause()` compile to `__dp4a` and
`__nanosleep` exactly as before.  Building for a 6.0 card needs a CUDA release that still
targets Pascal (CUDA 13 removed it; 12.x has compute_60), and `CMAKE_CUDA_STANDARD` has
to stay 17 for it: nvcc 12.9 refuses `-std=c++20` when the host compiler is VS2019's `cl`
and silently falls back to C++14, which rejects the nested
`namespace strata::kernels {` declarations.

Rebased onto 0.1.27 (0.1.21 -> 0.1.24 -> 0.1.27).  The 0.1.21 form of this patch clamped
the MTP and verify windows instead, because the fused GR read could not launch a 6-token
window at all.  Now that `fused_gr_read_multi` slices the batch itself, the clamp, its
`fused_gr_max_window` helper and the two `generate.cpp` call sites are gone, and the full
window runs:

    strata verify: window up to 6 tokens, 69.1 MiB of device buffers
    strata verify: captured the 6-token window (upload no error, sync no error)

Measured on a 6.0 card (GP100-class, four dies through the layer split, the model's
IQ3_XXS quant, an 883-token prompt, 256 generated, the shipped `--spec 4`): every one of
the 24576 experts resident, 100% decode cache hit rate, 110 tok/s prefill and 21.3 tok/s
decode (warm median).  This port on the 0.1.21 base measured 110.6 and 17.9 in the same
session with the same prompt, so the full window is worth about 19% of decode here.  One
RTX 3090 Ti with the release engine measures 305 and 79 tok/s for the same model.  The
port is about fitting, not speed: decode is bounded by Pascal's per-layer arithmetic, not
by capacity or memory.  Only the 6.0 path was exercised on hardware.
2026-09-30 16:36:32 +02:00
Strata b782066e3c Docker build (#96): the engine compiled in docker build, STRATA_EXECV so the server is PID 1, SIGTERM stops it cleanly, KV/GPUS/LOW_RAM as env vars
Merged by hand onto 0.1.29: SIGTERM takes #153's Ctrl+C path (the timed sleep loop and the second-Ctrl+C kill stay);
SIGINT keeps Python's handler; the image builds RTX 20 (75) too.
2026-09-30 16:36:25 +02:00
Niko1221 379d7d84b2 server (#208 follow-up): a request stamps last_request_at in load() (the idle thread cannot unload between load and run); unload() sends QUIT before terminate; the VRAM guard checks the first GPU (docs); #163's test engine answers poll() 2026-09-30 16:35:05 +02:00
bytethecookie 376430c7db server: the image encoder unloads and loads with the engine; docs for sharing the GPU 2026-09-30 16:32:11 +02:00
bytethecookie f61e688527 server: optional idle unload, POST /unload and /load, a free-VRAM guard and a before_load hook 2026-09-30 16:32:11 +02:00
Niko1221 3e3d69b4d4 prefill: every expert streams from 1024-token chunks (was 2048): +17-28% on 1-4K-token prompts, the same output; STRATA_PREFILL_STREAM_MIN overrides 2026-09-30 16:32:04 +02:00
Jeremiah Ritchey 7e94070cf2 Document retained snapshot ownership and admission contract 2026-09-30 16:31:46 +02:00
Jeremiah Ritchey 7d93cb6b03 Require fixed binaries and budgets in the incremental capture gate 2026-09-30 16:31:46 +02:00
Jeremiah Ritchey 92a3d5fda7 Bound incremental snapshot fragmentation and preserve cache admission
Reserve accounted space for later appends without moving prior payloads. Prefer full capture when optional capacity would evict useful conversations, and report the actual additional RAM required. Exercise 4096 small appends and non-mutating admission checks under sanitizers.
2026-09-30 16:31:46 +02:00
Jeremiah Ritchey 7f7f886886 Retain unchanged KV storage across repeated conversation parking
Grow snapshot buffers in segments, track the first rewritten token, and charge retained active storage to the existing RAM budget. Refresh running state, partial pages and draft boundary state. Add full-capture versus incremental growth/rewind checks and report snapshot sizes with usable pressure-test budget ranges.
2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 573bb36baa Compare cache-disabled engines against untouched upstream
Replay identical requests and require token, known-answer, reuse, resolved-setting and comparable main-state parity. Retain the complete pooled-state diagnostic and add a completed-row fingerprint matching upstream. Add negative controls that remain active under optimized Python.
2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 0fca77bfe0 Remove planning documents from the core PR 2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 3782659274 Ignore llama.cpp dependency directories and symlinks 2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 3a5b090014 Record final Linux snapshot and RAM cache acceptance 2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 8d46e95ff5 Record linked 0.1.27 core build and host validation 2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 876f254c78 Report actual draft residency in snapshot verification 2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 75fce92c93 Refresh core validation record for upstream 0.1.27 2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 13fd32a227 Verify restored draft KV and fail incomplete state fingerprints
Move core diagnostics from the dependent NVMe work (4d73bb3) into the shared-core review branch. Read back authoritative bytes and resident ring pages without rewriting state; remove a redundant GPU fixture refill that could mask restore failures. Bound hash workspace and check synchronization/copy errors. Opt-in diagnostics record batched versus token draft prefill.

Validation: current core translation units pass C++ syntax checks; 1188 host transfer checks pass with ASan/UBSan. Real GPU and full-model validation remain pending the benchmark window.
2026-09-30 16:31:45 +02:00
Jeremiah Ritchey f3072a95e6 Clear recoverable snapshot errors before batched draft prefill 2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 4ac028522e Focus shared-core patch on runtime, regression tests and current documentation 2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 28d07f8a1a Record upstream integration, Linux acceptance and controlled Pi results 2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 717519d345 Allow bounded Pi task completion and record benchmark provenance 2026-09-30 16:31:45 +02:00
Jeremiah Ritchey 055bc16e2a Match upstream K8V4 flags when sizing conversation snapshots 2026-09-30 16:31:44 +02:00
Jeremiah Ritchey 089d444278 Enforce Pi benchmark request limits and engine memory evidence 2026-09-30 16:31:44 +02:00
Jeremiah Ritchey e0feb8530c Add reproducible Pi cache comparison and document current integration 2026-09-30 16:31:44 +02:00
midhatn 6adb2e5ac4 test: require a real physical-memory sample on Windows 2026-09-30 16:31:44 +02:00
Jeremiah Ritchey 991203f2a9 Integrate validated conversation snapshot core with upstream 0.1.25 2026-09-30 16:31:44 +02:00
Jakub Luwierski a8e56761a6 generate: the in-window scaling note stops claiming YaRN's magnitude correction (TODO 22)
The note fired for every scaled run inside the trained 262144 and its text
named YaRN's magnitude correction even for linear, whose resolved mscale
is exactly 1.  Split in two: the in-window warning now only says that no
position needs the extension while the resolved scaling still applies to
every angle, and the magnitude explanation became its own note, printed
only when YaRN is resolved and its magnitude multiplier differs from 1
(yarn factor 1 inside the window stays quiet; linear never sees it).  The
main rope scaling line is unchanged, the numbers it prints already carry
the resolved mscale.

Diagnostics only.  Checked on the rebased tree: none prints nothing,
linear 2 prints the in-window note without the magnitude line, yarn 2
prints both (mscale 1.069315), yarn factor 1 prints the in-window note
only, and yarn 2 past the trained window prints the magnitude note
without the in-window one.
2026-09-30 16:31:31 +02:00
Jakub Luwierski 8e2f46ca8c prefill: the draft layer's batched RoPE takes the one rope config
v0.1.29's new draft_kv site (the 0.1.26 batched draft prompt pass) kept
upstream's float freq_base form through the rebase, which both misses the
scaling on the draft K/V and does not compile against the RopeScaling
signature the other four sites carry.  It passes rope_scaling() now, like
the prompt K, Q and indexer-query sites.
2026-09-30 16:31:31 +02:00
Jakub Luwierski f8c45322b3 test: the indexer batch-vs-sequential parity covers linear and compares bits
Item 8 verification.  The parity section now runs all three scaling
configs - none, linear 2 (angle shrink only), yarn 2 (ramp + mscale) -
and "bit-identical" is asserted on the BIT representations (memcmp of
the state words), not float !=, which would pass a NaN-payload or -0.0
flip.  Each scaled variant must also differ from the none baseline in
pooled-key bits, so the parity cannot pass because both sides ignore
the scaling.  Green on this tree: 0 of 33409 state words differ in
every config; 128 (linear) and 192 (yarn) pooled words move.
2026-09-30 16:31:31 +02:00
Jakub Luwierski 29f3aec04d test: pin the short-context rope table (§4, no factor-2 fallback in the window)
The implementation landed with the derived-factor change; per the item's
own scope note this is verification and tests, not a second one.  The
table from the item is now pinned case by case - 131072 and 262144 with
yarn and no factor resolve to 1, an explicit --rope-scale 2 stays 2 inside
the window, 393216/524288 keep 1.5/2 - and linear is checked under the
same rule the old fallback applied to it too.  On the real engine the
resolved combo runs as "rope scaling yarn, factor 1 (freq_scale 1, mscale
1.000000)" and a greedy 12-token run is token-identical to the stock
baseline - evidence on one path, not a bit-identity claim.
2026-09-30 16:31:31 +02:00
Jakub Luwierski 79926c0d3f setup: the automatic rope factor derives from the context actually served
The factor ladder (smallest of 1.5/2/3/4 covering the chosen context) is
gone.  The automatic factor is now the final context over the trained
262144, clamped at 1 - max(1.0, final / trained) - computed AFTER the
RAM reductions, so it always matches the context the engine will serve:

  512K + IQ3_S under 90 GB of RAM + yarn, no factor:  final 128K, factor 1
  no reduction:                                       384K -> 1.5, 512K -> 2
  a chosen method inside the trained range:           factor 1, not 2

Factor 1 removes the automatic expansion - the trained angles stand - but
it is not a switch for rope as a whole: an explicitly chosen method's
settings keep their defined behavior.  A user-supplied --rope-scale is
still kept verbatim when a reduction changes the context; the ok() line
now says where the factor came from (final context / trained, or as
requested), and help, docstring and docs/DETAILS.md drop the
"smallest covering factor" wording.
2026-09-30 16:31:31 +02:00
Jakub Luwierski 00db760854 setup: a free-form --context past the menu got a raw StopIteration
The triple-check pass found what the menu could not: --context is not
limited to CONTEXTS, and the factor ladder (1.5, 2.0) ended at 512K, so
`--context 600000` died with a bare traceback instead of a setup message.
The ladder extends (3, 4) and a context past its top refuses cleanly,
naming --rope-scale as the way out.  The interactive explanation block
also stays quiet under --yes, whose ok() line announces the choice
already.
2026-09-30 16:31:31 +02:00
Jakub Luwierski 9b83998d9d setup: the documented automatic rope configuration actually happens now
The comment said the setup adds the flag when the chosen context needs it;
the code called fail().  `START-HERE.bat --setup --context 393216` - the
command the docs give - stopped instead of configuring.  Now an omitted
--rope-scaling with a past-trained context resolves the config itself:
yarn (llama.cpp's extension method, recall-tested here at 512K; one
question when interactive, the silent default with --yes) and the smallest
covering factor (1.5 at 384K, 2 at 512K).  An explicit none is still
refused for such a context, with the reason and the way out spelled out
instead of a bare stop; explicit linear/yarn/scale pass verbatim; inside
the trained 262144 nothing turns on by itself.

The resolution moved AFTER the RAM reduction (the §4 ordering): the factor
must cover the context the engine will serve, so a 384K choice reduced to
128K by the RAM limit gets no scaling at all, and an explicit selection
that survives the reduction says so in a warning.

The rope config is now two pure functions (covering_factor, resolve_rope)
with its own unit tests (tools/test_setup_rope.py); the engine args take
the resolved values; help, module docstring, the context menu note, README
and docs/DETAILS.md describe the implemented behavior.
2026-09-30 16:31:31 +02:00
Jakub Luwierski 9adfaa42e5 indexer: the batched append takes the one rope config, with a parity test
The rebase onto 0.1.24 had brought the QSA indexer's C-2 chunk append,
whose kernels rotated the pooled keys inline - cosf/sinf of the unscaled
angle, no mscale - so a scaled prefill would have written indexer keys
under a different rotation than the per-token append the decode path uses
(rope_scaling.hpp's one-rotation rule, broken silently).  The batch path
now resolves freq_scale/corr_dims/mscale from the same RopeScaling the
single append reads and rotates through the shared rope_scaled_angle; the
raw freq_base parameter is gone from its signature.

qsa_parity pins the contract the C-2 rework claimed: the batch append's
whole end state (pooled, spare, tail ring, block_pos) is BIT-IDENTICAL to
the sequential single appends', under none and yarn 2 alike, and the
scaling is observable in the batched keys.
2026-09-30 16:31:31 +02:00
Jakub Luwierski f4ae11b736 bench: rope-scaling needles past the trained 262K (linear 2, yarn 2)
The first end-to-end check that a scaled run recalls past the trained end:
8 of 8 probes found the needle at mid-depth, temperature 0 - 1k/32k/128k on
the stock model (arm A), 262k and 512k prompts on linear factor 2 (arm B)
and yarn factor 2 (arm C), 512k being 2.01x the trained 262,144.  The yarn
262k probe was repeated green after the rebase onto 0.1.20, next to the
per-arm engine and server logs and the launch recipes.

What it does not establish is written down in the README: one depth, one
needle per length, and no long-document perplexity with and without
scaling at 262K yet - the one open measurement.
2026-09-30 16:31:31 +02:00
Jakub Luwierski c7d2766528 generate: an explicit --rope-scaling none or --rope-scale 1 overrides the GGUF rope keys
The defaults collided with the opt-outs: "none" was both the untouched
--rope-scaling default and the explicit switch-off, and 1.0 the same for
--rope-scale, so qwen4exp.rope.scaling.type/factor from the model file won
even against an explicit flag - the opposite of the stated precedence (and
of docs/DETAILS.md).  Now the empty string and 0 mean the flag is absent
(the same sentinel idiom as --rope-freq-base 0 and --yarn-orig-ctx 0), the
model file fills only what no explicit flag named, and `none` / `1` are
the opt-outs they read as.

The resolution moves above the weight pipeline: the config needs only the
CLI and the model file's metadata, its one hard constraint (set before
session_init builds the table and the graphs capture the constants) is
unchanged, and a bad rope key now dies before the shards are scanned.

Checked on the bench machine against a synthetic GGUF carrying
rope.scaling.type yarn / factor 4: the flags absent -> yarn 4; --rope-scaling
none -> no scaling; --rope-scale 1 -> yarn, factor 1, mscale 1; explicit
linear 2 -> linear 2; a GGUF type other than none/linear/yarn dies before
the weight scan.  The real artifact (no rope keys) starts and generates
unchanged, and rope_parity stays green.
2026-09-30 16:31:31 +02:00
Jakub Luwierski c1d061faa9 docs: context extension (rope scaling)
DETAILS.md gains the 'Context extension' subsection - what linear and yarn do,
the setup path (383K/512K in the context menu pick the factor themselves), the
engine flags with llama.cpp's names and their defaults, why the scaling is fixed
for the whole run (K sits in the cache post-RoPE), and the one honest caveat:
inside the trained range a scaled run is a slightly different model, and the
recall numbers are text-only at one depth.  Troubleshooting grows the row for
the refusal a context past 262,144 now raises without the flag; README points
the context question at it.
2026-09-30 16:31:31 +02:00
Jakub Luwierski 9ede9d94bc setup: --rope-scaling/--rope-scale; contexts past 262144 require scaling
CONTEXTS grows 383K/512K, labelled in the menu, and the setup refuses a context
past the trained 262,144 without --rope-scaling (the engine would refuse it
too).  The factor defaults to the smallest that covers the chosen context
(1.5 at 393K, 2 at 524K) and lands in the engine args like every other flag.
2026-09-30 16:31:31 +02:00
Jakub Luwierski 963679b35e engine: --rope-scaling/--rope-scale/--yarn-* flags; rope keys as GGUF defaults
Nine flags, llama.cpp's names: --rope-scaling none|linear|yarn, --rope-scale,
--rope-freq-base, --rope-freq-scale, --yarn-orig-ctx, --yarn-ext-factor,
--yarn-attn-factor, --yarn-beta-fast, --yarn-beta-slow.  Ranges die in the
validation block at second zero; the config itself resolves after the model file
has had its say and before session_init builds the table or captures a graph
(rope_scaling.hpp's one-writer rule).  Precedence: CLI over the model file's
qwen4exp.rope.* keys over the struct defaults - today's artifact ships no rope
keys, so that channel is a no-op defaults path for future fine-tunes.

A scaled run prints its resolved summary (type, factor, freq_scale, base,
mscale, context vs trained) to stderr, which is what the bench logs quote, and
warns when scaling is on with the context still inside the trained range -
YaRN's magnitude correction applies everywhere, so that run is not the stock
model.
2026-09-30 16:31:31 +02:00
Jakub Luwierski 0011637753 rope: thread scaling through the native, indexer and prefill rotation sites
The table path got scaling for free (it lives in the table contents); the three
ANALYTIC paths computed the angle in-kernel and so need the config explicitly.
Each wrapper now takes the RopeScaling and passes the resolved constants -
freq_scale, the corr_dims pair, ext_factor, attn_factor - as kernel arguments.
They are process constants set before session_init, so baking them at CUDA-graph
capture is correct by the same argument as every other kernel argument: only
per-token values must ride device memory, and positions still do (st.pos_dev).

The shared float32 arithmetic is rope_scaled_angle (rope_scaling.hpp), a
line-for-line rope_yarn: one definition for native_rope, the native indexer's
pooled-key rotation and prefill's rope, instead of three transcriptions that
could drift.  The spare indexer key keeps its zero angle; under YaRN the mscale
rides in through cos(0) on both pooled keys and indexer queries, so top-k is
unmoved.  rope_parity adds the check this whole wiring answers to: native vs
table on the same input, yarn and none alike - which caught the first draft
passing scaling.mscale() into the helper that applies the log term itself, a
double magnitude correction visible as ~7% on every rotated dim.
2026-09-30 16:31:31 +02:00
Jakub Luwierski 304d613cd0 kernels: rope scaling config and the scaled cos/sin table (none/linear/YaRN)
The artifact pins theta 1e7 with no rope.scaling keys, so the engine had exactly
one rope: inv[i] = theta**(-2i/n_rot), no freq_scale, no correction.  Contexts
past the trained 262,144 had no coherent path.

rope_scaling.hpp adds the one process config - none | linear | YaRN, llama.cpp's
types - and build_rope_table grows an overload that folds the whole scaled angle
(ggml's rope_yarn: interpolation, the corr_dims ramp along the pairs, and the
mscale magnitude correction) into the float64 host table.  The rotation kernels
cannot tell a scaled table from an unscaled one, so nothing downstream changes:
for the default decode path and the indexer's pooled key, scaling IS the table.

The math is transcribed from the vendored ggml (ggml.c corr_dims, ggml-cuda/
rope.cu rope_yarn/ramp, MIT headers kept), not re-derived; the one deliberate
deviation is bookkeeping - the ramp takes the PAIR index ggml's i0/2 would
produce, because every Strata rope kernel speaks in pairs.

For type None the new builder calls the original loop verbatim, and the parity
test holds it bit-identical; linear(4) is checked bit-exact against a float64
reference and equal row-for-row to none at p/4; YaRN against a float64
transcription of the ggml spec, plus the structural checks a tolerance cannot
fake: cos_tab[0] == mscale (position 0 is angle 0 for every pair), first pair
extrapolates / last interpolates at a far position (cos for the first, sin for
the last - near zero sin IS the angle, which is where interpolation happens),
and an observability assertion that the fixtures see scaling at all.
2026-09-30 16:31:31 +02:00
maxfridbe aeb21b6b11 docs: INTEL.md - 80k tokens at 1,065 tok/s with 12 staging threads; the SSD is the floor of the streamed experts 2026-09-30 09:15:09 -05:00
maxfridbe 74df8331cf docs: INTEL.md - the 80,000-token prompt: the VRAM plan trap, expert streaming per chunk, where the 77 s go 2026-09-30 09:12:52 -05:00
maxfridbe 3b48ee56ce sycl: PLE rows - a 64-deep read queue and a short first prompt chunk (2,184 tokens 711 -> 765 tok/s, 8,000 857 -> 986)
The rows of a 2,184-token prompt are 27k random 4 KB O_DIRECT reads (114 MB for ~7 MB of rows), all before the
first kernel: 466 ms with the reader's 16 blocking threads. 64 threads (the port's default now, a copy of
src/platform/direct_file.cpp; STRATA_IO_THREADS still overrides) give 330 ms and 128 / 256 the same - the drive
tops out near 85k IOPS. A 256-token first chunk (STRATA_PREFILL_FIRST, 0: off) lets the GPU start while the
rest of the rows are read behind it: 2,184 tokens 3,075 -> 2,860 ms, time to first token ~150 ms less; 8,000
tokens 986 tok/s. The chunk boundary moves rounding in the expert GEMMs, so a long greedy continuation can
diverge late (token 45 of 64 on the test prompt); short prompts are bit-identical.
2026-09-30 08:30:18 -05:00
maxfridbe c697b15994 sycl: iq4_nl dequant as runs of 8 (0.024 -> 0.017 ms per expert), host timers around the prompt path's per-layer grouping 2026-09-30 08:05:57 -05:00
maxfridbe 58e1f8d0c9 sycl: the speed round - warm-up captures, commit/draft overlap, vector-store dequant, XMX kernels (opt-in), profiles
Measured on the B70, outputs identical before and after each change (docs/INTEL.md "Speed work"):
- every window graph and the drafter's graphs captured at load (STRATA_WARM_GRAPHS=0 restores first-use capture)
- the commit graph is left running while the drafter's round runs on its own queue: decode 38.3 -> 43.1 tok/s at
  the 2,184-token context, 46.5 -> 49.7 on a short prompt
- the draft layer's batched prompt pass takes prompts under 64 rows (106 -> 16 ms on 19 tokens)
- one device module per kernel: the first launch in the prompt path 245 -> 1 ms
- the expert dequant writes each thread's run as one vector store: 0.085 -> 0.030 ms per expert; the 2,184-token
  prompt 566 -> 682 tok/s, 8,000 tokens 720 -> 841
- SWAR sign compare/subtract in the expert dots, a local-memory resident-plan kernel, a split-K fused down kernel
  (bit-identical to the single-token kernel, gr_parity): parity-clean, no measurable decode change

XMX: oneMKL's FP16 GEMMs already run on the XMX units (30-60 TFLOP/s). Two joint_matrix kernels are in the tree,
correct and opt-in because both lose to the paths they would replace on this card: xmx_gemm_iq (fused dequant +
GEMM from the quantized rows; xmx_gemm_bench) and qsa_prompt_attn_xmx (the mma.sync prompt attention's port;
qsa_prompt_attn_parity passes at 1e-6 of scale; STRATA_PROMPT_ATTN_XMX=1).

Profiling: unitrace -q needs Intel's metrics libraries (Dockerfile.metrics) and dev.xe.observation_paranoid=0;
the per-kernel table is in INTEL.md. A trap recorded there: --prefill-until with a native pack drops the prompt
tail (the token loop is skipped), so a "windows for short prompts" routing was invalid and is not in this commit.
2026-09-30 07:47:11 -05:00
Niko1221 0ea2fc3176 Engine 0.1.29: sampled answers up to 40% faster with the same tokens (#197), faster prompt kernels (#187, #188, #207), correctness fixes (#154); setup requires it 2026-09-30 14:01:53 +02:00
Niko1221 bb628ce12f A fatal CUDA fault in the prompt path exits at once instead of hanging until the watchdog (#224); CMake warns when sm_120 is built with CUDA < 13.0 (#220, #224); iq_pack writes native_experts.txt under a temporary name, so a stop part-way leaves no partial pack (#172) 2026-09-30 14:01:52 +02:00
Niko1221 c3242f095c generate: the session state is zeroed for every pack in CLI generate mode (#167 follow-up); no .pi/ ignore line 2026-09-30 14:01:52 +02:00
Enky 15dd501b05 tests: bitwise check of native_mmvq's multi_exact contract, with a negative control (#148; CMake on the backend variables, CUDA-only) 2026-09-30 14:01:52 +02:00
samuelishida 0ace554231 generate: zero session state for a native pack before the prompt path
The canonical path zeroes session state from put_input at position 0, but a
native pack breaks out of that loop before the first put_input and runs verify
windows instead, leaving cudaMalloc'd state uninitialized. On a reused
allocation that produced NaN/overflow and degenerate identical-token output.
Zero the state explicitly when native_pack is set.

Also removes an unused argmax() helper that emitted a compiler warning, and
ignores the local .pi/ harness directory.
2026-09-30 14:01:52 +02:00
architectds b353a06128 setup: the 3-bit models' 262K context is counted against RAM, not a fixed 90 GB
IQ3_S and IQ3_XXS asked for 262K were cut to 128K on any machine under
90 GB of RAM. The limit is now counted: the experts' arena, plus the
context's 8-bit KV (in RAM with KV streaming, ~13.7 KB a token), plus
24 GB of room.

- A 64 GB PC still gets 128K for both models, as before.
- A box with ~84 GB keeps the 262K it asked for. A Colab A100-40G
  (83.5 GiB) runs IQ3_S at 262K, with images, in 56 GiB.
2026-09-30 14:01:52 +02:00
Hendrik PolczynskiandCodex ba1c809948 Show prefill speed alongside decode speed in dashboard
Display both rates in t/s with independent graph scales and a darker
prefill curve. Expose prefill_tok_s_mean using the engine's existing
rate, excluding cached tokens.

Co-authored-by: Codex (gpt-6-astra-medium) <[email protected]>
2026-09-30 14:01:52 +02:00
Joost R. 1564404f62 WSL2: survive the driver's ~1 GiB pinned host budget with 3 GPUs
Under WSL2 the NVIDIA driver can pin/map only about 1 GiB of host memory in
total (dmesg: "dxgk: create_existing_sysmem: establish_gpadl failed: -122").
With --expert-cache-device1/2 the startup ran out of it twice:

- CUDA2's context is created after CUDA0's weights and MTP, whose mapped host
  buffers have spent the budget: "CUDA2 experts: cudaSetDevice(2) failed: out
  of memory". STRATA_EARLY_REMOTE_CONTEXTS=1 now creates every secondary
  context up front, like CUDA1's (opt-in: the default order is unchanged).
- With three contexts up, the 260 MiB mapped native embedding no longer fits:
  "native embedding: cannot pin 260 MiB". It now falls back to a device copy
  on the current GPU instead of failing the start.

Measured in Docker Desktop (WSL2), RTX 5070 Ti + 2x RTX 5060 Ti, Swift 1.5
IQ3_XXS: starts and serves with both helper caches (5000 experts each).
2026-09-30 14:01:52 +02:00
Hasegawa Takuya e258e6ec5b perf(prefill): allow explicit routed-only staging for large chunks 2026-09-30 14:01:52 +02:00
Andy be41a09e5b ple: --ple-io ram: refused on Windows (no mlock), 'locked' only when mlock succeeded else 'loaded (not locked)', neutral comments + --help (review) 2026-09-30 14:01:52 +02:00
dsh 0d40c17d2f ple: --ple-io ram locks the n-gram table in RAM (no SSD read on the prompt/token path) 2026-09-30 14:01:52 +02:00
Andy 802c6619df prefill: GDN recurrence pipelining - the neutral 16-column variant (STRATA_GDN_CB) dropped, one kernel on upstream's split (review) 2026-09-30 14:01:52 +02:00
Andy ab50d19c9b decode: QSA scores multi - comment names every caller that takes it (decode captured or not, prefill's pooled16); no box-specific note (review) 2026-09-30 14:01:52 +02:00
Apposite245 4ff986a0aa serve: on Windows the engine, vision encoder and MCP servers end with the server
Closing the console window (or a crash, or Task Manager) ends the server without its cleanup, and strata --serve,
strata-vision and the MCP servers kept running with their VRAM and RAM. Each child now goes into a job object that
kills everything in it when its only handle - the server's - closes; what the children start joins it too. The
server itself stays out, so a browser --open starts is not tied to it. A no-op elsewhere.

serve/test_winjob.py: a contained child and its grandchild end when the process that contained them is killed.
2026-09-30 14:01:52 +02:00
Guillaume PUTIER 05d4cb11a5 sampler: top_k by lexicographic threshold, split over the whole GPU
The sampled path (penalties, top_k, top_p, min_p, temperature, draw) kept one
row on one SM: sampler_kernel excluded the logits already kept by sweeping the
kept list for every logit of every round, O(k^2 x n_vocab) shared-memory
compares per row, and ran the double-precision tail on all 1,024 threads.

Three implementations now pick the same token:

- Split (new default): stage 1 cuts each row into 4,096-logit blocks (61 per
  row at 248,320 logits), each warp keeps the top_k of its 1,024 penalised
  logits in registers, and the block merges its four warp lists. Stage 2, one
  warp per row, merges the block lists and runs the tail on one warp.
- sampler_one_block_kernel: one block per row, top_k rounds that each take the
  logits strictly after the previous pick in the selection order (value
  descending, id ascending). It is the fallback when the split cannot run
  (stream under graph capture, vocabulary above 262,144, more than 64 rows,
  no scratch) and is selectable with STRATA_SAMPLER_ONE_BLOCK=1.
- sampler_kernel, the previous kernel, kept unchanged as the reference and
  selectable with STRATA_OLD_SAMPLER=1.

The list, its order and the pick are unchanged: the first k of a union lie
within the first k of each part, and a merge of ordered lists is ordered. The
tail keeps the same arithmetic, with the exps and quotients shared across one
warp and the ordered sums and scans run by lane 0.

The block lists live in a per-stream scratch buffer grown on demand. A
grown-out buffer is retired rather than freed, and a failed grow is
remembered so later calls of that size do not retry cudaMalloc.

sampler_parity is the parity test. Fixtures 16 to 18 pin the whole top_k list
position by position under ties (+inf, -inf, NaN, +0/-0, sentinel id 0,
penalised tokens landing on other tokens' values), tied draws through the whole
chain, and the automatic fallbacks (graph capture, row cap). Each pick is an
integer token id compared for equality with a host reference. ctest runs the
binary once per path: sampler_parity (split), sampler_parity_one_block and
sampler_parity_old, so all three paths are held to the same expected ids.

hip_compat/cuda_runtime.h: map cudaStreamIsCapturing, cudaStreamCaptureStatus
and cudaStreamCaptureStatusNone to their hip equivalents, which the new
capture check needs on HIP builds.
2026-09-30 11:46:25 +02:00
Andy 4305fdc3fb decode: QSA block scores read each key block once for all of a window's queries (bit-identical; STRATA_SCORES_MULTI=0 = old grid) 2026-09-30 11:45:45 +02:00
Andy 18106b1c31 prefill: software-pipelined loads in the column-split GDN recurrence (bit-identical; STRATA_GDN_PIPELINE=0 = old kernel) 2026-09-30 11:45:45 +02:00
pipeob0 95883f46e8 E-2 on the AVX-2 path too: prefetch the i-quant expert rows (same switch, CPUs without AVX-512)
24d4013 put the software prefetch in iq_avx512.cpp, so it only reaches CPUs with AVX-512; the AVX-2 kernels, which is what a Zen 3 / Haswell / Skylake-client box actually runs the i-quant rows on, had none.  Same env, same default, same hint: STRATA_IQ_PREFETCH is the distance in bytes, 0 = off, default 2048.

Measured on a Ryzen 7 5700X3D (AVX-2 only, 64 GB DDR4-2666, 4 KB pages - large pages refused) with IQ3_S decode, 4 rounds interleaved, outputs identical:
  gate/up phase   13.571 -> 13.024 ms/round   (-4.0%)
  rows            25.1   -> 26.1 GB/s         (+1.0)
  whole round     45.54  -> 44.94 ms/round    (-1.3%)
and with the pool cold (first round after the arena is built) the round is -2.4%.  The same 4 rounds with STRATA_IQ_PREFETCH=0 land within 0.1% of the unpatched binary, so the patch itself costs nothing.  native_expert_parity: 0 failures with the prefetch on and off.

The non-temporal hint was measured worse than T0 at the same distance (-0.7% vs -1.3%, +0.5 vs +1.0 GB/s), so this keeps T0.  4096 is a little worse than 1024/2048, which is why the default stays 2048 as in the AVX-512 file.
2026-09-30 11:45:45 +02:00
Guillaume PUTIER 5b9a5029dc build: guard the last two bench/micro targets on their file, as upstream does for the others 2026-09-30 11:45:44 +02:00
Guillaume PUTIER 255bf03d3e gguf_reader.hpp: define NOMINMAX before windows.h 2026-09-30 11:45:44 +02:00
Guillaume PUTIER c9d3fd6877 expert_source, s2_expert_grouped: guard the verify window's fixed tables 2026-09-30 11:45:44 +02:00
Guillaume PUTIER a8d79afab7 qsa: mask cells whose page did not resolve; refuse a clock sweep over fewer slots than the resolve block 2026-09-30 11:45:44 +02:00
Guillaume PUTIER e2b0cbcde9 bf16: a NaN stays a quiet NaN in f32 -> bf16, as in ggml 2026-09-30 11:45:44 +02:00
Guillaume PUTIER 91e8d21227 s_gemv: the q8 split kernel reaches its barrier before a rowless warp returns 2026-09-30 11:45:44 +02:00
Niko1221 10409135dd Engine 0.1.28: the expert cache reserves the draft head's VRAM (0.1.27 left 16 GB cards below the stall line), a cancelled request no longer fails the next one, the API key protects /status; setup requires it 2026-09-30 11:18:54 +02:00
Niko1221 03939f1c06 docs: the draft layer's token subset and --draft-vocab 2026-09-30 11:18:54 +02:00
Niko1221 75e6efeb77 setup: --host/--api-key/--draft-vocab on a start are kept for the model (#179); --draft-vocab en keeps the English/code subset (~110 MiB less VRAM); CUDA 13.0 for RTX 50 builds (#220); llama.cpp's web UI is not unpacked (Windows path limit, #206); Swift Q2_0 hidden (#171); the earlier data folder and nested Strata-data move into --data-dir (#198); whole shards without a finish mark count (#173) 2026-09-30 10:54:45 +02:00
Niko1221 fa59b3f3a9 server: /status needs the API key and forgets the answer's end (#212); constant-time key check, an explicitly empty key refuses to start (#213); an engine exit quotes its last log line (#215); tool calls end at their own </parameter> and </tool_call>, so values may contain them (#210) 2026-09-30 10:54:45 +02:00
Niko1221 eef241178c engine: the expert cache reserves the draft head's VRAM (0.1.27's CJK subset came out of the 700 MiB reserve, #199); a clear message when no VRAM is left for the cache (#174); the prompt's verify-window stage has its own label (#217) 2026-09-30 10:54:45 +02:00
Oluwabori Olaleye 7980d3719f Expert cache on WDDM: 1 GiB steps before quarter steps (~4 GiB more cache on a 32 GB card); Ctrl+C stops the server on Windows; no stack trace when a client hangs up (#153)
Squashed from PR #153.
2026-09-30 10:46:55 +02:00
GioStrives 0425829226 verify: cudaFuncGetName only with CUDA 12.3+ (an sm_75 build with CUDA 12.0 failed)
It names kernels only for the STRATA_VERIFY_NODES debug dump.
2026-09-30 10:46:55 +02:00
Pravesh Khatana 481b69246f fix(engine): clear stale error/cancellation state between requests and before prompt prefill
When a request is cancelled during prompt reading (e.g. client disconnect
or timeout), err is set to 'cancelled'. Because err is declared in main()
and was never cleared between requests, any subsequent request in v0.1.26+
evaluated 'if (!e.empty())' in sp.on_chunk on its first chunk, immediately
failing with 'strata serve: cancelled' and terminating the engine with code 1.

Clearing err at the start of each request, before prompt segment runs,
and on entry to Prefill::run prevents state pollution across requests.
2026-09-30 10:46:55 +02:00
maxfridbe 6396c46971 docs: INTEL.md - the merged port's numbers on the B70 (46.5 / 38.3 tok/s decode, 566 tok/s prompt) 2026-09-30 01:03:42 -05:00
maxfridbe b88eff688b sycl: refresh the port for upstream 0.1.25-0.1.27 (re-migration merge), AOT divide rounding, hybrid K8V4 KV
The merge of upstream main (99b4097) left 28 migrated copies behind. They are refreshed by re-migration:
dpct over the old and the merged tree, sycl/tools/normalize.sh (dpct's names, unchanged files, message
serials, fixups.py) on both, then a 3-way merge per file. Copies dpct never produced (verify.cpp, mtp.cpp)
take upstream's K8V4 diff by hand. The PTX gate fixup follows upstream's new __HIPCC__ guard (#elif).

The AOT build never received -cl-fp32-correctly-rounded-divide-sqrt (it went to the spir64 backend, which
an AOT build does not have): quantize_act_parity had its 303k mismatches back. The option now reaches
ocloc through -device "... -options ...". 19 of 22 parity tests pass again; kv_hybrid_parity (new) passes
all but its tensor-core step and is built, not registered.

B70, merged engine, AOT, --stream-experts --no-prefill-borrow --spec 4 --mtp: 2,184-token prompt 566.5
tok/s (was 475), decode 38.3 tok/s at that context (was 42.7; 77% draft acceptance on this text), MTP
prompt pass 38.6 ms (E-9 batched).
2026-09-30 01:01:25 -05:00
maxfridbe ac14e76bf5 Merge remote-tracking branch 'origin/main' into b70
# Conflicts:
#	setup.py
2026-09-30 00:10:48 -05:00
maxfridbe 828c3be921 docs: 42.7 tok/s decode at the 2,185-token context with MTP (prompt 475 tok/s in the same run) 2026-09-29 23:59:36 -05:00
maxfridbe d49f4b9d0f docs: 45.3 tok/s decode with the base model's MTP draft layer (87% accepted) - 1.8x llama.cpp on the same card 2026-09-29 23:58:26 -05:00
maxfridbe c550299fa8 docs: like-for-like against llama.cpp on the same prompt - prompt 560 vs 138-319 tok/s, decode 20.8 vs 24-26 2026-09-29 23:53:00 -05:00
maxfridbe 0b6624317a sycl: Q6_K 16-byte-load kernel (wide projections only), mmvq bench correctness check; bandwidth probe
bw probe (incompressible data): 4-byte loads stream at 395 GB/s, 16-byte at 596. The Q6_K matvec sits at
130-160 GB/s in every variant tried (lanes per row, rows per warp, unroll, 16-byte loads, software
pipelining): latency-bound on a dependent load->unpack->dp4a chain, not ALU or bandwidth. The 16-byte
kernel is kept for n_out >= 4096 (+13% there, slower on small shapes); rel 5e-8 against the shared one.
Decode 20.80 tok/s (spec 2). The drafter is the lever now: MTP fetch + pack running.
2026-09-29 23:51:36 -05:00
maxfridbe 1a234406dc sycl: long prompts - 693 tok/s at 2k tokens; the streaming source is a thread-safe 512-slot keyed cache
The prompt path collects hundreds of blob pointers per layer and copies from them on other threads later;
the 8-slot ring handed back pointers that were overwritten by then, and its index was not thread-safe.
Slots are now keyed by (layer, expert), reused oldest-first among 512 (~1.4 GB), under a mutex.

Long prompts also hung in the prompt path's streamed-expert handshake (lent cache slots make experts
non-resident, the host supplies them behind a flag the GPU wait kernel does not see). --no-prefill-borrow
keeps every expert resident and removes the handshake: 2,000 tokens 693 tok/s, 2,185 tokens 560 tok/s,
300 tokens 180 tok/s (llama.cpp on the same card: 150 short, 424 at 105k).

Rig: watchdog reports and kills a hung run at the expected time (EXPECT_S/QUIET_S); --spec 2 default
(20.75 tok/s decode vs 16.95 at spec 4: the suffix drafter accepts 9%).
2026-09-29 23:19:30 -05:00
maxfridbe 2eab02c231 sycl: clean exit, per-kernel profiling, Q6_K unpack hoisted; measured: the mmvq kernels run at 110-130 GB/s warm
- exit segfault: dpct's static global_memory/constant_memory objects destructed after the default queue
  (queue::get_device in the core); heap-allocated, never freed. Exit code 0; unitrace can write its table.
- Dockerfile.unitrace (pti-gpu unitrace in the dev image) + sycl/rank_kernels.py: per-kernel device time.
- Q6KTraits: the column-independent unpack (shifts, masks, saturating byte subtract) moved into load();
  acts()/dot() split; a row-blocked kernel (native_mmvq_rowwarp_kernel, STRATA_MMVQ_RPW) kept but off:
  with a 300 ms warm-up the shared kernel already does 2560x2560x4 in 48 us (110 GB/s) and the variants tie.
- mmvq_bench: the dense kernel timing harness (warm-up + 400 iterations; a 5 ms run measures the clock ramp).
2026-09-29 22:35:48 -05:00
maxfridbe 8b804379cc sycl: fused multi-token router for 256 experts (was 512-only); 16.95 tok/s decode
route<NE> templated on the expert count; native_router_top10_multi_ne dispatches 256/512. Both call sites
(the verify window and the per-token moe_route) take it for the Coder. 64 tokens: 16.25 -> 16.95 tok/s,
same output. Also: Dockerfile.unitrace (per-kernel Level Zero profiling image).
2026-09-29 21:53:31 -05:00
maxfridbe 27ca717e75 sycl: multi-entry expert dots - the resident-expert kernels 2.3x faster on iq3_xxs layers
A window routes the same expert for up to 6 tokens; the grouped kernels recomputed the dequantised weights
(grid lookups, sign unpacking, the byte-wise compare/xor/subtract emulations) once per token. Multi<TY>
splits each of the five formats this model uses (iq2_s, iq3_xxs, iq3_s gate/up; iq4_nl, q2_0 down) into
prep (once) and acts + finish (per token); the kernels take entries four at a time. Lanes per row is a
compile-time constant (STRATA_EXPERT_LANES, 8): 32 lanes on an 80-call row was mostly reduction.

Measured with the new NATIVE_BENCH=1 mode of native_expert_parity (10 experts x 4 entries, one layer):
iq3_xxs/iq4_nl 1.467 -> 0.649 ms, iq2_s/q2_0 ~0.68 -> 0.579 ms, iq3_s/iq4_nl 0.750 ms; parity unchanged.
strata::dp4a wraps dpct::dp4a (sycl::ext::oneapi::dot_acc is the same emulation with a header that breaks
the link across translation units).
2026-09-29 18:30:57 -05:00
maxfridbe 46ecab1310 sycl: AOT build (bmg-g31) - 15.2 tok/s decode, 28.8 tok/s prompt, first token in 0.85 s, no JIT
The -Xs device flag was mis-quoted; fixed. Measured on the B70 with the same 19-token prompt, 32 tokens:
decode 15.17 tok/s, prefill 28.79 tok/s, a 4-token window 73 ms on the card. The persistent JIT cache
(SYCL_CACHE_PERSISTENT=1) is the alternative for the JIT build: 15 MB, second start 15.6 tok/s.
2026-09-29 18:14:41 -05:00
maxfridbe 9af6ce12e3 sycl: ~13 tok/s steady state, coherent 64-token output; window timing, eager stage profiler, docs
Measured on the B70: 64 tokens in 52.0 s, of which ~47 s is the first window (the runtime JIT-compiles
every kernel on first use: 6 tokens take 47.5 s, 64 take 52.0 s). The output is the model's real answer.

Debug tooling kept in the port: STRATA_VERIFY_EAGER=1 runs the window on the queue instead of as a graph
and turns the stage stamps into host clocks, so STRATA_VERIFY_PROFILE=1 prints ms per stage without a
device timer; STRATA_VERIFY_DEBUG=1 prints the residual after every layer and the round's phase times.
build.sh takes BUILD_DIR and AOT (an ahead-of-time bmg-g31 build removes the JIT cost).
2026-09-29 18:04:13 -05:00
maxfridbe cf0e9c1e6e sycl: first light - the SYCL engine generates correct text on the Arc Pro B70
--stream-experts (GgufExpertSource): every expert goes straight from the GGUF into the VRAM cache through a
small ring of staging buffers; no resident host arena, so the engine runs on a 23 GiB machine.

What it took to get from "loads" to "<think>\nThe user wants a Python function":
- the doorbell handshake through host-mapped memory: volatile device loads do not bypass the caches on
  Intel; system-scope atomics (strata::sys_load/sys_store) do. A device-side spin is bounded (kSpinMax): an
  unbounded one wedged the GT twice when its process died.
- STRATA_VERIFY_NO_HOST=1 + STRATA_VERIFY_DEVICE_PLAN=1: with every expert resident the GPU plans each
  layer itself and the host waits for the whole window graph; per-layer ring visibility inside a graph is
  not reliable on this platform (measured with sycl/probe).
- -fsycl-default-sub-group-size=32: the kernels are written for 32-lane warps; dpct pinned only 134 of 289.
- cudaMemcpy is synchronous; dpct's default-queue memcpy had no wait, and the streaming ring reuses its
  buffers - the expert cache filled from overwritten memory (non-deterministic residuals, NaN by layer 5).
- native_expert_parity hand-ported (dpct cannot parse it without ggml-cpu.h): the GPU native expert
  kernel matches the float reference on real IQ1_M rows.
- verify.cpp debug readbacks (STRATA_VERIFY_DEBUG): the per-layer residual ladder that found all of it.

Not yet: speed (0.17 tok/s - the spin budgets), the segfault at exit, the tensor-core kernels.
2026-09-29 17:40:54 -05:00
maxfridbe a1c47bc90b sycl: the CUDA engine migrated to SYCL - builds with oneAPI, 19 of 22 kernel parity tests pass on the Arc Pro B70
The port lives in sycl/ and changes no upstream file: sycl/src and sycl/include hold only the files the
migration touched, sycl/CMakeLists.txt takes everything else from the original tree.

How it was made, reproducibly (sycl/tools/): a dev image (the llama.cpp SYCL image + SYCLomatic 2025.3 +
CUDA 12.8 headers from the pip wheels), migrate.sh (compilation database + dpct over 86 translation
units), fixups.py (every hand fix with its reason, idempotent), build.sh (icpx, ninja).

What dpct got wrong and the script repairs: CUDA's null stream became a null sycl::queue* (strata::q_of
maps it to the default queue); __ldg((const float*) p) lost its cast and read one byte; __fadd_rn lost
parentheses; ggml's lookup tables were threaded through kernel parameters with the wrong table per
template; helper headers renamed since 2025.3; cudaGraphUpload, graph introspection and %globaltimer
have no equivalents. Two compiler flags are load-bearing: -fp-model=precise, and the device compiler's
-cl-fp32-correctly-rounded-divide-sqrt - the Arc's fp32 divide is not correctly rounded by default, and
quantize_act_parity went from 303k mismatches to byte-exact with it.

Not ported: the three kernels with inline PTX (mma.sync, ldmatrix, cp.async) take their existing
pre-sm_80 fallback; the launchers refuse the device. The XMX joint_matrix versions are next.

The engine itself starts on the card, loads the pack, the projections, the PLE table and the 23.4 GiB
expert arena, and is then stopped by the test rig's memory guard: Strata keeps the experts as a resident
host copy, and the rig has 23 GiB of RAM (upstream asks for 32). A streaming fill of the VRAM cache
from the GGUF is the next piece; the whole model fits in the 32 GB card.
2026-09-29 14:06:20 -05:00
maxfridbe 39fdc3a56b docs: 128k context proven on the B70 - a 105k-token prompt read at 424 tok/s
Prompt reading scales up with prompt size (150 tok/s at 2.7k, 424 tok/s at 105k), so the full
window costs about five minutes, not fifteen. 30.3 GB in use with 1.5 GB free at 131,072.
2026-09-29 11:36:51 -05:00
maxfridbe 39cc2087e0 docs/INTEL.md: how much context fits on a 32 GB card, measured
About 20 KiB of KV per token (only 12 of 48 layers are full attention). 32k, 64k, 96k and 128k all
load with the whole model on the card, 128k with 1.6 GB to spare; 160k is under the safety margin
and 256k does not fit - asking for it spilled VRAM into host RAM and took the machine down until its
watchdog reset it, so the doc says so in bold.
2026-09-29 11:29:19 -05:00
maxfridbe 4ce698f199 gitignore: start-llama.sh, generated by setup on the Intel path 2026-09-29 11:14:27 -05:00
maxfridbe 3aa60f0e37 README: the Intel Arc port and the rig it was tested on, up top 2026-09-29 11:10:24 -05:00
maxfridbe f6e71c1c80 docs/INTEL.md: --port and --host, learned the hard way (8080 is open-webui here) 2026-09-29 11:09:39 -05:00
maxfridbe ca344a7c90 setup: an Intel Arc path (no CUDA), and the run script starts llama-server itself
Without nvidia-smi, setup now looks for an Intel discrete GPU in sysfs (vendor 0x8086 under xe or
i915, named by PCI id - lspci's database does not know an Arc Pro B70 yet) and takes a path with no
compiler and no CUDA toolkit: download the model, export the tokenizer, find a llama-server
(--llama-server PATH, one on PATH, or the B70 container image via docker), write a config with a
"llama" block and a start-llama.sh, and a run script that uses --engine llama.

The CUDA engine's rules that do not apply are stepped around rather than deleted: the compute
capability and driver-version checks, the experts-in-RAM gates (on llama.cpp the fit is VRAM,
shard 1 = the download minus the 28.8 GB lookup table), the MTP draft download (5 GB the llama
engine cannot use), and the engine's own argument list.

engine_from_config runs the config's start script when nothing answers at the url, so the run
script is one click and closing the server stops the container.

Verified on an Arc Pro B70: setup runs steps 1-7 clean against the downloaded Coder IQ1_M.
docs/INTEL.md has the whole picture and the measurements.
2026-09-29 11:09:39 -05:00
maxfridbe b3470a1722 serve: a llama.cpp engine behind the same boundary (--engine llama)
The Strata engine is CUDA. On a GPU without it - written for and measured on an Intel Arc Pro
B70 - the same GGUF weights run through llama.cpp's SYCL backend. serve/engine_llama.py puts
llama-server behind Engine.generate(ids, max_new, sampling, cancel), so the OpenAI and
Anthropic endpoints, streaming, tool calls, MCP and the web app are unchanged above it.

It sends the prompt as token ids (the server's own tokenizer, from the same GGUF) with
return_tokens, streams ids back with llama-server's timings mapped onto Strata's `last`,
heartbeats while a long prompt is read, and stops the server by closing the connection when a
client goes away. Attach to a running server ("llama": {"url"}) or spawn one ("llama": {"exe"}).

Not yet: images (Strata's Vision produces embeddings for the CUDA engine; llama-server takes
the image itself) - start without "vision" and image requests are refused cleanly.

Tests: a scripted llama-server (the wire format observed on b29c606), plus a live round trip
when STRATA_LLAMA_URL is set. Measured on the B70 with Coder IQ1_M: 23-25 tok/s decode,
~150 tok/s prefill, correct code, GPU-bound.
2026-09-29 11:09:39 -05:00
743 changed files with 256812 additions and 4187 deletions

No files matched your search

+27
View File
@@ -0,0 +1,27 @@
# Keep the image to the source only: everything generated is re-created on
# first start (inside the container or on the /data volume).
.git
# local Python environment (rebuilt in the image)
.venv/
__pycache__/
*.pyc
.pytest_cache/
# setup.py outputs and downloads (engine, packs, models, logs)
/engine/
/build/
/build*/
/dist/
/packs/
/mtp/
/models/
/Strata-data/
third_party/llama.cpp/
third_party/*.zip
*.done
*.log
strata-*.json
strata-*.txt
run-*.sh
run-*.bat
+3
View File
@@ -4,3 +4,6 @@ bench/prompts/** -text
# launchers keep their platform line endings wherever the repository is cloned
*.sh text eol=lf
*.bat text eol=crlf
# copies of real packs' native_experts.txt, parsed byte for byte by tests/core/expert_layout_test.cpp
tests/data/native_experts/** -text
+1
View File
@@ -0,0 +1 @@
buy_me_a_coffee: strataengine
+15 -1
View File
@@ -18,6 +18,8 @@ __pycache__/
# plan v0.3 P1 (repository hygiene, review E1): profiler captures and large diagnostic dumps stay out of git.
*.nsys-rep
# Pi harness metadata (local session state, not project source)
*.sqlite
*.npz
*.occ1
@@ -26,7 +28,7 @@ td.log
# created by setup.py on the user's machine
/.venv/
/build/
/third_party/llama.cpp/
/third_party/llama.cpp
/models/
/packs/
/mtp/
@@ -35,15 +37,27 @@ td.log
/strata-*.json
/strata-*.log
/build-strata.bat
/build-strata-cuda12.bat
/build-cuda12/
/.strata-mcp/
# image encoder (setup.py --vision): build output and the generated build script
build-vision*/
build-vision.bat
build-vision-cuda12.bat
# setup.py outputs (engine, downloads) and release builds
/engine/
/engine-cuda12/
/build-release*/
/dist/
*.done
/third_party/*.zip
# IDEs
.vscode/
.idea/
.cursor/
/.ccache/
/.rocm-win/
+23
View File
@@ -0,0 +1,23 @@
# AGENTS.md
Strata runs the Qwen3.8-Flash-Next mixture-of-experts model (and its Coder, Swift 1.5 and Unsloth variants) on a
normal PC: one NVIDIA or AMD graphics card plus system RAM, on Windows or Linux. It has a C++/CUDA/HIP engine
(`src/`, `include/`), a Python server with an OpenAI- and Anthropic-compatible API and a web app (`serve/`), and a
one-click installer (`setup.py`, started by `START-HERE.bat` / `setup.sh`).
## Installing Strata for a user
Follow **[docs/AI_SETUP.md](docs/AI_SETUP.md)**: check the PC, pick the model by RAM, run setup non-interactively,
start and verify the server, and connect the user's apps. Never expose the server beyond `127.0.0.1` without
`--api-key`. As an alternative to shell commands, Strata's MCP server ([docs/MCP_SERVER.md](docs/MCP_SERVER.md))
offers the same steps as tools.
## Working on the code
- How the engine works, every measured number, the API and all settings: [docs/DETAILS.md](docs/DETAILS.md) and
the [paper](docs/paper/Strata-Paper.pdf).
- AMD (HIP) build and validation: [docs/AMD_HIP.md](docs/AMD_HIP.md); multi-GPU: [docs/MULTI_GPU.md](docs/MULTI_GPU.md).
- Setup's own tests run without a GPU or downloads: `python tools/test_setup_<name>.py` (for example
`tools/test_setup_amd.py`, `tools/test_setup_choices.py`).
- Keep the docs' style: plain words, measured numbers with what they were measured on, no claims without a
measurement.
+691 -24
View File
@@ -8,7 +8,18 @@
# below refuses anything older: silently building for a pre-Ampere arch would produce a binary that runs
# and is wrong about its own performance, which is the worst of both outcomes.
cmake_minimum_required(VERSION 3.24)
project(strata VERSION 0.1.27 LANGUAGES CXX)
project(strata VERSION 0.1.40 LANGUAGES CXX)
# EXPERIMENTAL: the Intel Arc engine, the SYCL port in sycl/ (PR #423; icpx + oneMKL, docs/INTEL_ARC.md). It is its
# own project that takes the unported sources from src/; with this on, nothing below is configured.
option(STRATA_ENABLE_SYCL "EXPERIMENTAL: build the Intel Arc (SYCL) engine from sycl/ - docs/INTEL_ARC.md" OFF)
if(STRATA_ENABLE_SYCL)
if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
message(FATAL_ERROR "STRATA_ENABLE_SYCL is a separate backend; leave STRATA_ENABLE_CUDA and STRATA_ENABLE_HIP off")
endif()
message(WARNING "STRATA_ENABLE_SYCL: the Intel Arc engine is experimental (community port, docs/INTEL_ARC.md)")
add_subdirectory(sycl)
return()
endif()
add_compile_definitions(STRATA_VERSION="${PROJECT_VERSION}")
# issue #31: release builds keep a PDB beside the exe (not shipped in it), so a minidump from a stalled engine can
# be read back to the exact source line
@@ -21,6 +32,18 @@ endif()
# instead of this machine's (Strata's own AVX-512 kernels are per-file and chosen at run time either way), and
# the MSVC runtime linked in, so no Visual C++ redistributable is needed.
option(STRATA_PORTABLE "build for other PCs: AVX2 baseline, static MSVC runtime" OFF)
# EXPERIMENTAL, opt-in: an engine for CPUs without AVX2 (#394, #595, #623), compiled on that PC. ggml-cpu, which then
# computes every CPU expert row, is built for this floor instead of AVX2 or the build host: "avx" (Sandy/Ivy Bridge:
# AVX, no FMA/F16C/AVX2) or "none" (SSE4.2 + POPCNT: Nehalem/Westmere). Strata's own AVX2/AVX-512 kernels stay in the
# binary behind their CPU checks; the router lookahead gets an AVX1 kernel. Empty (the default) changes nothing.
set(STRATA_ISA_FLOOR "" CACHE STRING "experimental older-CPU build: empty (default, AVX2 floor), avx, or none (SSE4.2)")
set_property(CACHE STRATA_ISA_FLOOR PROPERTY STRINGS "" avx none)
if(NOT STRATA_ISA_FLOOR STREQUAL "" AND NOT STRATA_ISA_FLOOR STREQUAL "avx" AND NOT STRATA_ISA_FLOOR STREQUAL "none")
message(FATAL_ERROR "STRATA_ISA_FLOOR must be empty, avx or none (got '${STRATA_ISA_FLOOR}')")
endif()
if(STRATA_ISA_FLOOR AND STRATA_PORTABLE)
message(FATAL_ERROR "STRATA_ISA_FLOOR (an older-CPU build) and STRATA_PORTABLE (the AVX2 release build) exclude each other")
endif()
if(STRATA_PORTABLE AND MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded")
endif()
@@ -33,12 +56,36 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
endif()
option(STRATA_ENABLE_CUDA "Build the CUDA targets (Phase 2+)" OFF)
option(STRATA_ENABLE_HIP "Build the HIP targets for gfx1100 wave32 hardware" OFF)
# AMD gfx906 (MI50, wave64): the same .cu sources compiled as HIP through the gfx906 compat layer. The CUDA runtime and
# cuBLAS names are mapped by the headers in include/strata/platform/hip_compat/, which go first on the include path,
# and CUDA::cudart / CUDA::cublas become aliases of HIP's targets, so every CUDA target below stays as it is. This is
# separate from STRATA_ENABLE_HIP (the wave32 RDNA backend): with it on, STRATA_ENABLE_CUDA is on and
# STRATA_ENABLE_HIP stays off, so every "CUDA" branch of the tree is the one taken.
option(STRATA_HIP_GFX906 "Build the CUDA targets for AMD gfx906 through HIP (wave64 compat layer)" OFF)
if(STRATA_HIP_GFX906)
if(STRATA_ENABLE_HIP)
message(FATAL_ERROR "STRATA_HIP_GFX906 and STRATA_ENABLE_HIP are separate backends; enable only one")
endif()
set(STRATA_ENABLE_CUDA ON CACHE BOOL "" FORCE)
endif()
option(STRATA_ENABLE_HIP "Build the HIP targets for wave32 AMD GPUs (gfx1100, gfx1201; gfx1012/gfx1030 unvalidated)" OFF)
option(STRATA_PREFILL_MMQ "Build the optional GGML MMQ prefill path for HIP" OFF)
# CUDA: MMQ prompt kernels for Q4_K / Q5_K / Q5_1 (Unsloth's UD-Q4_K_XL experts). Off by default: the engine loads
# every kernel when it starts (CUDA_MODULE_LOADING=EAGER), so these took ~5 MB of VRAM - 1-3 expert slots - from every
# model, and the UD-Q4_K_XL prompt is SSD-bound with or without them (docs/UNSLOTH_Q4.md)
option(STRATA_MMQ_KQUANTS "Build the MMQ prompt kernels for Q4_K / Q5_K / Q5_1 / Q6_K: the CUDA experts of Unsloth's UD-Q4_K_XL, and on HIP the dense GGUF projections (STRATA_DENSE_MMQ)" OFF)
# CUDA: Q6_K gate/up in the grouped expert kernels (Unsloth's UD-Q6_K_XL, docs/UNSLOTH_Q6.md). Off by default: every
# grouped-kernel instance is loaded when the engine starts (CUDA_MODULE_LOADING=EAGER), so one more costs VRAM that
# every other model would lose as expert slots (PR #860 review)
option(STRATA_Q6K_EXPERTS "Build the Q6_K gate/up grouped expert kernels (UD-Q6_K_XL)" OFF)
if(STRATA_Q6K_EXPERTS)
add_compile_definitions(STRATA_Q6K_EXPERTS=1)
endif()
option(STRATA_ORCA_Q4KS_MMQ "Build the GGML Q5_0 MMQ instance for OrcaRouter Q4_K_S" OFF)
if(STRATA_PREFILL_MMQ AND NOT STRATA_ENABLE_HIP)
message(FATAL_ERROR "STRATA_PREFILL_MMQ requires STRATA_ENABLE_HIP=ON")
endif()
if(STRATA_ENABLE_CUDA AND STRATA_ENABLE_HIP)
if(STRATA_ENABLE_CUDA AND STRATA_ENABLE_HIP AND NOT STRATA_HIP_GFX906)
message(FATAL_ERROR "STRATA_ENABLE_CUDA and STRATA_ENABLE_HIP are separate backends; enable only one")
endif()
if(STRATA_ENABLE_HIP)
@@ -50,13 +97,58 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt AND EXISTS ${CMAKE_CU
set(_strata_tests_default ON)
endif()
option(STRATA_BUILD_TESTS "Build the test suite" ${_strata_tests_default})
option(STRATA_BUILD_CONVERSATION_TESTS "Build standalone conversation cache tests" OFF)
option(STRATA_WERROR "Treat compiler warnings as errors" OFF)
if(STRATA_ENABLE_CUDA)
if(STRATA_BUILD_CONVERSATION_TESTS)
enable_testing()
add_executable(conversation_cache_test src/core/conversation_cache_test.cpp)
target_include_directories(conversation_cache_test PRIVATE include)
add_test(NAME conversation_cache_test COMMAND conversation_cache_test)
add_executable(conversation_split_failure_test src/core/conversation_split_failure_test.cpp)
target_include_directories(conversation_split_failure_test PRIVATE include)
add_test(NAME conversation_split_failure_test COMMAND conversation_split_failure_test)
add_executable(conversation_memory_test src/core/conversation_memory_test.cpp src/core/conversation_memory.cpp)
target_include_directories(conversation_memory_test PRIVATE include)
add_test(NAME conversation_memory_test COMMAND conversation_memory_test)
add_executable(conversation_file_test src/core/conversation_file_test.cpp src/core/conversation_file.cpp)
target_include_directories(conversation_file_test PRIVATE include)
add_test(NAME conversation_file_test COMMAND conversation_file_test)
endif()
if(STRATA_HIP_GFX906)
if(NOT DEFINED CMAKE_HIP_ARCHITECTURES)
set(CMAKE_HIP_ARCHITECTURES gfx906 CACHE STRING "HIP architectures" FORCE)
endif()
enable_language(HIP)
find_package(hip REQUIRED)
find_package(hipblas REQUIRED)
add_library(CUDA::cudart INTERFACE IMPORTED)
target_link_libraries(CUDA::cudart INTERFACE hip::host)
target_compile_definitions(CUDA::cudart INTERFACE STRATA_HIP_GFX906=1 __HIP_PLATFORM_AMD__=1)
target_include_directories(CUDA::cudart BEFORE INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include/strata/platform/hip_compat)
add_library(CUDA::cublas INTERFACE IMPORTED)
target_link_libraries(CUDA::cublas INTERFACE roc::hipblas CUDA::cudart)
set(CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/include/strata/platform/hip_compat)
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/include/strata/platform/hip_compat)
add_compile_definitions(STRATA_HIP_GFX906=1)
message(STATUS "Strata: HIP (gfx906 compat) enabled, arch ${CMAKE_HIP_ARCHITECTURES}")
set(_strata_gpu_runtime_target CUDA::cudart)
set(_strata_gpu_blas_target CUDA::cublas)
set(_strata_gpu_include_directories ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
elseif(STRATA_ENABLE_CUDA)
# #585: CMake links CUDA code with the STATIC runtime by default, and the targets below also link CUDA::cudart (the
# DLL's import library). MSVC with a CUDA 12.x toolkit - the experimental Pascal/Volta build - then fails with
# LNK1169 (every cudart symbol defined twice); GNU ld lets it pass. That build links the shared runtime alone. The
# ready-made engine (CUDA 13, no STRATA_EXPERIMENTAL_SM60) is unchanged; -DCMAKE_CUDA_RUNTIME_LIBRARY overrides.
if(MSVC AND STRATA_EXPERIMENTAL_SM60 AND NOT DEFINED CMAKE_CUDA_RUNTIME_LIBRARY)
set(CMAKE_CUDA_RUNTIME_LIBRARY Shared)
endif()
enable_language(CUDA)
# `enable_language(CUDA)` gives the .cu compile rules but NOT the imported targets, so `CUDA::cudart` has to
# be brought in explicitly for the host-side tests that call cudaMalloc themselves.
find_package(CUDAToolkit REQUIRED)
option(STRATA_EXPERIMENTAL_SM60 "community build for GPUs below compute capability 7.5: Pascal sm_60, Volta sm_70 (#236)" OFF)
if(NOT DEFINED CMAKE_CUDA_ARCHITECTURES)
set(CMAKE_CUDA_ARCHITECTURES 120 CACHE STRING "CUDA architectures" FORCE)
endif()
@@ -68,19 +160,40 @@ if(STRATA_ENABLE_CUDA)
if(_base STREQUAL "native" OR _base STREQUAL "all" OR _base STREQUAL "all-major")
continue()
endif()
if(_base LESS 75)
# STRATA_EXPERIMENTAL_SM60: a Pascal (sm_60, GP100-class) or Volta (sm_70, V100 / Titan V, #236) build.
# These sit below every architecture the kernels were written for, so two intrinsics are replaced below
# their arch - `__dp4a` (6.1+) and `__nanosleep` (7.0+) - in include/strata/kernels/dp4a.hpp, which is
# bit-exact for the first and merely a shorter pause for the second (sm_70 has both). Community-tested,
# not in the ready-made engine; RTX 20/30/40/50 cards must use the release engine instead. It needs a CUDA
# 12.x toolkit: CUDA 13 dropped sm_60 and sm_70 (nvcc fails CMake's compiler test with "compute_70").
if(_base LESS 75 AND NOT STRATA_EXPERIMENTAL_SM60)
message(FATAL_ERROR
"Strata needs an NVIDIA GPU of compute capability 7.5 or newer (RTX 20 / 30 / 40 / 50 series), but "
"CMAKE_CUDA_ARCHITECTURES is '${CMAKE_CUDA_ARCHITECTURES}'.")
"CMAKE_CUDA_ARCHITECTURES is '${CMAKE_CUDA_ARCHITECTURES}'. (A Pascal sm_60 or Volta sm_70 build is "
"-DSTRATA_EXPERIMENTAL_SM60=ON; upstream does not support it.)")
endif()
if(_base LESS 60)
message(FATAL_ERROR "CMAKE_CUDA_ARCHITECTURES '${CMAKE_CUDA_ARCHITECTURES}': even the experimental build "
"needs compute capability 6.0 (sm_60) or newer")
endif()
# #220 / #224: RTX 50 engines built with CUDA 12.8 crashed in the prompt path on Linux (13.0 and newer did not)
if(_base GREATER_EQUAL 120 AND CMAKE_CUDA_COMPILER_VERSION VERSION_LESS 13.0)
message(WARNING "Building for sm_${_base} (RTX 50) with CUDA ${CMAKE_CUDA_COMPILER_VERSION}: engines built with "
"CUDA 12.8 crashed on long prompts on these cards (issues #220, #224). Use CUDA 13.0 or newer.")
endif()
endforeach()
if(STRATA_EXPERIMENTAL_SM60)
# every target sees it: the Pascal / Volta code paths (the Volta prompt attention, PR #600) are compiled into this
# build only, so the ready-made engine (sm_75+) keeps exactly the code it had
add_compile_definitions(STRATA_EXPERIMENTAL_SM60=1)
endif()
message(STATUS "Strata: CUDA enabled, arch ${CMAKE_CUDA_ARCHITECTURES}")
set(_strata_gpu_runtime_target CUDA::cudart)
set(_strata_gpu_blas_target CUDA::cublas)
set(_strata_gpu_include_directories ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
elseif(STRATA_ENABLE_HIP)
set(_strata_gpu_runtime_target strata_hip_runtime)
set(_strata_gpu_blas_target roc::hipblas)
set(_strata_gpu_blas_target ${STRATA_HIP_BLAS_TARGETS})
set(_strata_gpu_include_directories ${STRATA_HIP_COMPAT_INCLUDE_DIR})
endif()
@@ -127,6 +240,16 @@ if(STRATA_BUILD_TESTS)
add_executable(gguf_reader_test src/artifact/gguf_reader_test.cpp)
target_link_libraries(gguf_reader_test PRIVATE strata_artifact)
add_test(NAME gguf_reader_test COMMAND gguf_reader_test)
# a split model's shards and their joint view: missing shard, split keys, duplicates, truncation (synthetic)
add_executable(gguf_split_test tests/core/gguf_split_test.cpp)
target_link_libraries(gguf_split_test PRIVATE strata_artifact)
add_test(NAME gguf_split_test COMMAND gguf_split_test)
# the hipBLASLt tuning header's architecture gate: RDNA4 siblings share solution IDs, RDNA3 siblings share
# theirs, cross-family pairs and version mismatches stay rejected (synthetic tables: no model, no GPU)
add_executable(tuning_header_arch_family_test tests/prefill/tuning_header_arch_family_test.cpp)
target_include_directories(tuning_header_arch_family_test PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/prefill")
add_test(NAME tuning_header_arch_family_test COMMAND tuning_header_arch_family_test)
endif()
# ---- strata_plan ----------------------------------------------------------
@@ -145,6 +268,10 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
add_library(strata_core STATIC src/core/device.cu src/core/pinned.cu src/platform/memory.cpp src/core/graph.cpp src/core/weights.cpp
src/core/layout.cpp)
target_include_directories(strata_core PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
if(STRATA_ENABLE_CUDA AND STRATA_EXPERIMENTAL_SM60)
# the runtime device check (src/core/device.cu) admits the cards this build was made for (#236)
target_compile_definitions(strata_core PRIVATE STRATA_EXPERIMENTAL_SM60=1)
endif()
# The selected runtime is PUBLIC because graph.cpp is a HOST translation unit that calls cudaGraphLaunch and
# cudaEventQuery: the .cu sources get cudart through the CUDA language rules, a .cpp does not, and the
# linker error ("unresolved external symbol cudaGraphInstantiate") names the function rather than the cause.
@@ -227,12 +354,30 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
src/platform/direct_file.cpp)
target_link_libraries(strata_kernels PUBLIC strata_core strata_artifact)
# perf-review D-1: the tensor-core prompt attention vs the FP32 kernel and FP64 (GPU, synthetic, no model); with
# the tests, or alone with -DSTRATA_PARITY_PROMPT_ATTN=ON
if(STRATA_BUILD_TESTS OR STRATA_PARITY_PROMPT_ATTN)
# the tests, or alone with -DSTRATA_PARITY_PROMPT_ATTN=ON. CUDA only: HIP compiles the tensor-core kernel out.
if((STRATA_BUILD_TESTS OR STRATA_PARITY_PROMPT_ATTN) AND STRATA_ENABLE_CUDA)
add_executable(qsa_prompt_attn_parity src/kernels/qsa_prompt_attn_parity.cpp)
target_include_directories(qsa_prompt_attn_parity PRIVATE ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
target_link_libraries(qsa_prompt_attn_parity PRIVATE strata_kernels CUDA::cudart)
endif()
# #512: the top-k's active-block bound (Turing's dispatch, forced on any card by STRATA_TOPK_ACTIVE_ANY) against
# the capacity rule, selected ids bitwise
if(STRATA_BUILD_TESTS AND STRATA_ENABLE_CUDA)
add_executable(qsa_topk_active_parity src/kernels/qsa_topk_active_parity.cpp)
target_include_directories(qsa_topk_active_parity PRIVATE ${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})
target_link_libraries(qsa_topk_active_parity PRIVATE strata_kernels CUDA::cudart)
add_test(NAME qsa_topk_active_parity COMMAND qsa_topk_active_parity)
set_tests_properties(qsa_topk_active_parity PROPERTIES SKIP_RETURN_CODE 77)
endif()
# the QSA selection (block scores on the warp kernel and the tensor-core one, top-k): a GPU bench with a
# scorer-vs-scorer comparison and an FP64 accuracy gate (synthetic, no model); the ctest runs a 32K context under a
# 262144-cell capacity (the top-k dispatch follows the capacity) and exits non-zero on a failed gate
if((STRATA_BUILD_TESTS OR STRATA_PARITY_PROMPT_ATTN) AND STRATA_ENABLE_HIP)
add_executable(qsa_select_bench src/kernels/qsa_select_bench.cpp)
set_source_files_properties(src/kernels/qsa_select_bench.cpp PROPERTIES LANGUAGE HIP)
target_link_libraries(qsa_select_bench PRIVATE strata_kernels strata_hip_runtime)
add_test(NAME qsa_select_bench COMMAND qsa_select_bench 32768 256 3 262144)
endif()
# plan v0.3 P6: llama.cpp's block layouts and codebook grids for the i-quant formats (MIT, third_party/ggml)
target_include_directories(strata_kernels PRIVATE third_party/ggml)
# Match the pinned llama.cpp CUDA arithmetic contract for this adapter only.
@@ -250,7 +395,7 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
src/kernels/cuda/native_flash_attn.cu
src/kernels/cuda/native_qsa_indexer.cu
src/kernels/cuda/native_qsa_score.cu
PROPERTIES COMPILE_OPTIONS "--use_fast_math")
PROPERTIES COMPILE_OPTIONS "$<IF:$<BOOL:${STRATA_HIP_GFX906}>,,--use_fast_math>")
elseif(STRATA_ENABLE_HIP)
# Keep Q8_K's multiply and magic-bias rounding as separate FP32 operations on HIP; contraction to an
# FMA changes tie results. The embedding gather also relies on separately rounded operations.
@@ -289,15 +434,79 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
# library is the honest shape of the dependency graph: core knows about devices and weights, kernels know
# about arithmetic, and this one knows the ORDER the arithmetic happens in.
add_library(strata_engine STATIC src/core/layer.cpp src/core/session.cpp src/core/expert_source.cpp src/core/remote_experts.cpp
src/core/expert_cache.cpp src/core/native_head.cpp src/core/native_dense.cpp src/core/verify.cpp src/core/mtp.cpp)
src/core/remote_expert_opt.cu
src/core/expert_cache.cpp src/core/native_head.cpp src/core/native_dense.cpp src/core/verify.cpp src/core/mtp.cpp
src/core/conversation_snapshot.cpp src/core/conversation_state.cpp src/core/conversation_memory.cpp src/core/peer_experts.cpp
src/core/arch_defaults.cpp src/core/vmm.cpp src/core/conversation_file.cpp)
target_include_directories(strata_engine PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(strata_engine PUBLIC strata_core strata_kernels strata_kernels_cpu ${_strata_gpu_runtime_target})
if(STRATA_BUILD_TESTS AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/core/exchange_storage_test.cpp")
add_executable(exchange_storage_test tests/core/exchange_storage_test.cpp)
target_include_directories(exchange_storage_test PRIVATE include)
target_link_libraries(exchange_storage_test PRIVATE Threads::Threads)
add_test(NAME exchange_storage_test COMMAND exchange_storage_test)
set_tests_properties(exchange_storage_test PROPERTIES TIMEOUT 60)
endif()
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/core/file_expert_source_test.cpp")
enable_testing()
add_executable(file_expert_source_test tests/core/file_expert_source_test.cpp)
target_link_libraries(file_expert_source_test PRIVATE strata_engine)
add_test(NAME file_expert_source_test COMMAND file_expert_source_test)
set_tests_properties(file_expert_source_test PROPERTIES TIMEOUT 60)
add_executable(vmm_test tests/core/vmm_test.cpp)
target_link_libraries(vmm_test PRIVATE strata_engine)
add_test(NAME vmm_test COMMAND vmm_test)
set_tests_properties(vmm_test PROPERTIES TIMEOUT 60)
endif()
# #477: the learned expert profile (--expert-profile-save): its order and make_profile.py's file format (CPU only)
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/core/expert_profile_save_test.cpp")
enable_testing()
add_executable(expert_profile_save_test tests/core/expert_profile_save_test.cpp)
target_link_libraries(expert_profile_save_test PRIVATE strata_engine)
add_test(NAME expert_profile_save_test COMMAND expert_profile_save_test)
set_tests_properties(expert_profile_save_test PROPERTIES TIMEOUT 60)
endif()
if(STRATA_BUILD_TESTS AND STRATA_NATIVE_EXPERTS)
# native_experts.txt v2-v4 (the real packs' copies and the per-role shard column) and the arena filled from
# synthetic GGUF shards at the real expert dimensions
add_executable(expert_layout_test tests/core/expert_layout_test.cpp)
target_link_libraries(expert_layout_test PRIVATE strata_engine)
add_test(NAME expert_layout_test COMMAND expert_layout_test ${CMAKE_CURRENT_SOURCE_DIR}/tests/data/native_experts)
set_tests_properties(expert_layout_test PROPERTIES TIMEOUT 60)
# #326: a native pack's BF16 (--compat-bf16) PLE key stays in the arena; a quantized key row loads as before
add_executable(native_dense_ple_key_test tests/core/native_dense_ple_key_test.cpp)
target_link_libraries(native_dense_ple_key_test PRIVATE strata_engine)
add_test(NAME native_dense_ple_key_test COMMAND native_dense_ple_key_test)
set_tests_properties(native_dense_ple_key_test PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 60)
# #369: per-layer admission on a sized (native pack) cache starts each layer in its own range
add_executable(expert_cache_per_layer_test tests/core/expert_cache_per_layer_test.cpp)
target_link_libraries(expert_cache_per_layer_test PRIVATE strata_engine)
add_test(NAME expert_cache_per_layer_test COMMAND expert_cache_per_layer_test)
set_tests_properties(expert_cache_per_layer_test PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 60)
add_executable(expert_cache_segmented_test tests/core/expert_cache_segmented_test.cpp)
target_link_libraries(expert_cache_segmented_test PRIVATE strata_engine)
add_test(NAME expert_cache_segmented_test COMMAND expert_cache_segmented_test)
set_tests_properties(expert_cache_segmented_test PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 60)
endif()
if(STRATA_BUILD_CONVERSATION_TESTS)
add_executable(conversation_snapshot_test src/core/conversation_snapshot_test.cpp)
target_link_libraries(conversation_snapshot_test PRIVATE strata_engine)
add_test(NAME conversation_snapshot_test COMMAND conversation_snapshot_test)
set_tests_properties(conversation_snapshot_test PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 120)
add_executable(conversation_validation_test src/core/conversation_validation_test.cpp)
target_link_libraries(conversation_validation_test PRIVATE strata_engine)
add_test(NAME conversation_validation_test COMMAND conversation_validation_test)
set_tests_properties(conversation_validation_test PROPERTIES ENVIRONMENT "CUDA_VISIBLE_DEVICES=-1" TIMEOUT 120)
if(NOT STRATA_ENABLE_HIP AND UNIX AND NOT APPLE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
add_executable(conversation_transfer_test src/core/conversation_validation_test.cpp)
target_compile_definitions(conversation_transfer_test PRIVATE CONVERSATION_TEST_TRANSFERS)
target_link_options(conversation_transfer_test PRIVATE
-Wl,--wrap=cudaMemcpy -Wl,--wrap=cudaDeviceSynchronize -Wl,--wrap=cudaGetLastError)
target_link_libraries(conversation_transfer_test PRIVATE strata_engine)
add_test(NAME conversation_transfer_test COMMAND conversation_transfer_test)
set_tests_properties(conversation_transfer_test PROPERTIES ENVIRONMENT "CUDA_VISIBLE_DEVICES=-1" TIMEOUT 120)
endif()
endif()
# `strata generate` (P2.S6). The FIRST user-facing program: everything under it is a component, and this is
@@ -305,6 +514,10 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
# against llama.cpp on the SAME ids and a tokenizer on one side of that comparison is a second variable.
# plan v0.3 P5: batched prompt processing (tensor-core GEMMs through cuBLAS).
add_library(strata_prefill STATIC src/prefill/gemm.cu src/prefill/kernels.cu src/prefill/prefill.cpp)
if(STRATA_ENABLE_HIP)
# #313: the RDNA3 WMMA GEMMs include hip_runtime.h: AMD builds only (a CUDA build never sees this file)
target_sources(strata_prefill PRIVATE src/prefill/wmma_gemm.cu)
endif()
target_include_directories(strata_prefill PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include ${_strata_gpu_include_directories})
target_link_libraries(strata_prefill PUBLIC strata_engine ${_strata_gpu_blas_target} ${_strata_gpu_runtime_target})
if(STRATA_ENABLE_HIP AND STRATA_HIPBLASLT_AVAILABLE)
@@ -322,6 +535,18 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
if(STRATA_ENABLE_HIP)
enable_testing()
set(_strata_hip_tests)
add_executable(hip_prefill_gemm tests/hip/prefill_gemm.cpp)
target_link_libraries(hip_prefill_gemm PRIVATE strata_prefill strata_hip_runtime)
add_test(NAME hip_prefill_gemm COMMAND hip_prefill_gemm)
list(APPEND _strata_hip_tests hip_prefill_gemm)
add_executable(hip_gemm_f16_io_parity tests/hip/gemm_f16_io_parity.cpp)
target_link_libraries(hip_gemm_f16_io_parity PRIVATE strata_prefill strata_hip_runtime)
add_test(NAME hip_gemm_f16_io_parity COMMAND hip_gemm_f16_io_parity)
list(APPEND _strata_hip_tests hip_gemm_f16_io_parity)
add_executable(hip_q2_zero tests/hip/q2_zero.cpp)
target_link_libraries(hip_q2_zero PRIVATE strata_kernels strata_hip_runtime)
add_test(NAME hip_q2_zero COMMAND hip_q2_zero)
list(APPEND _strata_hip_tests hip_q2_zero)
add_executable(hip_expert_cache_staging tests/hip/expert_cache_staging.cpp)
target_link_libraries(hip_expert_cache_staging PRIVATE strata_engine)
add_test(NAME hip_expert_cache_staging COMMAND hip_expert_cache_staging)
@@ -338,6 +563,15 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
add_test(NAME hip_handoff COMMAND hip_handoff)
list(APPEND _strata_hip_tests hip_handoff)
endif()
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/hip/mapped_alias.cpp")
# #325: reports what a hipHostGetDevicePointer alias is on this stack (on Windows: the host pointer, and a
# D2D copy into it does not land - hip_handoff's timeout there). A diagnosis: exits 0 whenever it ran.
add_executable(hip_mapped_alias tests/hip/mapped_alias.cpp)
target_link_libraries(hip_mapped_alias PRIVATE strata_kernels strata_hip_runtime)
add_test(NAME hip_mapped_alias COMMAND hip_mapped_alias)
set_tests_properties(hip_mapped_alias PROPERTIES SKIP_RETURN_CODE 77)
list(APPEND _strata_hip_tests hip_mapped_alias)
endif()
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/hip/native_qsa_score.cpp")
add_executable(hip_native_qsa_score tests/hip/native_qsa_score.cpp)
target_link_libraries(hip_native_qsa_score PRIVATE strata_kernels strata_hip_runtime)
@@ -350,6 +584,34 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
add_test(NAME hip_prefill_native_batch COMMAND hip_prefill_native_batch)
list(APPEND _strata_hip_tests hip_prefill_native_batch)
endif()
# Aurora: the prompt GDN recurrence's per-head kernel against the column-split + norm kernels, bitwise
add_executable(hip_gdn_rec_head tests/hip/gdn_rec_head.cpp)
target_link_libraries(hip_gdn_rec_head PRIVATE strata_prefill strata_hip_runtime)
add_test(NAME hip_gdn_rec_head COMMAND hip_gdn_rec_head)
list(APPEND _strata_hip_tests hip_gdn_rec_head)
# #313: the RDNA3 / RDNA3.5 WMMA dense GEMMs (opt-in STRATA_WMMA_GEMM=1) against a reference
add_executable(hip_prefill_wmma_gemm_parity tests/hip/prefill_wmma_gemm_parity.cpp)
target_include_directories(hip_prefill_wmma_gemm_parity PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/prefill")
target_link_libraries(hip_prefill_wmma_gemm_parity PRIVATE strata_prefill strata_hip_runtime)
add_test(NAME hip_prefill_wmma_gemm_parity COMMAND hip_prefill_wmma_gemm_parity)
list(APPEND _strata_hip_tests hip_prefill_wmma_gemm_parity)
# S (STRATA_HCD_EXACT): the exact HC down kernel against hipBLASLt solution 1176 / 1177 (needs STRATA_HIPBLASLT_TUNING; exit 77 else)
add_executable(hip_prefill_hcd_exact_parity tests/hip/prefill_hcd_exact_parity.cpp)
target_link_libraries(hip_prefill_hcd_exact_parity PRIVATE strata_prefill strata_hip_runtime)
add_test(NAME hip_prefill_hcd_exact_parity COMMAND hip_prefill_hcd_exact_parity)
set_tests_properties(hip_prefill_hcd_exact_parity PROPERTIES SKIP_RETURN_CODE 77)
list(APPEND _strata_hip_tests hip_prefill_hcd_exact_parity)
# S6: the AMD fast router against the portable kernel, bitwise
add_executable(hip_router_fast tests/hip/router_fast.cpp)
target_link_libraries(hip_router_fast PRIVATE strata_kernels strata_hip_runtime)
add_test(NAME hip_router_fast COMMAND hip_router_fast)
list(APPEND _strata_hip_tests hip_router_fast)
# S6: the RDNA4 matrix-core prompt attention (STRATA_HIP_WMMA) against the FP32 kernel and FP64; skips off gfx12
add_executable(hip_prompt_attn_wmma src/kernels/qsa_prompt_attn_parity.cpp)
target_link_libraries(hip_prompt_attn_wmma PRIVATE strata_kernels strata_hip_runtime)
add_test(NAME hip_prompt_attn_wmma COMMAND hip_prompt_attn_wmma 32768 2048 3)
set_tests_properties(hip_prompt_attn_wmma PROPERTIES TIMEOUT 600 SKIP_RETURN_CODE 77)
list(APPEND _strata_hip_tests hip_prompt_attn_wmma)
if(STRATA_HIPBLASLT_AVAILABLE AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/tests/hip/prefill_hipblaslt_gemm.cpp")
add_executable(hip_prefill_hipblaslt_gemm tests/hip/prefill_hipblaslt_gemm.cpp)
target_include_directories(hip_prefill_hipblaslt_gemm PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/prefill")
@@ -385,11 +647,110 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
add_executable(iq_parity src/kernels/iq_parity.cpp)
target_include_directories(iq_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(iq_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
# TODO 24: the i-quant fixtures are generated, not shipped. tools/iq_fixture.py needs python3 + numpy
# and the repository's vendored gguf-py (no pip installs); it writes deterministic fixtures into the
# BUILD directory (the source tree is not touched). The CTest fixture makes generation-to-test order
# explicit even under parallel execution; a fixture-generation failure fails iq_parity with it.
find_package(Python3 COMPONENTS Interpreter QUIET)
# the generator needs an interpreter WITH numpy: probe the configured one, the setup's .venv, and the
# system python3; -DIQ_FIXTURE_PYTHON=... overrides the search outright.
set(_iq_python "")
set(_iq_candidates "")
if(IQ_FIXTURE_PYTHON)
list(APPEND _iq_candidates ${IQ_FIXTURE_PYTHON})
else()
if(Python3_Interpreter_FOUND)
list(APPEND _iq_candidates ${Python3_EXECUTABLE})
endif()
list(APPEND _iq_candidates "${CMAKE_CURRENT_SOURCE_DIR}/.venv/bin/python"
"${CMAKE_CURRENT_SOURCE_DIR}/.venv/Scripts/python.exe"
/usr/bin/python3
python3)
endif()
foreach(_cand IN LISTS _iq_candidates)
if(_cand STREQUAL "")
continue()
endif()
execute_process(COMMAND ${_cand} -c "import numpy" OUTPUT_QUIET ERROR_QUIET RESULT_VARIABLE _iq_probe)
if(_iq_probe EQUAL 0)
set(_iq_python "${_cand}")
break()
endif()
endforeach()
if(NOT _iq_python STREQUAL "")
add_test(NAME iq_parity_fixtures
COMMAND ${_iq_python} ${CMAKE_CURRENT_SOURCE_DIR}/tools/iq_fixture.py
--out ${CMAKE_CURRENT_BINARY_DIR}/iq_fixture)
# exit 3: numpy or the vendored gguf-py is missing (a trimmed third_party) - a skip, not a failure
set_tests_properties(iq_parity_fixtures PROPERTIES FIXTURES_SETUP iq_fixture_data SKIP_RETURN_CODE 3)
add_test(NAME iq_parity COMMAND iq_parity ${CMAKE_CURRENT_BINARY_DIR}/iq_fixture)
set_tests_properties(iq_parity PROPERTIES FIXTURES_REQUIRED iq_fixture_data SKIP_RETURN_CODE 3)
else()
message(STATUS "STRATA tests: no python3 with numpy was found (the configured interpreter and .venv "
"were probed) - the iq_parity fixtures and its test are not registered; the fixtures "
"need python3 with numpy and the repository's vendored gguf-py")
endif()
if(STRATA_ENABLE_CUDA)
# native_mmvq's multi_exact contract, bitwise: a T-column call against T single-column calls on the same Q8_1
# bytes, with the flag off as the negative control (synthetic, GPU, no model; the control assumes 32-lane warps)
add_executable(mmvq_multi_parity src/kernels/mmvq_multi_parity.cpp)
target_include_directories(mmvq_multi_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(mmvq_multi_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME mmvq_multi_parity COMMAND mmvq_multi_parity)
if(STRATA_HIP_GFX906) # the CUDA layout, where the negative control has power (the wave64 one is exact at every T)
add_test(NAME mmvq_multi_parity_cuda_layout COMMAND mmvq_multi_parity)
set_tests_properties(mmvq_multi_parity_cuda_layout PROPERTIES ENVIRONMENT "STRATA_MMVQ_WAVE=0")
endif()
endif()
# the IQ kernels that decode a weight part once for every column/entry, bitwise vs the per-column ones
# (GPU, synthetic, no model; --bench adds old/new timings)
add_executable(iq_multi_parity src/kernels/iq_multi_parity.cpp)
target_include_directories(iq_multi_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(iq_multi_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME iq_multi_parity COMMAND iq_multi_parity)
# the prompt path's DeltaNet recurrence: gdn_rec_kh_kernel against gdn_rec_cols_pipe_kernel, bitwise (GPU,
# synthetic, no model; --bench adds timings). NVIDIA only: cp.async and the CUDA occupancy API (not on gfx906)
if(STRATA_ENABLE_CUDA AND NOT STRATA_HIP_GFX906)
# Independent pinned expert uploads: byte parity and stream/event ordering.
add_executable(dma_batch_parity tests/core/dma_batch_parity.cu)
target_include_directories(dma_batch_parity PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(dma_batch_parity PRIVATE ${_strata_gpu_runtime_target})
add_test(NAME dma_batch_parity COMMAND dma_batch_parity)
set_tests_properties(dma_batch_parity PROPERTIES TIMEOUT 120)
if(WIN32)
add_test(NAME dma_batch_registered_parity COMMAND dma_batch_parity --registered)
set_tests_properties(dma_batch_registered_parity PROPERTIES TIMEOUT 120)
endif()
add_executable(gdn_rec_parity src/prefill/gdn_rec_parity.cu)
target_link_libraries(gdn_rec_parity PRIVATE ${_strata_gpu_runtime_target})
add_test(NAME gdn_rec_parity COMMAND gdn_rec_parity)
# the prompt path's BF16 products against cuBLAS's own BF16 GEMM, within fp32 rounding (sm_7x runs them on the
# FP16 tensor cores; GPU, synthetic, no model; --bench adds timings)
add_executable(gemm_bf16_parity src/prefill/gemm_bf16_parity.cu)
target_link_libraries(gemm_bf16_parity PRIVATE strata_prefill )
add_test(NAME gemm_bf16_parity COMMAND gemm_bf16_parity)
endif()
# native_expert_grouped's group stride and fused SwiGLU + q8_1, bitwise vs the launches before them (GPU, synthetic,
# no model; --bench adds v1/new timings of a window's 48 calls in a graph)
add_executable(native_grouped_parity src/kernels/native_grouped_parity.cpp)
target_include_directories(native_grouped_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(native_grouped_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME native_grouped_parity COMMAND native_grouped_parity)
add_executable(shared_expert_parity src/kernels/shared_expert_parity.cpp)
target_include_directories(shared_expert_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(shared_expert_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME shared_expert_parity COMMAND shared_expert_parity --selftest)
# the split / batched verify-window kernels (from eddoursul's fork), bitwise vs the kernels they replace; CUDA only
if(STRATA_ENABLE_CUDA)
add_executable(verify_parity src/kernels/verify_parity.cpp)
target_include_directories(verify_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(verify_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME verify_parity COMMAND verify_parity --selftest)
endif()
add_executable(fused_gr_bench src/kernels/fused_gr_bench.cpp)
target_include_directories(fused_gr_bench PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(fused_gr_bench PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_executable(gr_parity src/kernels/gr_parity.cpp)
target_include_directories(gr_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(gr_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
@@ -409,6 +770,20 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
target_include_directories(sampler_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(sampler_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME sampler_parity COMMAND sampler_parity --selftest)
set_tests_properties(sampler_parity PROPERTIES ENVIRONMENT "STRATA_OLD_SAMPLER=0;STRATA_SAMPLER_ONE_BLOCK=0")
# the same fixtures on the other two sampled paths: the one-block kernel and the 0.1.20 kernel
add_test(NAME sampler_parity_one_block COMMAND sampler_parity --selftest)
set_tests_properties(sampler_parity_one_block PROPERTIES ENVIRONMENT "STRATA_OLD_SAMPLER=0;STRATA_SAMPLER_ONE_BLOCK=1")
add_test(NAME sampler_parity_old COMMAND sampler_parity --selftest)
set_tests_properties(sampler_parity_old PROPERTIES ENVIRONMENT "STRATA_OLD_SAMPLER=1;STRATA_SAMPLER_ONE_BLOCK=0")
# S19: the decode QSA top-k and the greedy argmax on thread-block clusters (sm_90+) vs the one-CTA kernels, bitwise,
# captured in a graph too (GPU, synthetic, no model; skips below sm_90); --bench: per-call times
if(STRATA_ENABLE_CUDA)
add_executable(decode_cluster_parity src/kernels/decode_cluster_parity.cpp)
target_include_directories(decode_cluster_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(decode_cluster_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME decode_cluster_parity COMMAND decode_cluster_parity --selftest)
endif()
add_executable(rope_parity src/kernels/rope_parity.cpp)
target_include_directories(rope_parity PRIVATE ${_strata_gpu_include_directories})
@@ -420,10 +795,42 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
target_link_libraries(quantize_act_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME quantize_act_parity COMMAND quantize_act_parity --selftest)
# the verify window's routing in one multi-column BF16 projection + one top-k, bitwise the per-token calls
add_executable(route_window_parity src/kernels/route_window_parity.cpp)
target_include_directories(route_window_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(route_window_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME route_window_parity COMMAND route_window_parity)
add_executable(router_top10_parity src/kernels/router_top10_parity.cpp)
target_include_directories(router_top10_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(router_top10_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME router_top10_parity COMMAND router_top10_parity --selftest)
# #783 PR-c: the multi-token router and the k = 10 float4 combine, bitwise against the single-token contracts
add_executable(native_multi_parity src/kernels/native_multi_parity.cpp)
target_include_directories(native_multi_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(native_multi_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME native_multi_parity COMMAND native_multi_parity)
# #783 PR-d: the batched K/V append (INT8, Q4_0, the hybrid fold) against the per-cell appends, memcmp
add_executable(kv_steps_parity src/kernels/kv_steps_parity.cpp)
target_include_directories(kv_steps_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(kv_steps_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME kv_steps_parity COMMAND kv_steps_parity)
# #783 PR-e: the device-built expert plan (parallel grouping + prefix scan) against a host replay of its contract
add_executable(resident_plan_parity src/kernels/resident_plan_parity.cpp)
target_include_directories(resident_plan_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(resident_plan_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME resident_plan_parity COMMAND resident_plan_parity)
# #783 PR-g: the multi-token hyper-connection read/write (exact-T projections under them) against the single-token calls
add_executable(gr_multi_parity src/kernels/gr_multi_parity.cpp)
target_include_directories(gr_multi_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(gr_multi_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME gr_multi_parity COMMAND gr_multi_parity)
if(STRATA_HIP_GFX906)
# the S6 router (STRATA_HIP_ROUTER_FAST=1 on gfx906) against the portable kernel, bitwise, on wave64
add_executable(hip_router_fast tests/hip/router_fast.cpp)
target_include_directories(hip_router_fast PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(hip_router_fast PRIVATE strata_kernels ${_strata_gpu_runtime_target})
endif()
add_executable(s_gemv_parity src/kernels/s_gemv_parity.cpp)
target_include_directories(s_gemv_parity PRIVATE ${_strata_gpu_include_directories})
@@ -450,6 +857,13 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
target_link_libraries(qsa_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME qsa_parity COMMAND qsa_parity --selftest)
# the QSA top-k the engine dispatches against the original kernel: identical ids on both sides of the register
# kernel's reach, with tied and with equal scores (synthetic, no model)
add_executable(qsa_topk_parity src/kernels/qsa_topk_parity.cpp)
target_include_directories(qsa_topk_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(qsa_topk_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME qsa_topk_parity COMMAND qsa_topk_parity --selftest)
# ---- P2.S4: the PLE n-gram hash, the IQ4_NL table read, and the PLE block ----
# `ngram.cpp` is host-only but lives in `strata_kernels` because `ple.cu` shares its geometry constants, and
# splitting them across two libraries would only add a layer.
@@ -494,12 +908,19 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
target_link_libraries(cvec_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME cvec_parity COMMAND cvec_parity)
# The rewritten per-hit and grouped expert kernels vs the previous ones, bitwise (GPU, synthetic, no model).
# `--bench` adds previous/new timings on engine-like shapes.
add_executable(s2_expert_grouped_parity src/kernels/s2_expert_grouped_parity.cpp)
target_include_directories(s2_expert_grouped_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(s2_expert_grouped_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME s2_expert_grouped_parity COMMAND s2_expert_grouped_parity --selftest)
# Plan v0.3 P3: native MMVQ for 1..8 tokens (bitwise selftest + --bench timing); synthetic data, no model.
if(STRATA_BUILD_TESTS)
add_executable(native_mmvq_multi bench/micro/native_mmvq_multi.cpp)
target_include_directories(native_mmvq_multi PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(native_mmvq_multi PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME native_mmvq_multi COMMAND native_mmvq_multi --selftest)
if(STRATA_BUILD_TESTS AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/bench/micro/native_mmvq_multi.cpp")
add_executable(native_mmvq_multi bench/micro/native_mmvq_multi.cpp)
target_include_directories(native_mmvq_multi PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(native_mmvq_multi PRIVATE strata_kernels ${_strata_gpu_runtime_target})
add_test(NAME native_mmvq_multi COMMAND native_mmvq_multi --selftest)
endif()
# Plan v0.3 P0.1: working-set lock of a host region (CPU only).
@@ -507,6 +928,12 @@ if(STRATA_ENABLE_CUDA OR STRATA_ENABLE_HIP)
target_link_libraries(platform_memory_test PRIVATE strata_core ${_strata_gpu_runtime_target})
add_test(NAME platform_memory_test COMMAND platform_memory_test)
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_executable(pinned_shared_test src/core/pinned_shared_test.cpp)
target_link_libraries(pinned_shared_test PRIVATE strata_core ${_strata_gpu_runtime_target})
add_test(NAME pinned_shared_test COMMAND pinned_shared_test)
endif()
# Plan v0.3 P2: the n-gram table read straight from the SSD. The selftest needs only the CPU and a temp file.
add_executable(ple_reader_test src/ngram/ple_reader_test.cpp)
target_include_directories(ple_reader_test PRIVATE ${_strata_gpu_include_directories})
@@ -563,9 +990,13 @@ endif()
# worse opt-out. `cpu_require_expert_support()` therefore refuses at startup on a CPU without the
# features, and the fallback exists for tests, exactly as P2.S3 specifies.
# Plan v0.3 P6: speculation components that need no GPU.
add_library(strata_spec STATIC src/spec/suffix_drafter.cpp src/spec/controller.cpp src/spec/draft_policy.cpp)
add_library(strata_spec STATIC src/spec/suffix_drafter.cpp src/spec/controller.cpp src/spec/draft_policy.cpp
src/spec/draft_source.cpp)
target_include_directories(strata_spec PUBLIC include)
if(STRATA_BUILD_TESTS)
add_executable(arch_defaults_test src/core/arch_defaults_test.cpp src/core/arch_defaults.cpp)
target_include_directories(arch_defaults_test PRIVATE include)
add_test(NAME arch_defaults_test COMMAND arch_defaults_test)
add_executable(suffix_drafter_test src/spec/suffix_drafter_test.cpp)
target_link_libraries(suffix_drafter_test PRIVATE strata_spec)
add_test(NAME suffix_drafter_test COMMAND suffix_drafter_test)
@@ -575,10 +1006,23 @@ if(STRATA_BUILD_TESTS)
add_executable(draft_policy_test src/spec/draft_policy_test.cpp)
target_link_libraries(draft_policy_test PRIVATE strata_spec)
add_test(NAME draft_policy_test COMMAND draft_policy_test)
endif()
if(STRATA_BUILD_TESTS OR STRATA_BUILD_CONVERSATION_TESTS)
add_executable(message_boundary_test src/program/message_boundary_test.cpp)
target_include_directories(message_boundary_test PRIVATE include)
add_test(NAME message_boundary_test COMMAND message_boundary_test)
# the serve loop's conversation-cache retention policy (header-only, no library to link)
add_executable(conv_cache_test src/program/conv_cache_test.cpp)
target_include_directories(conv_cache_test PRIVATE include)
add_test(NAME conv_cache_test COMMAND conv_cache_test)
# coupled draft sampling's counter and penalty-ring arithmetic (header-only, CPU)
add_executable(coupled_draft_test src/core/coupled_draft_test.cpp)
target_include_directories(coupled_draft_test PRIVATE include)
add_test(NAME coupled_draft_test COMMAND coupled_draft_test)
# the f32 -> bf16 rounding against ggml's, NaN included, over every f32 bit pattern (header-only, CPU)
add_executable(bf16_bits_test src/kernels/bf16_bits_test.cpp)
target_include_directories(bf16_bits_test PRIVATE include)
add_test(NAME bf16_bits_test COMMAND bf16_bits_test)
endif()
add_library(strata_kernels_cpu STATIC src/kernels/cpu/expert.cpp src/kernels/cpu/pool.cpp
@@ -595,6 +1039,34 @@ else()
PROPERTIES COMPILE_OPTIONS "-mavx512f;-mavx512bw;-mavx512vl;-mavx512dq;-mavx512vnni;-mavx512vbmi;-mf16c;-mfma")
set_source_files_properties(src/kernels/cpu/q2_avx2.cpp PROPERTIES COMPILE_OPTIONS "-mavx2;-mfma;-mf16c")
endif()
# AVX-VNNI (Alder Lake, Sapphire Rapids and later): the AVX-2 expert kernels' vpdpwssd / vpdpbusd copies (q2_avx2.cpp,
# iq_avx2.cpp; *_rows.inl), taken at run time where cpu_avxvnni_ok(). GCC and Clang compile only those functions with
# target("avxvnni") - never -mavxvnni on a file, which would let the compiler use it anywhere - and MSVC takes the
# intrinsics under /arch:AVX2. A compiler without them (GCC < 11, Clang < 12) builds the files without the copies.
include(CheckCXXSourceCompiles)
if(MSVC)
set(CMAKE_REQUIRED_FLAGS "/arch:AVX2")
else()
set(CMAKE_REQUIRED_FLAGS "-mavx2 -mfma -mf16c")
endif()
check_cxx_source_compiles([=[
#include <immintrin.h>
#if defined(__GNUC__) || defined(__clang__)
__attribute__((target("avxvnni")))
#endif
static __m256i dots(__m256i a, __m256i b) { return _mm256_dpbusd_avx_epi32(_mm256_dpwssd_avx_epi32(a, a, b), a, b); }
int main() {
volatile int x = 1;
return _mm256_extract_epi32(dots(_mm256_set1_epi32(x), _mm256_set1_epi32(x)), 0) == 0;
}
]=] STRATA_HAVE_AVXVNNI_INTRINSICS)
unset(CMAKE_REQUIRED_FLAGS)
if(STRATA_HAVE_AVXVNNI_INTRINSICS)
set(_strata_avxvnni STRATA_AVXVNNI=1)
else()
set(_strata_avxvnni STRATA_AVXVNNI=0)
endif()
set_property(SOURCE src/kernels/cpu/q2_avx2.cpp APPEND PROPERTY COMPILE_DEFINITIONS ${_strata_avxvnni})
find_package(Threads REQUIRED)
target_link_libraries(strata_kernels_cpu PUBLIC Threads::Threads)
@@ -608,6 +1080,9 @@ set(STRATA_GGML_DIR "" CACHE PATH "llama.cpp checkout to take ggml from (empty:
if(STRATA_PREFILL_MMQ AND NOT STRATA_NATIVE_EXPERTS)
message(FATAL_ERROR "STRATA_PREFILL_MMQ requires STRATA_NATIVE_EXPERTS=ON for GGML sources")
endif()
if(STRATA_ORCA_Q4KS_MMQ AND NOT STRATA_NATIVE_EXPERTS)
message(FATAL_ERROR "STRATA_ORCA_Q4KS_MMQ requires STRATA_NATIVE_EXPERTS=ON for GGML sources")
endif()
if(STRATA_NATIVE_EXPERTS)
enable_language(C)
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
@@ -622,6 +1097,22 @@ if(STRATA_NATIVE_EXPERTS)
foreach(_f GGML_AVX GGML_AVX2 GGML_FMA GGML_F16C GGML_BMI2)
set(${_f} ON CACHE BOOL "" FORCE)
endforeach()
elseif(STRATA_ISA_FLOOR)
# the experimental older-CPU build (STRATA_ISA_FLOOR above): one ggml-cpu for the floor, ggml's "sandybridge"
# feature set (SSE4.2 + AVX) or SSE4.2 alone - not the build host's, which may be newer than the PC it runs on.
# From the Strata_Dirigo fork (rwkeyes). ggml's defaults turn the rest on when GGML_NATIVE is off: all off here.
set(GGML_NATIVE OFF CACHE BOOL "" FORCE)
set(GGML_CPU_ALL_VARIANTS OFF CACHE BOOL "" FORCE)
set(GGML_SSE42 ON CACHE BOOL "" FORCE)
if(STRATA_ISA_FLOOR STREQUAL "avx")
set(GGML_AVX ON CACHE BOOL "" FORCE)
else()
set(GGML_AVX OFF CACHE BOOL "" FORCE)
endif()
foreach(_f GGML_AVX2 GGML_FMA GGML_F16C GGML_BMI2 GGML_AVX_VNNI GGML_AVX512 GGML_AVX512_VBMI GGML_AVX512_VNNI
GGML_AVX512_BF16 GGML_AMX_TILE GGML_AMX_INT8 GGML_AMX_BF16)
set(${_f} OFF CACHE BOOL "" FORCE)
endforeach()
else()
set(GGML_NATIVE ON CACHE BOOL "" FORCE)
endif()
@@ -642,18 +1133,56 @@ if(STRATA_NATIVE_EXPERTS)
# part of strata_kernels_cpu (the pool calls these and they call its CPU probe: one library, so GNU ld's
# one-pass static linking has no cycle to resolve)
target_sources(strata_kernels_cpu PRIVATE src/kernels/cpu/native_expert.cpp src/kernels/cpu/iq_avx512.cpp
src/kernels/cpu/iq_avx2.cpp)
src/kernels/cpu/iq_avx2.cpp src/kernels/cpu/kq_avx2.cpp
src/kernels/cpu/kq_avx1.cpp)
target_include_directories(strata_kernels_cpu PRIVATE third_party/ggml)
if(MSVC)
set_source_files_properties(src/kernels/cpu/iq_avx512.cpp PROPERTIES COMPILE_OPTIONS "/arch:AVX512")
set_source_files_properties(src/kernels/cpu/iq_avx2.cpp PROPERTIES COMPILE_OPTIONS "/arch:AVX2")
set_source_files_properties(src/kernels/cpu/kq_avx2.cpp PROPERTIES COMPILE_OPTIONS "/arch:AVX2")
# the router lookahead's AVX1 dot (older CPUs; called behind cpu_avx1_ok): no FMA, no 256-bit integer ops
set_source_files_properties(src/kernels/cpu/kq_avx1.cpp PROPERTIES COMPILE_OPTIONS "/arch:AVX")
else()
set_source_files_properties(src/kernels/cpu/iq_avx512.cpp PROPERTIES COMPILE_OPTIONS
"-mavx512f;-mavx512bw;-mavx512vl;-mavx512dq;-mavx512vnni;-mavx512vbmi;-mf16c;-mfma")
set_source_files_properties(src/kernels/cpu/iq_avx2.cpp PROPERTIES COMPILE_OPTIONS "-mavx2;-mfma;-mf16c")
set_source_files_properties(src/kernels/cpu/kq_avx2.cpp PROPERTIES COMPILE_OPTIONS "-mavx2;-mfma;-mf16c")
set_source_files_properties(src/kernels/cpu/kq_avx1.cpp PROPERTIES COMPILE_OPTIONS "-mavx")
endif()
set_property(SOURCE src/kernels/cpu/iq_avx2.cpp APPEND PROPERTY COMPILE_DEFINITIONS ${_strata_avxvnni})
if(STRATA_ISA_FLOOR STREQUAL "avx")
target_compile_definitions(strata_kernels_cpu PRIVATE STRATA_ISA_FLOOR_AVX=1)
elseif(STRATA_ISA_FLOOR STREQUAL "none")
target_compile_definitions(strata_kernels_cpu PRIVATE STRATA_ISA_FLOOR_NONE=1)
endif()
target_link_libraries(strata_kernels_cpu PUBLIC ggml-cpu ggml-base)
target_compile_definitions(strata_kernels_cpu PUBLIC STRATA_NATIVE_EXPERTS=1)
if(STRATA_BUILD_TESTS)
# the Q5_1 block dequantizer (a Q5_1 PLE table) against ggml's, synthetic blocks: no model, no GPU
add_executable(dequant_q5_1_test tests/core/dequant_q5_1_test.cpp)
target_link_libraries(dequant_q5_1_test PRIVATE strata_artifact ggml-base)
add_test(NAME dequant_q5_1_test COMMAND dequant_q5_1_test)
endif()
# the router lookahead's dot on each rung this CPU has (AVX2, the older CPUs' AVX1) against a double reference
add_executable(router_dot_parity src/kernels/cpu/router_dot_parity.cpp)
target_link_libraries(router_dot_parity PRIVATE strata_kernels_cpu)
if(STRATA_BUILD_TESTS)
add_test(NAME router_dot_parity COMMAND router_dot_parity)
add_test(NAME router_dot_parity_avx COMMAND ${CMAKE_COMMAND} -E env STRATA_FORCE_ISA=avx $<TARGET_FILE:router_dot_parity>)
endif()
# the AVX-2 expert kernels' variants (iq_avx2.cpp, q2_avx2.cpp) bit for bit against each other at 1..8 tokens and
# against ggml-cpu's dot, on random blocks; --bench: ms per expert on one thread, the weights streamed from DRAM
add_executable(iq_avx2_parity src/kernels/cpu/iq_avx2_parity.cpp)
target_link_libraries(iq_avx2_parity PRIVATE strata_kernels_cpu)
if(STRATA_BUILD_TESTS)
add_test(NAME iq_avx2_parity COMMAND iq_avx2_parity)
add_test(NAME iq_avx2_parity_iq3s_mt1 COMMAND ${CMAKE_COMMAND} -E env STRATA_IQ3S_MT1=1 $<TARGET_FILE:iq_avx2_parity>)
endif()
set(_strata_mmq_types q2_0 iq2_xxs iq2_xs iq2_s iq3_xxs iq3_s iq4_nl iq4_xs q8_0)
# #296: OrcaRouter Q4_K_S's Q5_0 experts (Q4_K and Q5_1 come with STRATA_MMQ_KQUANTS on CUDA, S5's branch)
if(STRATA_ORCA_Q4KS_MMQ)
list(APPEND _strata_mmq_types q5_0)
endif()
if(STRATA_ENABLE_CUDA)
# prompt-speed plan step 2b: llama.cpp's MMQ kernels (ggml-cuda, MIT) for the prompt path's experts, compiled
# from the same checkout as ggml above - only mmq.cuh's instances for the packs' types and the quantizer, with
@@ -664,8 +1193,21 @@ if(STRATA_NATIVE_EXPERTS)
set(_strata_gg ${strata_llamacpp_SOURCE_DIR}/ggml)
endif()
set(_strata_mmq ${_strata_gg}/src/ggml-cuda)
add_library(strata_mmq STATIC src/prefill/moe_mmq.cu src/prefill/ggml_cuda_host.cu ${_strata_mmq}/quantize.cu)
foreach(_t q2_0 iq2_xxs iq2_xs iq2_s iq3_xxs iq3_s iq4_nl iq4_xs q8_0) # q8_0: the drafter's matrices (E-9)
# #136: the Q2_0 pack's prompt experts on Strata's own int8 kernels (moe_fused.cu, opt-in STRATA_PF_FUSED=1; CUDA
# only: the HIP branch below keeps MMQ, and an sm_75 device or an sm_75-only build reports them unavailable)
add_library(strata_mmq STATIC src/prefill/moe_mmq.cu src/prefill/moe_fused.cu src/prefill/moe_fused_iq.cu
src/prefill/ggml_cuda_host.cu ${_strata_mmq}/quantize.cu)
# q8_0: the drafter's matrices (E-9); STRATA_ORCA_Q4KS_MMQ adds q5_0 (#296, in _strata_mmq_types), and
# STRATA_MMQ_KQUANTS q4_k q5_k q5_1, the experts of Unsloth's UD-Q4_K_XL (docs/UNSLOTH_Q4.md; the dispatch
# follows eddoursul/Strata 7706c1b); q6_k is HIP only
set(_strata_mmq_cuda_types ${_strata_mmq_types})
if(STRATA_MMQ_KQUANTS)
list(APPEND _strata_mmq_cuda_types q4_k q5_k q5_1)
if(STRATA_Q6K_EXPERTS) # UD-Q6_K_XL gate/up (docs/UNSLOTH_Q6.md)
list(APPEND _strata_mmq_cuda_types q6_k)
endif()
endif()
foreach(_t IN LISTS _strata_mmq_cuda_types)
target_sources(strata_mmq PRIVATE ${_strata_mmq}/template-instances/mmq-instance-${_t}.cu)
endforeach()
target_include_directories(strata_mmq PRIVATE ${_strata_gg}/include ${_strata_gg}/src ${_strata_mmq}
@@ -675,8 +1217,33 @@ if(STRATA_NATIVE_EXPERTS)
target_compile_options(strata_mmq PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=/bigobj>)
endif()
target_link_libraries(strata_mmq PUBLIC ggml-base ${_strata_gpu_runtime_target})
if(STRATA_MMQ_KQUANTS)
target_compile_definitions(strata_mmq PRIVATE STRATA_MMQ_KQUANTS=1)
endif()
if(STRATA_ORCA_Q4KS_MMQ)
target_compile_definitions(strata_mmq PRIVATE STRATA_ORCA_Q4KS_MMQ=1)
endif()
target_link_libraries(strata_prefill PUBLIC strata_mmq)
target_compile_definitions(strata_prefill PUBLIC STRATA_PREFILL_MMQ=1)
target_compile_definitions(strata_prefill PUBLIC STRATA_PREFILL_MMQ=1 STRATA_PREFILL_FUSED=1)
if(STRATA_BUILD_TESTS)
# #136: the fused int8 experts against a double-precision reference and the MMQ path (exit 77 below sm_80)
add_executable(prefill_fused_moe_test tests/cuda/prefill_fused_moe_test.cpp)
target_link_libraries(prefill_fused_moe_test PRIVATE strata_mmq ggml-base ${_strata_gpu_runtime_target})
add_test(NAME prefill_fused_moe_test COMMAND prefill_fused_moe_test)
set_tests_properties(prefill_fused_moe_test PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 300)
# #136: the same for the native packs' formats (IQ2_XXS IQ2_XS IQ2_S IQ3_XXS IQ3_S IQ4_XS, down Q2_0 IQ4_NL)
add_executable(prefill_fused_iq_test tests/cuda/prefill_fused_iq_test.cpp)
target_link_libraries(prefill_fused_iq_test PRIVATE strata_mmq ggml-base ${_strata_gpu_runtime_target})
add_test(NAME prefill_fused_iq_test COMMAND prefill_fused_iq_test)
set_tests_properties(prefill_fused_iq_test PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 600)
endif()
if(STRATA_BUILD_TESTS AND STRATA_MMQ_KQUANTS)
# the UD-Q4_K_XL expert formats through MMQ against ggml's dequantized weights (synthetic, a few seconds)
add_executable(prefill_mmq_kquant_test tests/cuda/prefill_mmq_kquant_test.cpp)
target_link_libraries(prefill_mmq_kquant_test PRIVATE strata_mmq ggml-base ${_strata_gpu_runtime_target})
add_test(NAME prefill_mmq_kquant_test COMMAND prefill_mmq_kquant_test)
set_tests_properties(prefill_mmq_kquant_test PROPERTIES TIMEOUT 120)
endif()
elseif(STRATA_PREFILL_MMQ)
# Compile only the pinned GGML MMQ and activation-quantizer sources used by prefill. This uses
# common.cuh's native HIP path without enabling a second GGML HIP backend.
@@ -689,22 +1256,52 @@ if(STRATA_NATIVE_EXPERTS)
if(NOT EXISTS "${_strata_mmq}/common.cuh" OR NOT EXISTS "${_strata_mmq}/quantize.cu")
message(FATAL_ERROR "The selected GGML source is missing the ggml-cuda MMQ sources: ${_strata_mmq}")
endif()
# Aurora: moe_fused.cu's and moe_fused_iq.cu's gfx11 WMMA kernels for the prompt experts (opt-in STRATA_PF_FUSED=1)
set(_strata_mmq_sources
src/prefill/moe_mmq.cu
src/prefill/moe_fused.cu
src/prefill/moe_fused_iq.cu
src/prefill/ggml_cuda_host.cu
"${_strata_mmq}/quantize.cu")
foreach(_t q2_0 iq2_xxs iq2_xs iq2_s iq3_xxs iq3_s iq4_nl iq4_xs q8_0)
if(STRATA_MMQ_KQUANTS)
# the same K-quant instances as the CUDA branch: on HIP they serve the dense GGUF projections
# of Gemm::native (STRATA_DENSE_MMQ=1), the mixed-quant packs' attention/PLE tensors
list(APPEND _strata_mmq_types q4_k q5_k q5_1 q6_k)
endif()
foreach(_t IN LISTS _strata_mmq_types)
list(APPEND _strata_mmq_sources "${_strata_mmq}/template-instances/mmq-instance-${_t}.cu")
endforeach()
set_source_files_properties(${_strata_mmq_sources} PROPERTIES LANGUAGE HIP)
# moe_fused.cu is Strata's own CUDA-shaped source: it takes the HIP compat headers, ggml's MMQ sources do not
set_source_files_properties(src/prefill/moe_fused.cu src/prefill/moe_fused_iq.cu
PROPERTIES INCLUDE_DIRECTORIES "${STRATA_HIP_COMPAT_INCLUDE_DIR}")
add_library(strata_mmq STATIC ${_strata_mmq_sources})
target_include_directories(strata_mmq
PRIVATE "${_strata_gg}/include" "${_strata_gg}/src" "${_strata_mmq}"
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_definitions(strata_mmq PRIVATE GGML_USE_HIP=1)
if(STRATA_MMQ_KQUANTS)
target_compile_definitions(strata_mmq PRIVATE STRATA_MMQ_KQUANTS=1)
endif()
if(STRATA_ORCA_Q4KS_MMQ)
target_compile_definitions(strata_mmq PRIVATE STRATA_ORCA_Q4KS_MMQ=1)
endif()
target_link_libraries(strata_mmq PUBLIC ggml-base hip::host roc::hipblas)
target_link_libraries(strata_prefill PUBLIC strata_mmq)
target_compile_definitions(strata_prefill PUBLIC STRATA_PREFILL_MMQ=1)
target_compile_definitions(strata_prefill PUBLIC STRATA_PREFILL_MMQ=1 STRATA_PREFILL_FUSED=1)
# Aurora: the gfx11 fused experts against the FP64 reference and MMQ (tests/cuda's test; exit 77 off gfx11)
add_executable(hip_prefill_fused_moe tests/cuda/prefill_fused_moe_test.cpp)
target_include_directories(hip_prefill_fused_moe PRIVATE "${_strata_gg}/include")
target_link_libraries(hip_prefill_fused_moe PRIVATE strata_mmq ggml-base strata_hip_runtime)
add_test(NAME hip_prefill_fused_moe COMMAND hip_prefill_fused_moe)
set_tests_properties(hip_prefill_fused_moe PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 300)
list(APPEND _strata_hip_tests hip_prefill_fused_moe)
add_executable(hip_prefill_fused_iq tests/cuda/prefill_fused_iq_test.cpp)
target_include_directories(hip_prefill_fused_iq PRIVATE "${_strata_gg}/include")
target_link_libraries(hip_prefill_fused_iq PRIVATE strata_mmq ggml-base strata_hip_runtime)
add_test(NAME hip_prefill_fused_iq COMMAND hip_prefill_fused_iq)
set_tests_properties(hip_prefill_fused_iq PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 600)
list(APPEND _strata_hip_tests hip_prefill_fused_iq)
# Numerical diagnostic: synthetic layouts by default, optional first-expert IQ3_XXS/IQ4_NL check with a pack.
add_executable(hip_prefill_mmq_parity tests/hip/prefill_mmq_parity.cpp)
@@ -723,15 +1320,65 @@ if(STRATA_NATIVE_EXPERTS)
add_executable(native_expert_parity src/kernels/native_expert_parity.cpp)
target_include_directories(native_expert_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(native_expert_parity PRIVATE strata_kernels strata_kernels_cpu strata_artifact ${_strata_gpu_runtime_target})
add_executable(native_expert_bench src/kernels/native_expert_bench.cpp)
target_include_directories(native_expert_bench PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(native_expert_bench PRIVATE strata_kernels strata_kernels_cpu strata_artifact ${_strata_gpu_runtime_target})
if(STRATA_BUILD_TESTS AND STRATA_ENABLE_CUDA)
# Unsloth UD-Q4_K_XL's three expert pairs (and Q8_0 alone, its embedding) on synthetic ggml-quantized weights
# at 2560/640: GPU and CPU experts against the float reference, GPU dequantizers against to_float.
# q4_K/q5_0 and q5_0/q8_0: a plain llama-quantize "_M" tier GGUF (not Unsloth's dynamic method) commonly
# puts Q5_0 on down-projections (sometimes gate/up too) where this model's native_experts.txt had no GPU
# kernel for it before; q5_0/q5_0 (both roles Q5_0) is left out of this list since stacking the same
# lower-precision format on both roles pushes the GPU path over this test's 3% threshold (quantization
# noise, not a kernel bug -- see the PR).
# q4_0/q4_0 and q4_0/q4_1: a plain llama-quantize Q4_0 file (bartowski's Qwen3.8-Flash-Next-Q4_0: gate/up Q4_0,
# down Q4_0 on 42 layers and Q4_1 on 6)
# q6_K/q8_0: Unsloth UD-Q6_K_XL gate/up Q6_K with Q8_0 down (docs/UNSLOTH_Q6.md). Layer 2 is q8_0/q8_0, already listed.
set(_strata_parity_pairs q4_K/q5_1 q4_K/q8_0 q5_K/q8_0 q8_0/q8_0 q4_K/q5_0 q5_0/q8_0 q4_0/q4_0 q4_0/q4_1)
if(STRATA_Q6K_EXPERTS)
list(APPEND _strata_parity_pairs q6_K/q8_0)
else() # a pair without GPU kernels (Q6_K gate/up) is refused by native_expert_supported, not run
add_test(NAME native_expert_parity_refuses_q6_K COMMAND native_expert_parity --synthetic q6_K/q8_0)
set_tests_properties(native_expert_parity_refuses_q6_K PROPERTIES WILL_FAIL TRUE)
endif()
foreach(_pair ${_strata_parity_pairs})
string(REPLACE "/" "_" _name "${_pair}")
add_test(NAME native_expert_parity_${_name} COMMAND native_expert_parity --synthetic ${_pair})
set_tests_properties(native_expert_parity_${_name} PROPERTIES TIMEOUT 120)
endforeach()
add_test(NAME native_expert_parity_q5_1_min COMMAND native_expert_parity --q5_1-min)
# #290: the BF16 token embedding (--embd-gguf) gathered and dequantized bit for bit
add_test(NAME native_expert_parity_bf16_embd COMMAND native_expert_parity --bf16-embd)
endif()
endif()
# #296's real-weight checks (OrcaRouter Q4_K_S files; docs/ORCA_Q4_K_S.md) - test programs, not part of a release
if(STRATA_ENABLE_CUDA AND STRATA_BUILD_TESTS)
add_executable(ple_q5_parity src/kernels/ple_q5_parity.cpp)
target_link_libraries(ple_q5_parity PRIVATE strata_kernels strata_artifact ggml-base ${_strata_gpu_runtime_target})
add_executable(q5_projection_parity src/kernels/q5_projection_parity.cpp)
target_include_directories(q5_projection_parity PRIVATE ${_strata_gpu_include_directories})
target_link_libraries(q5_projection_parity PRIVATE strata_kernels strata_artifact ggml-base ${_strata_gpu_runtime_target})
# #291: the FP8 PLE table (tools/ple_fp8_pack.py) through PleTable vs the checkpoint's own values
add_executable(ple_fp8_parity src/kernels/ple_fp8_parity.cpp)
target_link_libraries(ple_fp8_parity PRIVATE strata_kernels ${_strata_gpu_runtime_target})
endif()
endif()
if(STRATA_ENABLE_CUDA AND STRATA_BUILD_TESTS)
if(STRATA_ENABLE_CUDA AND STRATA_BUILD_TESTS AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/bench/micro/hit_cpu_order_parity.cu")
add_executable(hit_cpu_order_parity bench/micro/hit_cpu_order_parity.cu)
target_link_libraries(hit_cpu_order_parity PRIVATE strata_kernels strata_kernels_cpu ${_strata_gpu_runtime_target})
endif()
if(STRATA_BUILD_TESTS)
if(WIN32)
add_executable(pool_affinity_test src/kernels/cpu/pool_affinity_test.cpp)
target_link_libraries(pool_affinity_test PRIVATE strata_kernels_cpu)
add_test(NAME pool_affinity_test COMMAND pool_affinity_test)
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
add_executable(pool_affinity_test src/kernels/cpu/pool_affinity_linux_test.cpp)
target_link_libraries(pool_affinity_test PRIVATE strata_kernels_cpu)
add_test(NAME pool_affinity_test COMMAND pool_affinity_test)
endif()
# Plan v0.3 P6: one expert applied to several tokens, bitwise vs the single-token kernel (synthetic, CPU only).
# plan v0.3 P5: the device dequantizers vs the artifact's CPU dequantizers on the real shards (not a ctest: needs
# the 38 GB model; run it by hand or from tools/gpu_session.py)
@@ -744,6 +1391,14 @@ if(STRATA_BUILD_TESTS)
target_link_libraries(expert_multi_test PRIVATE strata_kernels_cpu)
add_test(NAME expert_multi_test COMMAND expert_multi_test)
# PR #706: the opt-in AVX-2 Q2_0 bit-plane kernel (STRATA_Q2_BITPLANE=1) against the legacy one, bitwise alone/window
if(STRATA_BUILD_TESTS AND CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|x86_64|x64|X86")
add_executable(q2_bitplane_parity src/kernels/cpu/q2_bitplane_parity.cpp)
target_link_libraries(q2_bitplane_parity PRIVATE strata_kernels_cpu)
add_test(NAME q2_bitplane_parity COMMAND q2_bitplane_parity)
set_tests_properties(q2_bitplane_parity PROPERTIES ENVIRONMENT "STRATA_Q2_BITPLANE=1")
endif()
add_executable(expert_parity src/kernels/cpu/expert_parity.cpp)
target_link_libraries(expert_parity PRIVATE strata_kernels_cpu)
# The pack is a REQUIRED input, not an optional one: this test compares against a real expert blob, and a
@@ -774,3 +1429,15 @@ if(STRATA_BUILD_TESTS)
add_subdirectory(tests)
endif()
endif()
# ---- HIP gfx906: every CUDA source of the tree (and the ggml-cuda MMQ sources) is compiled as HIP ----
if(STRATA_HIP_GFX906)
file(GLOB_RECURSE _strata_cu CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cu ${CMAKE_CURRENT_SOURCE_DIR}/bench/micro/*.cu
${CMAKE_CURRENT_SOURCE_DIR}/tools/vision/*.cu)
if(_strata_mmq)
file(GLOB _strata_mmq_cu ${_strata_mmq}/*.cu ${_strata_mmq}/template-instances/*.cu)
list(APPEND _strata_cu ${_strata_mmq_cu})
target_compile_definitions(strata_mmq PRIVATE GGML_USE_HIP)
endif()
set_source_files_properties(${_strata_cu} PROPERTIES LANGUAGE HIP)
endif()
+115
View File
@@ -0,0 +1,115 @@
# syntax=docker/dockerfile:1
#
# Strata: Qwen3.8-Flash-Next on NVIDIA GPUs (RTX 30/40/50, 12+ GB VRAM; two or
# three cards can share one model, 8 GB each - docs/MULTI_GPU.md).
#
# The engine is compiled during docker build, so the first container start only
# downloads the model (~70 GB) and starts the server. docker build has no GPU,
# so the CUDA architectures are fixed here instead of read from nvidia-smi: the
# engine is a fat binary with a cubin per listed arch, and the runtime picks the
# one matching your card. Narrow CUDA_ARCHITECTURES to your card for a faster
# build; a card outside the set needs a rebuild with its own arch.
#
# Build:
# docker build -t strata .
# docker build -t strata --build-arg CUDA_ARCHITECTURES=89 . # RTX 40 only
#
# Run (host needs an NVIDIA driver >= 580 and nvidia-container-toolkit):
# docker run --rm --gpus all \
# -p 8080:8080 \
# --ulimit memlock=-1 \
# -v strata-data:/data \
# -e MODEL=IQ2_XS \
# strata
#
# Setup choices are env vars, read by docker-entrypoint.sh: FAMILY, MODEL, CONTEXT,
# VISION (no | yes | cpu), KV (int8 | q4_0 | k8v4), GPU (one card) or GPUS ("0,2"
# or "all", with LAYER_SPLIT), LOW_RAM (auto | on | off), HOST, PORT, API_KEY.
#
# Only the model files, the prepared pack, the MTP layer and the install config
# live in the /data volume; the engine is part of the image. Strata loads 32-62 GB
# into RAM, so a capped container needs -e LOW_RAM=on: setup.py reads the RAM from
# /proc/meminfo, which here is the host's total, not the container's limit. Add an
# API key before exposing the port to a network: -e API_KEY=<secret>. Pass
# -e REINSTALL=1 to change the model settings later.
#
# --gpus all on a host with two usable cards: setup takes both (the layer split is
# its recommended default). Pin one card with -e GPU=0, or name them with
# -e GPUS=0,2. A volume set up for one card switches to the pair on its first start
# on a two-card host unless GPU or GPUS pins it. LOW_RAM=on runs on one card.
FROM nvidia/cuda:13.0.0-devel-ubuntu24.04
# STRATA_EXECV=1: setup.py replaces itself with the server, so the server is PID 1
# and docker stop's SIGTERM reaches it (see setup.start). Normal Linux starts, which
# don't set it, keep spawning the server as a child.
ENV DEBIAN_FRONTEND=noninteractive PYTHONUNBUFFERED=1 LANG=C.UTF-8 STRATA_EXECV=1
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential ca-certificates curl git libatomic1 libgomp1 \
python3 python3-pip python3-venv unzip \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /opt/strata
COPY . .
# RTX 20 (75), RTX 30 (86), RTX 40 (89), RTX 50 (120), plus 80 for A-series. CMakeLists
# refuses anything below 75. BUILD_VISION=0 skips the image encoder build.
ARG CUDA_ARCHITECTURES=75;80;86;89;120
ARG BUILD_VISION=1
RUN python3 -m venv .venv \
&& .venv/bin/pip install --no-cache-dir --upgrade pip \
&& .venv/bin/pip install --no-cache-dir -r requirements.txt \
&& chmod +x setup.sh docker-entrypoint.sh
# llama.cpp at the pinned commit, then the engine and the image encoder, built
# exactly the way setup.py builds them. BUILD.json is what setup.py reads to
# decide whether an engine is current: source=local with a matching src hash
# means the first start reuses it instead of recompiling.
RUN .venv/bin/python - <<'PYEOF'
import json, os, pathlib, shutil
import setup
llama = setup.get_llama_cpp()
nvcc, _ = setup.find_nvcc()
arch = os.environ.get("CUDA_ARCHITECTURES", "75;80;86;89;120").strip().strip('"').replace(",", ";")
vision = "gpu" if os.environ.get("BUILD_VISION", "1") == "1" else "none"
setup.cmake_build(setup.ROOT, setup.ROOT / "build", "strata",
["-DSTRATA_ENABLE_CUDA=ON", "-DSTRATA_BUILD_TESTS=OFF",
f"-DCMAKE_CUDA_ARCHITECTURES={arch}", f"-DCMAKE_CUDA_COMPILER={nvcc}",
f"-DSTRATA_GGML_DIR={llama}"], None, "build-strata.bat")
if vision != "none":
setup.cmake_build(setup.ROOT / "tools" / "vision", setup.ROOT / "build-vision", "strata-vision",
[f"-DLLAMA_DIR={llama}", "-DSTRATA_VISION_CUDA=ON",
f"-DCMAKE_CUDA_ARCHITECTURES={arch}", f"-DCMAKE_CUDA_COMPILER={nvcc}"], None, "build-vision.bat")
eng = setup.ROOT / "engine"
eng.mkdir(exist_ok=True)
shutil.copy2(setup.ROOT / "build" / setup.EXE, eng / setup.EXE)
if vision != "none":
shutil.copy2(setup.ROOT / "build-vision" / "bin" / setup.VEXE, eng / setup.VEXE)
bindir = pathlib.Path(nvcc).parent
meta = {"source": "local", "version": setup.source_version(),
"archs": [int(a.split("-")[0]) for a in arch.split(";") if a.split("-")[0].isdigit()], "vision": vision,
"cuda_dirs": [str(d) for d in (bindir, bindir / "x64", bindir.parent / "lib64") if d.is_dir()],
"src": setup.source_hash(setup.ENGINE_SOURCES),
"vision_src": setup.source_hash(setup.VISION_SOURCES) if vision != "none" else None}
(eng / "BUILD.json").write_text(json.dumps(meta, indent=1))
PYEOF
# the cmake trees are build-time only; the engine itself is what the container needs
RUN rm -rf build build-vision
VOLUME ["/data"]
EXPOSE 8080
# /health is answered before the API key gate, so it works with or without one.
# The port only opens after the model loads (1-3 minutes, longer on a first run),
# so the start period is generous: a too short one marks a still-loading container
# unhealthy and a restart policy would kill it mid-download.
HEALTHCHECK --interval=30s --timeout=5s --start-period=600s --retries=3 \
CMD curl -fs "http://127.0.0.1:${PORT:-8080}/health" || exit 1
ENTRYPOINT ["./docker-entrypoint.sh"]
+222
View File
@@ -0,0 +1,222 @@
<h1 align="center">Strata</h1>
[English](README.md) · [简体中文](README.zh-CN.md) · [日本語](README.ja.md) · **Deutsch** · [Français](README.fr.md) · [Español](README.es.md) · [Português](README.pt-BR.md)
<p align="center"><b>Ein KI-Modell mit 125 Milliarden Parametern auf deinem eigenen Gaming-PC</b><br>
NVIDIA- oder AMD-Grafikkarte (ab 12 GB) · Windows oder Linux · kostenlos und Open Source</p>
<p align="center"><a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4"><img src="docs/media/pagoda-preview.webp" width="720" alt="Ein Voxel-Pagodengarten, den das Modell in Strata geschrieben hat, läuft im Browser"></a><br>
<sub>Ein Voxel-Pagodengarten aus einem einzigen Prompt, auf einer RTX 5070 mit Strata (IQ3_S, 128K Kontext) ·
<a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4">ganzes Video (49 s)</a></sub></p>
Strata lässt **[Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next)** auf einem normalen PC laufen.
Das ist ein großes, kluges KI-Modell, das sonst meist einen Server braucht. Es chattet, schreibt Code, versteht
Bilder und arbeitet mit deinen Apps und Coding-Agents zusammen. Nichts verlässt deinen PC.
## Wie schnell ist es?
Wir haben es auf zwei ganz normalen Gaming-PCs gemessen. Ein Token ist etwa ¾ eines Wortes.
- **Schreibt Antworten:** wie schnell die Antwort in einem kurzen Chat erscheint. 60 Tokens pro Sekunde sind
schneller, als du lesen kannst.
- **Liest deinen Prompt:** wie schnell es aufnimmt, was du schickst (hier ein Dokument, Code oder Chatverlauf mit
32K Tokens).
<table>
<tr><th>NVIDIA: RTX 5070 (12 GB), Ryzen 5 7600, 64 GB RAM</th><th>AMD: RX 9070 XT (16 GB), Ryzen 9 3900X, 47 GB RAM</th></tr>
<tr><td>
| Größe | Schreibt Antworten | Liest deinen Prompt |
| --- | ---: | ---: |
| **Q2_0** | 94 Tokens/s | 2,650 Tokens/s |
| **IQ2_XS** | 79 Tokens/s | 2,090 Tokens/s |
| **IQ3_XXS** | 62 Tokens/s | 1,750 Tokens/s |
| **IQ3_S** | 53 Tokens/s | 1,620 Tokens/s |
| **Coder** | 55 Tokens/s | 2,180 Tokens/s |
</td><td>
| Größe | Schreibt Antworten | Liest deinen Prompt |
| --- | ---: | ---: |
| **Q2_0** | 60 Tokens/s | 1,160 Tokens/s |
| **IQ2_XS** | 52 Tokens/s | 1,110 Tokens/s |
| **Coder** | 44 Tokens/s | 1,420 Tokens/s |
</td></tr>
</table>
NVIDIA: Q2_0 mit Engine 0.1.36, die anderen Zeilen mit 0.1.26 (4K Antworten, 32K Prompts). Die vollständigen
Tabellen stehen in [DETAILS.md](docs/DETAILS.md#speed-measured). Eine Karte mit mehr VRAM ist schneller: Eine
RTX 3090 (24 GB) sollte etwa 100-140 Tokens pro Sekunde schreiben. Lange Chats und andere Karten:
[Tempo jedes Modells](docs/MODELS.md#how-fast-is-each-size), [Ergebnisse aus der Community](docs/COMMUNITY_BENCHMARKS.md).
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a><br>
<sub>Strata ist kostenlos. Wenn es auf deinem PC gut läuft, hält ein Kaffee die Arbeit daran am Laufen.</sub></p>
## Was du brauchst
| | |
| --- | --- |
| **Grafikkarte** | **NVIDIA** GeForce RTX 20, 30, 40 oder 50 Serie, oder **AMD** Radeon RX 7900 XT / XTX, RX 7800 XT / 7700 XT, RX 9060 XT, RX 9070 / 9070 XT, Radeon AI PRO R9700 oder RX 6800 / 6900 Serie. Sie braucht **12 GB VRAM oder mehr**. |
| **RAM** | 32 GB oder mehr. Dein RAM entscheidet, [welches Modell](#welches-modell-soll-ich-nehmen) passt. Mit 64 GB laufen alle Größen. |
| **Festplatte** | Etwa 80 GB frei. Nimm wenn möglich eine SSD: Der erste Start geht dann viel schneller. |
| **System** | Windows 10 / 11 oder Linux und ein aktueller Grafiktreiber von NVIDIA oder AMD. |
Alles andere richtet der Installer ein. Zwei oder drei Karten können sich das Modell teilen ([Multi-GPU](docs/MULTI_GPU.md)).
Experimentell, von Community-Mitgliedern auf ihren eigenen Rechnern geschrieben und getestet:
- **Ältere Grafikkarten** (Tesla P40 / V100, GTX 10, Radeon VII / MI50, RX 6700 XT, RX 5500 XT): [Ältere GPUs](docs/OLDER_GPUS.md).
- **Intel Arc**, unter Linux aus dem Quellcode gebaut: [Intel Arc](docs/INTEL_ARC.md).
- **AMD Ryzen AI Max (Strix Halo)**, unter Linux aus dem Quellcode gebaut: [Strix Halo](docs/STRIX_HALO.md).
- **Ältere Prozessoren ohne AVX2**: Sie funktionieren, aber langsam. [Ältere CPUs](docs/INSTALL.md#older-cpus-experimental).
Die vollständige Liste: [docs/INSTALL.md](docs/INSTALL.md#what-you-need).
## Installieren
### Lass deine KI es einrichten
Nutzt du einen KI-Coding-Assistenten (Claude Code, Cursor, Codex, GitHub Copilot, ...)? Füge dort diesen Text ein:
```text
Set up Strata on this PC for me: https://github.com/Niko1221/Strata - follow docs/AI_SETUP.md in that repository.
```
Er prüft deine Grafikkarte, deinen RAM und deine Festplatte und wählt das passende Modell. Dann installiert und
startet er es und sagt dir, wie du deine Apps verbindest. KI-Tools können Strata auch über seinen
[MCP-Server](docs/MCP_SERVER.md) installieren, starten und stoppen.
### Oder mach es selbst
[Lade Strata herunter](https://github.com/Niko1221/Strata/archive/refs/heads/main.zip) und entpacke es (oder nutze
`git clone`). **Windows:** Doppelklick auf **`START-HERE.bat`**. **Linux:** Führe im Strata-Ordner **`./setup.sh`** aus.
Die Schritte sind für NVIDIA und AMD gleich. Der Installer erkennt deine Karte und richtet die passende Engine
dafür ein. Er stellt dir ein paar Fragen:
- welches Modell und welche Größe,
- wie viel Kontext (wie viel Text sich das Modell merkt),
- ob es Bilder lesen soll.
Drück jedes Mal Enter, um die empfohlene Antwort zu nehmen. Dann lädt er das Modell herunter (etwa 70 GB) und
startet es. Bricht der Download ab, starte ihn einfach neu: Er macht dort weiter, wo er aufgehört hat. Dein Browser
öffnet die Strata-App unter `http://127.0.0.1:8080`.
> **Während das Modell startet, kann dein PC 1-3 Minuten langsam sein oder nicht reagieren** (beim ersten Mal am
> längsten). Strata lädt 35-55 GB in deinen RAM und reserviert einen Teil davon für die Grafikkarte. Das ist normal.
> Warte und schließ das Fenster nicht. Im Fenster siehst du, was Strata gerade tut.
**Beim nächsten Mal** startest du wieder `START-HERE.bat` (oder `./setup.sh`). Es startet sofort und lädt nichts
doppelt herunter. Schließ das Fenster, um das Modell zu stoppen. `UPDATE.bat` (`./update.sh`) aktualisiert Strata,
ohne es zu starten. Updates, Docker, mehrere Karten, wo die Dateien landen und alle Optionen:
[docs/INSTALL.md](docs/INSTALL.md).
## Welches Modell soll ich nehmen?
Der Installer empfiehlt eins passend zu deinem RAM. Dasselbe Modell gibt es in mehreren Größen, mehr oder weniger
stark komprimiert. Kleinere Größen sind schneller. Größere sind etwas klüger.
| Dein RAM | Nimm | Warum |
| --- | --- | --- |
| **32 GB** | **Coder** | passt in 32 GB und ist für Code gemacht (mit einer 24-GB-Karte laufen auch Q2_0 und IQ2_XS) |
| **48 GB** | **IQ2_XS** (oder Q2_0, das schnellste) | die größeren Größen passen nicht |
| **64 GB** | **IQ2_XS** (empfohlen) oder IQ3_XXS / IQ3_S | alle Größen passen; IQ3_S ist das beste und das langsamste |
| **96 GB oder mehr** | **IQ3_S** oder Unsloths UD-IQ4_XS (~4 Bit) | Platz für die größten Größen, auch wenn alles andere offen ist |
- **[Coder](docs/MODELS.md#coder):** eine Version für Code, bei der die Hälfte der Experten entfernt wurde. Sie
erreicht 91 % des SWE-bench-Verified-Werts des vollen Modells (von ihren Autoren gemessen) und passt in 32 GB RAM.
Außerhalb von Code ist sie schwächer, auch bei chinesischem und anderem CJK-Text (#438). Nimm dafür Q2_0, IQ2_XS
oder IQ3_S, die alle Experten behalten.
- **[Swift 1.5](docs/MODELS.md#swift-15):** ein Fine-Tune, das viel kürzer nachdenkt, bevor es antwortet. Du
bekommst die Antwort früher, bei etwa gleicher Qualität.
- **[Unsloth UD-IQ4_XS](docs/MODELS.md#unsloth-ud-iq4_xs):** die ~4-Bit-Version von Unsloth, in der Qualität
zwischen IQ3_S und UD-Q4_K_XL. 94 GB Download. Mit weniger als ~80 GB RAM liest Strata einen Teil davon während
der Antwort von der SSD, dort ist es also langsamer (eine NVMe-SSD hilft).
- **[Unsloth UD-Q4_K_XL](docs/MODELS.md#unsloth-ud-q4_k_xl-experimental)** (experimentell): am nächsten am vollen
Modell. Aber Strata liest das meiste davon während der Antwort von der SSD, deshalb schreibt es auf einem PC mit
64 GB nur 7-8.5 Tokens/s.
- **[OrcaRouter's Uncensored IQ3_XXS](docs/MODELS.md#orcarouter-uncensored-iq3_xxs):** Das richtest du von Hand
ein. Es steht nicht im Menü des Installers.
Größen, Downloads und was wohin passt: [docs/MODELS.md](docs/MODELS.md). Um später ein weiteres Modell
hinzuzufügen, starte `SETUP.bat` (Linux: `./setup.sh --setup`).
## So benutzt du es
<p align="center"><img src="docs/media/runpagoda.png" width="900" alt="Der Monitor-Tab der Strata-App neben einem Coding-Agent"><br>
<sub>Der <b>Monitor</b> der Strata-App (links), während ein Coding-Agent den Pagodengarten aus dem Video schreibt (rechts)</sub></p>
- **Im Browser:** Öffne `http://127.0.0.1:8080`. Dort gibt es **Chat**, einen Live-**Monitor** für das Modell und
deine GPU/CPU/RAM und **About** mit den Einstellungen und Adressen.
- **Deine Apps und Coding-Agents:** Füge einen „OpenAI-kompatiblen“ Anbieter mit der Basis-URL
**`http://127.0.0.1:8080/v1`** hinzu. Jeder API-Key und jeder Modellname funktioniert.
- Apps, die die API von Anthropic nutzen: `http://127.0.0.1:8080/v1/messages` (Claude Code:
`ANTHROPIC_BASE_URL=http://127.0.0.1:8080`).
- Codex CLI und andere Apps, die die OpenAI Responses API nutzen: `/v1/responses`
([Einrichtung](docs/DETAILS.md#the-responses-api-and-codex-cli)).
- **Nachdenken:** Wähle **aus, niedrig, mittel oder hoch** im Chat-Menü oder unter „Reasoning Effort“ in deiner
App. Aus ist am schnellsten. Hoch ist am besten für schwierige Fragen.
- **Bilder:** Antworte im Setup mit Ja auf „Images?“. Klick dann im Chat auf **Picture** oder hänge Bilder in deiner
App an. AMD-Karten lesen Bilder unter Linux über den Prozessor; unter Windows geht das noch nicht.
- **Vom Handy oder einem anderen PC:** `START-HERE.bat --setup --host 0.0.0.0 --api-key <secret>`. Setz immer einen
Key.
- **Eine Anfrage nach der anderen:** Standardmäßig beantwortet Strata eine Anfrage, die anderen warten. Um mehrere
gleichzeitig zu beantworten, setz `"parallel": 2` ([BATCHING.md](docs/BATCHING.md)). Auf einer 12-GB-Karte wird
dadurch jede Antwort langsamer.
- **Lange Prompts:** Strata liest die erste Nachricht eines Chats komplett, etwa 1 Minute pro 30,000 Tokens.
Folgenachrichten starten in Sekunden.
Mehr: [wo deine Chats gespeichert werden](docs/INSTALL.md#where-things-are-stored), [die API](docs/DETAILS.md#using-it).
## Etwas ist schiefgelaufen?
- **Mein PC ist beim ersten Start von Strata eingefroren.** Das ist normal, während das Modell lädt. Warte und
schließ das Fenster nicht. Nach 10 Minuten immer noch eingefroren? Starte den PC neu, schließ andere Programme und
versuch es noch einmal, oder nimm eine kleinere Größe.
- **Es hat beim Herunterladen oder Installieren aufgehört.** Starte `START-HERE.bat` (oder `./setup.sh`) noch
einmal. Es macht dort weiter, wo es aufgehört hat.
- **Es ist sehr langsam und die Festplattenlampe blinkt ständig, oder es meldet „the engine stopped
unexpectedly“.** Dein PC hat nicht genug freien RAM. Schließ andere Programme (Browser brauchen viel) oder nimm
eine kleinere Größe (Q2_0 oder IQ2_XS).
- **Es meldet, dass Port 8080 schon belegt ist.** Strata läuft bereits. Such nach seinem Fenster.
Weitere Probleme und ihre Lösungen: [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md). Kommst du nicht weiter?
Öffne ein [Issue](https://github.com/Niko1221/Strata/issues) und hänge `strata-<model>.log` aus dem Strata-Ordner
an. Du hast ein Sicherheitsproblem gefunden? Melde es vertraulich: [SECURITY.md](SECURITY.md).
## Wie funktioniert es?
Modelle wie dieses laufen normalerweise auf Servern mit Hunderten Gigabyte Grafikspeicher. Deine Grafikkarte hat
12-24 GB. Strata bringt das Modell trotzdem unter, indem es **die Arbeit auf deinen ganzen PC verteilt**. Stell dir
eine Küche vor: Was du ständig brauchst, bleibt auf der Arbeitsfläche, der Rest wartet in der Vorratskammer.
<p align="center"><img src="docs/media/how-it-works.svg" width="860" alt="Die 24,576 Experten des Modells: die meistgenutzten auf der Grafikkarte, alle im RAM, eine Nachschlagetabelle auf der SSD"></p>
- **Das Modell ist ein Team aus 24,576 kleinen Spezialisten („Experten“).** Jedes Wort braucht nur 10 davon.
- **Deine Grafikkarte** hält die paar tausend Experten, die am häufigsten gebraucht werden. **Dein RAM** hält alle,
und **dein Prozessor** rechnet gleichzeitig am Rest. **Deine SSD** hält eine große Nachschlagetabelle.
<p align="center"><img src="docs/media/guess-and-check.svg" width="860" alt="Ein kleiner Helfer rät die nächsten Wörter; das große Modell prüft alle auf einmal und behält die richtigen"></p>
- **Raten, dann prüfen:** Ein kleiner Helfer rät die nächsten paar Wörter. Das große Modell prüft sie alle auf
einmal. Du bekommst dieselbe Antwort, nur 1.6-1.8x schneller.
- **Lange Texte werden in großen Stücken gelesen** (bis zu 8,192 Tokens auf einmal), mit über 1,000 Tokens pro
Sekunde.
Die längere Erklärung: [docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md). Jeder Teil und seine Zahlen:
[die Details](docs/DETAILS.md#how-it-works) und das [Paper](docs/paper/Strata-Paper.pdf).
## Danksagung und Lizenz
Das Modell ist [Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next) vom Qwen-Team. Komprimiert
wurde es von [ISTA-DASLab](https://huggingface.co/ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF), UkisAI (Swift 1.5)
und Unsloth. Strata nutzt Teile von [llama.cpp / ggml](https://github.com/ggml-org/llama.cpp). Alle Danksagungen:
[docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md#credits). Strata ist Open Source unter der [MIT-Lizenz](LICENSE). Ein
paar Teile und alle Modelle haben eigene Lizenzen ([welche](docs/HOW_IT_WORKS.md#license)).
## Strata unterstützen
Strata ist kostenlos und Open Source. Wenn es dir nützt, kannst du die Entwicklung unterstützen:
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a></p>
+216
View File
@@ -0,0 +1,216 @@
<h1 align="center">Strata</h1>
[English](README.md) · [简体中文](README.zh-CN.md) · [日本語](README.ja.md) · [Deutsch](README.de.md) · [Français](README.fr.md) · **Español** · [Português](README.pt-BR.md)
<p align="center"><b>Ejecuta un modelo de IA de 125 mil millones de parámetros en tu propio PC gaming</b><br>
Tarjeta gráfica NVIDIA o AMD (12 GB o más) · Windows o Linux · libre y de código abierto</p>
<p align="center"><a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4"><img src="docs/media/pagoda-preview.webp" width="720" alt="Un jardín con una pagoda de vóxeles que escribió el modelo de Strata, funcionando en el navegador"></a><br>
<sub>Un jardín con una pagoda de vóxeles, hecho con un solo prompt en una RTX 5070 con Strata (IQ3_S, contexto de 128K) ·
<a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4">vídeo completo (49 s)</a></sub></p>
Strata ejecuta **[Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next)** en un PC normal. Es un
modelo de IA grande e inteligente que normalmente necesita un servidor. Conversa, escribe código, entiende imágenes
y funciona con tus aplicaciones y agentes de programación. Nada sale de tu PC.
## ¿Qué velocidad tiene?
Lo medimos en dos PC gaming normales. Un token equivale más o menos a ¾ de una palabra.
- **Escribe respuestas:** lo rápido que aparece la respuesta en un chat corto. 60 tokens por segundo es más rápido de lo que puedes leer.
- **Lee tu prompt:** lo rápido que procesa lo que le envías (aquí, un documento, código o historial de chat de 32K tokens).
<table>
<tr><th>NVIDIA: RTX 5070 (12 GB), Ryzen 5 7600, 64 GB RAM</th><th>AMD: RX 9070 XT (16 GB), Ryzen 9 3900X, 47 GB RAM</th></tr>
<tr><td>
| Tamaño | Escribe respuestas | Lee tu prompt |
| --- | ---: | ---: |
| **Q2_0** | 94 tokens/s | 2,650 tokens/s |
| **IQ2_XS** | 79 tokens/s | 2,090 tokens/s |
| **IQ3_XXS** | 62 tokens/s | 1,750 tokens/s |
| **IQ3_S** | 53 tokens/s | 1,620 tokens/s |
| **Coder** | 55 tokens/s | 2,180 tokens/s |
</td><td>
| Tamaño | Escribe respuestas | Lee tu prompt |
| --- | ---: | ---: |
| **Q2_0** | 60 tokens/s | 1,160 tokens/s |
| **IQ2_XS** | 52 tokens/s | 1,110 tokens/s |
| **Coder** | 44 tokens/s | 1,420 tokens/s |
</td></tr>
</table>
NVIDIA: Q2_0 con el motor 0.1.36, las demás filas con 0.1.26 (respuestas de 4K, prompts de 32K). Las tablas
completas están en [DETAILS.md](docs/DETAILS.md#speed-measured). Una tarjeta con más VRAM es más rápida: una
RTX 3090 (24 GB) debería escribir unos 100-140 tokens por segundo. Chats largos y otras tarjetas:
[velocidad de cada modelo](docs/MODELS.md#how-fast-is-each-size), [resultados de la comunidad](docs/COMMUNITY_BENCHMARKS.md).
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a><br>
<sub>Strata es gratis. Si funciona bien en tu PC, un café ayuda a seguir trabajando en él.</sub></p>
## Qué necesitas
| | |
| --- | --- |
| **Tarjeta gráfica** | **NVIDIA** GeForce serie RTX 20, 30, 40 o 50, o **AMD** Radeon RX 7900 XT / XTX, RX 7800 XT / 7700 XT, RX 9060 XT, RX 9070 / 9070 XT, Radeon AI PRO R9700 o serie RX 6800 / 6900. Necesita **12 GB de VRAM o más**. |
| **RAM** | 32 GB o más. Tu RAM decide [qué modelo](#qué-modelo-elijo) cabe. Con 64 GB funcionan todos los tamaños. |
| **Disco** | Unos 80 GB libres. Usa un SSD si puedes: el primer arranque es mucho más rápido. |
| **Sistema** | Windows 10 / 11 o Linux, y un controlador gráfico actual de NVIDIA o AMD. |
El instalador prepara todo lo demás. Dos o tres tarjetas pueden repartirse el modelo ([multi-GPU](docs/MULTI_GPU.md)).
Experimental, escrito y probado por miembros de la comunidad en sus propios equipos:
- **Tarjetas gráficas antiguas** (Tesla P40 / V100, GTX 10, Radeon VII / MI50, RX 6700 XT, RX 5500 XT): [Older GPUs](docs/OLDER_GPUS.md).
- **Intel Arc**, compilado desde el código fuente en Linux: [Intel Arc](docs/INTEL_ARC.md).
- **AMD Ryzen AI Max (Strix Halo)**, compilado desde el código fuente en Linux: [Strix Halo](docs/STRIX_HALO.md).
- **Procesadores antiguos sin AVX2**: funcionan, pero despacio. [Older CPUs](docs/INSTALL.md#older-cpus-experimental).
La lista completa: [docs/INSTALL.md](docs/INSTALL.md#what-you-need).
## Instalación
### Deja que tu IA lo instale
¿Usas un asistente de programación con IA (Claude Code, Cursor, Codex, GitHub Copilot, ...)? Pega esto en él:
```text
Set up Strata on this PC for me: https://github.com/Niko1221/Strata - follow docs/AI_SETUP.md in that repository.
```
Revisa tu tarjeta gráfica, tu RAM y tu disco, y elige el modelo que cabe. Luego lo instala, lo arranca y te explica
cómo conectar tus aplicaciones. Las herramientas de IA también pueden instalar, arrancar y detener Strata con su
[servidor MCP](docs/MCP_SERVER.md).
### O hazlo tú mismo
[Descarga Strata](https://github.com/Niko1221/Strata/archive/refs/heads/main.zip) y descomprímelo (o usa `git clone`).
**Windows:** haz doble clic en **`START-HERE.bat`**. **Linux:** ejecuta **`./setup.sh`** en la carpeta de Strata.
Los pasos son los mismos para NVIDIA y AMD. El instalador detecta tu tarjeta y prepara el motor adecuado para ella.
Te hace unas pocas preguntas:
- qué modelo y qué tamaño,
- cuánto contexto (cuánto texto tiene presente el modelo),
- si debe entender imágenes.
Pulsa Enter cada vez para usar la respuesta recomendada. Después descarga el modelo (unos 70 GB) y lo arranca. Si la
descarga se detiene, vuelve a ejecutarlo: sigue donde lo dejó. Tu navegador abre la aplicación de Strata en
`http://127.0.0.1:8080`.
> **Mientras el modelo arranca, tu PC puede ir lento o dejar de responder durante 1-3 minutos** (más la primera vez).
> Strata carga 35-55 GB en tu RAM y reserva una parte para la tarjeta gráfica. Es normal. Espera y no cierres la
> ventana. La ventana muestra lo que está haciendo Strata.
**La próxima vez**, vuelve a ejecutar `START-HERE.bat` (o `./setup.sh`). Arranca enseguida y no descarga nada dos
veces. Cierra su ventana para detener el modelo. `UPDATE.bat` (`./update.sh`) actualiza Strata sin arrancarlo.
Actualizaciones, Docker, varias tarjetas, dónde se guardan los archivos y todas las opciones: [docs/INSTALL.md](docs/INSTALL.md).
## ¿Qué modelo elijo?
El instalador te recomienda uno según tu RAM. El mismo modelo viene en varios tamaños, más o menos comprimidos. Los
tamaños pequeños son más rápidos. Los grandes son algo más inteligentes.
| Tu RAM | Elige | Por qué |
| --- | --- | --- |
| **32 GB** | **Coder** | cabe en 32 GB y está hecho para programar (con una tarjeta de 24 GB también funcionan Q2_0 e IQ2_XS) |
| **48 GB** | **IQ2_XS** (o Q2_0, el más rápido) | los tamaños más grandes no caben |
| **64 GB** | **IQ2_XS** (recomendado), o IQ3_XXS / IQ3_S | caben todos los tamaños; IQ3_S es el mejor y el más lento |
| **96 GB o más** | **IQ3_S**, o el UD-IQ4_XS de Unsloth (~4 bits) | espacio para los tamaños más grandes con todo lo demás abierto |
- **[Coder](docs/MODELS.md#coder):** una versión para programar a la que se le quitó la mitad de los expertos. Alcanza
el 91% de la puntuación SWE-bench Verified del modelo completo (medido por sus autores) y cabe en 32 GB de RAM. Es
más flojo fuera del código, también con chino y otros textos CJK (#438). Para eso, elige Q2_0, IQ2_XS o IQ3_S, que
conservan todos los expertos.
- **[Swift 1.5](docs/MODELS.md#swift-15):** un ajuste fino que piensa mucho menos tiempo antes de responder. Recibes
la respuesta antes, con más o menos la misma calidad.
- **[Unsloth UD-IQ4_XS](docs/MODELS.md#unsloth-ud-iq4_xs):** la versión de ~4 bits de Unsloth, entre IQ3_S y
UD-Q4_K_XL en calidad. Una descarga de 94 GB. Con menos de ~80 GB de RAM, Strata lee una parte desde el SSD
mientras responde, así que ahí es más lento (un SSD NVMe ayuda).
- **[Unsloth UD-Q4_K_XL](docs/MODELS.md#unsloth-ud-q4_k_xl-experimental)** (experimental): el más parecido al modelo
completo. Pero Strata lee la mayor parte desde el SSD mientras responde, así que solo escribe 7-8.5 tokens/s en un
PC con 64 GB.
- **[OrcaRouter's Uncensored IQ3_XXS](docs/MODELS.md#orcarouter-uncensored-iq3_xxs):** se instala a mano. No está en
el menú del instalador.
Tamaños, descargas y qué cabe dónde: [docs/MODELS.md](docs/MODELS.md). Para añadir otro modelo más adelante, ejecuta
`SETUP.bat` (Linux: `./setup.sh --setup`).
## Cómo usarlo
<p align="center"><img src="docs/media/runpagoda.png" width="900" alt="La pestaña Monitor de la aplicación de Strata junto a un agente de programación"><br>
<sub>El <b>Monitor</b> de la aplicación de Strata (izquierda) mientras un agente de programación escribe el jardín de la pagoda del vídeo (derecha)</sub></p>
- **En el navegador:** abre `http://127.0.0.1:8080`. Tiene **Chat**, un **Monitor** en vivo del modelo y de tu
GPU/CPU/RAM, y **About** con los ajustes y las direcciones.
- **Tus aplicaciones y agentes de programación:** añade un proveedor "compatible con OpenAI" con la URL base
**`http://127.0.0.1:8080/v1`**. Sirve cualquier clave de API y cualquier nombre de modelo.
- Aplicaciones que usan la API de Anthropic: `http://127.0.0.1:8080/v1/messages` (Claude Code:
`ANTHROPIC_BASE_URL=http://127.0.0.1:8080`).
- Codex CLI y otras aplicaciones que usan la API Responses de OpenAI: `/v1/responses`
([configuración](docs/DETAILS.md#the-responses-api-and-codex-cli)).
- **Razonamiento:** elige **off, low, medium o high** en el menú del chat o en el "reasoning effort" de tu aplicación.
Off es lo más rápido. High es lo mejor para preguntas difíciles.
- **Imágenes:** responde que sí a "Images?" en la instalación. Luego haz clic en **Picture** en el chat, o adjunta
imágenes en tu aplicación. Las tarjetas AMD leen imágenes en Linux a través del procesador; en Windows todavía no.
- **Desde tu móvil u otro PC:** `START-HERE.bat --setup --host 0.0.0.0 --api-key <secret>`. Pon siempre una clave.
- **Una petición cada vez:** por defecto Strata responde una petición y las demás esperan. Para responder varias a la
vez, pon `"parallel": 2` ([BATCHING.md](docs/BATCHING.md)). En una tarjeta de 12 GB, cada respuesta va más lenta.
- **Prompts largos:** Strata lee entero el primer mensaje de un chat, más o menos 1 minuto por cada 30,000 tokens. Los
mensajes siguientes empiezan en segundos.
Más: [dónde se guardan tus chats](docs/INSTALL.md#where-things-are-stored), [la API](docs/DETAILS.md#using-it).
## ¿Algo salió mal?
- **Mi PC se congeló la primera vez que arrancó Strata.** Es normal mientras carga el modelo. Espera y no cierres la
ventana. ¿Sigue congelado después de 10 minutos? Reinicia el PC, cierra otros programas y vuelve a intentarlo, o
elige un tamaño más pequeño.
- **Se detuvo durante la descarga o la instalación.** Vuelve a ejecutar `START-HERE.bat` (o `./setup.sh`). Sigue
donde se detuvo.
- **Va muy lento y la luz del disco no deja de parpadear, o dice "the engine stopped unexpectedly".** Tu PC no tiene
suficiente RAM libre. Cierra otros programas (los navegadores usan mucha), o elige un tamaño más pequeño (Q2_0 o
IQ2_XS).
- **Dice que el puerto 8080 ya está en uso.** Strata ya está en marcha. Busca su ventana.
Más problemas y sus soluciones: [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md). ¿Sigues atascado? Abre un
[issue](https://github.com/Niko1221/Strata/issues) y adjunta `strata-<model>.log` de la carpeta de Strata. ¿Has
encontrado un problema de seguridad? Infórmalo en privado: [SECURITY.md](SECURITY.md).
## ¿Cómo funciona?
Los modelos como este suelen funcionar en servidores con cientos de gigabytes de memoria gráfica. Tu tarjeta gráfica
tiene 12-24 GB. Strata hace que el modelo quepa **repartiendo el trabajo por todo tu PC**. Piensa en una cocina: lo
que usas todo el rato se queda en la encimera, y el resto espera en la despensa.
<p align="center"><img src="docs/media/how-it-works.svg" width="860" alt="Los 24,576 expertos del modelo: los más usados en la tarjeta gráfica, todos en la RAM y una tabla de consulta en el SSD"></p>
- **El modelo es un equipo de 24,576 pequeños especialistas ("expertos").** Cada palabra solo necesita 10 de ellos.
- **Tu tarjeta gráfica** guarda los pocos miles de expertos que más se usan. **Tu RAM** los tiene todos, y **tu
procesador** trabaja con el resto al mismo tiempo. **Tu SSD** guarda una gran tabla de consulta.
<p align="center"><img src="docs/media/guess-and-check.svg" width="860" alt="Un pequeño ayudante adivina las siguientes palabras; el modelo grande las comprueba todas a la vez y se queda con las correctas"></p>
- **Adivinar y comprobar:** un pequeño ayudante adivina las siguientes palabras. El modelo grande las comprueba todas
a la vez. Recibes la misma respuesta, 1.6-1.8x antes.
- **Los textos largos se leen en trozos grandes** (hasta 8,192 tokens cada vez), a más de 1,000 tokens por segundo.
La explicación larga: [docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md). Cada parte y sus números:
[los detalles](docs/DETAILS.md#how-it-works) y el [artículo](docs/paper/Strata-Paper.pdf).
## Créditos y licencia
El modelo es [Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next), del equipo de Qwen. Lo
comprimieron [ISTA-DASLab](https://huggingface.co/ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF), UkisAI (Swift 1.5)
y Unsloth. Strata usa partes de [llama.cpp / ggml](https://github.com/ggml-org/llama.cpp). Todos los créditos:
[docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md#credits). Strata es de código abierto con la [licencia MIT](LICENSE).
Algunas partes y cada modelo tienen sus propias licencias ([cuáles](docs/HOW_IT_WORKS.md#license)).
## Apoya a Strata
Strata es libre y de código abierto. Si te resulta útil, puedes apoyar su desarrollo:
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a></p>
+221
View File
@@ -0,0 +1,221 @@
<h1 align="center">Strata</h1>
[English](README.md) · [简体中文](README.zh-CN.md) · [日本語](README.ja.md) · [Deutsch](README.de.md) · **Français** · [Español](README.es.md) · [Português](README.pt-BR.md)
<p align="center"><b>Faites tourner un modèle d'IA de 125 milliards de paramètres sur votre propre PC de jeu</b><br>
Carte graphique NVIDIA ou AMD (12 Go ou plus) · Windows ou Linux · gratuit et open source</p>
<p align="center"><a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4"><img src="docs/media/pagoda-preview.webp" width="720" alt="Un jardin de pagode en voxels écrit par le modèle de Strata, qui tourne dans le navigateur"></a><br>
<sub>Un jardin de pagode en voxels, généré en une seule requête sur une RTX 5070 avec Strata (IQ3_S, contexte de 128K) ·
<a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4">vidéo complète (49 s)</a></sub></p>
Strata fait tourner **[Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next)** sur un PC normal. C'est
un grand modèle d'IA, très capable, qui demande d'habitude un serveur. Il discute, écrit du code, lit des images et
fonctionne avec vos applications et vos agents de code. Rien ne quitte votre PC.
## Quelle est sa vitesse ?
Nous l'avons mesurée sur deux PC de jeu ordinaires. Un token correspond à environ ¾ d'un mot.
- **Écrit les réponses :** la vitesse à laquelle la réponse s'affiche dans une courte discussion. 60 tokens par seconde, c'est plus rapide que votre lecture.
- **Lit votre prompt :** la vitesse à laquelle il absorbe ce que vous envoyez (ici un document, du code ou un historique de discussion de 32K tokens).
<table>
<tr><th>NVIDIA : RTX 5070 (12 Go), Ryzen 5 7600, 64 Go de RAM</th><th>AMD : RX 9070 XT (16 Go), Ryzen 9 3900X, 47 Go de RAM</th></tr>
<tr><td>
| Taille | Écrit les réponses | Lit votre prompt |
| --- | ---: | ---: |
| **Q2_0** | 94 tokens/s | 2,650 tokens/s |
| **IQ2_XS** | 79 tokens/s | 2,090 tokens/s |
| **IQ3_XXS** | 62 tokens/s | 1,750 tokens/s |
| **IQ3_S** | 53 tokens/s | 1,620 tokens/s |
| **Coder** | 55 tokens/s | 2,180 tokens/s |
</td><td>
| Taille | Écrit les réponses | Lit votre prompt |
| --- | ---: | ---: |
| **Q2_0** | 60 tokens/s | 1,160 tokens/s |
| **IQ2_XS** | 52 tokens/s | 1,110 tokens/s |
| **Coder** | 44 tokens/s | 1,420 tokens/s |
</td></tr>
</table>
NVIDIA : Q2_0 avec le moteur 0.1.36, les autres lignes avec 0.1.26 (réponses de 4K, prompts de 32K). Les tableaux
complets sont dans [DETAILS.md](docs/DETAILS.md#speed-measured). Une carte avec plus de VRAM va plus vite : une
RTX 3090 (24 Go) devrait écrire environ 100-140 tokens par seconde. Longues discussions et autres cartes :
[vitesse de chaque modèle](docs/MODELS.md#how-fast-is-each-size), [résultats de la communauté](docs/COMMUNITY_BENCHMARKS.md).
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a><br>
<sub>Strata est gratuit. S'il tourne bien sur votre PC, un café aide à poursuivre le travail.</sub></p>
## Ce qu'il vous faut
| | |
| --- | --- |
| **Carte graphique** | **NVIDIA** GeForce RTX série 20, 30, 40 ou 50, ou **AMD** Radeon RX 7900 XT / XTX, RX 7800 XT / 7700 XT, RX 9060 XT, RX 9070 / 9070 XT, Radeon AI PRO R9700 ou série RX 6800 / 6900. Il faut **12 Go de VRAM ou plus**. |
| **RAM** | 32 Go ou plus. Votre RAM décide [quel modèle](#quel-modèle-choisir-) tient. Avec 64 Go, toutes les tailles tournent. |
| **Disque** | Environ 80 Go libres. Prenez un SSD si possible : le premier démarrage est bien plus rapide. |
| **Système** | Windows 10 / 11 ou Linux, avec un pilote graphique NVIDIA ou AMD à jour. |
L'installateur s'occupe de tout le reste. Deux ou trois cartes peuvent se partager le modèle ([multi-GPU](docs/MULTI_GPU.md)).
Expérimental, écrit et testé par des membres de la communauté sur leurs propres machines :
- **Cartes graphiques plus anciennes** (Tesla P40 / V100, GTX 10, Radeon VII / MI50, RX 6700 XT, RX 5500 XT) : [Older GPUs](docs/OLDER_GPUS.md).
- **Intel Arc**, compilé depuis les sources sous Linux : [Intel Arc](docs/INTEL_ARC.md).
- **AMD Ryzen AI Max (Strix Halo)**, compilé depuis les sources sous Linux : [Strix Halo](docs/STRIX_HALO.md).
- **Processeurs plus anciens sans AVX2** : ça marche, mais lentement. [Older CPUs](docs/INSTALL.md#older-cpus-experimental).
La liste complète : [docs/INSTALL.md](docs/INSTALL.md#what-you-need).
## Installation
### Laissez votre IA l'installer
Vous utilisez un assistant de code IA (Claude Code, Cursor, Codex, GitHub Copilot, ...) ? Collez-lui ceci :
```text
Set up Strata on this PC for me: https://github.com/Niko1221/Strata - follow docs/AI_SETUP.md in that repository.
```
Il vérifie votre carte graphique, votre RAM et votre disque, et choisit le modèle qui convient. Ensuite il l'installe,
le démarre et vous explique comment connecter vos applications. Les outils d'IA peuvent aussi installer, démarrer et
arrêter Strata grâce à son [serveur MCP](docs/MCP_SERVER.md).
### Ou faites-le vous-même
[Téléchargez Strata](https://github.com/Niko1221/Strata/archive/refs/heads/main.zip) et décompressez-le (ou faites un `git clone`).
**Windows :** double-cliquez sur **`START-HERE.bat`**. **Linux :** lancez **`./setup.sh`** dans le dossier Strata.
Les étapes sont les mêmes pour NVIDIA et AMD. L'installateur détecte votre carte et installe le bon moteur pour elle.
Il vous pose quelques questions :
- quel modèle et quelle taille,
- combien de contexte (la quantité de texte que le modèle garde en tête),
- s'il doit lire les images.
Appuyez sur Entrée à chaque fois pour garder la réponse recommandée. Ensuite il télécharge le modèle (environ 70 Go)
et le démarre. Si le téléchargement s'arrête, relancez-le : il reprend là où il s'était arrêté. Votre navigateur
ouvre l'application Strata à l'adresse `http://127.0.0.1:8080`.
> **Pendant le démarrage du modèle, votre PC peut ralentir ou ne plus répondre pendant 1-3 minutes** (plus longtemps la première fois).
> Strata charge 35-55 Go dans votre RAM et en réserve une partie pour la carte graphique. C'est normal. Attendez, et
> ne fermez pas la fenêtre. La fenêtre montre ce que fait Strata.
**La fois suivante**, relancez `START-HERE.bat` (ou `./setup.sh`). Il démarre tout de suite et ne télécharge rien
deux fois. Fermez sa fenêtre pour arrêter le modèle. `UPDATE.bat` (`./update.sh`) met Strata à jour sans le démarrer.
Mises à jour, Docker, plusieurs cartes, emplacement des fichiers et toutes les options : [docs/INSTALL.md](docs/INSTALL.md).
## Quel modèle choisir ?
L'installateur en recommande un selon votre RAM. Le même modèle existe en plusieurs tailles, plus ou moins
compressées. Les petites tailles sont plus rapides. Les grandes sont un peu plus intelligentes.
| Votre RAM | Prenez | Pourquoi |
| --- | --- | --- |
| **32 Go** | **Coder** | il tient dans 32 Go et il est fait pour le code (avec une carte de 24 Go, Q2_0 et IQ2_XS tournent aussi) |
| **48 Go** | **IQ2_XS** (ou Q2_0, le plus rapide) | les plus grandes tailles ne tiennent pas |
| **64 Go** | **IQ2_XS** (recommandé), ou IQ3_XXS / IQ3_S | toutes les tailles tiennent ; IQ3_S est le meilleur et le plus lent |
| **96 Go ou plus** | **IQ3_S**, ou l'UD-IQ4_XS d'Unsloth (~4 bits) | de la place pour les plus grandes tailles, avec tout le reste ouvert |
- **[Coder](docs/MODELS.md#coder) :** une version pour le code, avec la moitié des experts en moins. Elle atteint 91 %
du score SWE-bench Verified du modèle complet (mesuré par ses auteurs) et tient dans 32 Go de RAM. Elle est moins
bonne en dehors du code, y compris pour le chinois et les autres textes CJK (#438). Pour ces cas, prenez Q2_0,
IQ2_XS ou IQ3_S, qui gardent tous les experts.
- **[Swift 1.5](docs/MODELS.md#swift-15) :** un fine-tune qui réfléchit bien moins longtemps avant de répondre. Vous
avez la réponse plus tôt, avec à peu près la même qualité.
- **[Unsloth UD-IQ4_XS](docs/MODELS.md#unsloth-ud-iq4_xs)** : la version ~4 bits d'Unsloth, entre IQ3_S et
UD-Q4_K_XL en qualité. Un téléchargement de 94 Go. Avec moins de ~80 Go de RAM, Strata en lit une partie depuis
le SSD pendant qu'il répond, il y est donc plus lent (un SSD NVMe aide).
- **[Unsloth UD-Q4_K_XL](docs/MODELS.md#unsloth-ud-q4_k_xl-experimental)** (expérimental) : le plus proche du modèle
complet. Mais Strata en lit la plus grande partie depuis le SSD pendant qu'il répond, donc il n'écrit que
7-8.5 tokens/s sur un PC avec 64 Go.
- **[OrcaRouter's Uncensored IQ3_XXS](docs/MODELS.md#orcarouter-uncensored-iq3_xxs) :** vous l'installez à la main.
Il n'est pas dans le menu de l'installateur.
Tailles, téléchargements et ce qui tient où : [docs/MODELS.md](docs/MODELS.md). Pour ajouter un autre modèle plus
tard, lancez `SETUP.bat` (Linux : `./setup.sh --setup`).
## Utilisation
<p align="center"><img src="docs/media/runpagoda.png" width="900" alt="L'onglet Monitor de l'application Strata à côté d'un agent de code"><br>
<sub>Le <b>Monitor</b> de l'application Strata (à gauche) pendant qu'un agent de code écrit le jardin de pagode de la vidéo (à droite)</sub></p>
- **Dans le navigateur :** ouvrez `http://127.0.0.1:8080`. Vous y trouvez **Chat**, un **Monitor** en direct du
modèle et de votre GPU/CPU/RAM, et **About** avec les réglages et les adresses.
- **Vos applications et agents de code :** ajoutez un fournisseur « OpenAI-compatible » avec l'URL de base
**`http://127.0.0.1:8080/v1`**. N'importe quelle clé API et n'importe quel nom de modèle fonctionnent.
- Applications qui utilisent l'API d'Anthropic : `http://127.0.0.1:8080/v1/messages` (Claude Code :
`ANTHROPIC_BASE_URL=http://127.0.0.1:8080`).
- Codex CLI et les autres applications qui utilisent l'API OpenAI Responses : `/v1/responses`
([configuration](docs/DETAILS.md#the-responses-api-and-codex-cli)).
- **Réflexion :** choisissez **off, low, medium ou high** dans le menu du chat ou dans le « reasoning effort » de
votre application. Off est le plus rapide. High est le meilleur pour les questions difficiles.
- **Images :** répondez oui à « Images? » pendant l'installation. Ensuite cliquez sur **Picture** dans le chat, ou
joignez des images dans votre application. Les cartes AMD lisent les images sous Linux via le processeur ; sous
Windows, pas encore.
- **Depuis votre téléphone ou un autre PC :** `START-HERE.bat --setup --host 0.0.0.0 --api-key <secret>`. Définissez
toujours une clé.
- **Une requête à la fois :** par défaut, Strata répond à une requête et les autres attendent. Pour répondre à
plusieurs en même temps, mettez `"parallel": 2` ([BATCHING.md](docs/BATCHING.md)). Sur une carte de 12 Go, chaque
réponse devient alors plus lente.
- **Longs prompts :** Strata lit en entier le premier message d'une discussion, environ 1 minute pour 30,000 tokens.
Les messages suivants démarrent en quelques secondes.
Plus d'infos : [où sont stockées vos discussions](docs/INSTALL.md#where-things-are-stored), [l'API](docs/DETAILS.md#using-it).
## Un problème ?
- **Mon PC s'est figé au premier démarrage de Strata.** C'est normal pendant le chargement du modèle. Attendez, et ne
fermez pas la fenêtre. Toujours figé après 10 minutes ? Redémarrez le PC, fermez les autres programmes et
réessayez, ou choisissez une taille plus petite.
- **Il s'est arrêté pendant le téléchargement ou l'installation.** Relancez `START-HERE.bat` (ou `./setup.sh`). Il
reprend là où il s'était arrêté.
- **C'est très lent et le voyant du disque clignote sans arrêt, ou il affiche « the engine stopped unexpectedly ».**
Votre PC n'a pas assez de RAM libre. Fermez les autres programmes (les navigateurs en utilisent beaucoup), ou
choisissez une taille plus petite (Q2_0 ou IQ2_XS).
- **Il dit que le port 8080 est déjà utilisé.** Strata tourne déjà. Cherchez sa fenêtre.
Autres problèmes et leurs solutions : [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md). Toujours bloqué ? Ouvrez une
[issue](https://github.com/Niko1221/Strata/issues) et joignez `strata-<model>.log` depuis le dossier Strata. Vous
avez trouvé un problème de sécurité ? Signalez-le en privé : [SECURITY.md](SECURITY.md).
## Comment ça marche ?
Les modèles comme celui-ci tournent d'habitude sur des serveurs avec des centaines de gigaoctets de mémoire
graphique. Votre carte graphique a 12-24 Go. Strata fait tenir le modèle en **répartissant le travail sur tout votre
PC**. Pensez à une cuisine : ce que vous utilisez tout le temps reste sur le plan de travail, et le reste attend dans
le placard.
<p align="center"><img src="docs/media/how-it-works.svg" width="860" alt="Les 24,576 experts du modèle : les plus sollicités sur la carte graphique, tous en RAM, une table de correspondance sur le SSD"></p>
- **Le modèle est une équipe de 24,576 petits spécialistes (les « experts »).** Chaque mot n'en demande que 10.
- **Votre carte graphique** garde les quelques milliers d'experts les plus utilisés. **Votre RAM** les contient tous,
et **votre processeur** travaille sur les autres en même temps. **Votre SSD** contient une grande table de
correspondance.
<p align="center"><img src="docs/media/guess-and-check.svg" width="860" alt="Un petit assistant devine les mots suivants ; le grand modèle les vérifie tous d'un coup et garde les bons"></p>
- **Deviner, puis vérifier :** un petit assistant devine les quelques mots suivants. Le grand modèle les vérifie
tous d'un coup. Vous obtenez la même réponse, 1.6-1.8x plus tôt.
- **Les longs textes sont lus par gros morceaux** (jusqu'à 8,192 tokens à la fois), à plus de 1,000 tokens par seconde.
L'explication plus longue : [docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md). Chaque partie et ses chiffres :
[les détails](docs/DETAILS.md#how-it-works) et l'[article](docs/paper/Strata-Paper.pdf).
## Crédits et licence
Le modèle est [Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next), de l'équipe Qwen. Il a été
compressé par [ISTA-DASLab](https://huggingface.co/ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF), UkisAI (Swift 1.5)
et Unsloth. Strata utilise des parties de [llama.cpp / ggml](https://github.com/ggml-org/llama.cpp). Tous les
crédits : [docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md#credits). Strata est open source sous [licence MIT](LICENSE).
Quelques parties et chaque modèle ont leur propre licence ([lesquelles](docs/HOW_IT_WORKS.md#license)).
## Soutenir Strata
Strata est gratuit et open source. S'il vous est utile, vous pouvez soutenir son développement :
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a></p>
+211
View File
@@ -0,0 +1,211 @@
<h1 align="center">Strata</h1>
[English](README.md) · [简体中文](README.zh-CN.md) · **日本語** · [Deutsch](README.de.md) · [Français](README.fr.md) · [Español](README.es.md) · [Português](README.pt-BR.md)
<p align="center"><b>1,250 億パラメータの AI モデルを、手元のゲーミング PC で動かす</b><br>
NVIDIA または AMD のグラフィックカード(12 GB 以上) · Windows または Linux · 無料のオープンソース</p>
<p align="center"><a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4"><img src="docs/media/pagoda-preview.webp" width="720" alt="Strata のモデルが書いたボクセルの五重塔の庭。ブラウザで動いている様子"></a><br>
<sub>ボクセルの五重塔の庭。1 回のプロンプトで作成し、RTX 5070 上の Strata(IQ3_S、128K コンテキスト)で実行 ·
<a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4">動画全体(49 秒)</a></sub></p>
Strata は **[Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next)** を普通の PC で動かします。
これは大きくて賢い AI モデルで、ふつうはサーバーが必要です。チャットをしたり、コードを書いたり、画像を読んだりできます。
アプリやコーディングエージェントとも連携します。データが PC の外に出ることはありません。
## どのくらい速い?
ごく普通のゲーミング PC 2 台で測りました。1 トークンは英単語のおよそ ¾ です。
- **回答の書き出し:** 短いチャットで返答が表示される速さです。毎秒 60 トークンあれば、読むより速く表示されます。
- **プロンプトの読み込み:** 送った内容を取り込む速さです(ここでは 32K トークンの文書、コード、またはチャット履歴)。
<table>
<tr><th>NVIDIA: RTX 5070 (12 GB), Ryzen 5 7600, 64 GB RAM</th><th>AMD: RX 9070 XT (16 GB), Ryzen 9 3900X, 47 GB RAM</th></tr>
<tr><td>
| サイズ | 回答の書き出し | プロンプトの読み込み |
| --- | ---: | ---: |
| **Q2_0** | 94 tokens/s | 2,650 tokens/s |
| **IQ2_XS** | 79 tokens/s | 2,090 tokens/s |
| **IQ3_XXS** | 62 tokens/s | 1,750 tokens/s |
| **IQ3_S** | 53 tokens/s | 1,620 tokens/s |
| **Coder** | 55 tokens/s | 2,180 tokens/s |
</td><td>
| サイズ | 回答の書き出し | プロンプトの読み込み |
| --- | ---: | ---: |
| **Q2_0** | 60 tokens/s | 1,160 tokens/s |
| **IQ2_XS** | 52 tokens/s | 1,110 tokens/s |
| **Coder** | 44 tokens/s | 1,420 tokens/s |
</td></tr>
</table>
NVIDIA:Q2_0 はエンジン 0.1.36、ほかの行は 0.1.26 で測定(回答 4K、プロンプト 32K)。表の全体は
[DETAILS.md](docs/DETAILS.md#speed-measured) にあります。VRAM が多いカードほど速くなります。RTX 3090(24 GB)なら
毎秒およそ 100-140 トークンで書き出せるはずです。長いチャットやほかのカードについて:[モデルごとの速度](docs/MODELS.md#how-fast-is-each-size)、
[コミュニティの測定結果](docs/COMMUNITY_BENCHMARKS.md)。
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a><br>
<sub>Strata は無料です。あなたの PC でうまく動いたら、コーヒー 1 杯の支援が開発を続ける力になります。</sub></p>
## 必要なもの
| | |
| --- | --- |
| **グラフィックカード** | **NVIDIA** GeForce RTX 20、30、40、50 シリーズ、または **AMD** Radeon RX 7900 XT / XTX、RX 7800 XT / 7700 XT、RX 9060 XT、RX 9070 / 9070 XT、Radeon AI PRO R9700、RX 6800 / 6900 シリーズ。**VRAM 12 GB 以上**が必要です。 |
| **RAM** | 32 GB 以上。RAM の量で[使えるモデル](#どのモデルを選べばいい)が決まります。64 GB あればすべてのサイズが動きます。 |
| **ディスク** | 空き容量が約 80 GB。できれば SSD を使ってください。初回の起動がずっと速くなります。 |
| **OS** | Windows 10 / 11 または Linux。NVIDIA または AMD の最新のグラフィックドライバー。 |
ほかに必要なものはすべてインストーラーが用意します。2 枚や 3 枚のカードでモデルを分担することもできます([マルチ GPU](docs/MULTI_GPU.md))。
試験的なサポート。コミュニティのメンバーが自分のマシンで書き、テストしたものです:
- **古いグラフィックカード**(Tesla P40 / V100、GTX 10、Radeon VII / MI50、RX 6700 XT、RX 5500 XT):[Older GPUs](docs/OLDER_GPUS.md)。
- **Intel Arc**(Linux でソースからビルド):[Intel Arc](docs/INTEL_ARC.md)。
- **AMD Ryzen AI Max(Strix Halo)**(Linux でソースからビルド):[Strix Halo](docs/STRIX_HALO.md)。
- **AVX2 のない古いプロセッサー**:動きますが、遅いです。[Older CPUs](docs/INSTALL.md#older-cpus-experimental)。
全リスト:[docs/INSTALL.md](docs/INSTALL.md#what-you-need)。
## インストール
### AI にセットアップしてもらう
AI コーディングアシスタント(Claude Code、Cursor、Codex、GitHub Copilot など)を使っていますか? これを貼り付けてください:
```text
Set up Strata on this PC for me: https://github.com/Niko1221/Strata - follow docs/AI_SETUP.md in that repository.
```
AI がグラフィックカード、RAM、ディスクを調べて、合うモデルを選びます。それからインストールして起動し、
アプリのつなぎ方を教えてくれます。AI ツールは Strata の [MCP サーバー](docs/MCP_SERVER.md) を通じて、
Strata のインストール、起動、停止もできます。
### 自分でやる
[Strata をダウンロード](https://github.com/Niko1221/Strata/archive/refs/heads/main.zip)して展開します(または `git clone` します)。
**Windows:** **`START-HERE.bat`** をダブルクリック。**Linux:** Strata フォルダーで **`./setup.sh`** を実行します。
手順は NVIDIA でも AMD でも同じです。インストーラーがカードを見つけて、それに合うエンジンを用意します。
いくつか質問があります:
- どのモデルを、どのサイズで使うか
- コンテキストをどのくらいにするか(モデルが覚えておけるテキストの量)
- 画像を読ませるかどうか
毎回 Enter を押せば、おすすめの答えになります。そのあとモデル(約 70 GB)をダウンロードして起動します。
ダウンロードが止まったら、もう一度実行してください。続きから再開します。ブラウザーで Strata アプリが
`http://127.0.0.1:8080` に開きます。
> **モデルの起動中、1-3 分ほど PC が重くなったり、反応しなくなったりすることがあります**(初回がいちばん長いです)。
> Strata は 35-55 GB を RAM に読み込み、その一部をグラフィックカード用に固定します。これは正常です。
> ウィンドウを閉じずに待ってください。Strata が何をしているかはウィンドウに表示されます。
**次回からは** `START-HERE.bat`(または `./setup.sh`)をもう一度実行します。すぐに起動し、同じものを 2 回ダウンロードすることはありません。
モデルを止めるときはウィンドウを閉じます。`UPDATE.bat`(`./update.sh`)を使うと、Strata を起動せずに更新できます。
更新、Docker、複数のカード、ファイルの保存場所、すべてのオプションについて:[docs/INSTALL.md](docs/INSTALL.md)。
## どのモデルを選べばいい
インストーラーが RAM に合わせてひとつ勧めます。同じモデルにも、圧縮の強さが違う複数のサイズがあります。
小さいサイズほど速く、大きいサイズほど少し賢くなります。
| RAM | 選ぶもの | 理由 |
| --- | --- | --- |
| **32 GB** | **Coder** | 32 GB に収まり、コード向けに作られている(24 GB のカードなら Q2_0 と IQ2_XS も動く) |
| **48 GB** | **IQ2_XS**(または最速の Q2_0) | 大きいサイズは収まらない |
| **64 GB** | **IQ2_XS**(おすすめ)、または IQ3_XXS / IQ3_S | すべてのサイズが収まる。IQ3_S がいちばん賢く、いちばん遅い |
| **96 GB 以上** | **IQ3_S**、または Unsloth の UD-IQ4_XS(約 4-bit) | ほかのものを全部開いたままでも、最大のサイズが入る余裕がある |
- **[Coder](docs/MODELS.md#coder):** エキスパートを半分取り除いたコーディング向け版です。フルモデルの SWE-bench Verified スコアの
91% に届き(作者による測定)、32 GB の RAM に収まります。コード以外では弱く、中国語などの CJK のテキストも苦手です(#438)。
そうした用途には、すべてのエキスパートを残している Q2_0、IQ2_XS、IQ3_S を選んでください。
- **[Swift 1.5](docs/MODELS.md#swift-15):** 答える前に考える時間がずっと短いファインチューン版です。
ほぼ同じ品質のまま、答えが早く返ってきます。
- **[Unsloth UD-IQ4_XS](docs/MODELS.md#unsloth-ud-iq4_xs):** Unsloth の約 4-bit 版で、品質は IQ3_S と UD-Q4_K_XL の間です。
ダウンロードは 94 GB。RAM が約 80 GB 未満だと、答えている間に Strata がその一部を SSD から読むので遅くなります(NVMe SSD が有効です)。
- **[Unsloth UD-Q4_K_XL](docs/MODELS.md#unsloth-ud-q4_k_xl-experimental)**(試験的):フルモデルにいちばん近いものです。
ただし答えている間、Strata はその大部分を SSD から読むので、64 GB の PC では毎秒 7-8.5 トークンしか書き出せません。
- **[OrcaRouter's Uncensored IQ3_XXS](docs/MODELS.md#orcarouter-uncensored-iq3_xxs):** 手動でセットアップします。
インストーラーのメニューにはありません。
サイズ、ダウンロード、どれがどこに収まるかについて:[docs/MODELS.md](docs/MODELS.md)。あとで別のモデルを追加するには
`SETUP.bat`(Linux:`./setup.sh --setup`)を実行します。
## 使い方
<p align="center"><img src="docs/media/runpagoda.png" width="900" alt="Strata アプリの Monitor タブと、その横で動くコーディングエージェント"><br>
<sub>Strata アプリの <b>Monitor</b>(左)。コーディングエージェントが動画の五重塔の庭を書いているところ(右)</sub></p>
- **ブラウザーで:** `http://127.0.0.1:8080` を開きます。**Chat**、モデルと GPU/CPU/RAM の様子をリアルタイムで見る **Monitor**、
設定とアドレスが載った **About** があります。
- **アプリやコーディングエージェントから:** 「OpenAI-compatible」プロバイダーを追加し、ベース URL に
**`http://127.0.0.1:8080/v1`** を指定します。API キーとモデル名は何でもかまいません。
- Anthropic の API を使うアプリ:`http://127.0.0.1:8080/v1/messages`(Claude Code:
`ANTHROPIC_BASE_URL=http://127.0.0.1:8080`)。
- Codex CLI など OpenAI Responses API を使うアプリ:`/v1/responses`
([設定方法](docs/DETAILS.md#the-responses-api-and-codex-cli))。
- **思考(Thinking):** チャットのメニュー、またはアプリの「reasoning effort」で **off、low、medium、high** を選びます。
off がいちばん速く、high は難しい質問に向いています。
- **画像:** セットアップで「Images?」に yes と答えます。そのあとチャットで **Picture** をクリックするか、アプリで画像を添付します。
AMD のカードは、Linux ではプロセッサーを使って画像を読みます。Windows ではまだ読めません。
- **スマートフォンや別の PC から:** `START-HERE.bat --setup --host 0.0.0.0 --api-key <secret>`。キーは必ず設定してください。
- **リクエストは 1 つずつ:** 初期設定では Strata は 1 つのリクエストに答え、ほかは待ちます。複数に同時に答えるには
`"parallel": 2` を設定します([BATCHING.md](docs/BATCHING.md))。12 GB のカードでは、それぞれの回答が遅くなります。
- **長いプロンプト:** Strata はチャットの最初のメッセージをすべて読みます。30,000 トークンあたり約 1 分かかります。
2 通目以降のメッセージは数秒で始まります。
詳しくは:[チャットの保存場所](docs/INSTALL.md#where-things-are-stored)、[API](docs/DETAILS.md#using-it)。
## うまくいかないとき
- **Strata の初回起動で PC が固まった。** モデルの読み込み中はよくあることです。ウィンドウを閉じずに待ってください。
10 分たっても固まったまま? PC を再起動し、ほかのプログラムを閉じてもう一度試すか、小さいサイズを選んでください。
- **ダウンロードやインストールの途中で止まった。** `START-HERE.bat`(または `./setup.sh`)をもう一度実行してください。
止まったところから続きます。
- **とても遅く、ディスクのランプが点滅し続ける。または「the engine stopped unexpectedly」と表示される。** PC の空き RAM が
足りません。ほかのプログラムを閉じるか(ブラウザーは多く使います)、小さいサイズ(Q2_0 または IQ2_XS)を選んでください。
- **ポート 8080 がすでに使われていると表示される。** Strata はもう動いています。そのウィンドウを探してください。
ほかの問題と解決方法:[docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)。それでも解決しない場合は
[issue](https://github.com/Niko1221/Strata/issues) を作成し、Strata フォルダーにある `strata-<model>.log` を添付してください。
セキュリティの問題を見つけたら、非公開で報告してください:[SECURITY.md](SECURITY.md)。
## しくみ
このようなモデルは、ふつう数百ギガバイトのグラフィックメモリを持つサーバーで動きます。あなたのグラフィックカードは
12-24 GB です。Strata は **PC 全体で作業を分担する** ことで、モデルを収めています。台所を思い浮かべてください。
いつも使う道具は調理台に置き、残りは食料庫にしまっておきます。
<p align="center"><img src="docs/media/how-it-works.svg" width="860" alt="モデルの 24,576 個のエキスパート:よく使うものはグラフィックカードに、すべては RAM に、ルックアップテーブルは SSD に"></p>
- **モデルは 24,576 個の小さな専門家(「エキスパート」)のチームです。** 1 語ごとに必要なのはそのうち 10 個だけです。
- **グラフィックカード** は、よく使われる数千個のエキスパートを持ちます。**RAM** はすべてのエキスパートを持ち、
**プロセッサー** が残りを同時に処理します。**SSD** は大きなルックアップテーブルを持ちます。
<p align="center"><img src="docs/media/guess-and-check.svg" width="860" alt="小さなヘルパーが次の単語を予想し、大きなモデルがまとめて確認して正しいものを残す"></p>
- **予想してから確認:** 小さなヘルパーが次の数語を予想します。大きなモデルがそれをまとめて確認します。
答えは同じまま、1.6-1.8x 早く返ってきます。
- **長いテキストは大きなまとまりで読みます**(一度に最大 8,192 トークン)。速さは毎秒 1,000 トークン以上です。
もっと詳しい説明:[docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md)。各部分とその数値:
[詳細](docs/DETAILS.md#how-it-works)と[論文](docs/paper/Strata-Paper.pdf)。
## クレジットとライセンス
モデルは Qwen チームの [Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next) です。
圧縮は [ISTA-DASLab](https://huggingface.co/ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF)、UkisAI(Swift 1.5)、
Unsloth によるものです。Strata は [llama.cpp / ggml](https://github.com/ggml-org/llama.cpp) の一部を使っています。すべてのクレジット:
[docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md#credits)。Strata は [MIT License](LICENSE) のオープンソースです。一部のパーツと
すべてのモデルには、それぞれ独自のライセンスがあります([どれか](docs/HOW_IT_WORKS.md#license))。
## Strata を支援する
Strata は無料のオープンソースです。役に立ったら、開発を支援していただけます:
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a></p>
+153 -162
View File
@@ -1,221 +1,212 @@
<h1 align="center">Strata</h1>
<p align="center"><b>Run a 125-billion-parameter AI model on a normal gaming PC</b><br>
one NVIDIA card (12-24 GB) + 64 GB of RAM · Windows or Linux · one click to install</p>
**English** · [简体中文](README.zh-CN.md) · [日本語](README.ja.md) · [Deutsch](README.de.md) · [Français](README.fr.md) · [Español](README.es.md) · [Português](README.pt-BR.md)
<p align="center"><b>Run a 125-billion-parameter AI model on your own gaming PC</b><br>
NVIDIA or AMD graphics card (12 GB or more) · Windows or Linux · free and open source</p>
<p align="center"><a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4"><img src="docs/media/pagoda-preview.webp" width="720" alt="A voxel pagoda garden that Strata's model wrote, running in the browser"></a><br>
<sub>A voxel pagoda garden, 1 shot prompt running on an RTX 5070 with Strata (IQ3_S, 128K context) ·
<a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4">full video (49 s)</a></sub></p>
Strata runs **[Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next)** - a large, smart AI model that
normally needs a server - on your own PC. It writes its answers at **60-95 tokens per second** (a token is about ¾
of a word): faster than you can read.
- **Free and open source.**
> **Jump to:** [How fast?](#how-fast-is-it) · [Which model?](#which-model-should-i-pick) · [Install](#install) ·
> [Using it](#using-it) · [Problems?](#something-went-wrong) · [How it works](#how-does-it-work) ·
> [All the details](docs/DETAILS.md)
---
Strata runs **[Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next)** on a normal PC. This is a
large, smart AI model that usually needs a server. It chats, writes code, reads pictures and works with your apps
and coding agents. Nothing leaves your PC.
## How fast is it?
Measured on an RTX 5070 (12 GB), a Ryzen 5 7600 and 64 GB of RAM:
We measured it on two ordinary gaming PCs. A token is about ¾ of a word.
| Size | Writes answers (short chat) | Writes answers (128K context) | Reads your prompt |
| --- | ---: | ---: | ---: |
| **Q2_0** | 93 tokens/s | 74 tokens/s | 2,170 tokens/s |
| **IQ2_XS** | 79 tokens/s | 63 tokens/s | 2,090 tokens/s |
| **IQ3_XXS** | 62 tokens/s | 49 tokens/s | 1,750 tokens/s |
| **IQ3_S** | 53 tokens/s | 46 tokens/s | 1,620 tokens/s |
| **Coder** (IQ1_M) | 55 tokens/s | 43 tokens/s | 2,180 tokens/s |
- **Writes answers:** how fast the reply appears in a short chat. 60 tokens per second is faster than you can read.
- **Reads your prompt:** how fast it takes in what you send (here a 32K-token document, code or chat history).
- **Writes answers** = how fast the reply appears (tokens per second).
- **Reads your prompt** = how fast it takes in what you send (long documents, code, chat history), measured on a
32K-token prompt; a 4K prompt reads at 910-1,580 tokens/s. A 32K prompt takes about 15 seconds with Q2_0.
<table>
<tr><th>NVIDIA: RTX 5070 (12 GB), Ryzen 5 7600, 64 GB RAM</th><th>AMD: RX 9070 XT (16 GB), Ryzen 9 3900X, 47 GB RAM</th></tr>
<tr><td>
A card with more VRAM is faster, because more of the model fits on the GPU: an RTX 3090 (24 GB) should do roughly
100-140 tokens per second. All measurements, long-context numbers and estimates for other cards are in the
[details](docs/DETAILS.md#speed-measured).
| Size | Writes answers | Reads your prompt |
| --- | ---: | ---: |
| **Q2_0** | 94 tokens/s | 2,650 tokens/s |
| **IQ2_XS** | 79 tokens/s | 2,090 tokens/s |
| **IQ3_XXS** | 62 tokens/s | 1,750 tokens/s |
| **IQ3_S** | 53 tokens/s | 1,620 tokens/s |
| **Coder** | 55 tokens/s | 2,180 tokens/s |
Every PC is different: `START-HERE.bat --calibrate` measures a few engine settings on yours and keeps the fastest
(about 5-10 minutes; on the PC above it made the Coder 7% faster).
</td><td>
**Two or three NVIDIA cards?** Just run `START-HERE.bat`: it lists your cards, says which ones Strata can use, and
asks whether to share the model across them (recommended when two can). An install made on one card asks once at
its next start. Or choose yourself: `START-HERE.bat --gpus 0,2` (both, remembered), `--gpus all`, or `--gpu 0` (one
card, this start only). Each card keeps the experts of its own layers, and prompts flow through the cards in a
pipeline: on an RTX 5080 + RTX 3090 prompts were read 18-20% faster than on the 5080 alone, decoding on par.
Every card must be an RTX 20 series or newer with 8 GB or more. See [docs/MULTI_GPU.md](docs/MULTI_GPU.md).
| Size | Writes answers | Reads your prompt |
| --- | ---: | ---: |
| **Q2_0** | 60 tokens/s | 1,160 tokens/s |
| **IQ2_XS** | 52 tokens/s | 1,110 tokens/s |
| **Coder** | 44 tokens/s | 1,420 tokens/s |
## Which model should I pick?
</td></tr>
</table>
**The size** (the same model, compressed more or less):
NVIDIA: Q2_0 with engine 0.1.36, the other rows with 0.1.26 (4K answers, 32K prompts). The full tables are in
[DETAILS.md](docs/DETAILS.md#speed-measured). A card with more VRAM is faster: an RTX 3090 (24 GB) should write
about 100-140 tokens per second. Long chats and other cards: [speed of each model](docs/MODELS.md#how-fast-is-each-size),
[community results](docs/COMMUNITY_BENCHMARKS.md).
| Model | RAM+VRAM Requirements | Speed | Quality |
| --- | ---: | --- | --- |
| **Q2_0** | 37.6 GB | fastest | good |
| **IQ2_XS** | 39.2 GB | fast | better (**recommended**) |
| **IQ3_XXS** | 47.0 GB | slower | great |
| **IQ3_S** | 54.8 GB | slowest | best: matches the full model on the published tests (original model only) |
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a><br>
<sub>Strata is free. If it runs well on your PC, a coffee keeps the work on it going.</sub></p>
**Will it fit?** Shard 1 is the part of the model that gets loaded when it starts: its experts go into your **RAM**,
the rest onto your graphics card (the second shard, a 29 GB lookup table, stays on the SSD). So it fits when your
**RAM is at least shard 1 + about 10 GB** for Windows and your other programs. With 64 GB of RAM every size fits
(IQ3_S with little else open); with 48 GB, Q2_0 and IQ2_XS. A bigger graphics card makes it faster, but it doesn't
lower the RAM needed.
## What you need
**The version:**
| | |
| --- | --- |
| **Graphics card** | **NVIDIA** GeForce RTX 20, 30, 40 or 50 series, or **AMD** Radeon RX 7900 XT / XTX, RX 7800 XT / 7700 XT, RX 9060 XT, RX 9070 / 9070 XT, Radeon AI PRO R9700 or RX 6800 / 6900 series. It needs **12 GB of VRAM or more**. |
| **RAM** | 32 GB or more. Your RAM decides [which model](#which-model-should-i-pick) fits. 64 GB runs every size. |
| **Disk** | About 80 GB free. Use an SSD if you can: the first start is much faster. |
| **System** | Windows 10 / 11 or Linux, and a current graphics driver from NVIDIA or AMD. |
- **Qwen3.8-Flash-Next** - the original.
- **[Coder](https://huggingface.co/ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-Coder-GGUF)** - ISTA-DASLab's coding
version: half of the experts removed, keeping the ones that code, tool use and images need (91% of the full model's
SWE-bench Verified score, 99% of LiveCodeBench, by its authors). One size (IQ1_M: its experts stored like IQ3_S):
shard 1 is **29.6 GB**, so it fits a PC with **32 GB of RAM**, runs 262K context on 64 GB, and reads long prompts
the fastest of all. Weaker outside coding.
- **[Swift 1.5](https://huggingface.co/ukisai/Swift-1.5-Qwen3.8-Flash-Next-GSQ-RCO-GGUF)** - a fine-tune by UkisAI
that thinks much shorter before answering, so you get the answer sooner, with about the same quality. Same speed per
token, and about the same RAM as the same size of the original (no IQ3_S). Its own license applies (see its page).
The installer sets up everything else. Two or three cards can share the model ([multi-GPU](docs/MULTI_GPU.md)).
Not sure? Take **IQ2_XS** - or the **Coder** if you mainly write code, or have 32-48 GB of RAM. You can add another
one later with `SETUP.bat` (the same as `START-HERE.bat --setup`; on Linux `./setup.sh --setup`).
Experimental, written and tested by community members on their own machines:
For **OrcaRouter's Flash-Next Uncensored IQ3_XXS**, see the [manual compatibility setup](docs/ORCA.md).
It needs an explicit packing conversion and is not an installer menu option.
- **Older graphics cards** (Tesla P40 / V100, GTX 10, Radeon VII / MI50, RX 6700 XT, RX 5500 XT): [Older GPUs](docs/OLDER_GPUS.md).
- **Intel Arc**, built from source on Linux: [Intel Arc](docs/INTEL_ARC.md).
- **AMD Ryzen AI Max (Strix Halo)**, built from source on Linux: [Strix Halo](docs/STRIX_HALO.md).
- **Older processors without AVX2**: they work, but slowly. [Older CPUs](docs/INSTALL.md#older-cpus-experimental).
An **AMD Radeon RX 7900 XT / XTX on Linux** works too (experimental): `./setup.sh --backend hip`, chosen by itself on
a PC with no NVIDIA card Strata can use. It installs ROCm without sudo and compiles the engine (one GPU, no images
yet). Details: [AMD HIP](docs/AMD_HIP.md).
The full list: [docs/INSTALL.md](docs/INSTALL.md#what-you-need).
## Install
**You need:** an NVIDIA RTX 20, 30, 40 or 50 card with 12 GB of VRAM or more (RTX 20 since 0.1.27), enough RAM for the size you pick (above;
a big GPU makes up for less RAM - the [low-RAM mode](docs/DETAILS.md)),
~80 GB of free disk space (an SSD makes the first start much faster), and Windows 10/11 or Linux. The only thing you
install yourself is a current **NVIDIA driver** ([nvidia.com/drivers](https://www.nvidia.com/drivers) or the NVIDIA
App). Everything else - Python, the engine, the model - is set up for you.
### Let your AI set it up
**Windows**
Do you use an AI coding assistant (Claude Code, Cursor, Codex, GitHub Copilot, ...)? Paste this into it:
1. [Download this project](https://github.com/Niko1221/Strata/archive/refs/heads/main.zip) and unzip it (or `git clone` it).
2. Double-click **`START-HERE.bat`**.
3. Answer a few questions - or just press Enter each time for the recommended choice:
- **Which model and size?** The original or Swift 1.5, and Q2_0, IQ2_XS, IQ3_XXS or IQ3_S - see [above](#which-model-should-i-pick)
- **How much context?** How much text it can keep in mind at once (it suggests one for your card)
- **Images?** Whether it should also read pictures
- **Experimental speed projection?** Off unless you say yes - [read what it does](docs/DETAILS.md#experimental-speed-projection-experimental-off-by-default) first
```text
Set up Strata on this PC for me: https://github.com/Niko1221/Strata - follow docs/AI_SETUP.md in that repository.
```
Then it downloads everything (the model is ~70 GB, so the first time takes a while - you can stop and it picks up
where it left off) and **starts the model**. Your browser opens the Strata app at `http://127.0.0.1:8080`.
It checks your graphics card, RAM and disk and picks the model that fits. Then it installs and starts it and tells
you how to connect your apps. AI tools can also install, start and stop Strata through its
[MCP server](docs/MCP_SERVER.md).
> **While the model starts, your PC can be slow or stop responding for 1-3 minutes** (longest the first time): Strata
> loads 35-55 GB into your RAM and locks part of it for the graphics card. That's normal - wait, and don't close the
> window. The window tells you what it is doing.
### Or do it yourself
**Next time**, just double-click `START-HERE.bat` again: it starts right away, nothing is downloaded twice. Close its
window to stop the model.
[Download Strata](https://github.com/Niko1221/Strata/archive/refs/heads/main.zip) and unzip it (or `git clone` it).
**Windows:** double-click **`START-HERE.bat`**. **Linux:** run **`./setup.sh`** in the Strata folder.
**Updating:** download the new version and unzip it anywhere (or `git pull`), then run `START-HERE.bat` in it. The
model files are kept in a `Strata-data` folder next to your Strata folder, so a new copy finds them and sets itself up
the same way - nothing big is downloaded again.
The steps are the same for NVIDIA and AMD. The installer finds your card and sets up the right engine for it. It
asks you a few questions:
**Linux:** run `./setup.sh` - same questions, same result.
- which model and which size,
- how much context (how much text the model keeps in mind),
- whether it should read pictures.
Press Enter each time for the recommended answer. Then it downloads the model (about 70 GB) and starts it. If the
download stops, run it again: it continues where it left off. Your browser opens the Strata app at
`http://127.0.0.1:8080`.
> **While the model starts, your PC can be slow or stop responding for 1-3 minutes** (longest the first time).
> Strata loads 35-55 GB into your RAM and locks part of it for the graphics card. This is normal. Wait, and don't
> close the window. The window shows what Strata is doing.
**Next time**, run `START-HERE.bat` (or `./setup.sh`) again. It starts right away and downloads nothing twice. Close
its window to stop the model. `UPDATE.bat` (`./update.sh`) updates Strata without starting it. Updating, Docker,
several cards, where the files go and every option: [docs/INSTALL.md](docs/INSTALL.md).
## Which model should I pick?
The installer recommends one for your RAM. The same model comes in several sizes, compressed more or less. Smaller
sizes are faster. Larger sizes are a bit smarter.
| Your RAM | Take | Why |
| --- | --- | --- |
| **32 GB** | **Coder** | it fits 32 GB, and it is made for code (with a 24 GB card, Q2_0 and IQ2_XS run too) |
| **48 GB** | **IQ2_XS** (or Q2_0, the fastest) | the larger sizes do not fit |
| **64 GB** | **IQ2_XS** (recommended), or IQ3_XXS / IQ3_S | every size fits; IQ3_S is the best and the slowest |
| **96 GB or more** | **IQ3_S**, or Unsloth's UD-IQ4_XS (~4-bit) | room for the largest sizes with everything else open |
- **[Coder](docs/MODELS.md#coder):** a coding version with half of the experts removed. It reaches 91% of the full
model's SWE-bench Verified score (measured by its authors) and fits 32 GB of RAM. It is weaker outside code,
including Chinese and other CJK text (#438). For those, take Q2_0, IQ2_XS or IQ3_S, which keep every expert.
- **[Swift 1.5](docs/MODELS.md#swift-15):** a fine-tune that thinks for a much shorter time before it answers. You
get the answer sooner, at about the same quality.
- **[Unsloth UD-IQ4_XS](docs/MODELS.md#unsloth-ud-iq4_xs):** Unsloth's ~4-bit version, between IQ3_S and
UD-Q4_K_XL in quality. A 94 GB download. With less than ~80 GB of RAM, Strata reads part of it from the SSD
while it answers, so it is slower there (an NVMe SSD helps).
- **[Unsloth UD-Q4_K_XL](docs/MODELS.md#unsloth-ud-q4_k_xl-experimental)** (experimental): the closest to the full
model. But Strata reads most of it from the SSD while it answers, so it writes only 7-8.5 tokens/s on a 64 GB PC.
- **[OrcaRouter's Uncensored IQ3_XXS](docs/MODELS.md#orcarouter-uncensored-iq3_xxs):** you set it up by hand. It is
not in the installer's menu.
Sizes, downloads and what fits where: [docs/MODELS.md](docs/MODELS.md). To add another model later, run
`SETUP.bat` (Linux: `./setup.sh --setup`).
## Using it
<p align="center"><img src="docs/media/runpagoda.png" width="900" alt="The Strata app's Monitor tab next to a coding agent"><br>
<sub>The Strata app's <b>Monitor</b> (left) while a coding agent writes the pagoda garden from the video (right)</sub></p>
- **In the browser:** `http://127.0.0.1:8080` - the Strata app (it opens by itself when the model starts): **Chat**, a
live **Monitor** of the model and your GPU/CPU/RAM, and **About** with the settings and addresses.
- **Chat in the terminal:** `.venv\Scripts\python chat.py`
- **Your apps and coding agents:** add it as an "OpenAI-compatible" provider with base URL
**`http://127.0.0.1:8080/v1`**, any API key and any model name. Apps that use Anthropic's API: `http://127.0.0.1:8080/v1/messages`.
- **Thinking:** the model thinks before it answers. Choose **off, low, medium or high** - in the chat page menu, with
`/think low` in `chat.py`, or with your app's "reasoning effort" setting. Off is fastest; high is best for hard questions.
- **Pictures:** in the chat page click **Picture**; in `chat.py` type `/image <path>`; in apps just attach them.
- **From your phone or another PC:** `START-HERE.bat --setup --host 0.0.0.0 --api-key <secret>`, then open the
address the server window prints; see the [details](docs/DETAILS.md#using-it).
- **Experimental speed projection (off by default):** an experimental control vector that setup can turn on; it
changes how the model answers - read [what it does](docs/DETAILS.md#experimental-speed-projection-experimental-off-by-default) first.
- **In the browser:** open `http://127.0.0.1:8080`. It has **Chat**, a live **Monitor** of the model and your
GPU/CPU/RAM, and **About** with the settings and addresses.
- **Your apps and coding agents:** add an "OpenAI-compatible" provider with the base URL
**`http://127.0.0.1:8080/v1`**. Any API key and any model name work.
- Apps that use Anthropic's API: `http://127.0.0.1:8080/v1/messages` (Claude Code:
`ANTHROPIC_BASE_URL=http://127.0.0.1:8080`).
- Codex CLI and other apps that use the OpenAI Responses API: `/v1/responses`
([setup](docs/DETAILS.md#the-responses-api-and-codex-cli)).
- **Thinking:** choose **off, low, medium or high** in the chat menu or in your app's "reasoning effort". Off is the
fastest. High is best for hard questions.
- **Pictures:** say yes to "Images?" in setup. Then click **Picture** in the chat, or attach pictures in your app.
AMD cards read pictures on Linux through the processor; on Windows they can't yet.
- **From your phone or another PC:** `START-HERE.bat --setup --host 0.0.0.0 --api-key <secret>`. Always set a key.
- **One request at a time:** by default Strata answers one request, and the others wait. To answer several at once,
set `"parallel": 2` ([BATCHING.md](docs/BATCHING.md)). On a 12 GB card this makes each answer slower.
- **Long prompts:** Strata reads the first message of a chat in full, about 1 minute per 30,000 tokens. Follow-up
messages start in seconds.
**Good to know:** it answers one request at a time. The first message of a chat is read in full (about 1 minute per
30,000 tokens); after that it keeps the conversation and reads only what is new, so follow-ups start in seconds.
More: [where your chats are stored](docs/INSTALL.md#where-things-are-stored), [the API](docs/DETAILS.md#using-it).
## Something went wrong?
**My PC froze, or got very slow, the first time Strata started.**
That's normal while it starts, most of all the first time. Strata loads 35-55 GB into your RAM, locks part of it for
the graphics card, and works out how much of the model fits on your GPU. The mouse can freeze for a few minutes. **Wait, and don't close the
window.** The next starts are much faster. Still frozen after 10 minutes? Restart the PC, close other programs
(browsers use a lot of RAM) and try again. If it keeps happening, pick a smaller size (Q2_0 or IQ2_XS).
- **My PC froze the first time Strata started.** This is normal while it loads the model. Wait, and don't close the
window. Still frozen after 10 minutes? Restart the PC, close other programs and try again, or pick a smaller size.
- **It stopped while downloading or installing.** Run `START-HERE.bat` (or `./setup.sh`) again. It continues where
it stopped.
- **It's very slow and the disk light keeps blinking, or it says "the engine stopped unexpectedly".** Your PC does
not have enough free RAM. Close other programs (browsers use a lot), or pick a smaller size (Q2_0 or IQ2_XS).
- **It says port 8080 is already in use.** Strata is already running. Look for its window.
**It stopped while downloading or installing.**
Run `START-HERE.bat` again. It continues where it stopped.
**It says the NVIDIA driver is too old.**
Update it (NVIDIA App or [nvidia.com/drivers](https://www.nvidia.com/drivers)), restart the PC, and run
`START-HERE.bat` again.
**It says port 8080 is already in use.**
Strata is already running. Look for its window.
**It's very slow and the disk light keeps blinking.**
Your PC is out of free RAM. Close other programs, or pick a smaller size (Q2_0 or IQ2_XS).
**An answer stopped with "the engine stopped unexpectedly".**
Usually not enough RAM (on Linux the system then stops the engine). Just send your message again: Strata starts the
engine by itself. If it keeps happening, close other programs or pick a smaller size.
**It says the prompt exceeds the context.**
The conversation is longer than the context you chose. Start a new chat, or run `SETUP.bat` and pick more
context.
**Still stuck?** Look in the [full troubleshooting table](docs/DETAILS.md#troubleshooting), or open an issue and
attach `strata-<model>.log` from the Strata folder.
More problems and their fixes: [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md). Still stuck? Open an
[issue](https://github.com/Niko1221/Strata/issues) and attach `strata-<model>.log` from the Strata folder. Found a
security problem? Report it privately: [SECURITY.md](SECURITY.md).
## How does it work?
Models like this one normally run on servers with hundreds of gigabytes of graphics memory. Your graphics card has
12-24 GB. Strata makes it fit by **sharing the work across your whole PC** - the same idea as a kitchen, where the
things you use all the time stay on the counter and the rest waits in the pantry.
Models like this one usually run on servers with hundreds of gigabytes of graphics memory. Your graphics card has
12-24 GB. Strata makes the model fit by **sharing the work across your whole PC**. Think of a kitchen: the things
you use all the time stay on the counter, and the rest waits in the pantry.
<p align="center"><img src="docs/media/how-it-works.svg" width="860" alt="The model's 24,576 experts: the busiest on the graphics card, all of them in RAM, a lookup table on the SSD"></p>
- **The model is a team of 24,576 small specialists ("experts"),** and each word it writes needs only 10 of them.
So it doesn't have to have all of them on the graphics card at once.
- **Your graphics card** does the part of the work needed for every word, and keeps the few thousand experts that
are asked most often. It keeps learning which ones those are while you use it.
- **Your RAM** holds every expert. When a word needs one the card doesn't have, **your processor** works on it -
at the same time as the graphics card, so neither waits for the other.
- **Your SSD** holds a big lookup table; the model only reads a few small rows of it per word.
- **The model is a team of 24,576 small specialists ("experts").** Each word needs only 10 of them.
- **Your graphics card** keeps the few thousand experts that are used most often. **Your RAM** holds all of them,
and **your processor** works on the rest at the same time. **Your SSD** holds a big lookup table.
<p align="center"><img src="docs/media/guess-and-check.svg" width="860" alt="A small helper guesses the next words; the big model checks them all at once and keeps the right ones"></p>
- **Guess, then check.** A small, fast helper built into the model guesses the next few words, and the big model
checks all the guesses in one go. It keeps the ones it agrees with and writes the next word itself - so one step
often produces several words. The helper only guesses - the big model decides every word - so you get the same
quality answer, 1.6-1.8x sooner.
- **Long texts are read in big pieces** (up to 8,192 tokens - pieces of words - at a time), which is why a long
document or code base is read at over 1,000 tokens per second.
- **Guess, then check:** a small helper guesses the next few words. The big model checks them all at once. You get
the same answer, 1.6-1.8x sooner.
- **Long texts are read in big pieces** (up to 8,192 tokens at a time), at over 1,000 tokens per second.
Want the full picture? The [details](docs/DETAILS.md#how-it-works) explain every part and its numbers, and the
[paper](docs/paper/Strata-Paper.pdf) tells the whole story, with the measurements behind it.
The longer explanation: [docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md). Every part and its numbers:
[the details](docs/DETAILS.md#how-it-works) and the [paper](docs/paper/Strata-Paper.pdf).
## Credits
## Credits and license
- Model: [Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next) by the Qwen team; compressed versions by
[ISTA-DASLab](https://huggingface.co/ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF);
[Swift 1.5](https://huggingface.co/ukisai/Swift-1.5-Qwen3.8-Flash-Next-GSQ-RCO-GGUF) by UkisAI. Their licenses apply
to the model files.
- Built with parts of [llama.cpp / ggml](https://github.com/ggml-org/llama.cpp) (MIT). Ideas from
[Splash](https://github.com/incoai/splash), [ninfer](https://github.com/Neroued/ninfer) and
[HyperQwen](https://github.com/syv-ai/HyperQwen). More in the [details](docs/DETAILS.md#credits-and-licenses).
The model is [Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next) by the Qwen team. It was
compressed by [ISTA-DASLab](https://huggingface.co/ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF), UkisAI (Swift 1.5)
and Unsloth. Strata uses parts of [llama.cpp / ggml](https://github.com/ggml-org/llama.cpp). All credits:
[docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md#credits). Strata is open source under the [MIT License](LICENSE). A few
parts and every model have their own licenses ([which ones](docs/HOW_IT_WORKS.md#license)).
## License
## Support Strata
Strata is open source under the [MIT License](LICENSE). A few parts carry their own licenses: `third_party/ggml`
(MIT, llama.cpp / ggml), the web app's font (SIL Open Font License 1.1) and the experimental speed projection's
vector in `data/experimental-speed-projection` (Qwen Community License 1.0, from the model's activations). The
models are not part of this repository; each model's own license applies to its files.
Strata is free and open source. If it is useful to you, you can support its development:
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a></p>
+217
View File
@@ -0,0 +1,217 @@
<h1 align="center">Strata</h1>
[English](README.md) · [简体中文](README.zh-CN.md) · [日本語](README.ja.md) · [Deutsch](README.de.md) · [Français](README.fr.md) · [Español](README.es.md) · **Português**
<p align="center"><b>Rode um modelo de IA de 125 bilhões de parâmetros no seu próprio PC gamer</b><br>
Placa de vídeo NVIDIA ou AMD (12 GB ou mais) · Windows ou Linux · gratuito e de código aberto</p>
<p align="center"><a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4"><img src="docs/media/pagoda-preview.webp" width="720" alt="Um jardim com pagode em voxels que o modelo do Strata escreveu, rodando no navegador"></a><br>
<sub>Um jardim com pagode em voxels, feito com um único prompt numa RTX 5070 com o Strata (IQ3_S, contexto de 128K) ·
<a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4">vídeo completo (49 s)</a></sub></p>
O Strata roda o **[Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next)** num PC comum. É um modelo
de IA grande e inteligente que normalmente precisa de um servidor. Ele conversa, escreve código, entende imagens e
funciona com seus apps e agentes de programação. Nada sai do seu PC.
## Qual é a velocidade?
Medimos em dois PCs gamer comuns. Um token equivale a cerca de ¾ de uma palavra.
- **Escreve respostas:** a velocidade com que a resposta aparece numa conversa curta. 60 tokens por segundo é mais rápido do que você consegue ler.
- **Lê seu prompt:** a velocidade com que ele absorve o que você envia (aqui, um documento, código ou histórico de conversa de 32K tokens).
<table>
<tr><th>NVIDIA: RTX 5070 (12 GB), Ryzen 5 7600, 64 GB de RAM</th><th>AMD: RX 9070 XT (16 GB), Ryzen 9 3900X, 47 GB de RAM</th></tr>
<tr><td>
| Tamanho | Escreve respostas | Lê seu prompt |
| --- | ---: | ---: |
| **Q2_0** | 94 tokens/s | 2,650 tokens/s |
| **IQ2_XS** | 79 tokens/s | 2,090 tokens/s |
| **IQ3_XXS** | 62 tokens/s | 1,750 tokens/s |
| **IQ3_S** | 53 tokens/s | 1,620 tokens/s |
| **Coder** | 55 tokens/s | 2,180 tokens/s |
</td><td>
| Tamanho | Escreve respostas | Lê seu prompt |
| --- | ---: | ---: |
| **Q2_0** | 60 tokens/s | 1,160 tokens/s |
| **IQ2_XS** | 52 tokens/s | 1,110 tokens/s |
| **Coder** | 44 tokens/s | 1,420 tokens/s |
</td></tr>
</table>
NVIDIA: Q2_0 com o engine 0.1.36, as outras linhas com 0.1.26 (respostas de 4K, prompts de 32K). As tabelas
completas estão em [DETAILS.md](docs/DETAILS.md#speed-measured). Uma placa com mais VRAM é mais rápida: uma
RTX 3090 (24 GB) deve escrever cerca de 100-140 tokens por segundo. Conversas longas e outras placas:
[velocidade de cada modelo](docs/MODELS.md#how-fast-is-each-size), [resultados da comunidade](docs/COMMUNITY_BENCHMARKS.md).
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a><br>
<sub>O Strata é gratuito. Se ele roda bem no seu PC, um café ajuda a manter o trabalho nele.</sub></p>
## Do que você precisa
| | |
| --- | --- |
| **Placa de vídeo** | **NVIDIA** GeForce RTX séries 20, 30, 40 ou 50, ou **AMD** Radeon RX 7900 XT / XTX, RX 7800 XT / 7700 XT, RX 9060 XT, RX 9070 / 9070 XT, Radeon AI PRO R9700 ou séries RX 6800 / 6900. Ela precisa de **12 GB de VRAM ou mais**. |
| **RAM** | 32 GB ou mais. Sua RAM decide [qual modelo](#qual-modelo-devo-escolher) cabe. Com 64 GB, roda qualquer tamanho. |
| **Disco** | Cerca de 80 GB livres. Use um SSD se puder: a primeira inicialização fica bem mais rápida. |
| **Sistema** | Windows 10 / 11 ou Linux, e um driver de vídeo atualizado da NVIDIA ou da AMD. |
O instalador cuida de todo o resto. Duas ou três placas podem dividir o modelo ([multi-GPU](docs/MULTI_GPU.md)).
Experimental, escrito e testado por membros da comunidade nas próprias máquinas:
- **Placas de vídeo mais antigas** (Tesla P40 / V100, GTX 10, Radeon VII / MI50, RX 6700 XT, RX 5500 XT): [Older GPUs](docs/OLDER_GPUS.md).
- **Intel Arc**, compilado a partir do código-fonte no Linux: [Intel Arc](docs/INTEL_ARC.md).
- **AMD Ryzen AI Max (Strix Halo)**, compilado a partir do código-fonte no Linux: [Strix Halo](docs/STRIX_HALO.md).
- **Processadores mais antigos sem AVX2**: funcionam, mas devagar. [Older CPUs](docs/INSTALL.md#older-cpus-experimental).
A lista completa: [docs/INSTALL.md](docs/INSTALL.md#what-you-need).
## Instalação
### Deixe sua IA instalar
Você usa um assistente de programação com IA (Claude Code, Cursor, Codex, GitHub Copilot, ...)? Cole isto nele:
```text
Set up Strata on this PC for me: https://github.com/Niko1221/Strata - follow docs/AI_SETUP.md in that repository.
```
Ele verifica sua placa de vídeo, RAM e disco e escolhe o modelo que cabe. Depois instala, inicia e explica como
conectar seus apps. Ferramentas de IA também podem instalar, iniciar e parar o Strata pelo
[servidor MCP](docs/MCP_SERVER.md) dele.
### Ou faça você mesmo
[Baixe o Strata](https://github.com/Niko1221/Strata/archive/refs/heads/main.zip) e descompacte (ou use `git clone`).
**Windows:** clique duas vezes em **`START-HERE.bat`**. **Linux:** rode **`./setup.sh`** na pasta do Strata.
Os passos são os mesmos para NVIDIA e AMD. O instalador encontra sua placa e configura o engine certo para ela.
Ele faz algumas perguntas:
- qual modelo e qual tamanho,
- quanto contexto (quanto texto o modelo guarda na memória),
- se ele deve entender imagens.
Aperte Enter em cada uma para usar a resposta recomendada. Depois ele baixa o modelo (cerca de 70 GB) e o inicia.
Se o download parar, rode de novo: ele continua de onde parou. Seu navegador abre o app do Strata em
`http://127.0.0.1:8080`.
> **Enquanto o modelo inicia, seu PC pode ficar lento ou parar de responder por 1-3 minutos** (mais na primeira vez).
> O Strata carrega 35-55 GB na sua RAM e reserva parte dela para a placa de vídeo. Isso é normal. Espere e não
> feche a janela. A janela mostra o que o Strata está fazendo.
**Da próxima vez**, rode `START-HERE.bat` (ou `./setup.sh`) de novo. Ele inicia na hora e não baixa nada duas
vezes. Feche a janela para parar o modelo. `UPDATE.bat` (`./update.sh`) atualiza o Strata sem iniciá-lo.
Atualização, Docker, várias placas, onde ficam os arquivos e todas as opções: [docs/INSTALL.md](docs/INSTALL.md).
## Qual modelo devo escolher?
O instalador recomenda um de acordo com sua RAM. O mesmo modelo vem em vários tamanhos, mais ou menos comprimidos.
Os tamanhos menores são mais rápidos. Os maiores são um pouco mais inteligentes.
| Sua RAM | Escolha | Por quê |
| --- | --- | --- |
| **32 GB** | **Coder** | cabe em 32 GB e é feito para código (com uma placa de 24 GB, Q2_0 e IQ2_XS também rodam) |
| **48 GB** | **IQ2_XS** (ou Q2_0, o mais rápido) | os tamanhos maiores não cabem |
| **64 GB** | **IQ2_XS** (recomendado), ou IQ3_XXS / IQ3_S | todos os tamanhos cabem; IQ3_S é o melhor e o mais lento |
| **96 GB ou mais** | **IQ3_S**, ou o UD-IQ4_XS da Unsloth (~4-bit) | espaço para os maiores tamanhos com todo o resto aberto |
- **[Coder](docs/MODELS.md#coder):** uma versão para programação com metade dos experts removida. Ela alcança 91%
da pontuação do modelo completo no SWE-bench Verified (medido pelos autores) e cabe em 32 GB de RAM. É mais fraca
fora do código, inclusive em chinês e outros textos CJK (#438). Para isso, escolha Q2_0, IQ2_XS ou IQ3_S, que
mantêm todos os experts.
- **[Swift 1.5](docs/MODELS.md#swift-15):** um fine-tune que pensa por bem menos tempo antes de responder. Você
recebe a resposta mais cedo, com quase a mesma qualidade.
- **[Unsloth UD-IQ4_XS](docs/MODELS.md#unsloth-ud-iq4_xs):** a versão de ~4 bits da Unsloth, entre IQ3_S e
UD-Q4_K_XL em qualidade. Um download de 94 GB. Com menos de ~80 GB de RAM, o Strata lê uma parte dele do SSD
enquanto responde, então ali ele fica mais lento (um SSD NVMe ajuda).
- **[Unsloth UD-Q4_K_XL](docs/MODELS.md#unsloth-ud-q4_k_xl-experimental)** (experimental): o mais próximo do modelo
completo. Mas o Strata lê a maior parte dele do SSD enquanto responde, então ele escreve só 7-8.5 tokens/s num PC
com 64 GB.
- **[OrcaRouter's Uncensored IQ3_XXS](docs/MODELS.md#orcarouter-uncensored-iq3_xxs):** você configura à mão. Ele
não está no menu do instalador.
Tamanhos, downloads e o que cabe onde: [docs/MODELS.md](docs/MODELS.md). Para adicionar outro modelo depois, rode
`SETUP.bat` (Linux: `./setup.sh --setup`).
## Como usar
<p align="center"><img src="docs/media/runpagoda.png" width="900" alt="A aba Monitor do app Strata ao lado de um agente de programação"><br>
<sub>O <b>Monitor</b> do app Strata (à esquerda) enquanto um agente de programação escreve o jardim com pagode do vídeo (à direita)</sub></p>
- **No navegador:** abra `http://127.0.0.1:8080`. Lá tem o **Chat**, um **Monitor** ao vivo do modelo e da sua
GPU/CPU/RAM, e o **About** com as configurações e os endereços.
- **Seus apps e agentes de programação:** adicione um provedor "OpenAI-compatible" com a URL base
**`http://127.0.0.1:8080/v1`**. Qualquer chave de API e qualquer nome de modelo funcionam.
- Apps que usam a API da Anthropic: `http://127.0.0.1:8080/v1/messages` (Claude Code:
`ANTHROPIC_BASE_URL=http://127.0.0.1:8080`).
- Codex CLI e outros apps que usam a OpenAI Responses API: `/v1/responses`
([configuração](docs/DETAILS.md#the-responses-api-and-codex-cli)).
- **Raciocínio:** escolha **off, low, medium ou high** no menu do chat ou no "reasoning effort" do seu app. Off é o
mais rápido. High é o melhor para perguntas difíceis.
- **Imagens:** responda sim para "Images?" na instalação. Depois clique em **Picture** no chat, ou anexe imagens no
seu app. Placas AMD entendem imagens no Linux usando o processador; no Windows, ainda não.
- **Do seu celular ou de outro PC:** `START-HERE.bat --setup --host 0.0.0.0 --api-key <secret>`. Sempre defina uma chave.
- **Uma requisição por vez:** por padrão, o Strata responde uma requisição e as outras esperam. Para responder
várias ao mesmo tempo, defina `"parallel": 2` ([BATCHING.md](docs/BATCHING.md)). Numa placa de 12 GB, isso deixa
cada resposta mais lenta.
- **Prompts longos:** o Strata lê a primeira mensagem de uma conversa inteira, cerca de 1 minuto a cada 30,000
tokens. As mensagens seguintes começam em segundos.
Mais: [onde suas conversas ficam salvas](docs/INSTALL.md#where-things-are-stored), [a API](docs/DETAILS.md#using-it).
## Algo deu errado?
- **Meu PC travou na primeira vez que o Strata iniciou.** Isso é normal enquanto ele carrega o modelo. Espere e não
feche a janela. Ainda travado depois de 10 minutos? Reinicie o PC, feche outros programas e tente de novo, ou
escolha um tamanho menor.
- **Parou durante o download ou a instalação.** Rode `START-HERE.bat` (ou `./setup.sh`) de novo. Ele continua de
onde parou.
- **Está muito lento e a luz do disco não para de piscar, ou aparece "the engine stopped unexpectedly".** Seu PC
não tem RAM livre suficiente. Feche outros programas (navegadores usam muita), ou escolha um tamanho menor (Q2_0
ou IQ2_XS).
- **Diz que a porta 8080 já está em uso.** O Strata já está rodando. Procure a janela dele.
Mais problemas e como resolver: [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md). Ainda sem solução? Abra uma
[issue](https://github.com/Niko1221/Strata/issues) e anexe o `strata-<model>.log` da pasta do Strata. Encontrou um
problema de segurança? Informe em particular: [SECURITY.md](SECURITY.md).
## Como funciona?
Modelos como este normalmente rodam em servidores com centenas de gigabytes de memória de vídeo. Sua placa de vídeo
tem 12-24 GB. O Strata faz o modelo caber **dividindo o trabalho pelo PC inteiro**. Pense numa cozinha: o que você
usa o tempo todo fica na bancada, e o resto espera na despensa.
<p align="center"><img src="docs/media/how-it-works.svg" width="860" alt="Os 24,576 experts do modelo: os mais usados na placa de vídeo, todos na RAM, uma tabela de consulta no SSD"></p>
- **O modelo é uma equipe de 24,576 pequenos especialistas ("experts").** Cada palavra precisa de só 10 deles.
- **Sua placa de vídeo** guarda os poucos milhares de experts usados com mais frequência. **Sua RAM** guarda todos
eles, e **seu processador** trabalha no resto ao mesmo tempo. **Seu SSD** guarda uma grande tabela de consulta.
<p align="center"><img src="docs/media/guess-and-check.svg" width="860" alt="Um pequeno ajudante adivinha as próximas palavras; o modelo grande confere todas de uma vez e fica com as certas"></p>
- **Adivinhar e conferir:** um pequeno ajudante adivinha as próximas palavras. O modelo grande confere todas de
uma vez. Você recebe a mesma resposta, 1.6-1.8x mais cedo.
- **Textos longos são lidos em grandes pedaços** (até 8,192 tokens por vez), a mais de 1,000 tokens por segundo.
A explicação mais longa: [docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md). Cada parte e seus números:
[os detalhes](docs/DETAILS.md#how-it-works) e o [artigo](docs/paper/Strata-Paper.pdf).
## Créditos e licença
O modelo é o [Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next), da equipe Qwen. Ele foi
comprimido por [ISTA-DASLab](https://huggingface.co/ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF), UkisAI (Swift 1.5)
e Unsloth. O Strata usa partes do [llama.cpp / ggml](https://github.com/ggml-org/llama.cpp). Todos os créditos:
[docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md#credits). O Strata é de código aberto sob a [MIT License](LICENSE).
Algumas partes e todos os modelos têm licenças próprias ([quais](docs/HOW_IT_WORKS.md#license)).
## Apoie o Strata
O Strata é gratuito e de código aberto. Se ele é útil para você, você pode apoiar o desenvolvimento:
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" height="50"></a></p>
+200
View File
@@ -0,0 +1,200 @@
<h1 align="center">Strata</h1>
[English](README.md) · **简体中文** · [日本語](README.ja.md) · [Deutsch](README.de.md) · [Français](README.fr.md) · [Español](README.es.md) · [Português](README.pt-BR.md)
<p align="center"><b>在你自己的游戏电脑上运行 1250 亿参数的 AI 模型</b><br>
NVIDIA 或 AMD 显卡(12 GB 及以上)· Windows 或 Linux · 免费开源</p>
<p align="center"><a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4"><img src="docs/media/pagoda-preview.webp" width="720" alt="Strata 的模型写出的体素宝塔花园,在浏览器中运行"></a><br>
<sub>体素宝塔花园,一次提示生成,在 RTX 5070 上用 Strata 运行(IQ3_S,128K 上下文)·
<a href="https://github.com/Niko1221/Strata/releases/download/v0.1.10/Pagoda.mp4">完整视频(49 秒)</a></sub></p>
Strata 能在普通电脑上运行 **[Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next)**。这是一个又大又聪明的
AI 模型,通常要用服务器才能跑。它能聊天、写代码、看图片,还能配合你的应用和编程智能体一起工作。所有数据都留在你的电脑上。
## 速度有多快?
我们在两台普通的游戏电脑上做了测试。一个 token 大约相当于 ¾ 个英文单词。
- **写回答:** 短对话中回复出现的速度。每秒 60 个 token 已经比你的阅读速度还快。
- **读提示:** 读入你发送内容的速度(这里是一份 32K token 的文档、代码或聊天记录)。
<table>
<tr><th>NVIDIA:RTX 5070(12 GB)、Ryzen 5 7600、64 GB 内存</th><th>AMD:RX 9070 XT(16 GB)、Ryzen 9 3900X、47 GB 内存</th></tr>
<tr><td>
| 规格 | 写回答 | 读提示 |
| --- | ---: | ---: |
| **Q2_0** | 94 tokens/s | 2,650 tokens/s |
| **IQ2_XS** | 79 tokens/s | 2,090 tokens/s |
| **IQ3_XXS** | 62 tokens/s | 1,750 tokens/s |
| **IQ3_S** | 53 tokens/s | 1,620 tokens/s |
| **Coder** | 55 tokens/s | 2,180 tokens/s |
</td><td>
| 规格 | 写回答 | 读提示 |
| --- | ---: | ---: |
| **Q2_0** | 60 tokens/s | 1,160 tokens/s |
| **IQ2_XS** | 52 tokens/s | 1,110 tokens/s |
| **Coder** | 44 tokens/s | 1,420 tokens/s |
</td></tr>
</table>
NVIDIA:Q2_0 用的是引擎 0.1.36,其他各行用的是 0.1.26(4K 回答,32K 提示)。完整表格见
[DETAILS.md](docs/DETAILS.md#speed-measured)。显存越大的显卡越快:RTX 3090(24 GB)写回答应该能达到每秒约
100-140 个 token。长对话和其他显卡的数据:[各模型的速度](docs/MODELS.md#how-fast-is-each-size)、
[社区测试结果](docs/COMMUNITY_BENCHMARKS.md)。
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="请我喝杯咖啡" height="50"></a><br>
<sub>Strata 是免费的。如果它在你的电脑上跑得不错,请我喝杯咖啡,让这个项目继续下去。</sub></p>
## 你需要什么
| | |
| --- | --- |
| **显卡** | **NVIDIA** GeForce RTX 20、30、40 或 50 系列,或 **AMD** Radeon RX 7900 XT / XTX、RX 7800 XT / 7700 XT、RX 9060 XT、RX 9070 / 9070 XT、Radeon AI PRO R9700 或 RX 6800 / 6900 系列。需要 **12 GB 或以上显存**。 |
| **内存** | 32 GB 或以上。内存大小决定能装下[哪个模型](#该选哪个模型)。64 GB 可以运行所有规格。 |
| **硬盘** | 约 80 GB 可用空间。尽量用 SSD:第一次启动会快很多。 |
| **系统** | Windows 10 / 11 或 Linux,以及 NVIDIA 或 AMD 的最新显卡驱动。 |
其他的都由安装程序搞定。两到三张显卡可以分担同一个模型([多 GPU](docs/MULTI_GPU.md))。
实验性支持,由社区成员在自己的机器上编写和测试:
- **较老的显卡**(Tesla P40 / V100、GTX 10、Radeon VII / MI50、RX 6700 XT、RX 5500 XT):[较老的 GPU](docs/OLDER_GPUS.md)。
- **Intel Arc**,在 Linux 上从源码构建:[Intel Arc](docs/INTEL_ARC.md)。
- **AMD Ryzen AI Max(Strix Halo)**,在 Linux 上从源码构建:[Strix Halo](docs/STRIX_HALO.md)。
- **不支持 AVX2 的老处理器**:能用,但很慢。[较老的 CPU](docs/INSTALL.md#older-cpus-experimental)。
完整列表:[docs/INSTALL.md](docs/INSTALL.md#what-you-need)。
## 安装
### 让你的 AI 帮你装
你在用 AI 编程助手吗(Claude Code、Cursor、Codex、GitHub Copilot 等)?把下面这段粘贴给它:
```text
Set up Strata on this PC for me: https://github.com/Niko1221/Strata - follow docs/AI_SETUP.md in that repository.
```
它会检查你的显卡、内存和硬盘,选出合适的模型。然后安装并启动它,再告诉你怎么连接你的应用。AI 工具也可以通过
Strata 的 [MCP 服务器](docs/MCP_SERVER.md)来安装、启动和停止 Strata。
### 或者自己动手
[下载 Strata](https://github.com/Niko1221/Strata/archive/refs/heads/main.zip) 并解压(或者用 `git clone`)。
**Windows:** 双击 **`START-HERE.bat`**。**Linux:** 在 Strata 文件夹里运行 **`./setup.sh`**。
NVIDIA 和 AMD 的步骤完全一样。安装程序会识别你的显卡,并装好对应的引擎。它会问你几个问题:
- 用哪个模型、哪个规格,
- 上下文多大(模型能记住多少文字),
- 是否要识别图片。
每次直接按回车就是推荐选项。之后它会下载模型(约 70 GB)并启动。如果下载中断了,再运行一次即可:它会从中断的地方继续。
浏览器会打开 Strata 应用,地址是 `http://127.0.0.1:8080`。
> **模型启动时,你的电脑可能会变慢或卡住 1-3 分钟**(第一次最久)。
> Strata 会把 35-55 GB 加载到内存,并为显卡锁定其中一部分。这是正常的。请耐心等待,不要关闭窗口。
> 窗口里会显示 Strata 正在做什么。
**下次使用时**,再运行一次 `START-HERE.bat`(或 `./setup.sh`)。它会马上启动,已下载的东西不会重复下载。关闭它的窗口就能停止模型。
`UPDATE.bat`(`./update.sh`)只更新 Strata,不启动。更新、Docker、多张显卡、文件存放位置以及所有选项:
[docs/INSTALL.md](docs/INSTALL.md)。
## 该选哪个模型
安装程序会根据你的内存推荐一个。同一个模型有几种规格,压缩程度不同。规格越小越快,越大越聪明一些。
| 你的内存 | 选择 | 原因 |
| --- | --- | --- |
| **32 GB** | **Coder** | 32 GB 装得下,而且专为代码打造(如果显卡是 24 GB,Q2_0 和 IQ2_XS 也能跑) |
| **48 GB** | **IQ2_XS**(或 Q2_0,最快) | 更大的规格装不下 |
| **64 GB** | **IQ2_XS**(推荐),或 IQ3_XXS / IQ3_S | 所有规格都装得下;IQ3_S 最好,也最慢 |
| **96 GB 或以上** | **IQ3_S**,或 Unsloth 的 UD-IQ4_XS(约 4-bit) | 开着其他程序也能放下最大的规格 |
- **[Coder](docs/MODELS.md#coder):** 编程版本,去掉了一半专家。它达到完整模型 SWE-bench Verified 分数的 91%(由其作者测得),
32 GB 内存就能装下。代码以外的能力较弱,包括中文和其他中日韩文本(#438)。这类用途请选 Q2_0、IQ2_XS 或 IQ3_S,
它们保留了所有专家。
- **[Swift 1.5](docs/MODELS.md#swift-15):** 一个微调版本,回答前思考的时间短得多。你能更早拿到答案,质量基本不变。
- **[Unsloth UD-IQ4_XS](docs/MODELS.md#unsloth-ud-iq4_xs):** Unsloth 的约 4-bit 版本,质量介于 IQ3_S 和 UD-Q4_K_XL 之间。
下载 94 GB。内存少于约 80 GB 时,Strata 回答时要从 SSD 读取其中一部分,所以会更慢(NVMe SSD 有帮助)。
- **[Unsloth UD-Q4_K_XL](docs/MODELS.md#unsloth-ud-q4_k_xl-experimental)**(实验性):最接近完整模型。但 Strata
回答时要从 SSD 读取其中大部分内容,所以在 64 GB 的电脑上每秒只能写 7-8.5 个 token。
- **[OrcaRouter 的 Uncensored IQ3_XXS](docs/MODELS.md#orcarouter-uncensored-iq3_xxs):** 需要手动设置,不在安装程序的菜单里。
规格、下载以及各配置能装下什么:[docs/MODELS.md](docs/MODELS.md)。以后想再添加模型,运行
`SETUP.bat`(Linux:`./setup.sh --setup`)。
## 使用方法
<p align="center"><img src="docs/media/runpagoda.png" width="900" alt="Strata 应用的 Monitor 标签页,旁边是一个编程智能体"><br>
<sub>Strata 应用的 <b>Monitor</b>(左),编程智能体正在写视频里的宝塔花园(右)</sub></p>
- **在浏览器里:** 打开 `http://127.0.0.1:8080`。里面有 **Chat**(聊天)、实时 **Monitor**(监控模型和你的
GPU/CPU/内存),以及 **About**(设置和地址)。
- **你的应用和编程智能体:** 添加一个“OpenAI 兼容”的提供商,base URL 填 **`http://127.0.0.1:8080/v1`**。
API key 和模型名随便填都行。
- 使用 Anthropic API 的应用:`http://127.0.0.1:8080/v1/messages`(Claude Code:
`ANTHROPIC_BASE_URL=http://127.0.0.1:8080`)。
- Codex CLI 和其他使用 OpenAI Responses API 的应用:`/v1/responses`
([设置方法](docs/DETAILS.md#the-responses-api-and-codex-cli))。
- **思考:** 在聊天菜单或应用的“reasoning effort”里选择 **off、low、medium 或 high**。off 最快,
high 最适合难题。
- **图片:** 在安装时对“Images?”选是。然后在聊天里点 **Picture**,或在你的应用里附上图片。
AMD 显卡在 Linux 上通过处理器识别图片;在 Windows 上暂时还不行。
- **从手机或另一台电脑访问:** `START-HERE.bat --setup --host 0.0.0.0 --api-key <secret>`。一定要设置 key。
- **一次处理一个请求:** 默认情况下 Strata 一次只回答一个请求,其他请求排队等待。想同时回答多个,
设置 `"parallel": 2`([BATCHING.md](docs/BATCHING.md))。在 12 GB 显卡上,这会让每个回答变慢。
- **长提示:** Strata 会完整读入对话的第一条消息,大约每 30,000 个 token 需要 1 分钟。之后的消息几秒内就开始回答。
更多:[聊天记录存在哪里](docs/INSTALL.md#where-things-are-stored)、[API](docs/DETAILS.md#using-it)。
## 出问题了?
- **Strata 第一次启动时电脑卡死了。** 加载模型时这是正常的。请耐心等待,不要关闭窗口。
10 分钟后还卡着?重启电脑,关掉其他程序再试一次,或者换一个更小的规格。
- **下载或安装时中断了。** 再运行一次 `START-HERE.bat`(或 `./setup.sh`)。它会从中断的地方继续。
- **非常慢,硬盘灯一直闪,或者提示“the engine stopped unexpectedly”。** 你的电脑可用内存不够。
关掉其他程序(浏览器很占内存),或者换一个更小的规格(Q2_0 或 IQ2_XS)。
- **提示 8080 端口已被占用。** Strata 已经在运行了。找一下它的窗口。
更多问题和解决办法:[docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md)。还是解决不了?提交一个
[issue](https://github.com/Niko1221/Strata/issues),并附上 Strata 文件夹里的 `strata-<model>.log`。发现了安全问题?
请私下报告:[SECURITY.md](SECURITY.md)。
## 它是怎么工作的?
这类模型通常运行在拥有数百 GB 显存的服务器上。而你的显卡只有 12-24 GB。Strata 让模型装得下的办法是
**把工作分摊到整台电脑上**。可以想象一个厨房:常用的东西放在台面上,其余的放在储藏室里。
<p align="center"><img src="docs/media/how-it-works.svg" width="860" alt="模型的 24,576 个专家:最常用的在显卡上,全部在内存里,一张查找表在 SSD 上"></p>
- **这个模型是由 24,576 个小专家(“experts”)组成的团队。** 每个词只需要其中 10 个。
- **你的显卡** 存放最常用的几千个专家。**你的内存** 存放全部专家,
**你的处理器** 同时处理其余的部分。**你的 SSD** 存放一张大查找表。
<p align="center"><img src="docs/media/guess-and-check.svg" width="860" alt="一个小助手猜测接下来的几个词;大模型一次性全部检查,保留正确的"></p>
- **先猜,再检查:** 一个小助手先猜接下来的几个词,大模型再一次性检查它们。答案完全一样,但快 1.6-1.8 倍。
- **长文本分大块读入**(每次最多 8,192 个 token),速度超过每秒 1,000 个 token。
更详细的解释:[docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md)。每个部分及其数据:
[详细说明](docs/DETAILS.md#how-it-works)和[论文](docs/paper/Strata-Paper.pdf)。
## 致谢与许可证
模型是 Qwen 团队的 [Qwen3.8-Flash-Next](https://huggingface.co/Qwen/Qwen3.8-Flash-Next)。它由
[ISTA-DASLab](https://huggingface.co/ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF)、UkisAI(Swift 1.5)
和 Unsloth 压缩。Strata 使用了 [llama.cpp / ggml](https://github.com/ggml-org/llama.cpp) 的部分代码。完整致谢:
[docs/HOW_IT_WORKS.md](docs/HOW_IT_WORKS.md#credits)。Strata 以 [MIT 许可证](LICENSE)开源。少数部分和每个模型
有各自的许可证([具体是哪些](docs/HOW_IT_WORKS.md#license))。
## 支持 Strata
Strata 免费且开源。如果它对你有用,欢迎支持它的开发:
<p align="center"><a href="https://buymeacoffee.com/strataengine"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="请我喝杯咖啡" height="50"></a></p>
+44
View File
@@ -0,0 +1,44 @@
# Security
## Reporting a vulnerability
Please report anything that should not be public until it is fixed **privately**, through GitHub's private
vulnerability reporting: the repository's **Security** tab, **Report a vulnerability**
([direct link](https://github.com/Niko1221/Strata/security/advisories/new)). Say what you found, how to reproduce it
(the request, the config keys involved, the Strata version), and what an attacker gains. We answer there, fix it in
a release, and credit you in the advisory unless you ask us not to.
Ordinary hardening ideas and findings that are safe to discuss in public are welcome as an
[issue](https://github.com/Niko1221/Strata/issues) (#544 collects audit findings) or as a pull request, which we
review like our own code.
Supported: the latest release. Fixes go into the next release, not into older ones.
## What the server exposes
Strata runs a model on your PC and serves it over HTTP (`serve/server.py`). Out of the box it is reachable from
this PC only. The details and every setting are in [docs/DETAILS.md](docs/DETAILS.md) ("From other devices",
"Host names", "Web pages without an API key", "Tools from MCP servers").
- **Where it listens.** `127.0.0.1` by default. `--host 0.0.0.0` (or `"host"` in `strata-<model>.json`) opens it to
your network, and the server then warns when no API key is set.
- **API key.** `"api_key"` in the run config (or `STRATA_API_KEY`) is required on `/v1/*` and on every endpoint
that shows the model's state, requests or answers (`/status`, `/metrics`, `/settings`, `/mcp`, `/props`, `/slots`,
`/api/requests`, `/config`) and on every `POST`. It is compared in constant time. Set one before you open the
server to your network or put a tunnel in front of it.
- **Host check (DNS rebinding, 0.1.38).** Without an API key the server answers only requests whose `Host` is a name
it knows (`localhost`, an IP address, the address it listens on and, when it listens beyond this PC, this PC's
name). Others get 403. `"allowed_hosts"` adds names; with an API key the key decides.
- **Origin check (0.1.38).** Without an API key, a browser `POST` to `/v1/*` from another web site's page (it carries
an `Origin` header) gets 403 unless that origin is Strata's own page, `localhost`, an allowed host, or listed in
`"trusted_origins"` / `"cors_origins"`. Changing settings (`/settings`, and `/config`: the few run config keys the
page's Model settings may change - never the network, key, MCP or program keys), `/load` and `/unload` and the
MCP tools are accepted only as JSON from Strata's own page (or `"trusted_origins"`), so a page elsewhere cannot
change settings or run tools.
- **CORS** is off unless `"cors_origins"` lists origins, and then only for `/v1/*`.
- **MCP tools** are opt-in: only the servers you put in the run config, only for requests from Strata's own page
that ask for them. They run with your user's rights, and the model decides when to call them.
- **The request monitor** (`/api-monitor`, which keeps the last prompts and answers in memory) is off unless
`"api_monitor": true` is set.
Strata has not had an outside security audit yet.
+1 -1
View File
@@ -1,6 +1,6 @@
@echo off
rem Strata for Windows: the first run installs everything and starts the model; later runs just start it.
rem Needs only an NVIDIA driver. Python is installed for your user account if it is missing (no admin needed).
rem Needs only an NVIDIA or AMD graphics driver. Python is installed for your user account if it is missing (no admin needed).
setlocal
title Strata
cd /d "%~dp0"
+36
View File
@@ -0,0 +1,36 @@
@echo off
rem Update Strata without starting the model (#475): the newest code (git pull, when this folder is a git clone), then
rem what START-HERE.bat does before a start - the engine (a new one when this version needs it), the Python packages,
rem each installed model's settings and draft subset. The model files are not touched. Start the model later with
rem START-HERE.bat. Options are passed on to setup.py.
setlocal
title Strata - update
cd /d "%~dp0"
rem All of it in one block: cmd reads a .bat file while it runs it, and the git pull can change this very file.
(
if exist ".git" (
where git >nul 2>nul || (
echo This folder is a git clone, but git is not on PATH: install Git for Windows ^(winget install Git.Git^)
echo or run "git pull" here yourself, then run UPDATE.bat again.
pause
exit /b 1
)
echo Getting the newest Strata ^(git pull^) ...
git pull --ff-only || (
echo.
echo git pull did not succeed ^(the reason is above^): nothing was updated. Files you changed here can stop it:
echo "git status" lists them.
pause
exit /b 1
)
) else (
echo This copy of Strata was not made with git, so it cannot fetch new files itself. Download the newest one:
echo https://github.com/Niko1221/Strata/archive/refs/heads/main.zip
echo unzip it anywhere and run START-HERE.bat ^(or UPDATE.bat^) in it: it finds the model files in Strata-data
echo and sets itself up the same way - nothing big is downloaded again.
echo Checking this copy's engine and settings meanwhile ...
)
call "%~dp0START-HERE.bat" --update %*
if not errorlevel 1 pause
exit /b
)
@@ -0,0 +1,49 @@
# Rope scaling: needle recall past the trained 262K
The feature (PR #84, experimental): `--rope-scaling none|linear|yarn` extends the context past the model's
trained 262,144 positions by rescaling the rotary angles - llama.cpp's types, ggml's `rope_yarn`
arithmetic, one process config applied at the cos/sin table (default path) and as kernel constants
(`--native-rope`, the native indexer, prefill). The three tables here are the first end-to-end check
that a scaled run actually recalls past the trained end.
**Hardware:** RTX 4070 Ti SUPER 16 GB, Ryzen 9 5900X (no AVX-512 - the IQ3_XXS native pack runs its
expert kernels on AVX-2), 125 GB RAM, Linux. **Engine:** this branch built from source (the log records
`rope scaling ... --max-context ... against a trained context of 262144` at startup). The runs below
were taken on the rope tree built over the 0.1.17-era base; the branch then rebased onto main (engine
0.1.20) - the drift touches none of the rope files - and the rebase was re-validated: `rope_parity`
green, a 64-token greedy run token-identical to the plain 0.1.20 build, and the yarn 262k probe
repeated green (see the last table row). Baseline arm A also re-checked the default is the stock
model: a 64-token greedy run produces the same token ids as the ready-made 0.1.17 engine, and
`rope_parity` holds the `none` table bit-identical to the pre-scaling builder.
**Method:** `tools/needle_bench.py` against a running server (launch recipes in `config-*.json`),
`temperature 0`, thinking off, depth 50%, one probe per length.
| Arm | Scaling | Context | Probe | Prompt tokens | Result | Probe time |
| --- | --- | --- | --- | --- | --- | --- |
| A | none | 262,144 | 1k @ 50% | 1,442 | FOUND | 4 s |
| A | none | 262,144 | 32k @ 50% | 31,763 | FOUND | 27 s |
| A | none | 262,144 | 128k @ 50% | 128,328 | FOUND | 86 s |
| B | linear, factor 2 | 560,000 | 262k @ 50% | 274,222 | FOUND | 232 s |
| B | linear, factor 2 | 560,000 | 512k @ 50% | 527,051 | FOUND | 619 s |
| C | yarn, factor 2 | 560,000 | 262k @ 50% | 274,215 | FOUND | 236 s |
| C | yarn, factor 2 | 560,000 | 512k @ 50% | 526,988 | FOUND | 615 s |
| C | yarn, factor 2 | 560,000 | 262k @ 50% (the rebase re-check) | 273,708 | FOUND | 235 s |
All 8 of 8 probes found the needle; JSON per arm: `needle-A-none.json`, `needle-B-linear2.json`,
`needle-B-linear2-512k.json`, `needle-C-yarn2.json` (+ the rebase re-check in
`needle-C-yarn2-rebased.json`); server and engine logs alongside.
What this establishes, and what it does not:
- **Past the trained end the model still reads.** 512k probes are 2.01x the trained 262,144 - position
interpolation (B) and YaRN (C) both hold a mid-context lookup there.
- **Scaled runs within the trained range are a slightly different model.** `yarn`'s mscale applies at
every position (a 64-token greedy prompt diverges from the stock run after ~19 tokens); arm A is the
stock model, arms B/C are not, by design.
- **One depth, one needle, one machine.** A single probe per (length, arm) at depth 50% says "recall
works there", not "no degradation anywhere" - a full depth sweep and a longer-length ladder (768K,
1M) on the bench machine (64 GB RAM there vs 125 GB here, so 262K IQ3_XXS fits either way) is the
natural follow-up. 512K prompts prefill at ~850-950 tokens/s on this card; the probe time is almost
entirely prefill.
- **The `560,000` context** in arms B/C is headroom for the needle harness's tokenizer overshoot
(a "512k" probe tokenizes to ~527k); 524,288 exactly would refuse the probe.
@@ -0,0 +1,38 @@
{
"exe": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata/build/strata",
"cwd": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata",
"tokenizer": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/packs/iq3_xxs/tokenizer",
"model_name": "qwen3.8-flash-next-iq3_xxs-rope-scaling",
"lib_dirs": [
"/usr/local/cuda/bin",
"/usr/local/cuda/lib64"
],
"port": 8130,
"args": [
"--pack",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/packs/iq3_xxs",
"--native",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/models/IQ3_XXS/Qwen3.8-Flash-Next-GSQ-RCO-IQ3_XXS-00001-of-00002.gguf",
"--ple-gguf",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/models/IQ3_XXS/Qwen3.8-Flash-Next-GSQ-RCO-IQ3_XXS-00002-of-00002.gguf",
"--expert-profile",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata/data/expert-profile.bin",
"--expert-cache",
"auto",
"--prefill",
"auto",
"--spec",
"4",
"--spec-min-p",
"0.5",
"--mtp",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/mtp/rt",
"--kv",
"int8",
"--kv-resident",
"32768",
"--max-context",
"262144"
],
"log": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata/bench/results/2026-09-28-rope-scaling/engine-A-none-262144.log"
}
@@ -0,0 +1,42 @@
{
"exe": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata/build/strata",
"cwd": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata",
"tokenizer": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/packs/iq3_xxs/tokenizer",
"model_name": "qwen3.8-flash-next-iq3_xxs-rope-scaling",
"lib_dirs": [
"/usr/local/cuda/bin",
"/usr/local/cuda/lib64"
],
"port": 8130,
"args": [
"--pack",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/packs/iq3_xxs",
"--native",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/models/IQ3_XXS/Qwen3.8-Flash-Next-GSQ-RCO-IQ3_XXS-00001-of-00002.gguf",
"--ple-gguf",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/models/IQ3_XXS/Qwen3.8-Flash-Next-GSQ-RCO-IQ3_XXS-00002-of-00002.gguf",
"--expert-profile",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata/data/expert-profile.bin",
"--expert-cache",
"auto",
"--prefill",
"auto",
"--spec",
"4",
"--spec-min-p",
"0.5",
"--mtp",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/mtp/rt",
"--kv",
"int8",
"--kv-resident",
"32768",
"--max-context",
"560000",
"--rope-scaling",
"linear",
"--rope-scale",
"2"
],
"log": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata/bench/results/2026-09-28-rope-scaling/engine-B-linear2-524288.log"
}
@@ -0,0 +1,42 @@
{
"exe": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata/build/strata",
"cwd": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata",
"tokenizer": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/packs/iq3_xxs/tokenizer",
"model_name": "qwen3.8-flash-next-iq3_xxs-rope-scaling",
"lib_dirs": [
"/usr/local/cuda/bin",
"/usr/local/cuda/lib64"
],
"port": 8130,
"args": [
"--pack",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/packs/iq3_xxs",
"--native",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/models/IQ3_XXS/Qwen3.8-Flash-Next-GSQ-RCO-IQ3_XXS-00001-of-00002.gguf",
"--ple-gguf",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/models/IQ3_XXS/Qwen3.8-Flash-Next-GSQ-RCO-IQ3_XXS-00002-of-00002.gguf",
"--expert-profile",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata/data/expert-profile.bin",
"--expert-cache",
"auto",
"--prefill",
"auto",
"--spec",
"4",
"--spec-min-p",
"0.5",
"--mtp",
"/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata-data/mtp/rt",
"--kv",
"int8",
"--kv-resident",
"32768",
"--max-context",
"560000",
"--rope-scaling",
"yarn",
"--rope-scale",
"2"
],
"log": "/home/jakub/workspace/deepseek-harness/harnes_workspace/Strata/bench/results/2026-09-28-rope-scaling/engine-C-yarn2-524288.log"
}
@@ -0,0 +1,121 @@
[
{
"length": "128k",
"round": 0,
"kind": "decode",
"prompt_tok": 128401,
"read": 52,
"gen": 357,
"read_tok_s": 79.2,
"gen_tok_s": 56.3,
"drafts_ok": 182,
"drafts_all": 305,
"seg_blocks": 3284340,
"seg_mib": 370.0,
"seg_misses": 91744,
"seg_hit_pct": 97.207,
"kib_per_token": 1061.29
},
{
"length": "128k",
"round": 1,
"kind": "read",
"prompt_tok": 128357,
"read": 128357,
"gen": 24,
"read_tok_s": 1389.2,
"gen_tok_s": 41.7,
"drafts_ok": 11,
"drafts_all": 23,
"seg_blocks": -3253560,
"seg_mib": -391.7,
"seg_misses": -97147,
"seg_hit_pct": 97.014,
"kib_per_token": -3.12
},
{
"length": "128k",
"round": 1,
"kind": "decode",
"prompt_tok": 128402,
"read": 52,
"gen": 388,
"read_tok_s": 76.5,
"gen_tok_s": 54.6,
"drafts_ok": 195,
"drafts_all": 363,
"seg_blocks": 3752616,
"seg_mib": 463.5,
"seg_misses": 114911,
"seg_hit_pct": 96.938,
"kib_per_token": 1223.26
},
{
"length": "512k",
"round": 0,
"kind": "read",
"prompt_tok": 522983,
"read": 522983,
"gen": 24,
"read_tok_s": 868.4,
"gen_tok_s": 42.4,
"drafts_ok": 13,
"drafts_all": 16,
"seg_blocks": -3808056,
"seg_mib": -387.8,
"seg_misses": -96113,
"seg_hit_pct": 97.476,
"kib_per_token": -0.76
},
{
"length": "512k",
"round": 0,
"kind": "decode",
"prompt_tok": 523028,
"read": 52,
"gen": 402,
"read_tok_s": 63.3,
"gen_tok_s": 48.4,
"drafts_ok": 221,
"drafts_all": 348,
"seg_blocks": 3580056,
"seg_mib": 920.4,
"seg_misses": 228658,
"seg_hit_pct": 93.613,
"kib_per_token": 2344.5
},
{
"length": "512k",
"round": 1,
"kind": "read",
"prompt_tok": 522984,
"read": 522984,
"gen": 24,
"read_tok_s": 857.1,
"gen_tok_s": 35.5,
"drafts_ok": 9,
"drafts_all": 18,
"seg_blocks": -3555408,
"seg_mib": -905.8,
"seg_misses": -225016,
"seg_hit_pct": 93.671,
"kib_per_token": -1.77
},
{
"length": "512k",
"round": 1,
"kind": "decode",
"prompt_tok": 523029,
"read": 52,
"gen": 402,
"read_tok_s": 61.3,
"gen_tok_s": 42.8,
"drafts_ok": 192,
"drafts_all": 388,
"seg_blocks": 4005216,
"seg_mib": 1079.9,
"seg_misses": 268221,
"seg_hit_pct": 93.303,
"kib_per_token": 2750.79
}
]
@@ -0,0 +1,29 @@
[
{
"length": "1k",
"depth": 50,
"prompt_tokens": 1442,
"seconds": 3.7,
"found": true,
"word": "meadow-copper-504",
"answer": "meadow-copper-504"
},
{
"length": "32k",
"depth": 50,
"prompt_tokens": 31763,
"seconds": 27.5,
"found": true,
"word": "falcon-quartz-940",
"answer": "falcon-quartz-940"
},
{
"length": "128k",
"depth": 50,
"prompt_tokens": 128328,
"seconds": 86.1,
"found": true,
"word": "willow-cobalt-696",
"answer": "willow-cobalt-696"
}
]
@@ -0,0 +1,11 @@
[
{
"length": "512k",
"depth": 50,
"prompt_tokens": 527051,
"seconds": 619.0,
"found": true,
"word": "meadow-copper-504",
"answer": "meadow-copper-504"
}
]
@@ -0,0 +1,16 @@
[
{
"length": "262k",
"depth": 50,
"prompt_tokens": 274222,
"seconds": 232.2,
"found": true,
"word": "meadow-copper-504",
"answer": "meadow-copper-504"
},
{
"length": "512k",
"depth": 50,
"error": "HTTP Error 400: Bad Request"
}
]
@@ -0,0 +1,11 @@
[
{
"length": "262k",
"depth": 50,
"prompt_tokens": 273708,
"seconds": 234.8,
"found": true,
"word": "meadow-copper-504",
"answer": "meadow-copper-504"
}
]
@@ -0,0 +1,20 @@
[
{
"length": "262k",
"depth": 50,
"prompt_tokens": 274215,
"seconds": 235.5,
"found": true,
"word": "meadow-copper-504",
"answer": "meadow-copper-504"
},
{
"length": "512k",
"depth": 50,
"prompt_tokens": 526988,
"seconds": 615.0,
"found": true,
"word": "falcon-quartz-940",
"answer": "falcon-quartz-940"
}
]
@@ -0,0 +1,46 @@
# Preliminary native RTX 3090 / EPYC 7453 results
Issue: [#165](https://github.com/Niko1221/Strata/issues/165)
Engine: Strata v0.1.26, source build at `ac8b251`
Status: preliminary; prompt set and harness guidance requested upstream.
## Hardware
| Component | Guest-visible details |
|---|---|
| CPU | AMD EPYC 7453, 20 vCPU, AVX2; AVX-512 not exposed |
| RAM | 165 GiB visible to Ubuntu 24.04.5 KVM guest; physical DIMM layout and bandwidth not verified |
| GPUs | 2x RTX 3090 24 GB; PCIe Gen4 x16 maximum reported per card; driver 595.91.07 |
| Power limit | 280 W configured on each GPU; defaults are 350 W / 420 W, max-adjustable limits 366 W / 450 W |
| Storage | 541 GiB ext4 guest data disk; host storage layout not verified |
The power values above are configured caps, not measured workload draw. Idle draw during the hardware capture was approximately 35 W / 29 W.
## Method
Native Linux setup, local build from v0.1.26, `--prefill auto`, shipped expert profile, automatic expert cache, int8 KV, MTP on, images off, experimental speed projection off. The GPU power limit was 280 W per card. Native runs used a systemd service with `LimitMEMLOCK=infinity`; other llama-swap model containers were stopped.
The local API harness used the public Strata source tree as its prompt corpus, with generated tasks, `temperature: 0`, `reasoning_effort: none`, and `max_tokens: 256`. It is not the upstream code-agent prompt set or harness. Runs use unique request IDs and no conversation reuse in speed mode. Three runs per speed cell are summarized by medians; actual `usage.prompt_tokens` are recorded because nominal context labels can drift. The first decode run is also shown. Several requests ended early on EOS, so actual generated counts are in the raw JSON.
No calibration comparison, upstream prompt comparison, `STRATA_SPLIT_TIMING` stage timing, or under-load power-draw capture has been done. Treat all prompt/decode comparisons with upstream as indicative only until the requested upstream method is available.
## Results
See [`matrix.md`](matrix.md) for summary tables and [`matrix.json`](matrix.json) for all successful run records. Per-run source JSON, logs, the local harness, and scrubbed hardware facts are in [`data/`](data/).
Highlights:
- IQ3_XXS on one 3090: 1K–262K cells, three runs each; 262K prompts were 232,183 / 259,589 / 261,068 tokens and fit within the 262,144 context.
- Coder IQ1_M at 32K: single-GPU median decode 66.8 tok/s; dual-GPU auto (K=19) median 98.6 tok/s.
- Fixed Coder K sweep: K=22 was the highest observed three-run median (103.3 tok/s); independently generated prompts mean this is not a paired ranking.
- IQ3_XXS and IQ3_S dual-GPU auto both selected K=24 at 32K.
- IQ3_XXS and IQ3_S needles passed 3/3 at 8K / 16K / 28K on the tested single/dual configurations; two-turn checkpoint reuse passed for both.
## Limits and follow-up
- Upstream prompts/harness are not yet available; all current speed data uses a local source-tree corpus.
- The guest exposes one NUMA node and 165 GiB RAM, but physical DIMM topology and memory bandwidth are unknown.
- PCIe x16 is the reported maximum link width; the engine probes were about 23–26 GB/s. Verify PCIe generation/width under sustained load before claiming a direct x16-vs-x4 comparison.
- Coder dual-GPU needle/two-turn checks and dual-GPU timing breakdowns are not run yet.
- K=18 has one successful run at 83.1 tok/s; a repeated startup failed while uploading a dense weight with an out-of-memory error, so it is not a three-run median.
- Calibration/default comparisons and IQ3_S single-GPU results remain outstanding.
@@ -0,0 +1,360 @@
{
"label": "native-v0.1.26-Coder-1x3090",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 1,
"run_id": "6c1252339f83",
"corpus_repeated": false,
"time": "2026-09-29T21:11:07",
"prompt_tokens": 28317,
"completion_tokens": 48,
"ttft_s": 12.868,
"e2e_s": 13.739,
"api_prompt_tps": 2200.5,
"api_decode_tps": 54.0,
"engine_prompt_tps": 2229.2,
"engine_decode_tps": 52.7,
"log_lines": [
"strata serve: prompt 28317 tokens = 0 reused + 28317 read in 12703 ms (2229.2 tok/s), 48 generated in 911 ms (52.7 tok/s), drafts accepted 31 of 38, 2 checkpoints",
"strata serve: decode expert cache hit rate: 96.3% (25001 hits / 25956 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what's there and identify the last file.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 8973,
"expert_cache_mib": 17503,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 369,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790716268.10927,
"duration_s": 13.6,
"finish": "stop",
"prompt_tokens": 28317,
"reused": 0,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 12702.6,
"decode_ms": 910.6,
"decode_tok_s": 52.7,
"hit_rate": 0.963
}
],
"requests_kept": 1,
"totals": {
"since": 1790716256.7391467,
"requests": 1,
"prompt_tokens": 28317,
"reused": 0,
"output_tokens": 48,
"prompt_ms": 12702.6,
"decode_ms": 910.6
},
"hardware": {
"gpu_util": 88,
"gpu_mem_used": 25531711488,
"gpu_mem_total": 25769803776,
"gpu_temp": 46,
"gpu_power": 220.362,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.28515625,
"gpu_pcie_tx_mb": 0.4287109375,
"cpu": 81.3,
"ram_used": 43964985344,
"ram_total": 177175990272,
"disk_read_mb": 2.9148478336133063,
"disk_write_mb": 0.0,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
99,
100,
100,
96,
100,
99,
100,
99,
99,
100,
100,
88
],
"gpu_mem_used": [
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25407979520,
25418465280,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25531711488
],
"gpu_temp": [
43,
42,
42,
42,
42,
42,
42,
42,
42,
42,
42,
42,
42,
46,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
46
],
"gpu_power": [
148.8,
140.48,
132.59,
119.03,
118.99,
119.03,
119.04,
119.03,
119.12,
119.17,
119.16,
119.15,
119.26,
191.57,
276.49,
276.88,
275.95,
277.04,
277.35,
267.91,
275.37,
276.16,
278.28,
279.07,
220.36
],
"gpu_pcie_rx_mb": [
0.33,
0.33,
0.29,
0.29,
0.33,
0.33,
0.33,
0.29,
0.33,
0.29,
0.33,
0.29,
385.14,
19.88,
1892.23,
13280.39,
85.45,
16838.55,
680.06,
1060.72,
13.45,
15.74,
5013.75,
1194.52,
0.29
],
"cpu": [
0.0,
0.7,
7.3,
15.7,
7.1,
2.0,
1.2,
2.0,
2.1,
1.6,
1.9,
7.4,
13.9,
18.3,
6.1,
6.0,
16.7,
24.9,
13.2,
12.0,
7.1,
6.2,
6.0,
8.8,
81.3
],
"ram_used": [
43381886976,
43381694464,
43410796544,
43434872832,
43483377664,
43485900800,
43484897280,
43481210880,
43469135872,
43462295552,
43458363392,
43496140800,
43624353792,
43648593920,
43633405952,
43641139200,
43635249152,
43689267200,
43846070272,
43924541440,
43924467712,
43918565376,
43883311104,
44002877440,
43964985344
],
"disk_read_mb": [
null,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
25.43,
204.93,
214.14,
7.41,
0.22,
184.19,
135.03,
0.0,
101.27,
0.0,
0.0,
0.0,
0.78,
2.91
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790716282.234284
}
}
@@ -0,0 +1,491 @@
{
"label": "native-v0.1.26-Coder-1x3090",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 2,
"run_id": "894af0ad69b7",
"corpus_repeated": false,
"time": "2026-09-29T21:11:22",
"prompt_tokens": 31630,
"completion_tokens": 26,
"ttft_s": 12.792,
"e2e_s": 13.164,
"api_prompt_tps": 2472.7,
"api_decode_tps": 67.3,
"engine_prompt_tps": 2506.6,
"engine_decode_tps": 66.8,
"log_lines": [
"strata serve: prompt 31630 tokens = 0 reused + 31630 read in 12619 ms (2506.6 tok/s), 26 generated in 389 ms (66.8 tok/s), drafts accepted 12 of 21, 2 checkpoints",
"strata serve: decode expert cache hit rate: 99.1% (16646 hits / 16791 lookups)"
],
"answer_head": "I don't see any file content in the conversation above. Could you please share the file you'd like me to analyze?",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 8973,
"expert_cache_mib": 17503,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 369,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790716282.3818104,
"duration_s": 13.0,
"finish": "stop",
"prompt_tokens": 31630,
"reused": 0,
"output_tokens": 26,
"engine_generated": 26,
"prompt_ms": 12618.8,
"decode_ms": 389.0,
"decode_tok_s": 66.8,
"hit_rate": 0.991
},
{
"projection": null,
"time": 1790716268.10927,
"duration_s": 13.6,
"finish": "stop",
"prompt_tokens": 28317,
"reused": 0,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 12702.6,
"decode_ms": 910.6,
"decode_tok_s": 52.7,
"hit_rate": 0.963
}
],
"requests_kept": 2,
"totals": {
"since": 1790716256.7391467,
"requests": 2,
"prompt_tokens": 59947,
"reused": 0,
"output_tokens": 74,
"prompt_ms": 25321.4,
"decode_ms": 1299.6
},
"hardware": {
"gpu_util": 81,
"gpu_mem_used": 25531711488,
"gpu_mem_total": 25769803776,
"gpu_temp": 45,
"gpu_power": 256.109,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 9.7744140625,
"gpu_pcie_tx_mb": 25.1767578125,
"cpu": 46.1,
"ram_used": 43872071680,
"ram_total": 177175990272,
"disk_read_mb": 1.6222807345356267,
"disk_write_mb": 0.018689870213544086,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
99,
100,
100,
96,
100,
99,
100,
99,
99,
100,
100,
88,
0,
100,
99,
100,
99,
100,
98,
99,
99,
100,
99,
100,
81
],
"gpu_mem_used": [
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25407979520,
25418465280,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488
],
"gpu_temp": [
43,
42,
42,
42,
42,
42,
42,
42,
42,
42,
42,
42,
42,
46,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
46,
44,
47,
47,
47,
47,
47,
47,
47,
47,
47,
48,
47,
45
],
"gpu_power": [
148.8,
140.48,
132.59,
119.03,
118.99,
119.03,
119.04,
119.03,
119.12,
119.17,
119.16,
119.15,
119.26,
191.57,
276.49,
276.88,
275.95,
277.04,
277.35,
267.91,
275.37,
276.16,
278.28,
279.07,
220.36,
189.89,
258.72,
276.75,
276.67,
277.52,
275.34,
268.93,
277.69,
277.77,
276.91,
278.53,
278.56,
256.11
],
"gpu_pcie_rx_mb": [
0.33,
0.33,
0.29,
0.29,
0.33,
0.33,
0.33,
0.29,
0.33,
0.29,
0.33,
0.29,
385.14,
19.88,
1892.23,
13280.39,
85.45,
16838.55,
680.06,
1060.72,
13.45,
15.74,
5013.75,
1194.52,
0.29,
2531.19,
14.02,
3715.09,
10.68,
13440.37,
8568.48,
14.92,
15.31,
15.69,
6486.56,
17.31,
9674.45,
9.77
],
"cpu": [
0.0,
0.7,
7.3,
15.7,
7.1,
2.0,
1.2,
2.0,
2.1,
1.6,
1.9,
7.4,
13.9,
18.3,
6.1,
6.0,
16.7,
24.9,
13.2,
12.0,
7.1,
6.2,
6.0,
8.8,
81.3,
4.2,
6.8,
6.4,
7.6,
5.5,
6.0,
20.6,
12.9,
6.2,
7.0,
5.7,
5.9,
46.1
],
"ram_used": [
43381886976,
43381694464,
43410796544,
43434872832,
43483377664,
43485900800,
43484897280,
43481210880,
43469135872,
43462295552,
43458363392,
43496140800,
43624353792,
43648593920,
43633405952,
43641139200,
43635249152,
43689267200,
43846070272,
43924541440,
43924467712,
43918565376,
43883311104,
44002877440,
43964985344,
43959267328,
43943862272,
43937861632,
43930320896,
43922284544,
43915001856,
43817238528,
43819147264,
43818729472,
43828027392,
43824201728,
43825434624,
43872071680
],
"disk_read_mb": [
null,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
25.43,
204.93,
214.14,
7.41,
0.22,
184.19,
135.03,
0.0,
101.27,
0.0,
0.0,
0.0,
0.78,
2.91,
0.61,
0.0,
0.0,
0.02,
0.0,
0.0,
79.64,
41.92,
0.0,
0.0,
0.0,
0.0,
1.62
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790716295.9009006
}
}
@@ -0,0 +1,622 @@
{
"label": "native-v0.1.26-Coder-1x3090",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 3,
"run_id": "a4c63bd599ab",
"corpus_repeated": false,
"time": "2026-09-29T21:11:35",
"prompt_tokens": 31601,
"completion_tokens": 45,
"ttft_s": 12.796,
"e2e_s": 13.243,
"api_prompt_tps": 2469.6,
"api_decode_tps": 98.5,
"engine_prompt_tps": 2502.4,
"engine_decode_tps": 97.4,
"log_lines": [
"strata serve: prompt 31601 tokens = 0 reused + 31601 read in 12628 ms (2502.4 tok/s), 45 generated in 462 ms (97.4 tok/s), drafts accepted 33 of 37, 2 checkpoints",
"strata serve: decode expert cache hit rate: 98.6% (23985 hits / 24333 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what we're working with.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 8973,
"expert_cache_mib": 17503,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 369,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790716296.0458817,
"duration_s": 13.1,
"finish": "stop",
"prompt_tokens": 31601,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 12628.3,
"decode_ms": 461.9,
"decode_tok_s": 97.4,
"hit_rate": 0.986
},
{
"projection": null,
"time": 1790716282.3818104,
"duration_s": 13.0,
"finish": "stop",
"prompt_tokens": 31630,
"reused": 0,
"output_tokens": 26,
"engine_generated": 26,
"prompt_ms": 12618.8,
"decode_ms": 389.0,
"decode_tok_s": 66.8,
"hit_rate": 0.991
},
{
"projection": null,
"time": 1790716268.10927,
"duration_s": 13.6,
"finish": "stop",
"prompt_tokens": 28317,
"reused": 0,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 12702.6,
"decode_ms": 910.6,
"decode_tok_s": 52.7,
"hit_rate": 0.963
}
],
"requests_kept": 3,
"totals": {
"since": 1790716256.7391467,
"requests": 3,
"prompt_tokens": 91548,
"reused": 0,
"output_tokens": 119,
"prompt_ms": 37949.7,
"decode_ms": 1761.5
},
"hardware": {
"gpu_util": 96,
"gpu_mem_used": 25531711488,
"gpu_mem_total": 25769803776,
"gpu_temp": 47,
"gpu_power": 245.399,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 414.037109375,
"gpu_pcie_tx_mb": 303.36328125,
"cpu": 35.1,
"ram_used": 43772702720,
"ram_total": 177175990272,
"disk_read_mb": 0.6087260569540994,
"disk_write_mb": 0.20539836277592313,
"tok_s": 97.29124144311484,
"tok_s_mean": 96.62332449971758
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
99,
100,
100,
96,
100,
99,
100,
99,
99,
100,
100,
88,
0,
100,
99,
100,
99,
100,
98,
99,
99,
100,
99,
100,
81,
99,
100,
100,
99,
100,
99,
17,
99,
100,
99,
99,
99,
96
],
"gpu_mem_used": [
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25382813696,
25407979520,
25418465280,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25424756736,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488,
25531711488
],
"gpu_temp": [
43,
42,
42,
42,
42,
42,
42,
42,
42,
42,
42,
42,
42,
46,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
46,
44,
47,
47,
47,
47,
47,
47,
47,
47,
47,
48,
47,
45,
47,
47,
47,
48,
48,
48,
46,
47,
48,
48,
48,
48,
47
],
"gpu_power": [
148.8,
140.48,
132.59,
119.03,
118.99,
119.03,
119.04,
119.03,
119.12,
119.17,
119.16,
119.15,
119.26,
191.57,
276.49,
276.88,
275.95,
277.04,
277.35,
267.91,
275.37,
276.16,
278.28,
279.07,
220.36,
189.89,
258.72,
276.75,
276.67,
277.52,
275.34,
268.93,
277.69,
277.77,
276.91,
278.53,
278.56,
256.11,
199.6,
275.35,
275.49,
276.31,
275.46,
277.78,
266.35,
267.73,
276.71,
276.41,
275.34,
278.17,
245.4
],
"gpu_pcie_rx_mb": [
0.33,
0.33,
0.29,
0.29,
0.33,
0.33,
0.33,
0.29,
0.33,
0.29,
0.33,
0.29,
385.14,
19.88,
1892.23,
13280.39,
85.45,
16838.55,
680.06,
1060.72,
13.45,
15.74,
5013.75,
1194.52,
0.29,
2531.19,
14.02,
3715.09,
10.68,
13440.37,
8568.48,
14.92,
15.31,
15.69,
6486.56,
17.31,
9674.45,
9.77,
2795.22,
4473.69,
14.5,
12.97,
14.92,
7716.66,
2819.78,
4278.33,
12009.48,
17.07,
9916.78,
8518.17,
414.04
],
"cpu": [
0.0,
0.7,
7.3,
15.7,
7.1,
2.0,
1.2,
2.0,
2.1,
1.6,
1.9,
7.4,
13.9,
18.3,
6.1,
6.0,
16.7,
24.9,
13.2,
12.0,
7.1,
6.2,
6.0,
8.8,
81.3,
4.2,
6.8,
6.4,
7.6,
5.5,
6.0,
20.6,
12.9,
6.2,
7.0,
5.7,
5.9,
46.1,
4.0,
6.9,
5.7,
6.2,
7.1,
5.5,
5.6,
9.9,
13.7,
8.4,
7.7,
6.4,
35.1
],
"ram_used": [
43381886976,
43381694464,
43410796544,
43434872832,
43483377664,
43485900800,
43484897280,
43481210880,
43469135872,
43462295552,
43458363392,
43496140800,
43624353792,
43648593920,
43633405952,
43641139200,
43635249152,
43689267200,
43846070272,
43924541440,
43924467712,
43918565376,
43883311104,
44002877440,
43964985344,
43959267328,
43943862272,
43937861632,
43930320896,
43922284544,
43915001856,
43817238528,
43819147264,
43818729472,
43828027392,
43824201728,
43825434624,
43872071680,
43734614016,
43728027648,
43719413760,
43703148544,
43695366144,
43687342080,
43744829440,
43791024128,
43789787136,
43766198272,
43761831936,
43750072320,
43772702720
],
"disk_read_mb": [
null,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
25.43,
204.93,
214.14,
7.41,
0.22,
184.19,
135.03,
0.0,
101.27,
0.0,
0.0,
0.0,
0.78,
2.91,
0.61,
0.0,
0.0,
0.02,
0.0,
0.0,
79.64,
41.92,
0.0,
0.0,
0.0,
0.0,
1.62,
0.72,
0.0,
0.0,
0.05,
0.0,
0.0,
0.18,
0.0,
0.0,
0.0,
0.0,
0.0,
0.61
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
97.29
]
},
"time": 1790716309.6464093
}
}
@@ -0,0 +1,423 @@
{
"label": "native-v0.1.26-Coder-2x3090-K18",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 1,
"run_id": "052cbcbb7af7",
"corpus_repeated": false,
"time": "2026-09-29T21:21:48",
"prompt_tokens": 28313,
"completion_tokens": 57,
"ttft_s": 12.346,
"e2e_s": 12.991,
"api_prompt_tps": 2293.3,
"api_decode_tps": 86.9,
"engine_prompt_tps": 2324.6,
"engine_decode_tps": 83.1,
"log_lines": [
"strata serve: prompt 28313 tokens = 0 reused + 28313 read in 12180 ms (2324.6 tok/s), 57 generated in 686 ms (83.1 tok/s), drafts accepted 39 of 41, 2 checkpoints",
"strata serve: decode expert cache hit rate: 99.7% (28717 hits / 28800 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what's there and identify the last file.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 4608,
"expert_cache_mib": 8437,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 9557,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790716909.0337873,
"duration_s": 12.9,
"finish": "stop",
"prompt_tokens": 28313,
"reused": 0,
"output_tokens": 57,
"engine_generated": 57,
"prompt_ms": 12179.9,
"decode_ms": 685.7,
"decode_tok_s": 83.1,
"hit_rate": 0.997
}
],
"requests_kept": 1,
"totals": {
"since": 1790716889.8200681,
"requests": 1,
"prompt_tokens": 28313,
"reused": 0,
"output_tokens": 57,
"prompt_ms": 12179.9,
"decode_ms": 685.7
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 0,
"mem_used": 15823994880,
"mem_total": 25769803776,
"temp": 44,
"power": 161.267
},
{
"index": 1,
"util": 90,
"mem_used": 24208408576,
"mem_total": 25769803776,
"temp": 51,
"power": 278.413
}
],
"gpu_util": 45.0,
"gpu_mem_used": 40032403456,
"gpu_mem_total": 51539607552,
"gpu_temp": 51,
"gpu_power": 439.68,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 5.33984375,
"gpu_pcie_tx_mb": 18.5009765625,
"cpu": 16.1,
"ram_used": 44574941184,
"ram_total": 177175990272,
"disk_read_mb": 0.9737281407762519,
"disk_write_mb": 0.11497896865254635,
"tok_s": 36.0,
"tok_s_mean": 64.01736582189179
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
41.5,
68.0,
50.0,
73.0,
87.5,
41.5,
47.0,
50.0,
78.0,
50.5,
45.0
],
"gpu_mem_used": [
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39866728448,
39965294592,
39965294592,
39965294592,
39965294592,
39965294592,
39965294592,
39965294592,
39965294592,
39965294592,
39965294592,
40032403456
],
"gpu_temp": [
45,
44,
44,
44,
44,
44,
45,
44,
44,
45,
45,
45,
45,
45,
45,
45,
42,
41,
41,
47,
50,
51,
51,
51,
52,
51,
52,
51,
52,
51
],
"gpu_power": [
255.0,
240.14,
239.41,
239.38,
239.55,
239.75,
239.74,
239.65,
239.56,
239.63,
239.71,
239.58,
239.49,
239.62,
239.83,
239.9,
200.58,
138.26,
69.98,
230.69,
516.11,
485.77,
500.33,
518.82,
491.98,
467.22,
490.75,
506.65,
510.68,
439.68
],
"gpu_pcie_rx_mb": [
0.71,
0.62,
0.67,
0.67,
0.67,
0.57,
0.71,
0.62,
0.62,
0.57,
0.67,
0.62,
0.71,
0.67,
0.67,
0.62,
0.76,
0.86,
0.71,
1243.59,
45.3,
2454.38,
77.06,
3382.78,
1099.87,
47.06,
2677.87,
79.25,
1143.26,
5.34
],
"cpu": [
0.0,
1.0,
2.8,
3.4,
1.0,
1.6,
1.6,
1.0,
1.4,
0.7,
3.6,
8.3,
1.0,
8.2,
5.7,
2.6,
3.4,
1.4,
10.1,
12.9,
8.2,
10.3,
10.7,
11.6,
27.0,
14.9,
11.2,
18.3,
15.0,
16.1
],
"ram_used": [
43962929152,
43965493248,
43981484032,
43968327680,
43968602112,
43968954368,
43964538880,
43964022784,
43964801024,
43964657664,
43961843712,
43958075392,
43958878208,
43967004672,
43967807488,
43951247360,
43945017344,
43945320448,
43971616768,
44103409664,
44112924672,
44112818176,
43979321344,
43978510336,
44145692672,
44276580352,
44275351552,
44327723008,
44296556544,
44574941184
],
"disk_read_mb": [
null,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
64.21,
105.78,
24.45,
89.11,
67.32,
92.34,
145.4,
79.43,
98.92,
75.23,
0.0,
0.97
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
36.0
]
},
"time": 1790716922.4098496
}
}
@@ -0,0 +1,270 @@
{
"label": "native-v0.1.26-Coder-2x3090-K22",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 1,
"run_id": "69d919ce1297",
"corpus_repeated": false,
"time": "2026-09-29T21:32:53",
"prompt_tokens": 28316,
"completion_tokens": 57,
"ttft_s": 10.575,
"e2e_s": 11.256,
"api_prompt_tps": 2677.7,
"api_decode_tps": 82.2,
"engine_prompt_tps": 2718.9,
"engine_decode_tps": 79.8,
"log_lines": [
"strata serve: prompt 28316 tokens = 0 reused + 28316 read in 10414 ms (2718.9 tok/s), 57 generated in 715 ms (79.8 tok/s), drafts accepted 37 of 48, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (34080 hits / 34080 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what's there and identify the last file.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 5632,
"expert_cache_mib": 10325,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 7669,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717573.1737459,
"duration_s": 11.1,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 57,
"engine_generated": 57,
"prompt_ms": 10414.4,
"decode_ms": 714.5,
"decode_tok_s": 79.8,
"hit_rate": 1.0
}
],
"requests_kept": 1,
"totals": {
"since": 1790717571.262619,
"requests": 1,
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 57,
"prompt_ms": 10414.4,
"decode_ms": 714.5
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 34,
"mem_used": 17822580736,
"mem_total": 25769803776,
"temp": 49,
"power": 184.581
},
{
"index": 1,
"util": 54,
"mem_used": 22828482560,
"mem_total": 25769803776,
"temp": 52,
"power": 232.993
}
],
"gpu_util": 44.0,
"gpu_mem_used": 40651063296,
"gpu_mem_total": 51539607552,
"gpu_temp": 52,
"gpu_power": 417.57399999999996,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.666015625,
"gpu_pcie_tx_mb": 0.953125,
"cpu": 6.2,
"ram_used": 44281556992,
"ram_total": 177175990272,
"disk_read_mb": 3.421090719626586,
"disk_write_mb": 0.0,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
1.0,
0.0,
0.0,
73.5,
58.5,
96.0,
57.5,
95.5,
47.5,
93.0,
58.5,
50.0,
44.0
],
"gpu_mem_used": [
40449736704,
40449736704,
40449736704,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40651063296
],
"gpu_temp": [
48,
47,
47,
50,
53,
53,
54,
53,
54,
54,
54,
54,
52
],
"gpu_power": [
256.98,
244.54,
244.03,
340.49,
532.78,
528.1,
525.31,
536.01,
504.78,
526.85,
529.86,
484.8,
417.57
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
0.67,
78.72,
82.54,
76.1,
85.97,
55.17,
62.23,
87.12,
83.54,
85.83,
0.67
],
"cpu": [
0.0,
1.2,
5.4,
10.7,
10.0,
9.8,
14.0,
18.3,
17.8,
18.6,
9.0,
5.8,
6.2
],
"ram_used": [
43564908544,
43556737024,
43564126208,
43739512832,
43734302720,
43734560768,
43735560192,
43898122240,
44013469696,
43991674880,
43978436608,
43974189056,
44281556992
],
"disk_read_mb": [
null,
0.0,
73.94,
96.25,
39.8,
73.77,
144.08,
110.85,
127.27,
131.68,
42.81,
0.0,
3.42
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790717584.813652
}
}
@@ -0,0 +1,383 @@
{
"label": "native-v0.1.26-Coder-2x3090-K22",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 2,
"run_id": "8506420b91e1",
"corpus_repeated": false,
"time": "2026-09-29T21:33:04",
"prompt_tokens": 31633,
"completion_tokens": 45,
"ttft_s": 10.85,
"e2e_s": 11.271,
"api_prompt_tps": 2915.4,
"api_decode_tps": 104.6,
"engine_prompt_tps": 2962.7,
"engine_decode_tps": 103.3,
"log_lines": [
"strata serve: prompt 31633 tokens = 0 reused + 31633 read in 10677 ms (2962.7 tok/s), 45 generated in 436 ms (103.3 tok/s), drafts accepted 32 of 37, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (24960 hits / 24960 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what the last file does.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 5632,
"expert_cache_mib": 10325,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 7669,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717584.9637764,
"duration_s": 11.1,
"finish": "stop",
"prompt_tokens": 31633,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 10677.2,
"decode_ms": 435.6,
"decode_tok_s": 103.3,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717573.1737459,
"duration_s": 11.1,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 57,
"engine_generated": 57,
"prompt_ms": 10414.4,
"decode_ms": 714.5,
"decode_tok_s": 79.8,
"hit_rate": 1.0
}
],
"requests_kept": 2,
"totals": {
"since": 1790717571.262619,
"requests": 2,
"prompt_tokens": 59949,
"reused": 0,
"output_tokens": 102,
"prompt_ms": 21091.6,
"decode_ms": 1150.1
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 37,
"mem_used": 17822580736,
"mem_total": 25769803776,
"temp": 49,
"power": 187.064
},
{
"index": 1,
"util": 60,
"mem_used": 22828482560,
"mem_total": 25769803776,
"temp": 53,
"power": 243.674
}
],
"gpu_util": 48.5,
"gpu_mem_used": 40651063296,
"gpu_mem_total": 51539607552,
"gpu_temp": 53,
"gpu_power": 430.738,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.6181640625,
"gpu_pcie_tx_mb": 1.0,
"cpu": 6.1,
"ram_used": 44308209664,
"ram_total": 177175990272,
"disk_read_mb": 0.7959400039611647,
"disk_write_mb": 0.24130307812397303,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
1.0,
0.0,
0.0,
73.5,
58.5,
96.0,
57.5,
95.5,
47.5,
93.0,
58.5,
50.0,
44.0,
18.0,
52.0,
95.5,
50.0,
97.0,
24.5,
95.5,
82.0,
96.5,
50.0,
48.5
],
"gpu_mem_used": [
40449736704,
40449736704,
40449736704,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296
],
"gpu_temp": [
48,
47,
47,
50,
53,
53,
54,
53,
54,
54,
54,
54,
52,
49,
54,
54,
54,
54,
52,
54,
54,
54,
54,
53
],
"gpu_power": [
256.98,
244.54,
244.03,
340.49,
532.78,
528.1,
525.31,
536.01,
504.78,
526.85,
529.86,
484.8,
417.57,
353.2,
539.11,
526.73,
525.83,
531.55,
507.76,
523.24,
527.24,
526.07,
501.32,
430.74
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
0.67,
78.72,
82.54,
76.1,
85.97,
55.17,
62.23,
87.12,
83.54,
85.83,
0.67,
1765.25,
83.88,
85.4,
85.07,
88.59,
82.35,
78.3,
85.16,
61.94,
46.3,
0.62
],
"cpu": [
0.0,
1.2,
5.4,
10.7,
10.0,
9.8,
14.0,
18.3,
17.8,
18.6,
9.0,
5.8,
6.2,
4.4,
6.6,
6.4,
5.8,
6.1,
7.4,
5.9,
6.8,
19.8,
14.2,
6.1
],
"ram_used": [
43564908544,
43556737024,
43564126208,
43739512832,
43734302720,
43734560768,
43735560192,
43898122240,
44013469696,
43991674880,
43978436608,
43974189056,
44281556992,
44278607872,
44263776256,
44251099136,
44242841600,
44235354112,
44232339456,
44218642432,
44210057216,
44216344576,
44288196608,
44308209664
],
"disk_read_mb": [
null,
0.0,
73.94,
96.25,
39.8,
73.77,
144.08,
110.85,
127.27,
131.68,
42.81,
0.0,
3.42,
0.48,
0.01,
0.04,
0.06,
0.02,
0.02,
0.02,
12.53,
104.78,
0.0,
0.8
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790717596.5877995
}
}
@@ -0,0 +1,496 @@
{
"label": "native-v0.1.26-Coder-2x3090-K22",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 3,
"run_id": "831d87a1dacc",
"corpus_repeated": false,
"time": "2026-09-29T21:33:16",
"prompt_tokens": 31601,
"completion_tokens": 60,
"ttft_s": 10.877,
"e2e_s": 11.43,
"api_prompt_tps": 2905.4,
"api_decode_tps": 106.7,
"engine_prompt_tps": 2951.6,
"engine_decode_tps": 105.7,
"log_lines": [
"strata serve: prompt 31601 tokens = 0 reused + 31601 read in 10706 ms (2951.6 tok/s), 60 generated in 568 ms (105.7 tok/s), drafts accepted 41 of 46, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (31680 hits / 31680 lookups)"
],
"answer_head": "I'll start by examining the repository structure to understand what the last file does.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 5632,
"expert_cache_mib": 10325,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 7669,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717596.735188,
"duration_s": 11.3,
"finish": "stop",
"prompt_tokens": 31601,
"reused": 0,
"output_tokens": 60,
"engine_generated": 60,
"prompt_ms": 10706.3,
"decode_ms": 567.6,
"decode_tok_s": 105.7,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717584.9637764,
"duration_s": 11.1,
"finish": "stop",
"prompt_tokens": 31633,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 10677.2,
"decode_ms": 435.6,
"decode_tok_s": 103.3,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717573.1737459,
"duration_s": 11.1,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 57,
"engine_generated": 57,
"prompt_ms": 10414.4,
"decode_ms": 714.5,
"decode_tok_s": 79.8,
"hit_rate": 1.0
}
],
"requests_kept": 3,
"totals": {
"since": 1790717571.262619,
"requests": 3,
"prompt_tokens": 91550,
"reused": 0,
"output_tokens": 162,
"prompt_ms": 31797.899999999998,
"decode_ms": 1717.6999999999998
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 25,
"mem_used": 17822580736,
"mem_total": 25769803776,
"temp": 50,
"power": 201.214
},
{
"index": 1,
"util": 61,
"mem_used": 22828482560,
"mem_total": 25769803776,
"temp": 53,
"power": 238.993
}
],
"gpu_util": 43.0,
"gpu_mem_used": 40651063296,
"gpu_mem_total": 51539607552,
"gpu_temp": 53,
"gpu_power": 440.207,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.666015625,
"gpu_pcie_tx_mb": 0.9052734375,
"cpu": 4.4,
"ram_used": 44291919872,
"ram_total": 177175990272,
"disk_read_mb": 0.7281688058408962,
"disk_write_mb": 0.01802398034259644,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
1.0,
0.0,
0.0,
73.5,
58.5,
96.0,
57.5,
95.5,
47.5,
93.0,
58.5,
50.0,
44.0,
18.0,
52.0,
95.5,
50.0,
97.0,
24.5,
95.5,
82.0,
96.5,
50.0,
48.5,
49.5,
96.0,
48.0,
96.0,
47.5,
94.5,
61.0,
97.5,
47.5,
49.5,
43.0
],
"gpu_mem_used": [
40449736704,
40449736704,
40449736704,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296,
40651063296
],
"gpu_temp": [
48,
47,
47,
50,
53,
53,
54,
53,
54,
54,
54,
54,
52,
49,
54,
54,
54,
54,
52,
54,
54,
54,
54,
53,
50,
54,
54,
54,
55,
54,
54,
54,
55,
55,
53
],
"gpu_power": [
256.98,
244.54,
244.03,
340.49,
532.78,
528.1,
525.31,
536.01,
504.78,
526.85,
529.86,
484.8,
417.57,
353.2,
539.11,
526.73,
525.83,
531.55,
507.76,
523.24,
527.24,
526.07,
501.32,
430.74,
359.38,
510.67,
527.45,
526.85,
532.56,
501.47,
534.58,
526.16,
522.92,
475.95,
440.21
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
0.67,
78.72,
82.54,
76.1,
85.97,
55.17,
62.23,
87.12,
83.54,
85.83,
0.67,
1765.25,
83.88,
85.4,
85.07,
88.59,
82.35,
78.3,
85.16,
61.94,
46.3,
0.62,
87.45,
41.53,
89.07,
84.21,
76.25,
52.17,
78.29,
83.59,
51.45,
47.92,
0.67
],
"cpu": [
0.0,
1.2,
5.4,
10.7,
10.0,
9.8,
14.0,
18.3,
17.8,
18.6,
9.0,
5.8,
6.2,
4.4,
6.6,
6.4,
5.8,
6.1,
7.4,
5.9,
6.8,
19.8,
14.2,
6.1,
7.3,
6.6,
6.3,
5.7,
6.0,
6.2,
6.3,
6.1,
7.3,
6.4,
4.4
],
"ram_used": [
43564908544,
43556737024,
43564126208,
43739512832,
43734302720,
43734560768,
43735560192,
43898122240,
44013469696,
43991674880,
43978436608,
43974189056,
44281556992,
44278607872,
44263776256,
44251099136,
44242841600,
44235354112,
44232339456,
44218642432,
44210057216,
44216344576,
44288196608,
44308209664,
44011671552,
43989819392,
43978940416,
43970682880,
43962933248,
44045533184,
44039798784,
44039798784,
44047568896,
44044705792,
44291919872
],
"disk_read_mb": [
null,
0.0,
73.94,
96.25,
39.8,
73.77,
144.08,
110.85,
127.27,
131.68,
42.81,
0.0,
3.42,
0.48,
0.01,
0.04,
0.06,
0.02,
0.02,
0.02,
12.53,
104.78,
0.0,
0.8,
0.61,
0.05,
0.03,
0.09,
0.08,
0.04,
0.05,
0.04,
0.15,
0.0,
0.73
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790717608.5200934
}
}
@@ -0,0 +1,279 @@
{
"label": "native-v0.1.26-Coder-2x3090-K24",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 1,
"run_id": "87af67edfd2d",
"corpus_repeated": false,
"time": "2026-09-29T21:34:02",
"prompt_tokens": 28314,
"completion_tokens": 256,
"ttft_s": 10.029,
"e2e_s": 12.977,
"api_prompt_tps": 2823.1,
"api_decode_tps": 86.5,
"engine_prompt_tps": 2871.1,
"engine_decode_tps": 85.9,
"log_lines": [
"strata serve: prompt 28314 tokens = 0 reused + 28314 read in 9862 ms (2871.1 tok/s), 256 generated in 2981 ms (85.9 tok/s), drafts accepted 143 of 193, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (147360 hits / 147360 lookups)"
],
"answer_head": "Looking at the last file above, `docs/AMD_HIP_PERFORMANCE.md`, it documents the performance evidence and correctness limits for the experimental AMD HIP backend targeting gfx1100 (RX 7900 XTX). It records:\n\n- The exact build/runtime configuration used for the benchmark (env vars, CLI flags, model pa",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 6144,
"expert_cache_mib": 11337,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 6657,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717642.434618,
"duration_s": 12.9,
"finish": "length",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 9861.8,
"decode_ms": 2981.5,
"decode_tok_s": 85.9,
"hit_rate": 1.0
}
],
"requests_kept": 1,
"totals": {
"since": 1790717640.7776525,
"requests": 1,
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 256,
"prompt_ms": 9861.8,
"decode_ms": 2981.5
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 43,
"mem_used": 18898419712,
"mem_total": 25769803776,
"temp": 50,
"power": 244.874
},
{
"index": 1,
"util": 57,
"mem_used": 21758935040,
"mem_total": 25769803776,
"temp": 54,
"power": 254.71
}
],
"gpu_util": 50.0,
"gpu_mem_used": 40657354752,
"gpu_mem_total": 51539607552,
"gpu_temp": 54,
"gpu_power": 499.584,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 5.38671875,
"gpu_pcie_tx_mb": 87.7373046875,
"cpu": 11.7,
"ram_used": 44619116544,
"ram_total": 177175990272,
"disk_read_mb": 4.515214018548113,
"disk_write_mb": 0.17657261525048487,
"tok_s": 107.09643367230112,
"tok_s_mean": 83.26979350665239
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
1.0,
0.0,
1.0,
93.0,
94.0,
64.0,
94.5,
88.5,
95.5,
92.5,
48.5,
32.0,
48.0,
50.0
],
"gpu_mem_used": [
40447639552,
40447639552,
40476999680,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40657354752,
40657354752,
40657354752
],
"gpu_temp": [
49,
49,
49,
53,
54,
54,
55,
54,
55,
55,
55,
52,
54,
54
],
"gpu_power": [
259.59,
247.18,
245.88,
414.53,
546.71,
547.76,
546.95,
533.57,
531.41,
545.46,
539.14,
402.04,
486.67,
499.58
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
247.86,
81.11,
78.2,
80.92,
83.88,
57.6,
82.87,
79.92,
40.29,
5.39,
9.77,
5.39
],
"cpu": [
0.0,
1.9,
9.1,
8.8,
9.5,
10.7,
13.9,
10.5,
13.9,
11.8,
6.0,
6.3,
12.4,
11.7
],
"ram_used": [
43887411200,
43859918848,
43956232192,
44034678784,
44030210048,
44028076032,
44015280128,
44252610560,
44247789568,
44243210240,
44230340608,
44558966784,
44619108352,
44619116544
],
"disk_read_mb": [
null,
0.0,
126.09,
44.05,
80.0,
93.94,
138.6,
104.01,
156.43,
97.38,
0.0,
1.76,
4.66,
4.52
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
78.74,
81.4,
107.1
]
},
"time": 1790717655.7892108
}
}
@@ -0,0 +1,392 @@
{
"label": "native-v0.1.26-Coder-2x3090-K24",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 2,
"run_id": "b38394f620b3",
"corpus_repeated": false,
"time": "2026-09-29T21:34:15",
"prompt_tokens": 31635,
"completion_tokens": 45,
"ttft_s": 10.269,
"e2e_s": 10.686,
"api_prompt_tps": 3080.5,
"api_decode_tps": 105.5,
"engine_prompt_tps": 3130.4,
"engine_decode_tps": 104.2,
"log_lines": [
"strata serve: prompt 31635 tokens = 0 reused + 31635 read in 10106 ms (3130.4 tok/s), 45 generated in 432 ms (104.2 tok/s), drafts accepted 33 of 37, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (24480 hits / 24480 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what we're working with.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 6144,
"expert_cache_mib": 11337,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 6657,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717655.9301767,
"duration_s": 10.5,
"finish": "stop",
"prompt_tokens": 31635,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 10105.9,
"decode_ms": 431.8,
"decode_tok_s": 104.2,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717642.434618,
"duration_s": 12.9,
"finish": "length",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 9861.8,
"decode_ms": 2981.5,
"decode_tok_s": 85.9,
"hit_rate": 1.0
}
],
"requests_kept": 2,
"totals": {
"since": 1790717640.7776525,
"requests": 2,
"prompt_tokens": 59949,
"reused": 0,
"output_tokens": 301,
"prompt_ms": 19967.699999999997,
"decode_ms": 3413.3
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 20,
"mem_used": 18898419712,
"mem_total": 25769803776,
"temp": 50,
"power": 191.174
},
{
"index": 1,
"util": 53,
"mem_used": 21758935040,
"mem_total": 25769803776,
"temp": 54,
"power": 238.032
}
],
"gpu_util": 36.5,
"gpu_mem_used": 40657354752,
"gpu_mem_total": 51539607552,
"gpu_temp": 54,
"gpu_power": 429.206,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.6181640625,
"gpu_pcie_tx_mb": 0.857421875,
"cpu": 5.3,
"ram_used": 44575621120,
"ram_total": 177175990272,
"disk_read_mb": 2.4688909410966033,
"disk_write_mb": 0.23427432287777988,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
1.0,
0.0,
1.0,
93.0,
94.0,
64.0,
94.5,
88.5,
95.5,
92.5,
48.5,
32.0,
48.0,
50.0,
0.0,
84.5,
96.0,
95.5,
79.0,
97.5,
97.0,
95.5,
96.0,
50.0,
36.5
],
"gpu_mem_used": [
40447639552,
40447639552,
40476999680,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752
],
"gpu_temp": [
49,
49,
49,
53,
54,
54,
55,
54,
55,
55,
55,
52,
54,
54,
50,
54,
55,
55,
55,
55,
55,
55,
55,
55,
54
],
"gpu_power": [
259.59,
247.18,
245.88,
414.53,
546.71,
547.76,
546.95,
533.57,
531.41,
545.46,
539.14,
402.04,
486.67,
499.58,
409.59,
480.21,
551.08,
548.0,
547.82,
539.97,
537.72,
548.44,
548.33,
513.55,
429.21
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
247.86,
81.11,
78.2,
80.92,
83.88,
57.6,
82.87,
79.92,
40.29,
5.39,
9.77,
5.39,
45.78,
64.8,
1284.55,
129.94,
83.06,
82.63,
84.78,
73.15,
82.44,
0.57,
0.62
],
"cpu": [
0.0,
1.9,
9.1,
8.8,
9.5,
10.7,
13.9,
10.5,
13.9,
11.8,
6.0,
6.3,
12.4,
11.7,
6.7,
8.3,
6.5,
7.2,
6.1,
6.0,
6.1,
6.5,
11.2,
8.0,
5.3
],
"ram_used": [
43887411200,
43859918848,
43956232192,
44034678784,
44030210048,
44028076032,
44015280128,
44252610560,
44247789568,
44243210240,
44230340608,
44558966784,
44619108352,
44619116544,
44154675200,
44152926208,
44151242752,
44149854208,
44145594368,
44375150592,
44366180352,
44365656064,
44362940416,
44400578560,
44575621120
],
"disk_read_mb": [
null,
0.0,
126.09,
44.05,
80.0,
93.94,
138.6,
104.01,
156.43,
97.38,
0.0,
1.76,
4.66,
4.52,
0.63,
0.02,
0.04,
0.03,
0.05,
0.03,
0.02,
13.87,
103.6,
0.0,
2.47
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
78.74,
81.4,
107.1,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790717666.9788535
}
}
@@ -0,0 +1,496 @@
{
"label": "native-v0.1.26-Coder-2x3090-K24",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 3,
"run_id": "3bee1c1e482a",
"corpus_repeated": false,
"time": "2026-09-29T21:34:26",
"prompt_tokens": 31602,
"completion_tokens": 60,
"ttft_s": 10.281,
"e2e_s": 10.865,
"api_prompt_tps": 3073.8,
"api_decode_tps": 101.0,
"engine_prompt_tps": 3123.2,
"engine_decode_tps": 100.2,
"log_lines": [
"strata serve: prompt 31602 tokens = 0 reused + 31602 read in 10118 ms (3123.2 tok/s), 60 generated in 599 ms (100.2 tok/s), drafts accepted 40 of 52, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (34560 hits / 34560 lookups)"
],
"answer_head": "I'll start by examining the repository structure to understand what the last file does.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 6144,
"expert_cache_mib": 11337,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 6657,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717667.1193056,
"duration_s": 10.7,
"finish": "stop",
"prompt_tokens": 31602,
"reused": 0,
"output_tokens": 60,
"engine_generated": 60,
"prompt_ms": 10118.5,
"decode_ms": 599.0,
"decode_tok_s": 100.2,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717655.9301767,
"duration_s": 10.5,
"finish": "stop",
"prompt_tokens": 31635,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 10105.9,
"decode_ms": 431.8,
"decode_tok_s": 104.2,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717642.434618,
"duration_s": 12.9,
"finish": "length",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 9861.8,
"decode_ms": 2981.5,
"decode_tok_s": 85.9,
"hit_rate": 1.0
}
],
"requests_kept": 3,
"totals": {
"since": 1790717640.7776525,
"requests": 3,
"prompt_tokens": 91551,
"reused": 0,
"output_tokens": 361,
"prompt_ms": 30086.199999999997,
"decode_ms": 4012.3
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 43,
"mem_used": 18898419712,
"mem_total": 25769803776,
"temp": 51,
"power": 178.691
},
{
"index": 1,
"util": 51,
"mem_used": 21758935040,
"mem_total": 25769803776,
"temp": 54,
"power": 244.501
}
],
"gpu_util": 47.0,
"gpu_mem_used": 40657354752,
"gpu_mem_total": 51539607552,
"gpu_temp": 54,
"gpu_power": 423.192,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 5.1962890625,
"gpu_pcie_tx_mb": 103.138671875,
"cpu": 6.6,
"ram_used": 44596383744,
"ram_total": 177175990272,
"disk_read_mb": 1.1207609014346964,
"disk_write_mb": 0.0288298624163266,
"tok_s": 110.47676922161895,
"tok_s_mean": 99.0096070780873
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
1.0,
0.0,
1.0,
93.0,
94.0,
64.0,
94.5,
88.5,
95.5,
92.5,
48.5,
32.0,
48.0,
50.0,
0.0,
84.5,
96.0,
95.5,
79.0,
97.5,
97.0,
95.5,
96.0,
50.0,
36.5,
49.5,
96.5,
61.0,
94.5,
91.0,
97.0,
95.5,
98.5,
47.5,
47.0
],
"gpu_mem_used": [
40447639552,
40447639552,
40476999680,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40546205696,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752,
40657354752
],
"gpu_temp": [
49,
49,
49,
53,
54,
54,
55,
54,
55,
55,
55,
52,
54,
54,
50,
54,
55,
55,
55,
55,
55,
55,
55,
55,
54,
52,
55,
55,
55,
55,
56,
56,
55,
56,
54
],
"gpu_power": [
259.59,
247.18,
245.88,
414.53,
546.71,
547.76,
546.95,
533.57,
531.41,
545.46,
539.14,
402.04,
486.67,
499.58,
409.59,
480.21,
551.08,
548.0,
547.82,
539.97,
537.72,
548.44,
548.33,
513.55,
429.21,
354.61,
553.75,
546.57,
547.59,
532.21,
535.5,
547.28,
548.49,
534.02,
423.19
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
247.86,
81.11,
78.2,
80.92,
83.88,
57.6,
82.87,
79.92,
40.29,
5.39,
9.77,
5.39,
45.78,
64.8,
1284.55,
129.94,
83.06,
82.63,
84.78,
73.15,
82.44,
0.57,
0.62,
81.82,
83.45,
75.34,
84.16,
82.11,
81.49,
70.95,
73.91,
52.55,
5.2
],
"cpu": [
0.0,
1.9,
9.1,
8.8,
9.5,
10.7,
13.9,
10.5,
13.9,
11.8,
6.0,
6.3,
12.4,
11.7,
6.7,
8.3,
6.5,
7.2,
6.1,
6.0,
6.1,
6.5,
11.2,
8.0,
5.3,
6.7,
12.7,
10.0,
5.9,
6.4,
6.0,
7.1,
5.7,
6.8,
6.6
],
"ram_used": [
43887411200,
43859918848,
43956232192,
44034678784,
44030210048,
44028076032,
44015280128,
44252610560,
44247789568,
44243210240,
44230340608,
44558966784,
44619108352,
44619116544,
44154675200,
44152926208,
44151242752,
44149854208,
44145594368,
44375150592,
44366180352,
44365656064,
44362940416,
44400578560,
44575621120,
44112637952,
44134821888,
44114948096,
44112486400,
44240445440,
44343197696,
44341800960,
44344549376,
44344029184,
44596383744
],
"disk_read_mb": [
null,
0.0,
126.09,
44.05,
80.0,
93.94,
138.6,
104.01,
156.43,
97.38,
0.0,
1.76,
4.66,
4.52,
0.63,
0.02,
0.04,
0.03,
0.05,
0.03,
0.02,
13.87,
103.6,
0.0,
2.47,
0.63,
0.05,
0.08,
0.08,
0.04,
0.07,
0.04,
0.17,
0.0,
1.12
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
78.74,
81.4,
107.1,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
110.48
]
},
"time": 1790717678.3471994
}
}
@@ -0,0 +1,261 @@
{
"label": "native-v0.1.26-Coder-2x3090-K26",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 1,
"run_id": "5ca39dba7489",
"corpus_repeated": false,
"time": "2026-09-29T21:35:22",
"prompt_tokens": 28314,
"completion_tokens": 48,
"ttft_s": 9.79,
"e2e_s": 10.297,
"api_prompt_tps": 2892.2,
"api_decode_tps": 92.7,
"engine_prompt_tps": 2940.2,
"engine_decode_tps": 88.8,
"log_lines": [
"strata serve: prompt 28314 tokens = 0 reused + 28314 read in 9630 ms (2940.2 tok/s), 48 generated in 540 ms (88.8 tok/s), drafts accepted 33 of 37, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (25920 hits / 25920 lookups)"
],
"answer_head": "I'll first look at the repository structure to understand what files exist and identify the last file.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 6656,
"expert_cache_mib": 12387,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 5607,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717722.129571,
"duration_s": 10.2,
"finish": "stop",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 9630.1,
"decode_ms": 540.5,
"decode_tok_s": 88.8,
"hit_rate": 1.0
}
],
"requests_kept": 1,
"totals": {
"since": 1790717720.412441,
"requests": 1,
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 48,
"prompt_ms": 9630.1,
"decode_ms": 540.5
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 47,
"mem_used": 19980550144,
"mem_total": 25769803776,
"temp": 51,
"power": 179.665
},
{
"index": 1,
"util": 28,
"mem_used": 20641153024,
"mem_total": 25769803776,
"temp": 53,
"power": 236.004
}
],
"gpu_util": 37.5,
"gpu_mem_used": 40621703168,
"gpu_mem_total": 51539607552,
"gpu_temp": 53,
"gpu_power": 415.669,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.666015625,
"gpu_pcie_tx_mb": 0.9052734375,
"cpu": 6.0,
"ram_used": 44539072512,
"ram_total": 177175990272,
"disk_read_mb": 2.97776661958663,
"disk_write_mb": 0.0,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
0.0,
0.5,
71.0,
95.5,
96.0,
91.5,
66.5,
95.5,
90.5,
84.5,
37.5
],
"gpu_mem_used": [
40447639552,
40447639552,
40472805376,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40621703168
],
"gpu_temp": [
50,
50,
50,
52,
55,
55,
56,
56,
56,
55,
56,
53
],
"gpu_power": [
261.03,
248.02,
247.5,
351.95,
548.48,
553.77,
555.05,
536.77,
531.38,
552.37,
551.57,
415.67
],
"gpu_pcie_rx_mb": [
0.76,
0.62,
224.64,
86.02,
83.16,
75.62,
86.69,
102.66,
65.66,
83.97,
38.86,
0.67
],
"cpu": [
0.0,
1.1,
8.1,
9.1,
9.3,
12.2,
12.6,
12.6,
23.5,
14.7,
5.9,
6.0
],
"ram_used": [
43871281152,
43867545600,
43958726656,
44040531968,
44041007104,
44033200128,
44032602112,
44244361216,
44250234880,
44236812288,
44233678848,
44539072512
],
"disk_read_mb": [
null,
0.0,
122.8,
47.19,
79.99,
100.77,
127.09,
108.72,
156.54,
97.45,
0.0,
2.98
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790717732.8116624
}
}
@@ -0,0 +1,365 @@
{
"label": "native-v0.1.26-Coder-2x3090-K26",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 2,
"run_id": "14c7210ce0e9",
"corpus_repeated": false,
"time": "2026-09-29T21:35:32",
"prompt_tokens": 31635,
"completion_tokens": 45,
"ttft_s": 10.029,
"e2e_s": 10.496,
"api_prompt_tps": 3154.3,
"api_decode_tps": 94.3,
"engine_prompt_tps": 3205.2,
"engine_decode_tps": 93.5,
"log_lines": [
"strata serve: prompt 31635 tokens = 0 reused + 31635 read in 9870 ms (3205.2 tok/s), 45 generated in 481 ms (93.5 tok/s), drafts accepted 31 of 36, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (25440 hits / 25440 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what the last file does.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 6656,
"expert_cache_mib": 12387,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 5607,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717732.947479,
"duration_s": 10.4,
"finish": "stop",
"prompt_tokens": 31635,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 9870.0,
"decode_ms": 481.3,
"decode_tok_s": 93.5,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717722.129571,
"duration_s": 10.2,
"finish": "stop",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 9630.1,
"decode_ms": 540.5,
"decode_tok_s": 88.8,
"hit_rate": 1.0
}
],
"requests_kept": 2,
"totals": {
"since": 1790717720.412441,
"requests": 2,
"prompt_tokens": 59949,
"reused": 0,
"output_tokens": 93,
"prompt_ms": 19500.1,
"decode_ms": 1021.8
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 51,
"mem_used": 19991035904,
"mem_total": 25769803776,
"temp": 51,
"power": 190.866
},
{
"index": 1,
"util": 56,
"mem_used": 20653735936,
"mem_total": 25769803776,
"temp": 55,
"power": 249.813
}
],
"gpu_util": 53.5,
"gpu_mem_used": 40644771840,
"gpu_mem_total": 51539607552,
"gpu_temp": 55,
"gpu_power": 440.679,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 16.44921875,
"gpu_pcie_tx_mb": 82.0625,
"cpu": 6.0,
"ram_used": 44553875456,
"ram_total": 177175990272,
"disk_read_mb": 0.6053434938228842,
"disk_write_mb": 0.0,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
0.0,
0.5,
71.0,
95.5,
96.0,
91.5,
66.5,
95.5,
90.5,
84.5,
37.5,
1.5,
97.0,
96.0,
81.0,
86.5,
95.5,
95.0,
96.5,
95.0,
53.5
],
"gpu_mem_used": [
40447639552,
40447639552,
40472805376,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40644771840
],
"gpu_temp": [
50,
50,
50,
52,
55,
55,
56,
56,
56,
55,
56,
53,
51,
56,
56,
56,
56,
56,
56,
56,
56,
55
],
"gpu_power": [
261.03,
248.02,
247.5,
351.95,
548.48,
553.77,
555.05,
536.77,
531.38,
552.37,
551.57,
415.67,
326.37,
532.86,
555.24,
552.15,
555.12,
507.8,
554.85,
554.0,
554.13,
440.68
],
"gpu_pcie_rx_mb": [
0.76,
0.62,
224.64,
86.02,
83.16,
75.62,
86.69,
102.66,
65.66,
83.97,
38.86,
0.67,
3698.35,
132.46,
131.89,
82.06,
85.92,
83.02,
1279.88,
50.4,
86.21,
16.45
],
"cpu": [
0.0,
1.1,
8.1,
9.1,
9.3,
12.2,
12.6,
12.6,
23.5,
14.7,
5.9,
6.0,
4.5,
6.1,
6.0,
6.4,
6.7,
5.9,
6.7,
9.9,
7.4,
6.0
],
"ram_used": [
43871281152,
43867545600,
43958726656,
44040531968,
44041007104,
44033200128,
44032602112,
44244361216,
44250234880,
44236812288,
44233678848,
44539072512,
44064968704,
44058497024,
44058497024,
44058501120,
44175929344,
44294356992,
44294352896,
44295569408,
44291391488,
44553875456
],
"disk_read_mb": [
null,
0.0,
122.8,
47.19,
79.99,
100.77,
127.09,
108.72,
156.54,
97.45,
0.0,
2.98,
0.47,
0.01,
0.04,
0.06,
0.03,
0.03,
12.57,
71.85,
33.12,
0.61
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790717743.8106396
}
}
@@ -0,0 +1,469 @@
{
"label": "native-v0.1.26-Coder-2x3090-K26",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 3,
"run_id": "3f243fdb63ee",
"corpus_repeated": false,
"time": "2026-09-29T21:35:43",
"prompt_tokens": 31601,
"completion_tokens": 60,
"ttft_s": 10.026,
"e2e_s": 10.61,
"api_prompt_tps": 3151.9,
"api_decode_tps": 101.0,
"engine_prompt_tps": 3208.3,
"engine_decode_tps": 100.2,
"log_lines": [
"strata serve: prompt 31601 tokens = 0 reused + 31601 read in 9850 ms (3208.3 tok/s), 60 generated in 599 ms (100.2 tok/s), drafts accepted 40 of 50, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (34080 hits / 34080 lookups)"
],
"answer_head": "I'll start by examining the repository structure to understand what the last file is.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 6656,
"expert_cache_mib": 12387,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 5607,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717743.964174,
"duration_s": 10.5,
"finish": "stop",
"prompt_tokens": 31601,
"reused": 0,
"output_tokens": 60,
"engine_generated": 60,
"prompt_ms": 9849.9,
"decode_ms": 598.9,
"decode_tok_s": 100.2,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717732.947479,
"duration_s": 10.4,
"finish": "stop",
"prompt_tokens": 31635,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 9870.0,
"decode_ms": 481.3,
"decode_tok_s": 93.5,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717722.129571,
"duration_s": 10.2,
"finish": "stop",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 9630.1,
"decode_ms": 540.5,
"decode_tok_s": 88.8,
"hit_rate": 1.0
}
],
"requests_kept": 3,
"totals": {
"since": 1790717720.412441,
"requests": 3,
"prompt_tokens": 91550,
"reused": 0,
"output_tokens": 153,
"prompt_ms": 29350.0,
"decode_ms": 1620.6999999999998
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 46,
"mem_used": 19991035904,
"mem_total": 25769803776,
"temp": 52,
"power": 189.922
},
{
"index": 1,
"util": 52,
"mem_used": 20653735936,
"mem_total": 25769803776,
"temp": 55,
"power": 246.398
}
],
"gpu_util": 49.0,
"gpu_mem_used": 40644771840,
"gpu_mem_total": 51539607552,
"gpu_temp": 55,
"gpu_power": 436.32,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 17.8330078125,
"gpu_pcie_tx_mb": 43.1533203125,
"cpu": 6.0,
"ram_used": 44614168576,
"ram_total": 177175990272,
"disk_read_mb": 0.4973320821900814,
"disk_write_mb": 0.05405783502066102,
"tok_s": 99.26679787882165,
"tok_s_mean": 97.997900113756
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
0.0,
0.5,
71.0,
95.5,
96.0,
91.5,
66.5,
95.5,
90.5,
84.5,
37.5,
1.5,
97.0,
96.0,
81.0,
86.5,
95.5,
95.0,
96.5,
95.0,
53.5,
0.0,
95.0,
95.5,
82.0,
94.5,
93.0,
88.5,
96.0,
97.0,
49.0
],
"gpu_mem_used": [
40447639552,
40447639552,
40472805376,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40535719936,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40621703168,
40644771840,
40644771840,
40644771840,
40644771840,
40644771840,
40644771840,
40644771840,
40644771840,
40644771840,
40644771840,
40644771840
],
"gpu_temp": [
50,
50,
50,
52,
55,
55,
56,
56,
56,
55,
56,
53,
51,
56,
56,
56,
56,
56,
56,
56,
56,
55,
52,
55,
56,
56,
56,
56,
56,
56,
56,
55
],
"gpu_power": [
261.03,
248.02,
247.5,
351.95,
548.48,
553.77,
555.05,
536.77,
531.38,
552.37,
551.57,
415.67,
326.37,
532.86,
555.24,
552.15,
555.12,
507.8,
554.85,
554.0,
554.13,
440.68,
363.75,
474.54,
552.72,
554.16,
554.3,
509.24,
555.11,
555.88,
555.36,
436.32
],
"gpu_pcie_rx_mb": [
0.76,
0.62,
224.64,
86.02,
83.16,
75.62,
86.69,
102.66,
65.66,
83.97,
38.86,
0.67,
3698.35,
132.46,
131.89,
82.06,
85.92,
83.02,
1279.88,
50.4,
86.21,
16.45,
38.96,
81.63,
83.25,
84.4,
72.53,
127.22,
48.4,
96.51,
100.71,
17.83
],
"cpu": [
0.0,
1.1,
8.1,
9.1,
9.3,
12.2,
12.6,
12.6,
23.5,
14.7,
5.9,
6.0,
4.5,
6.1,
6.0,
6.4,
6.7,
5.9,
6.7,
9.9,
7.4,
6.0,
11.7,
10.8,
6.2,
11.4,
7.0,
6.7,
5.6,
5.4,
6.0,
6.0
],
"ram_used": [
43871281152,
43867545600,
43958726656,
44040531968,
44041007104,
44033200128,
44032602112,
44244361216,
44250234880,
44236812288,
44233678848,
44539072512,
44064968704,
44058497024,
44058497024,
44058501120,
44175929344,
44294356992,
44294352896,
44295569408,
44291391488,
44553875456,
44129808384,
44180946944,
44184666112,
44182659072,
44296114176,
44404658176,
44394999808,
44386783232,
44374441984,
44614168576
],
"disk_read_mb": [
null,
0.0,
122.8,
47.19,
79.99,
100.77,
127.09,
108.72,
156.54,
97.45,
0.0,
2.98,
0.47,
0.01,
0.04,
0.06,
0.03,
0.03,
12.57,
71.85,
33.12,
0.61,
0.53,
0.06,
0.06,
0.09,
0.08,
0.04,
0.04,
0.04,
0.15,
0.5
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
99.27
]
},
"time": 1790717754.9239163
}
}
@@ -0,0 +1,261 @@
{
"label": "native-v0.1.26-Coder-2x3090-K28",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 1,
"run_id": "0796a1ce12e4",
"corpus_repeated": false,
"time": "2026-09-29T21:36:29",
"prompt_tokens": 28316,
"completion_tokens": 57,
"ttft_s": 10.285,
"e2e_s": 10.86,
"api_prompt_tps": 2753.1,
"api_decode_tps": 97.4,
"engine_prompt_tps": 2798.5,
"engine_decode_tps": 93.7,
"log_lines": [
"strata serve: prompt 28316 tokens = 0 reused + 28316 read in 10118 ms (2798.5 tok/s), 57 generated in 608 ms (93.7 tok/s), drafts accepted 40 of 42, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (28800 hits / 28800 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what's there and identify the last file.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 7168,
"expert_cache_mib": 13437,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 4557,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717789.1846194,
"duration_s": 10.7,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 57,
"engine_generated": 57,
"prompt_ms": 10118.2,
"decode_ms": 608.0,
"decode_tok_s": 93.8,
"hit_rate": 1.0
}
],
"requests_kept": 1,
"totals": {
"since": 1790717787.625935,
"requests": 1,
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 57,
"prompt_ms": 10118.2,
"decode_ms": 608.0
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 41,
"mem_used": 21104623616,
"mem_total": 25769803776,
"temp": 52,
"power": 189.832
},
{
"index": 1,
"util": 42,
"mem_used": 19548536832,
"mem_total": 25769803776,
"temp": 54,
"power": 230.563
}
],
"gpu_util": 41.5,
"gpu_mem_used": 40653160448,
"gpu_mem_total": 51539607552,
"gpu_temp": 54,
"gpu_power": 420.395,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 17.1650390625,
"gpu_pcie_tx_mb": 53.119140625,
"cpu": 6.1,
"ram_used": 44503613440,
"ram_total": 177175990272,
"disk_read_mb": 1.946188226381293,
"disk_write_mb": 0.0036040522710764685,
"tok_s": 81.42212134334822,
"tok_s_mean": 78.79383849818437
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
0.0,
0.0,
46.5,
96.0,
72.5,
93.0,
90.0,
95.5,
93.5,
97.5,
41.5
],
"gpu_mem_used": [
40447639552,
40447639552,
40495874048,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40653160448
],
"gpu_temp": [
51,
50,
50,
52,
55,
54,
56,
54,
56,
56,
57,
54
],
"gpu_power": [
261.46,
249.04,
248.59,
342.07,
531.07,
533.47,
545.68,
511.29,
533.34,
534.58,
541.51,
420.39
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
182.48,
55.88,
87.02,
80.58,
57.5,
78.87,
83.88,
1294.42,
46.78,
17.17
],
"cpu": [
0.0,
6.6,
18.0,
11.3,
10.5,
9.8,
11.5,
13.9,
11.4,
12.9,
7.4,
6.1
],
"ram_used": [
43799613440,
43777974272,
43950305280,
43962880000,
43939622912,
43930345472,
43932086272,
44071780352,
44183257088,
44182880256,
44179062784,
44503613440
],
"disk_read_mb": [
null,
0.0,
129.59,
40.83,
79.94,
84.92,
115.02,
136.42,
117.79,
106.04,
29.9,
1.95
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
81.42
]
},
"time": 1790717800.421838
}
}
@@ -0,0 +1,374 @@
{
"label": "native-v0.1.26-Coder-2x3090-K28",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 2,
"run_id": "3d5bf2c2aa6f",
"corpus_repeated": false,
"time": "2026-09-29T21:36:40",
"prompt_tokens": 31631,
"completion_tokens": 45,
"ttft_s": 10.58,
"e2e_s": 10.972,
"api_prompt_tps": 2989.7,
"api_decode_tps": 112.3,
"engine_prompt_tps": 3034.9,
"engine_decode_tps": 110.6,
"log_lines": [
"strata serve: prompt 31631 tokens = 0 reused + 31631 read in 10423 ms (3034.9 tok/s), 45 generated in 407 ms (110.6 tok/s), drafts accepted 33 of 34, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (23040 hits / 23040 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what we're working with.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 7168,
"expert_cache_mib": 13437,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 4557,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717800.5571585,
"duration_s": 10.8,
"finish": "stop",
"prompt_tokens": 31631,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 10422.5,
"decode_ms": 406.8,
"decode_tok_s": 110.6,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717789.1846194,
"duration_s": 10.7,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 57,
"engine_generated": 57,
"prompt_ms": 10118.2,
"decode_ms": 608.0,
"decode_tok_s": 93.8,
"hit_rate": 1.0
}
],
"requests_kept": 2,
"totals": {
"since": 1790717787.625935,
"requests": 2,
"prompt_tokens": 59947,
"reused": 0,
"output_tokens": 102,
"prompt_ms": 20540.7,
"decode_ms": 1014.8
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 46,
"mem_used": 21104623616,
"mem_total": 25769803776,
"temp": 51,
"power": 204.027
},
{
"index": 1,
"util": 12,
"mem_used": 19548536832,
"mem_total": 25769803776,
"temp": 54,
"power": 226.431
}
],
"gpu_util": 29.0,
"gpu_mem_used": 40653160448,
"gpu_mem_total": 51539607552,
"gpu_temp": 54,
"gpu_power": 430.45799999999997,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.6181640625,
"gpu_pcie_tx_mb": 0.9052734375,
"cpu": 4.3,
"ram_used": 44573519872,
"ram_total": 177175990272,
"disk_read_mb": 0.9768799607845553,
"disk_write_mb": 0.0,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
0.0,
0.0,
46.5,
96.0,
72.5,
93.0,
90.0,
95.5,
93.5,
97.5,
41.5,
0.0,
96.0,
93.0,
97.5,
94.5,
97.0,
95.0,
97.0,
93.5,
67.0,
29.0
],
"gpu_mem_used": [
40447639552,
40447639552,
40495874048,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448
],
"gpu_temp": [
51,
50,
50,
52,
55,
54,
56,
54,
56,
56,
57,
54,
52,
55,
54,
56,
56,
56,
56,
57,
57,
56,
54
],
"gpu_power": [
261.46,
249.04,
248.59,
342.07,
531.07,
533.47,
545.68,
511.29,
533.34,
534.58,
541.51,
420.39,
375.37,
452.84,
528.99,
547.53,
532.29,
524.3,
518.92,
543.34,
532.25,
534.03,
430.46
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
182.48,
55.88,
87.02,
80.58,
57.5,
78.87,
83.88,
1294.42,
46.78,
17.17,
42.15,
1288.27,
41.05,
75.34,
70.76,
44.15,
79.87,
61.61,
75.63,
42.06,
0.62
],
"cpu": [
0.0,
6.6,
18.0,
11.3,
10.5,
9.8,
11.5,
13.9,
11.4,
12.9,
7.4,
6.1,
4.2,
6.4,
6.0,
12.9,
11.2,
6.1,
8.2,
8.8,
14.0,
6.4,
4.3
],
"ram_used": [
43799613440,
43777974272,
43950305280,
43962880000,
43939622912,
43930345472,
43932086272,
44071780352,
44183257088,
44182880256,
44179062784,
44503613440,
44015304704,
44019281920,
44021350400,
44034875392,
44111585280,
44348657664,
44344815616,
44359872512,
44334280704,
44327985152,
44573519872
],
"disk_read_mb": [
null,
0.0,
129.59,
40.83,
79.94,
84.92,
115.02,
136.42,
117.79,
106.04,
29.9,
1.95,
1.72,
0.02,
0.02,
0.05,
0.06,
0.01,
0.03,
12.6,
101.64,
2.94,
0.98
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
81.42,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790717811.896799
}
}
@@ -0,0 +1,487 @@
{
"label": "native-v0.1.26-Coder-2x3090-K28",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 3,
"run_id": "d22ca9d8c7b8",
"corpus_repeated": false,
"time": "2026-09-29T21:36:51",
"prompt_tokens": 31602,
"completion_tokens": 59,
"ttft_s": 10.575,
"e2e_s": 11.17,
"api_prompt_tps": 2988.5,
"api_decode_tps": 97.4,
"engine_prompt_tps": 3037.5,
"engine_decode_tps": 96.6,
"log_lines": [
"strata serve: prompt 31602 tokens = 0 reused + 31602 read in 10404 ms (3037.5 tok/s), 59 generated in 611 ms (96.6 tok/s), drafts accepted 41 of 52, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (35040 hits / 35040 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what's there.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 7168,
"expert_cache_mib": 13437,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 4557,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717812.0454123,
"duration_s": 11.0,
"finish": "stop",
"prompt_tokens": 31602,
"reused": 0,
"output_tokens": 59,
"engine_generated": 59,
"prompt_ms": 10404.1,
"decode_ms": 610.6,
"decode_tok_s": 96.6,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717800.5571585,
"duration_s": 10.8,
"finish": "stop",
"prompt_tokens": 31631,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 10422.5,
"decode_ms": 406.8,
"decode_tok_s": 110.6,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717789.1846194,
"duration_s": 10.7,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 57,
"engine_generated": 57,
"prompt_ms": 10118.2,
"decode_ms": 608.0,
"decode_tok_s": 93.8,
"hit_rate": 1.0
}
],
"requests_kept": 3,
"totals": {
"since": 1790717787.625935,
"requests": 3,
"prompt_tokens": 91549,
"reused": 0,
"output_tokens": 161,
"prompt_ms": 30944.800000000003,
"decode_ms": 1625.4
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 48,
"mem_used": 21104623616,
"mem_total": 25769803776,
"temp": 53,
"power": 214.931
},
{
"index": 1,
"util": 0,
"mem_used": 19548536832,
"mem_total": 25769803776,
"temp": 53,
"power": 199.379
}
],
"gpu_util": 24.0,
"gpu_mem_used": 40653160448,
"gpu_mem_total": 51539607552,
"gpu_temp": 53,
"gpu_power": 414.31,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.666015625,
"gpu_pcie_tx_mb": 0.857421875,
"cpu": 3.6,
"ram_used": 44545851392,
"ram_total": 177175990272,
"disk_read_mb": 0.7062443272525659,
"disk_write_mb": 0.11530519628613321,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
0.0,
0.0,
46.5,
96.0,
72.5,
93.0,
90.0,
95.5,
93.5,
97.5,
41.5,
0.0,
96.0,
93.0,
97.5,
94.5,
97.0,
95.0,
97.0,
93.5,
67.0,
29.0,
50.0,
96.5,
47.5,
95.5,
96.5,
95.5,
62.5,
96.5,
95.5,
50.0,
24.0
],
"gpu_mem_used": [
40447639552,
40447639552,
40495874048,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40542011392,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448,
40653160448
],
"gpu_temp": [
51,
50,
50,
52,
55,
54,
56,
54,
56,
56,
57,
54,
52,
55,
54,
56,
56,
56,
56,
57,
57,
56,
54,
53,
56,
54,
57,
57,
57,
56,
57,
56,
57,
53
],
"gpu_power": [
261.46,
249.04,
248.59,
342.07,
531.07,
533.47,
545.68,
511.29,
533.34,
534.58,
541.51,
420.39,
375.37,
452.84,
528.99,
547.53,
532.29,
524.3,
518.92,
543.34,
532.25,
534.03,
430.46,
354.3,
519.1,
530.52,
534.81,
532.5,
512.45,
532.86,
540.0,
532.72,
513.31,
414.31
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
182.48,
55.88,
87.02,
80.58,
57.5,
78.87,
83.88,
1294.42,
46.78,
17.17,
42.15,
1288.27,
41.05,
75.34,
70.76,
44.15,
79.87,
61.61,
75.63,
42.06,
0.62,
84.64,
74.34,
85.5,
81.54,
0.67,
75.72,
81.82,
82.83,
28.8,
17.74,
0.67
],
"cpu": [
0.0,
6.6,
18.0,
11.3,
10.5,
9.8,
11.5,
13.9,
11.4,
12.9,
7.4,
6.1,
4.2,
6.4,
6.0,
12.9,
11.2,
6.1,
8.2,
8.8,
14.0,
6.4,
4.3,
4.2,
6.6,
6.0,
17.8,
8.5,
6.2,
15.1,
14.3,
6.7,
6.9,
3.6
],
"ram_used": [
43799613440,
43777974272,
43950305280,
43962880000,
43939622912,
43930345472,
43932086272,
44071780352,
44183257088,
44182880256,
44179062784,
44503613440,
44015304704,
44019281920,
44021350400,
44034875392,
44111585280,
44348657664,
44344815616,
44359872512,
44334280704,
44327985152,
44573519872,
44103626752,
44105744384,
44105732096,
44159885312,
44275363840,
44375539712,
44373200896,
44318019584,
44307988480,
44545863680,
44545851392
],
"disk_read_mb": [
null,
0.0,
129.59,
40.83,
79.94,
84.92,
115.02,
136.42,
117.79,
106.04,
29.9,
1.95,
1.72,
0.02,
0.02,
0.05,
0.06,
0.01,
0.03,
12.6,
101.64,
2.94,
0.98,
0.74,
0.02,
0.06,
0.32,
0.08,
0.04,
0.05,
0.04,
0.1,
0.0,
0.71
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
81.42,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790717823.5700235
}
}
@@ -0,0 +1,608 @@
{
"label": "native-v0.1.26-Coder-2x3090-K30",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 1,
"run_id": "b4895f87f439",
"corpus_repeated": false,
"time": "2026-09-29T21:28:38",
"prompt_tokens": 28316,
"completion_tokens": 45,
"ttft_s": 9.936,
"e2e_s": 10.4,
"api_prompt_tps": 2849.8,
"api_decode_tps": 94.9,
"engine_prompt_tps": 2892.0,
"engine_decode_tps": 94.1,
"log_lines": [
"strata serve: prompt 28316 tokens = 0 reused + 28316 read in 9791 ms (2892.0 tok/s), 45 generated in 478 ms (94.1 tok/s), drafts accepted 31 of 37, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (25440 hits / 25440 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what's there.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 7680,
"expert_cache_mib": 14575,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 3419,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717318.4067442,
"duration_s": 10.3,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 9791.3,
"decode_ms": 478.1,
"decode_tok_s": 94.1,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717288.2692974,
"duration_s": 11.1,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 56,
"engine_generated": 56,
"prompt_ms": 10484.4,
"decode_ms": 636.0,
"decode_tok_s": 88.1,
"hit_rate": 1.0
}
],
"requests_kept": 2,
"totals": {
"since": 1790717276.5105639,
"requests": 2,
"prompt_tokens": 56632,
"reused": 0,
"output_tokens": 101,
"prompt_ms": 20275.699999999997,
"decode_ms": 1114.1
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 53,
"mem_used": 22306291712,
"mem_total": 25769803776,
"temp": 51,
"power": 200.427
},
{
"index": 1,
"util": 46,
"mem_used": 18353160192,
"mem_total": 25769803776,
"temp": 53,
"power": 223.879
}
],
"gpu_util": 49.5,
"gpu_mem_used": 40659451904,
"gpu_mem_total": 51539607552,
"gpu_temp": 53,
"gpu_power": 424.306,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 5.8642578125,
"gpu_pcie_tx_mb": 107.4306640625,
"cpu": 6.9,
"ram_used": 44604223488,
"ram_total": 177175990272,
"disk_read_mb": 1.1417042620069329,
"disk_write_mb": 0.04682067951447989,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
50.0,
94.0,
63.0,
95.0,
50.0,
92.0,
95.0,
82.5,
97.0,
35.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.5,
97.5,
49.0,
94.5,
50.0,
96.5,
53.0,
94.5,
97.0,
49.5
],
"gpu_mem_used": [
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40542011392,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40659451904
],
"gpu_temp": [
49,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
50,
52,
53,
53,
53,
52,
54,
51,
54,
52,
50,
49,
49,
49,
49,
49,
49,
48,
49,
48,
48,
48,
49,
49,
49,
49,
46,
46,
53,
52,
54,
52,
54,
52,
54,
54,
53
],
"gpu_power": [
257.9,
244.84,
244.4,
244.1,
244.29,
244.43,
244.32,
244.0,
243.79,
243.86,
244.04,
244.43,
304.5,
504.99,
527.59,
513.34,
519.55,
489.82,
537.3,
515.01,
534.71,
416.26,
390.46,
299.77,
260.05,
241.54,
241.56,
241.75,
241.63,
241.51,
241.46,
241.4,
241.29,
241.13,
241.31,
241.69,
241.72,
221.92,
136.12,
67.69,
469.97,
521.96,
512.77,
514.47,
496.64,
522.43,
513.55,
532.56,
424.31
],
"gpu_pcie_rx_mb": [
0.67,
0.67,
0.62,
0.62,
0.62,
0.62,
0.67,
1.62,
0.67,
0.62,
0.62,
0.62,
4319.14,
134.51,
87.31,
96.37,
111.91,
79.87,
41.53,
80.25,
44.15,
15.88,
0.67,
0.57,
0.57,
0.57,
0.62,
0.62,
0.62,
0.62,
0.62,
0.57,
0.62,
0.62,
0.62,
0.62,
0.57,
0.81,
0.81,
44.34,
97.08,
1308.87,
41.25,
84.97,
155.3,
46.68,
84.26,
3604.32,
5.86
],
"cpu": [
0.0,
1.4,
4.7,
7.8,
13.7,
1.8,
1.4,
1.9,
1.6,
1.4,
1.5,
9.7,
13.3,
10.3,
10.0,
9.4,
23.0,
17.6,
10.6,
13.1,
6.5,
6.2,
1.3,
8.4,
5.4,
1.3,
1.2,
1.8,
1.6,
0.9,
10.0,
4.2,
0.8,
1.8,
1.6,
2.2,
2.6,
1.9,
2.8,
7.4,
8.7,
7.1,
5.6,
6.2,
14.3,
8.5,
5.8,
9.0,
6.9
],
"ram_used": [
43796508672,
43800592384,
43805933568,
43809234944,
43832729600,
43832090624,
43837464576,
43835621376,
43830910976,
43829395456,
43825078272,
43852685312,
44052480000,
44036640768,
44033179648,
44028084224,
44053590016,
44291584000,
44290129920,
44269481984,
44257243136,
44556734464,
44502183936,
44524433408,
44526993408,
44523057152,
44523831296,
44519899136,
44508749824,
44508250112,
44527558656,
44529721344,
44527198208,
44529672192,
44530278400,
44537171968,
44538560512,
44524920832,
44552687616,
44075163648,
44090421248,
44086198272,
44085055488,
44084731904,
44364992512,
44360019968,
44359946240,
44359090176,
44604223488
],
"disk_read_mb": [
null,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
56.63,
73.79,
64.08,
89.26,
71.49,
160.33,
111.7,
115.85,
97.53,
0.0,
3.5,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.56,
0.02,
0.04,
0.03,
0.05,
0.01,
0.03,
0.01,
0.0,
1.14
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790717329.186504
}
}
@@ -0,0 +1,721 @@
{
"label": "native-v0.1.26-Coder-2x3090-K30",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 2,
"run_id": "f81947893a8b",
"corpus_repeated": false,
"time": "2026-09-29T21:28:49",
"prompt_tokens": 31632,
"completion_tokens": 48,
"ttft_s": 11.011,
"e2e_s": 11.496,
"api_prompt_tps": 2872.7,
"api_decode_tps": 97.0,
"engine_prompt_tps": 2926.4,
"engine_decode_tps": 96.1,
"log_lines": [
"strata serve: prompt 31632 tokens = 0 reused + 31632 read in 10809 ms (2926.4 tok/s), 48 generated in 499 ms (96.1 tok/s), drafts accepted 32 of 38, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (27360 hits / 27360 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what's there and identify the last file.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 7680,
"expert_cache_mib": 14575,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 3419,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717329.364414,
"duration_s": 11.3,
"finish": "stop",
"prompt_tokens": 31632,
"reused": 0,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 10809.3,
"decode_ms": 499.4,
"decode_tok_s": 96.1,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717318.4067442,
"duration_s": 10.3,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 9791.3,
"decode_ms": 478.1,
"decode_tok_s": 94.1,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717288.2692974,
"duration_s": 11.1,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 56,
"engine_generated": 56,
"prompt_ms": 10484.4,
"decode_ms": 636.0,
"decode_tok_s": 88.1,
"hit_rate": 1.0
}
],
"requests_kept": 3,
"totals": {
"since": 1790717276.5105639,
"requests": 3,
"prompt_tokens": 88264,
"reused": 0,
"output_tokens": 149,
"prompt_ms": 31084.999999999996,
"decode_ms": 1613.5
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 48,
"mem_used": 22306291712,
"mem_total": 25769803776,
"temp": 51,
"power": 211.949
},
{
"index": 1,
"util": 41,
"mem_used": 18353160192,
"mem_total": 25769803776,
"temp": 54,
"power": 238.158
}
],
"gpu_util": 44.5,
"gpu_mem_used": 40659451904,
"gpu_mem_total": 51539607552,
"gpu_temp": 54,
"gpu_power": 450.10699999999997,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 16.3544921875,
"gpu_pcie_tx_mb": 94.6513671875,
"cpu": 12.9,
"ram_used": 44387663872,
"ram_total": 177175990272,
"disk_read_mb": 0.417992184024029,
"disk_write_mb": 0.0972912842124895,
"tok_s": 101.46942145535564,
"tok_s_mean": 93.06246895838419
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
50.0,
94.0,
63.0,
95.0,
50.0,
92.0,
95.0,
82.5,
97.0,
35.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.5,
97.5,
49.0,
94.5,
50.0,
96.5,
53.0,
94.5,
97.0,
49.5,
50.0,
97.5,
97.0,
98.5,
68.5,
96.0,
49.5,
96.0,
68.5,
97.0,
44.5
],
"gpu_mem_used": [
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40449736704,
40542011392,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904
],
"gpu_temp": [
49,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
50,
52,
53,
53,
53,
52,
54,
51,
54,
52,
50,
49,
49,
49,
49,
49,
49,
48,
49,
48,
48,
48,
49,
49,
49,
49,
46,
46,
53,
52,
54,
52,
54,
52,
54,
54,
53,
50,
54,
54,
55,
54,
55,
52,
55,
54,
55,
54
],
"gpu_power": [
257.9,
244.84,
244.4,
244.1,
244.29,
244.43,
244.32,
244.0,
243.79,
243.86,
244.04,
244.43,
304.5,
504.99,
527.59,
513.34,
519.55,
489.82,
537.3,
515.01,
534.71,
416.26,
390.46,
299.77,
260.05,
241.54,
241.56,
241.75,
241.63,
241.51,
241.46,
241.4,
241.29,
241.13,
241.31,
241.69,
241.72,
221.92,
136.12,
67.69,
469.97,
521.96,
512.77,
514.47,
496.64,
522.43,
513.55,
532.56,
424.31,
362.71,
481.71,
508.96,
525.74,
511.3,
510.79,
506.4,
523.98,
513.03,
516.57,
450.11
],
"gpu_pcie_rx_mb": [
0.67,
0.67,
0.62,
0.62,
0.62,
0.62,
0.67,
1.62,
0.67,
0.62,
0.62,
0.62,
4319.14,
134.51,
87.31,
96.37,
111.91,
79.87,
41.53,
80.25,
44.15,
15.88,
0.67,
0.57,
0.57,
0.57,
0.62,
0.62,
0.62,
0.62,
0.62,
0.57,
0.62,
0.62,
0.62,
0.62,
0.57,
0.81,
0.81,
44.34,
97.08,
1308.87,
41.25,
84.97,
155.3,
46.68,
84.26,
3604.32,
5.86,
45.25,
84.11,
42.39,
128.98,
67.52,
42.77,
92.46,
81.82,
43.3,
95.32,
16.35
],
"cpu": [
0.0,
1.4,
4.7,
7.8,
13.7,
1.8,
1.4,
1.9,
1.6,
1.4,
1.5,
9.7,
13.3,
10.3,
10.0,
9.4,
23.0,
17.6,
10.6,
13.1,
6.5,
6.2,
1.3,
8.4,
5.4,
1.3,
1.2,
1.8,
1.6,
0.9,
10.0,
4.2,
0.8,
1.8,
1.6,
2.2,
2.6,
1.9,
2.8,
7.4,
8.7,
7.1,
5.6,
6.2,
14.3,
8.5,
5.8,
9.0,
6.9,
3.9,
5.5,
5.8,
5.9,
6.4,
7.5,
6.6,
6.1,
8.7,
17.4,
12.9
],
"ram_used": [
43796508672,
43800592384,
43805933568,
43809234944,
43832729600,
43832090624,
43837464576,
43835621376,
43830910976,
43829395456,
43825078272,
43852685312,
44052480000,
44036640768,
44033179648,
44028084224,
44053590016,
44291584000,
44290129920,
44269481984,
44257243136,
44556734464,
44502183936,
44524433408,
44526993408,
44523057152,
44523831296,
44519899136,
44508749824,
44508250112,
44527558656,
44529721344,
44527198208,
44529672192,
44530278400,
44537171968,
44538560512,
44524920832,
44552687616,
44075163648,
44090421248,
44086198272,
44085055488,
44084731904,
44364992512,
44360019968,
44359946240,
44359090176,
44604223488,
44141965312,
44142555136,
44129452032,
44121694208,
44121939968,
44354928640,
44349378560,
44349894656,
44349890560,
44144226304,
44387663872
],
"disk_read_mb": [
null,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
56.63,
73.79,
64.08,
89.26,
71.49,
160.33,
111.7,
115.85,
97.53,
0.0,
3.5,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.56,
0.02,
0.04,
0.03,
0.05,
0.01,
0.03,
0.01,
0.0,
1.14,
0.4,
0.01,
0.0,
0.03,
0.04,
0.01,
0.03,
12.58,
71.94,
32.9,
0.42
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
101.47
]
},
"time": 1790717341.185252
}
}
@@ -0,0 +1,735 @@
{
"label": "native-v0.1.26-Coder-2x3090-K30",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 3,
"run_id": "cb947708c5cc",
"corpus_repeated": false,
"time": "2026-09-29T21:29:01",
"prompt_tokens": 31602,
"completion_tokens": 45,
"ttft_s": 10.976,
"e2e_s": 11.378,
"api_prompt_tps": 2879.2,
"api_decode_tps": 109.6,
"engine_prompt_tps": 2920.6,
"engine_decode_tps": 108.0,
"log_lines": [
"strata serve: prompt 31602 tokens = 0 reused + 31602 read in 10820 ms (2920.6 tok/s), 45 generated in 417 ms (108.0 tok/s), drafts accepted 33 of 37, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (24480 hits / 24480 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what we're working with.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 7680,
"expert_cache_mib": 14575,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 3419,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717341.3189692,
"duration_s": 11.2,
"finish": "stop",
"prompt_tokens": 31602,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 10820.3,
"decode_ms": 416.8,
"decode_tok_s": 108.0,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717329.364414,
"duration_s": 11.3,
"finish": "stop",
"prompt_tokens": 31632,
"reused": 0,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 10809.3,
"decode_ms": 499.4,
"decode_tok_s": 96.1,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717318.4067442,
"duration_s": 10.3,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 9791.3,
"decode_ms": 478.1,
"decode_tok_s": 94.1,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790717288.2692974,
"duration_s": 11.1,
"finish": "stop",
"prompt_tokens": 28316,
"reused": 0,
"output_tokens": 56,
"engine_generated": 56,
"prompt_ms": 10484.4,
"decode_ms": 636.0,
"decode_tok_s": 88.1,
"hit_rate": 1.0
}
],
"requests_kept": 4,
"totals": {
"since": 1790717276.5105639,
"requests": 4,
"prompt_tokens": 119866,
"reused": 0,
"output_tokens": 194,
"prompt_ms": 41905.299999999996,
"decode_ms": 2030.3
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 5,
"mem_used": 22306291712,
"mem_total": 25769803776,
"temp": 49,
"power": 227.165
},
{
"index": 1,
"util": 42,
"mem_used": 18353160192,
"mem_total": 25769803776,
"temp": 54,
"power": 235.691
}
],
"gpu_util": 23.5,
"gpu_mem_used": 40659451904,
"gpu_mem_total": 51539607552,
"gpu_temp": 54,
"gpu_power": 462.856,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 17.0703125,
"gpu_pcie_tx_mb": 56.361328125,
"cpu": 5.5,
"ram_used": 44383059968,
"ram_total": 177175990272,
"disk_read_mb": 0.38547172180233397,
"disk_write_mb": 0.09366602585851105,
"tok_s": 121.26075785511577,
"tok_s_mean": 112.03069063875886
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.0,
50.0,
94.0,
63.0,
95.0,
50.0,
92.0,
95.0,
82.5,
97.0,
35.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.5,
97.5,
49.0,
94.5,
50.0,
96.5,
53.0,
94.5,
97.0,
49.5,
50.0,
97.5,
97.0,
98.5,
68.5,
96.0,
49.5,
96.0,
68.5,
97.0,
44.5,
50.0,
85.5,
94.5,
73.0,
79.0,
96.0,
48.0,
95.0,
72.5,
95.5,
23.5
],
"gpu_mem_used": [
40449736704,
40542011392,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40548302848,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40636383232,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904,
40659451904
],
"gpu_temp": [
48,
50,
52,
53,
53,
53,
52,
54,
51,
54,
52,
50,
49,
49,
49,
49,
49,
49,
48,
49,
48,
48,
48,
49,
49,
49,
49,
46,
46,
53,
52,
54,
52,
54,
52,
54,
54,
53,
50,
54,
54,
55,
54,
55,
52,
55,
54,
55,
54,
51,
53,
54,
53,
54,
55,
54,
55,
55,
55,
54
],
"gpu_power": [
244.43,
304.5,
504.99,
527.59,
513.34,
519.55,
489.82,
537.3,
515.01,
534.71,
416.26,
390.46,
299.77,
260.05,
241.54,
241.56,
241.75,
241.63,
241.51,
241.46,
241.4,
241.29,
241.13,
241.31,
241.69,
241.72,
221.92,
136.12,
67.69,
469.97,
521.96,
512.77,
514.47,
496.64,
522.43,
513.55,
532.56,
424.31,
362.71,
481.71,
508.96,
525.74,
511.3,
510.79,
506.4,
523.98,
513.03,
516.57,
450.11,
369.53,
481.25,
509.29,
527.58,
511.62,
510.74,
510.07,
527.16,
513.42,
533.96,
462.86
],
"gpu_pcie_rx_mb": [
0.62,
4319.14,
134.51,
87.31,
96.37,
111.91,
79.87,
41.53,
80.25,
44.15,
15.88,
0.67,
0.57,
0.57,
0.57,
0.62,
0.62,
0.62,
0.62,
0.62,
0.57,
0.62,
0.62,
0.62,
0.62,
0.57,
0.81,
0.81,
44.34,
97.08,
1308.87,
41.25,
84.97,
155.3,
46.68,
84.26,
3604.32,
5.86,
45.25,
84.11,
42.39,
128.98,
67.52,
42.77,
92.46,
81.82,
43.3,
95.32,
16.35,
43.1,
79.92,
41.63,
65.23,
80.39,
37.1,
81.92,
1273.96,
41.01,
79.15,
17.07
],
"cpu": [
9.7,
13.3,
10.3,
10.0,
9.4,
23.0,
17.6,
10.6,
13.1,
6.5,
6.2,
1.3,
8.4,
5.4,
1.3,
1.2,
1.8,
1.6,
0.9,
10.0,
4.2,
0.8,
1.8,
1.6,
2.2,
2.6,
1.9,
2.8,
7.4,
8.7,
7.1,
5.6,
6.2,
14.3,
8.5,
5.8,
9.0,
6.9,
3.9,
5.5,
5.8,
5.9,
6.4,
7.5,
6.6,
6.1,
8.7,
17.4,
12.9,
4.0,
6.3,
7.4,
6.1,
5.4,
6.6,
5.7,
6.7,
9.3,
6.7,
5.5
],
"ram_used": [
43852685312,
44052480000,
44036640768,
44033179648,
44028084224,
44053590016,
44291584000,
44290129920,
44269481984,
44257243136,
44556734464,
44502183936,
44524433408,
44526993408,
44523057152,
44523831296,
44519899136,
44508749824,
44508250112,
44527558656,
44529721344,
44527198208,
44529672192,
44530278400,
44537171968,
44538560512,
44524920832,
44552687616,
44075163648,
44090421248,
44086198272,
44085055488,
44084731904,
44364992512,
44360019968,
44359946240,
44359090176,
44604223488,
44141965312,
44142555136,
44129452032,
44121694208,
44121939968,
44354928640,
44349378560,
44349894656,
44349890560,
44144226304,
44387663872,
44206063616,
44194983936,
44169220096,
44150177792,
44142342144,
44137152512,
44138057728,
44126892032,
44160794624,
44161884160,
44383059968
],
"disk_read_mb": [
56.63,
73.79,
64.08,
89.26,
71.49,
160.33,
111.7,
115.85,
97.53,
0.0,
3.5,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.56,
0.02,
0.04,
0.03,
0.05,
0.01,
0.03,
0.01,
0.0,
1.14,
0.4,
0.01,
0.0,
0.03,
0.04,
0.01,
0.03,
12.58,
71.94,
32.9,
0.42,
0.53,
0.06,
0.03,
0.08,
0.09,
0.04,
0.08,
0.03,
0.02,
0.22,
0.39
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
101.47,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
121.26
]
},
"time": 1790717353.0661266
}
}
@@ -0,0 +1,585 @@
{
"label": "native-v0.1.26-Coder-2x3090-auto",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 1,
"run_id": "3e44ccd7ec28",
"corpus_repeated": false,
"time": "2026-09-29T21:18:00",
"prompt_tokens": 28314,
"completion_tokens": 48,
"ttft_s": 11.385,
"e2e_s": 11.891,
"api_prompt_tps": 2486.9,
"api_decode_tps": 93.0,
"engine_prompt_tps": 2524.7,
"engine_decode_tps": 88.5,
"log_lines": [
"strata serve: prompt 28314 tokens = 0 reused + 28314 read in 11215 ms (2524.7 tok/s), 48 generated in 542 ms (88.5 tok/s), drafts accepted 34 of 36, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (24958 hits / 24960 lookups)"
],
"answer_head": "I'll first look at the repository structure to understand what files exist and identify the last file.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 4864,
"expert_cache_mib": 8968,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 9025,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790716680.7795944,
"duration_s": 11.8,
"finish": "stop",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 11214.6,
"decode_ms": 542.2,
"decode_tok_s": 88.5,
"hit_rate": 1.0
}
],
"requests_kept": 1,
"totals": {
"since": 1790716641.243247,
"requests": 1,
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 48,
"prompt_ms": 11214.6,
"decode_ms": 542.2
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 2,
"mem_used": 16383934464,
"mem_total": 25769803776,
"temp": 43,
"power": 147.336
},
{
"index": 1,
"util": 7,
"mem_used": 24227282944,
"mem_total": 25769803776,
"temp": 48,
"power": 266.007
}
],
"gpu_util": 4.5,
"gpu_mem_used": 40611217408,
"gpu_mem_total": 51539607552,
"gpu_temp": 48,
"gpu_power": 413.343,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 16.8310546875,
"gpu_pcie_tx_mb": 71.810546875,
"cpu": 8.4,
"ram_used": 44637356032,
"ram_total": 177175990272,
"disk_read_mb": 2.277384309569965,
"disk_write_mb": 0.07927603609262536,
"tok_s": 96.0473472439008,
"tok_s_mean": 90.3424282028167
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.0,
48.0,
91.5,
69.0,
77.0,
91.0,
93.0,
49.5,
94.0,
50.0,
4.5
],
"gpu_mem_used": [
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40489582592,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40611217408
],
"gpu_temp": [
44,
43,
43,
43,
43,
43,
44,
44,
43,
44,
44,
44,
44,
44,
44,
44,
44,
41,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
43,
49,
50,
50,
50,
50,
50,
50,
51,
51,
48
],
"gpu_power": [
253.73,
239.29,
238.99,
238.62,
238.58,
238.53,
238.39,
238.34,
238.4,
238.51,
238.61,
238.53,
238.49,
238.83,
238.96,
238.97,
226.8,
148.88,
73.97,
64.38,
63.94,
63.69,
63.56,
63.75,
63.53,
63.8,
63.68,
63.62,
63.84,
63.74,
63.81,
64.11,
63.92,
63.72,
63.85,
63.64,
63.78,
139.81,
418.68,
508.54,
520.36,
495.57,
522.4,
506.1,
501.02,
508.77,
509.32,
413.34
],
"gpu_pcie_rx_mb": [
0.67,
0.67,
0.71,
0.57,
0.62,
0.57,
0.67,
0.57,
0.67,
0.62,
0.57,
0.67,
0.62,
0.57,
1.05,
0.57,
0.76,
0.81,
0.81,
0.81,
0.76,
0.76,
0.81,
0.86,
1.43,
0.81,
0.81,
0.76,
0.86,
0.81,
0.76,
0.95,
0.86,
0.86,
0.76,
0.86,
0.86,
70.24,
68.14,
64.66,
75.24,
42.29,
84.73,
70.48,
75.05,
54.45,
44.44,
16.83
],
"cpu": [
0.0,
0.6,
1.0,
1.6,
2.5,
1.0,
3.1,
8.1,
6.5,
1.2,
1.9,
2.1,
1.5,
3.2,
2.4,
1.3,
2.0,
1.4,
1.3,
0.9,
0.9,
14.0,
6.6,
2.5,
2.7,
1.7,
1.2,
0.6,
1.1,
1.2,
1.7,
1.3,
1.4,
2.7,
4.4,
12.3,
12.4,
11.4,
12.5,
10.3,
9.0,
12.2,
12.1,
12.5,
11.3,
10.4,
5.8,
8.4
],
"ram_used": [
43649658880,
43652177920,
43664764928,
43666993152,
43672375296,
43665145856,
43695276032,
43759751168,
43760455680,
43757346816,
43754053632,
43711803392,
43717255168,
43692584960,
43693260800,
43687956480,
43682111488,
43635728384,
43632320512,
43636883456,
43633815552,
43735252992,
43881848832,
43881005056,
43875524608,
43879301120,
43878330368,
43866976256,
43862958080,
43863728128,
43854176256,
43855548416,
43854200832,
43859615744,
43895934976,
43929411584,
43962118144,
44169498624,
44107767808,
44110077952,
44109590528,
44111515648,
44233150464,
44346421248,
44340047872,
44335108096,
44329865216,
44637356032
],
"disk_read_mb": [
null,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
129.56,
55.21,
65.53,
55.86,
128.68,
113.77,
117.74,
106.28,
68.13,
0.0,
2.28
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
96.05
]
},
"time": 1790716693.048385
}
}
@@ -0,0 +1,707 @@
{
"label": "native-v0.1.26-Coder-2x3090-auto",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 2,
"run_id": "0b6b57dfa6a4",
"corpus_repeated": false,
"time": "2026-09-29T21:18:13",
"prompt_tokens": 31634,
"completion_tokens": 55,
"ttft_s": 11.855,
"e2e_s": 12.398,
"api_prompt_tps": 2668.4,
"api_decode_tps": 99.4,
"engine_prompt_tps": 2704.3,
"engine_decode_tps": 98.6,
"log_lines": [
"strata serve: prompt 31634 tokens = 0 reused + 31634 read in 11698 ms (2704.3 tok/s), 55 generated in 558 ms (98.6 tok/s), drafts accepted 38 of 44, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (29759 hits / 29760 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what we're working with.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 4864,
"expert_cache_mib": 8968,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 9025,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790716693.1835682,
"duration_s": 12.3,
"finish": "stop",
"prompt_tokens": 31634,
"reused": 0,
"output_tokens": 55,
"engine_generated": 55,
"prompt_ms": 11697.7,
"decode_ms": 557.8,
"decode_tok_s": 98.6,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790716680.7795944,
"duration_s": 11.8,
"finish": "stop",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 11214.6,
"decode_ms": 542.2,
"decode_tok_s": 88.5,
"hit_rate": 1.0
}
],
"requests_kept": 2,
"totals": {
"since": 1790716641.243247,
"requests": 2,
"prompt_tokens": 59948,
"reused": 0,
"output_tokens": 103,
"prompt_ms": 22912.300000000003,
"decode_ms": 1100.0
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 30,
"mem_used": 16392323072,
"mem_total": 25769803776,
"temp": 45,
"power": 154.497
},
{
"index": 1,
"util": 0,
"mem_used": 24241963008,
"mem_total": 25769803776,
"temp": 47,
"power": 250.412
}
],
"gpu_util": 15.0,
"gpu_mem_used": 40634286080,
"gpu_mem_total": 51539607552,
"gpu_temp": 47,
"gpu_power": 404.909,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 19.310546875,
"gpu_pcie_tx_mb": 48.8271484375,
"cpu": 8.6,
"ram_used": 44481728512,
"ram_total": 177175990272,
"disk_read_mb": 1.583864660002197,
"disk_write_mb": 0.12238954190926069,
"tok_s": 112.53532236859756,
"tok_s_mean": 97.92814776699883
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.0,
48.0,
91.5,
69.0,
77.0,
91.0,
93.0,
49.5,
94.0,
50.0,
4.5,
0.5,
94.5,
73.5,
72.5,
96.5,
49.0,
97.5,
97.5,
48.5,
94.0,
48.5,
15.0
],
"gpu_mem_used": [
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40489582592,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40634286080
],
"gpu_temp": [
44,
43,
43,
43,
43,
43,
44,
44,
43,
44,
44,
44,
44,
44,
44,
44,
44,
41,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
43,
49,
50,
50,
50,
50,
50,
50,
51,
51,
48,
45,
51,
51,
50,
51,
51,
51,
51,
51,
51,
51,
47
],
"gpu_power": [
253.73,
239.29,
238.99,
238.62,
238.58,
238.53,
238.39,
238.34,
238.4,
238.51,
238.61,
238.53,
238.49,
238.83,
238.96,
238.97,
226.8,
148.88,
73.97,
64.38,
63.94,
63.69,
63.56,
63.75,
63.53,
63.8,
63.68,
63.62,
63.84,
63.74,
63.81,
64.11,
63.92,
63.72,
63.85,
63.64,
63.78,
139.81,
418.68,
508.54,
520.36,
495.57,
522.4,
506.1,
501.02,
508.77,
509.32,
413.34,
344.59,
491.91,
520.34,
491.14,
524.22,
495.09,
489.28,
512.02,
509.99,
497.54,
503.94,
404.91
],
"gpu_pcie_rx_mb": [
0.67,
0.67,
0.71,
0.57,
0.62,
0.57,
0.67,
0.57,
0.67,
0.62,
0.57,
0.67,
0.62,
0.57,
1.05,
0.57,
0.76,
0.81,
0.81,
0.81,
0.76,
0.76,
0.81,
0.86,
1.43,
0.81,
0.81,
0.76,
0.86,
0.81,
0.76,
0.95,
0.86,
0.86,
0.76,
0.86,
0.86,
70.24,
68.14,
64.66,
75.24,
42.29,
84.73,
70.48,
75.05,
54.45,
44.44,
16.83,
43.1,
73.43,
85.92,
85.16,
1285.6,
83.21,
5496.41,
73.67,
83.68,
89.36,
52.83,
19.31
],
"cpu": [
0.0,
0.6,
1.0,
1.6,
2.5,
1.0,
3.1,
8.1,
6.5,
1.2,
1.9,
2.1,
1.5,
3.2,
2.4,
1.3,
2.0,
1.4,
1.3,
0.9,
0.9,
14.0,
6.6,
2.5,
2.7,
1.7,
1.2,
0.6,
1.1,
1.2,
1.7,
1.3,
1.4,
2.7,
4.4,
12.3,
12.4,
11.4,
12.5,
10.3,
9.0,
12.2,
12.1,
12.5,
11.3,
10.4,
5.8,
8.4,
5.5,
16.9,
8.9,
8.2,
6.7,
6.4,
6.4,
5.5,
7.3,
10.1,
6.1,
8.6
],
"ram_used": [
43649658880,
43652177920,
43664764928,
43666993152,
43672375296,
43665145856,
43695276032,
43759751168,
43760455680,
43757346816,
43754053632,
43711803392,
43717255168,
43692584960,
43693260800,
43687956480,
43682111488,
43635728384,
43632320512,
43636883456,
43633815552,
43735252992,
43881848832,
43881005056,
43875524608,
43879301120,
43878330368,
43866976256,
43862958080,
43863728128,
43854176256,
43855548416,
43854200832,
43859615744,
43895934976,
43929411584,
43962118144,
44169498624,
44107767808,
44110077952,
44109590528,
44111515648,
44233150464,
44346421248,
44340047872,
44335108096,
44329865216,
44637356032,
44551315456,
44588969984,
44562165760,
44546224128,
44540850176,
44543295488,
44547391488,
44375429120,
44370026496,
44363567104,
44368113664,
44481728512
],
"disk_read_mb": [
null,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
129.56,
55.21,
65.53,
55.86,
128.68,
113.77,
117.74,
106.28,
68.13,
0.0,
2.28,
1.11,
0.12,
0.02,
0.05,
0.05,
0.01,
0.03,
0.0,
25.35,
92.15,
0.01,
1.58
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
96.05,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
112.54
]
},
"time": 1790716705.9498026
}
}
@@ -0,0 +1,721 @@
{
"label": "native-v0.1.26-Coder-2x3090-auto",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 3,
"run_id": "caa0b992dd74",
"corpus_repeated": false,
"time": "2026-09-29T21:18:25",
"prompt_tokens": 31601,
"completion_tokens": 45,
"ttft_s": 11.847,
"e2e_s": 12.249,
"api_prompt_tps": 2667.3,
"api_decode_tps": 109.5,
"engine_prompt_tps": 2704.5,
"engine_decode_tps": 108.1,
"log_lines": [
"strata serve: prompt 31601 tokens = 0 reused + 31601 read in 11684 ms (2704.5 tok/s), 45 generated in 416 ms (108.1 tok/s), drafts accepted 33 of 36, 2 checkpoints",
"strata serve: decode expert cache hit rate: 100.0% (24000 hits / 24000 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what we're working with.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-coder-iq1_m",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 4864,
"expert_cache_mib": 8968,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 9025,
"cvec": 0,
"arena_mib": 23981,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790716706.0904436,
"duration_s": 12.1,
"finish": "stop",
"prompt_tokens": 31601,
"reused": 0,
"output_tokens": 45,
"engine_generated": 45,
"prompt_ms": 11684.5,
"decode_ms": 416.2,
"decode_tok_s": 108.1,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790716693.1835682,
"duration_s": 12.3,
"finish": "stop",
"prompt_tokens": 31634,
"reused": 0,
"output_tokens": 55,
"engine_generated": 55,
"prompt_ms": 11697.7,
"decode_ms": 557.8,
"decode_tok_s": 98.6,
"hit_rate": 1.0
},
{
"projection": null,
"time": 1790716680.7795944,
"duration_s": 11.8,
"finish": "stop",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 11214.6,
"decode_ms": 542.2,
"decode_tok_s": 88.5,
"hit_rate": 1.0
}
],
"requests_kept": 3,
"totals": {
"since": 1790716641.243247,
"requests": 3,
"prompt_tokens": 91549,
"reused": 0,
"output_tokens": 148,
"prompt_ms": 34596.8,
"decode_ms": 1516.2
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 30,
"mem_used": 16392323072,
"mem_total": 25769803776,
"temp": 46,
"power": 161.526
},
{
"index": 1,
"util": 0,
"mem_used": 24241963008,
"mem_total": 25769803776,
"temp": 48,
"power": 223.689
}
],
"gpu_util": 15.0,
"gpu_mem_used": 40634286080,
"gpu_mem_total": 51539607552,
"gpu_temp": 48,
"gpu_power": 385.21500000000003,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.5703125,
"gpu_pcie_tx_mb": 0.857421875,
"cpu": 6.1,
"ram_used": 44274470912,
"ram_total": 177175990272,
"disk_read_mb": 0.14419269932051038,
"disk_write_mb": 0.2595468587769187,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.0,
48.0,
91.5,
69.0,
77.0,
91.0,
93.0,
49.5,
94.0,
50.0,
4.5,
0.5,
94.5,
73.5,
72.5,
96.5,
49.0,
97.5,
97.5,
48.5,
94.0,
48.5,
15.0,
0.0,
97.5,
49.0,
93.5,
72.5,
70.5,
97.0,
95.5,
50.0,
96.0,
50.0,
15.0
],
"gpu_mem_used": [
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40426668032,
40489582592,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40521039872,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40611217408,
40634286080,
40634286080,
40634286080,
40634286080,
40634286080,
40634286080,
40634286080,
40634286080,
40634286080,
40634286080,
40634286080,
40634286080,
40634286080
],
"gpu_temp": [
44,
44,
44,
44,
44,
41,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
43,
49,
50,
50,
50,
50,
50,
50,
51,
51,
48,
45,
51,
51,
50,
51,
51,
51,
51,
51,
51,
51,
47,
45,
51,
51,
51,
51,
51,
51,
51,
51,
52,
52,
48
],
"gpu_power": [
238.49,
238.83,
238.96,
238.97,
226.8,
148.88,
73.97,
64.38,
63.94,
63.69,
63.56,
63.75,
63.53,
63.8,
63.68,
63.62,
63.84,
63.74,
63.81,
64.11,
63.92,
63.72,
63.85,
63.64,
63.78,
139.81,
418.68,
508.54,
520.36,
495.57,
522.4,
506.1,
501.02,
508.77,
509.32,
413.34,
344.59,
491.91,
520.34,
491.14,
524.22,
495.09,
489.28,
512.02,
509.99,
497.54,
503.94,
404.91,
336.42,
502.95,
510.85,
498.42,
519.36,
492.86,
501.0,
522.94,
497.46,
508.62,
494.37,
385.22
],
"gpu_pcie_rx_mb": [
0.62,
0.57,
1.05,
0.57,
0.76,
0.81,
0.81,
0.81,
0.76,
0.76,
0.81,
0.86,
1.43,
0.81,
0.81,
0.76,
0.86,
0.81,
0.76,
0.95,
0.86,
0.86,
0.76,
0.86,
0.86,
70.24,
68.14,
64.66,
75.24,
42.29,
84.73,
70.48,
75.05,
54.45,
44.44,
16.83,
43.1,
73.43,
85.92,
85.16,
1285.6,
83.21,
5496.41,
73.67,
83.68,
89.36,
52.83,
19.31,
45.11,
82.73,
85.31,
43.06,
94.36,
41.63,
73.48,
42.01,
87.26,
45.92,
121.97,
0.57
],
"cpu": [
1.5,
3.2,
2.4,
1.3,
2.0,
1.4,
1.3,
0.9,
0.9,
14.0,
6.6,
2.5,
2.7,
1.7,
1.2,
0.6,
1.1,
1.2,
1.7,
1.3,
1.4,
2.7,
4.4,
12.3,
12.4,
11.4,
12.5,
10.3,
9.0,
12.2,
12.1,
12.5,
11.3,
10.4,
5.8,
8.4,
5.5,
16.9,
8.9,
8.2,
6.7,
6.4,
6.4,
5.5,
7.3,
10.1,
6.1,
8.6,
3.1,
6.2,
9.6,
17.9,
6.1,
7.4,
6.0,
6.4,
6.4,
5.7,
5.9,
6.1
],
"ram_used": [
43717255168,
43692584960,
43693260800,
43687956480,
43682111488,
43635728384,
43632320512,
43636883456,
43633815552,
43735252992,
43881848832,
43881005056,
43875524608,
43879301120,
43878330368,
43866976256,
43862958080,
43863728128,
43854176256,
43855548416,
43854200832,
43859615744,
43895934976,
43929411584,
43962118144,
44169498624,
44107767808,
44110077952,
44109590528,
44111515648,
44233150464,
44346421248,
44340047872,
44335108096,
44329865216,
44637356032,
44551315456,
44588969984,
44562165760,
44546224128,
44540850176,
44543295488,
44547391488,
44375429120,
44370026496,
44363567104,
44368113664,
44481728512,
44224720896,
44216463360,
44188299264,
44025966592,
44017278976,
44014284800,
44060004352,
44042358784,
44044165120,
44044423168,
44044165120,
44274470912
],
"disk_read_mb": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
129.56,
55.21,
65.53,
55.86,
128.68,
113.77,
117.74,
106.28,
68.13,
0.0,
2.28,
1.11,
0.12,
0.02,
0.05,
0.05,
0.01,
0.03,
0.0,
25.35,
92.15,
0.01,
1.58,
0.57,
0.06,
0.06,
0.05,
0.08,
0.04,
0.07,
0.01,
0.04,
0.15,
0.0,
0.14
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
96.05,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
112.54,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790716718.7022452
}
}
@@ -0,0 +1,750 @@
{
"label": "native-v0.1.26-IQ3_S-2x3090-auto-needle",
"mode": "needle",
"ctx": "16k",
"target_tokens": 16384,
"run": 1,
"run_id": "1e52cb484c7f",
"corpus_repeated": false,
"time": "2026-09-29T21:55:17",
"prompt_tokens": 17345,
"completion_tokens": 8,
"ttft_s": 23.389,
"e2e_s": 23.454,
"api_prompt_tps": 741.6,
"api_decode_tps": 106.6,
"engine_prompt_tps": 744.7,
"engine_decode_tps": 101.7,
"log_lines": [
"strata serve: prompt 17345 tokens = 0 reused + 17345 read in 23292 ms (744.7 tok/s), 8 generated in 79 ms (101.7 tok/s), drafts accepted 6 of 6, 2 checkpoints",
"strata serve: decode expert cache hit rate: 96.3% (4159 hits / 4317 lookups)"
],
"answer_head": "A466BDE8",
"needle_found": true,
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_s",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 9376,
"expert_cache_mib": 17297,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 635,
"cvec": 0,
"arena_mib": 47962,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790718917.8830457,
"duration_s": 23.4,
"finish": "stop",
"prompt_tokens": 17345,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 23292.2,
"decode_ms": 78.7,
"decode_tok_s": 101.7,
"hit_rate": 0.963
},
{
"projection": null,
"time": 1790718906.5660036,
"duration_s": 10.7,
"finish": "stop",
"prompt_tokens": 7491,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 10625.3,
"decode_ms": 109.4,
"decode_tok_s": 73.1,
"hit_rate": 0.902
},
{
"projection": null,
"time": 1790718828.4807332,
"duration_s": 42.6,
"finish": "stop",
"prompt_tokens": 31604,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 42110.8,
"decode_ms": 460.9,
"decode_tok_s": 106.3,
"hit_rate": 0.991
},
{
"projection": null,
"time": 1790718784.8375118,
"duration_s": 43.0,
"finish": "stop",
"prompt_tokens": 31633,
"reused": 0,
"output_tokens": 88,
"engine_generated": 88,
"prompt_ms": 42216.7,
"decode_ms": 776.7,
"decode_tok_s": 113.3,
"hit_rate": 0.978
},
{
"projection": null,
"time": 1790718743.8685048,
"duration_s": 40.3,
"finish": "stop",
"prompt_tokens": 28315,
"reused": 0,
"output_tokens": 84,
"engine_generated": 84,
"prompt_ms": 39286.5,
"decode_ms": 1011.1,
"decode_tok_s": 83.1,
"hit_rate": 0.949
}
],
"requests_kept": 5,
"totals": {
"since": 1790718725.4039552,
"requests": 5,
"prompt_tokens": 116388,
"reused": 0,
"output_tokens": 237,
"prompt_ms": 157531.5,
"decode_ms": 2436.8
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 5,
"mem_used": 25212944384,
"mem_total": 25769803776,
"temp": 46,
"power": 125.093
},
{
"index": 1,
"util": 0,
"mem_used": 24227282944,
"mem_total": 25769803776,
"temp": 51,
"power": 215.964
}
],
"gpu_util": 2.5,
"gpu_mem_used": 49440227328,
"gpu_mem_total": 51539607552,
"gpu_temp": 51,
"gpu_power": 341.057,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.666015625,
"gpu_pcie_tx_mb": 0.9052734375,
"cpu": 16.5,
"ram_used": 70477971456,
"ram_total": 177175990272,
"disk_read_mb": 0.17303348536954039,
"disk_write_mb": 0.0036048642785320916,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
37.0,
28.0,
22.5,
30.0,
37.0,
18.0,
29.0,
22.0,
21.0,
0.5,
50.0,
34.5,
25.0,
60.5,
31.5,
26.0,
33.5,
46.5,
25.0,
31.5,
21.0,
30.0,
35.0,
37.0,
32.5,
22.0,
26.5,
19.5,
49.5,
26.5,
21.0,
2.5
],
"gpu_mem_used": [
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328
],
"gpu_temp": [
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
45,
45,
45,
45,
45,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
50,
49,
51,
51,
51,
51,
50,
51,
52,
50,
49,
49,
51,
52,
50,
52,
51,
51,
51,
51,
52,
51,
52,
51,
51,
52,
52,
51,
52,
52,
53,
51
],
"gpu_power": [
242.53,
242.44,
242.38,
242.52,
242.49,
242.46,
242.59,
242.37,
242.36,
242.5,
242.54,
140.5,
84.6,
65.59,
65.03,
64.81,
64.81,
64.9,
64.51,
64.65,
64.87,
64.67,
64.8,
64.5,
64.56,
64.64,
64.52,
64.48,
252.37,
388.02,
363.78,
375.15,
399.66,
368.5,
396.75,
362.75,
365.62,
336.59,
296.73,
407.69,
367.08,
376.76,
397.12,
384.8,
382.99,
408.25,
371.72,
397.41,
373.98,
388.78,
413.99,
362.47,
402.46,
358.68,
403.34,
387.12,
369.06,
426.5,
375.9,
341.06
],
"gpu_pcie_rx_mb": [
0.62,
0.62,
0.67,
0.67,
0.67,
0.62,
0.62,
0.57,
0.62,
0.67,
0.71,
0.81,
0.81,
0.86,
0.81,
0.86,
0.81,
0.86,
0.76,
0.81,
0.86,
0.81,
0.95,
0.81,
0.86,
0.86,
0.86,
0.71,
7078.07,
5438.42,
7891.61,
5618.71,
5824.99,
6656.5,
6553.84,
1295.8,
3929.76,
0.67,
7089.76,
6013.73,
7916.07,
5803.39,
5749.08,
4295.01,
6229.4,
7158.52,
6448.94,
8972.07,
4133.89,
5762.81,
4218.58,
7081.13,
5446.96,
19399.45,
7164.1,
6657.41,
4340.22,
8272.65,
7551.43,
0.67
],
"cpu": [
1.4,
3.7,
2.4,
2.6,
2.2,
1.6,
7.0,
7.8,
0.8,
3.8,
6.2,
1.4,
1.5,
1.3,
0.5,
0.8,
1.4,
1.7,
1.4,
1.5,
8.2,
9.2,
2.9,
5.7,
1.3,
5.6,
1.2,
7.3,
6.3,
9.1,
6.4,
7.4,
6.7,
6.4,
16.3,
9.8,
6.3,
19.7,
4.9,
6.7,
5.5,
6.3,
6.2,
6.4,
7.1,
6.3,
6.6,
6.4,
16.7,
8.7,
6.4,
6.7,
6.7,
6.4,
6.1,
7.1,
5.5,
9.0,
6.7,
16.5
],
"ram_used": [
70616137728,
70634639360,
70632943616,
70619291648,
70622433280,
70624546816,
70651342848,
70754201600,
70754394112,
70772871168,
70811869184,
70806048768,
70788648960,
70775001088,
70770065408,
70761766912,
70762528768,
70758371328,
70767398912,
70768398336,
70723190784,
70684524544,
70713102336,
70694293504,
70656102400,
70685872128,
70679355392,
70251024384,
70250827776,
70240993280,
70217400320,
70216302592,
70220156928,
70211788800,
70218944512,
70240178176,
70232375296,
70472826880,
70432313344,
70401486848,
70392971264,
70382305280,
70365552640,
70356713472,
70348333056,
70341337088,
70134956032,
70120873984,
70109106176,
70101512192,
70084435968,
70076407808,
70066089984,
70059646976,
70027522048,
70087983104,
70087725056,
70115901440,
70239928320,
70477971456
],
"disk_read_mb": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.04,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.46,
0.01,
0.0,
0.0,
0.82,
0.0,
0.0,
0.0,
0.0,
0.0,
0.2,
0.52,
0.0,
0.0,
0.0,
0.0,
0.59,
0.0,
0.0,
0.02,
0.0,
0.04,
0.0,
0.0,
0.05,
0.0,
0.22,
0.0,
0.0,
0.0,
0.0,
0.0,
0.17
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790718941.76262
}
}
@@ -0,0 +1,764 @@
{
"label": "native-v0.1.26-IQ3_S-2x3090-auto-needle",
"mode": "needle",
"ctx": "28k",
"target_tokens": 28672,
"run": 1,
"run_id": "c61aafff2d90",
"corpus_repeated": false,
"time": "2026-09-29T21:55:41",
"prompt_tokens": 29827,
"completion_tokens": 8,
"ttft_s": 39.958,
"e2e_s": 40.036,
"api_prompt_tps": 746.5,
"api_decode_tps": 89.7,
"engine_prompt_tps": 749.2,
"engine_decode_tps": 85.9,
"log_lines": [
"strata serve: prompt 29827 tokens = 0 reused + 29827 read in 39812 ms (749.2 tok/s), 8 generated in 93 ms (85.9 tok/s), drafts accepted 6 of 6, 2 checkpoints",
"strata serve: decode expert cache hit rate: 96.2% (4154 hits / 4318 lookups)"
],
"answer_head": "7BDBA3C1",
"needle_found": true,
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_s",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 9376,
"expert_cache_mib": 17297,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 635,
"cvec": 0,
"arena_mib": 47962,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790718941.8879943,
"duration_s": 39.9,
"finish": "stop",
"prompt_tokens": 29827,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 39812.1,
"decode_ms": 93.1,
"decode_tok_s": 85.9,
"hit_rate": 0.962
},
{
"projection": null,
"time": 1790718917.8830457,
"duration_s": 23.4,
"finish": "stop",
"prompt_tokens": 17345,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 23292.2,
"decode_ms": 78.7,
"decode_tok_s": 101.7,
"hit_rate": 0.963
},
{
"projection": null,
"time": 1790718906.5660036,
"duration_s": 10.7,
"finish": "stop",
"prompt_tokens": 7491,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 10625.3,
"decode_ms": 109.4,
"decode_tok_s": 73.1,
"hit_rate": 0.902
},
{
"projection": null,
"time": 1790718828.4807332,
"duration_s": 42.6,
"finish": "stop",
"prompt_tokens": 31604,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 42110.8,
"decode_ms": 460.9,
"decode_tok_s": 106.3,
"hit_rate": 0.991
},
{
"projection": null,
"time": 1790718784.8375118,
"duration_s": 43.0,
"finish": "stop",
"prompt_tokens": 31633,
"reused": 0,
"output_tokens": 88,
"engine_generated": 88,
"prompt_ms": 42216.7,
"decode_ms": 776.7,
"decode_tok_s": 113.3,
"hit_rate": 0.978
},
{
"projection": null,
"time": 1790718743.8685048,
"duration_s": 40.3,
"finish": "stop",
"prompt_tokens": 28315,
"reused": 0,
"output_tokens": 84,
"engine_generated": 84,
"prompt_ms": 39286.5,
"decode_ms": 1011.1,
"decode_tok_s": 83.1,
"hit_rate": 0.949
}
],
"requests_kept": 6,
"totals": {
"since": 1790718725.4039552,
"requests": 6,
"prompt_tokens": 146215,
"reused": 0,
"output_tokens": 245,
"prompt_ms": 197343.6,
"decode_ms": 2529.9
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 0,
"mem_used": 25212944384,
"mem_total": 25769803776,
"temp": 47,
"power": 130.942
},
{
"index": 1,
"util": 42,
"mem_used": 24227282944,
"mem_total": 25769803776,
"temp": 53,
"power": 227.639
}
],
"gpu_util": 21.0,
"gpu_mem_used": 49440227328,
"gpu_mem_total": 51539607552,
"gpu_temp": 53,
"gpu_power": 358.581,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.666015625,
"gpu_pcie_tx_mb": 0.857421875,
"cpu": 6.3,
"ram_used": 70479159296,
"ram_total": 177175990272,
"disk_read_mb": 0.0,
"disk_write_mb": 0.014414807554752778,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
50.0,
34.5,
25.0,
60.5,
31.5,
26.0,
33.5,
46.5,
25.0,
31.5,
21.0,
30.0,
35.0,
37.0,
32.5,
22.0,
26.5,
19.5,
49.5,
26.5,
21.0,
2.5,
50.5,
42.0,
43.0,
38.0,
32.0,
21.5,
29.0,
34.0,
13.5,
36.0,
23.0,
30.0,
11.0,
77.5,
34.5,
23.5,
29.0,
17.5,
69.0,
34.5,
23.5,
32.5,
24.5,
57.5,
32.0,
26.0,
33.5,
25.0,
32.0,
32.5,
22.5,
36.0,
37.0,
36.5,
28.5,
42.5,
21.0
],
"gpu_mem_used": [
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328
],
"gpu_temp": [
50,
49,
49,
51,
52,
50,
52,
51,
51,
51,
51,
52,
51,
52,
51,
51,
52,
52,
51,
52,
52,
53,
51,
50,
50,
51,
53,
51,
52,
52,
51,
52,
51,
52,
52,
52,
53,
52,
52,
51,
51,
53,
52,
52,
52,
52,
52,
51,
53,
52,
52,
52,
52,
53,
52,
53,
52,
53,
52,
53
],
"gpu_power": [
336.59,
296.73,
407.69,
367.08,
376.76,
397.12,
384.8,
382.99,
408.25,
371.72,
397.41,
373.98,
388.78,
413.99,
362.47,
402.46,
358.68,
403.34,
387.12,
369.06,
426.5,
375.9,
341.06,
316.12,
396.45,
370.14,
378.61,
411.6,
381.87,
383.44,
399.03,
378.32,
399.6,
372.43,
400.43,
390.19,
384.29,
405.22,
398.65,
405.33,
377.77,
347.82,
408.44,
395.16,
399.76,
391.18,
383.68,
395.97,
381.79,
371.58,
387.34,
367.36,
390.18,
377.99,
404.54,
406.77,
371.21,
404.91,
389.57,
358.58
],
"gpu_pcie_rx_mb": [
0.67,
7089.76,
6013.73,
7916.07,
5803.39,
5749.08,
4295.01,
6229.4,
7158.52,
6448.94,
8972.07,
4133.89,
5762.81,
4218.58,
7081.13,
5446.96,
19399.45,
7164.1,
6657.41,
4340.22,
8272.65,
7551.43,
0.67,
5912.64,
6668.66,
4836.32,
15187.07,
6919.96,
7012.13,
4668.04,
8340.98,
5615.52,
6986.24,
8358.29,
8231.35,
7154.13,
6558.46,
5322.65,
14744.81,
6437.3,
7645.75,
4067.04,
5734.82,
1.62,
5507.04,
5994.7,
5715.7,
6093.12,
89.88,
6215.57,
4331.35,
6045.63,
5971.19,
6178.04,
5846.59,
7484.53,
5744.65,
5095.67,
7809.07,
0.67
],
"cpu": [
19.7,
4.9,
6.7,
5.5,
6.3,
6.2,
6.4,
7.1,
6.3,
6.6,
6.4,
16.7,
8.7,
6.4,
6.7,
6.7,
6.4,
6.1,
7.1,
5.5,
9.0,
6.7,
16.5,
4.3,
8.5,
17.0,
10.5,
8.0,
8.5,
6.2,
6.8,
6.0,
6.0,
5.6,
6.4,
7.1,
5.6,
6.3,
11.3,
13.8,
13.6,
7.0,
5.8,
6.1,
6.1,
6.3,
6.2,
6.0,
9.3,
6.5,
6.1,
6.0,
14.5,
11.7,
5.6,
8.6,
7.7,
6.1,
6.7,
6.3
],
"ram_used": [
70472826880,
70432313344,
70401486848,
70392971264,
70382305280,
70365552640,
70356713472,
70348333056,
70341337088,
70134956032,
70120873984,
70109106176,
70101512192,
70084435968,
70076407808,
70066089984,
70059646976,
70027522048,
70087983104,
70087725056,
70115901440,
70239928320,
70477971456,
70343557120,
70337265664,
70309584896,
70434922496,
70428250112,
70420987904,
70412926976,
70409207808,
70400454656,
70391336960,
70383079424,
70374731776,
70367465472,
70359465984,
70354010112,
70334316544,
70343401472,
70345613312,
70344155136,
70340018176,
70356168704,
70375772160,
70372450304,
70371860480,
70366474240,
70373842944,
70374035456,
70365605888,
70363926528,
70340509696,
70341251072,
70340546560,
70343122944,
70346379264,
70347120640,
70345048064,
70479159296
],
"disk_read_mb": [
0.2,
0.52,
0.0,
0.0,
0.0,
0.0,
0.59,
0.0,
0.0,
0.02,
0.0,
0.04,
0.0,
0.0,
0.05,
0.0,
0.22,
0.0,
0.0,
0.0,
0.0,
0.0,
0.17,
0.53,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.6,
0.0,
0.03,
0.0,
0.0,
0.05,
0.0,
0.0,
0.05,
0.0,
0.05,
0.0,
0.0,
0.03,
0.0,
0.04,
0.0,
0.0,
0.18,
0.0,
0.0,
0.0,
0.0,
0.0
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790718982.302463
}
}
@@ -0,0 +1,736 @@
{
"label": "native-v0.1.26-IQ3_S-2x3090-auto-needle",
"mode": "needle",
"ctx": "8k",
"target_tokens": 8192,
"run": 1,
"run_id": "7c040dd4c6d7",
"corpus_repeated": false,
"time": "2026-09-29T21:55:06",
"prompt_tokens": 7491,
"completion_tokens": 8,
"ttft_s": 10.682,
"e2e_s": 10.776,
"api_prompt_tps": 701.3,
"api_decode_tps": 74.7,
"engine_prompt_tps": 705.0,
"engine_decode_tps": 73.1,
"log_lines": [
"strata serve: prompt 7491 tokens = 0 reused + 7491 read in 10625 ms (705.0 tok/s), 8 generated in 109 ms (73.1 tok/s), drafts accepted 6 of 6, 1 checkpoints",
"strata serve: decode expert cache hit rate: 90.2% (3891 hits / 4313 lookups)"
],
"answer_head": "C43C98BD",
"needle_found": true,
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_s",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 9376,
"expert_cache_mib": 17297,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 635,
"cvec": 0,
"arena_mib": 47962,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790718906.5660036,
"duration_s": 10.7,
"finish": "stop",
"prompt_tokens": 7491,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 10625.3,
"decode_ms": 109.4,
"decode_tok_s": 73.1,
"hit_rate": 0.902
},
{
"projection": null,
"time": 1790718828.4807332,
"duration_s": 42.6,
"finish": "stop",
"prompt_tokens": 31604,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 42110.8,
"decode_ms": 460.9,
"decode_tok_s": 106.3,
"hit_rate": 0.991
},
{
"projection": null,
"time": 1790718784.8375118,
"duration_s": 43.0,
"finish": "stop",
"prompt_tokens": 31633,
"reused": 0,
"output_tokens": 88,
"engine_generated": 88,
"prompt_ms": 42216.7,
"decode_ms": 776.7,
"decode_tok_s": 113.3,
"hit_rate": 0.978
},
{
"projection": null,
"time": 1790718743.8685048,
"duration_s": 40.3,
"finish": "stop",
"prompt_tokens": 28315,
"reused": 0,
"output_tokens": 84,
"engine_generated": 84,
"prompt_ms": 39286.5,
"decode_ms": 1011.1,
"decode_tok_s": 83.1,
"hit_rate": 0.949
}
],
"requests_kept": 4,
"totals": {
"since": 1790718725.4039552,
"requests": 4,
"prompt_tokens": 99043,
"reused": 0,
"output_tokens": 229,
"prompt_ms": 134239.3,
"decode_ms": 2358.1000000000004
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 1,
"mem_used": 25212944384,
"mem_total": 25769803776,
"temp": 46,
"power": 122.865
},
{
"index": 1,
"util": 0,
"mem_used": 24227282944,
"mem_total": 25769803776,
"temp": 50,
"power": 213.727
}
],
"gpu_util": 0.5,
"gpu_mem_used": 49440227328,
"gpu_mem_total": 51539607552,
"gpu_temp": 50,
"gpu_power": 336.592,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.666015625,
"gpu_pcie_tx_mb": 0.9052734375,
"cpu": 19.7,
"ram_used": 70472826880,
"ram_total": 177175990272,
"disk_read_mb": 0.2018157842351215,
"disk_write_mb": 0.28470440990311785,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
25.0,
33.5,
47.0,
15.5,
32.5,
24.0,
32.5,
29.0,
55.0,
34.0,
48.0,
33.0,
22.5,
31.5,
24.5,
20.0,
20.5,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
37.0,
28.0,
22.5,
30.0,
37.0,
18.0,
29.0,
22.0,
21.0,
0.5
],
"gpu_mem_used": [
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328
],
"gpu_temp": [
51,
50,
51,
51,
51,
51,
51,
51,
51,
50,
52,
52,
52,
51,
52,
52,
50,
49,
49,
49,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
45,
45,
45,
45,
45,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
50,
49,
51,
51,
51,
51,
50,
51,
52,
50
],
"gpu_power": [
380.19,
386.69,
409.76,
359.41,
400.68,
368.54,
396.07,
393.99,
371.52,
407.92,
367.65,
416.33,
386.19,
394.79,
409.75,
373.56,
329.84,
371.48,
309.69,
279.06,
254.32,
242.47,
242.53,
242.44,
242.38,
242.52,
242.49,
242.46,
242.59,
242.37,
242.36,
242.5,
242.54,
140.5,
84.6,
65.59,
65.03,
64.81,
64.81,
64.9,
64.51,
64.65,
64.87,
64.67,
64.8,
64.5,
64.56,
64.64,
64.52,
64.48,
252.37,
388.02,
363.78,
375.15,
399.66,
368.5,
396.75,
362.75,
365.62,
336.59
],
"gpu_pcie_rx_mb": [
5368.61,
7806.78,
7675.93,
8469.58,
5669.88,
14723.06,
5790.85,
6188.01,
6980.23,
7332.23,
12898.87,
6754.21,
6340.74,
6000.61,
6420.09,
4455.66,
19.74,
0.62,
0.62,
0.57,
0.67,
0.62,
0.62,
0.62,
0.67,
0.67,
0.67,
0.62,
0.62,
0.57,
0.62,
0.67,
0.71,
0.81,
0.81,
0.86,
0.81,
0.86,
0.81,
0.86,
0.76,
0.81,
0.86,
0.81,
0.95,
0.81,
0.86,
0.86,
0.86,
0.71,
7078.07,
5438.42,
7891.61,
5618.71,
5824.99,
6656.5,
6553.84,
1295.8,
3929.76,
0.67
],
"cpu": [
7.3,
17.5,
8.0,
7.9,
6.6,
6.2,
6.2,
6.1,
6.6,
5.7,
6.8,
7.1,
7.8,
6.2,
9.8,
15.0,
32.2,
20.2,
4.3,
11.3,
2.0,
1.5,
1.4,
3.7,
2.4,
2.6,
2.2,
1.6,
7.0,
7.8,
0.8,
3.8,
6.2,
1.4,
1.5,
1.3,
0.5,
0.8,
1.4,
1.7,
1.4,
1.5,
8.2,
9.2,
2.9,
5.7,
1.3,
5.6,
1.2,
7.3,
6.3,
9.1,
6.4,
7.4,
6.7,
6.4,
16.3,
9.8,
6.3,
19.7
],
"ram_used": [
70159552512,
70270476288,
70270668800,
70271184896,
70263926784,
70264184832,
70264291328,
70265167872,
70267035648,
70267035648,
70264389632,
70261067776,
70265782272,
70268100608,
70275043328,
70091866112,
70312075264,
70311395328,
70465576960,
70613889024,
70610006016,
70609461248,
70616137728,
70634639360,
70632943616,
70619291648,
70622433280,
70624546816,
70651342848,
70754201600,
70754394112,
70772871168,
70811869184,
70806048768,
70788648960,
70775001088,
70770065408,
70761766912,
70762528768,
70758371328,
70767398912,
70768398336,
70723190784,
70684524544,
70713102336,
70694293504,
70656102400,
70685872128,
70679355392,
70251024384,
70250827776,
70240993280,
70217400320,
70216302592,
70220156928,
70211788800,
70218944512,
70240178176,
70232375296,
70472826880
],
"disk_read_mb": [
0.0,
0.04,
0.0,
0.01,
0.0,
0.02,
0.0,
0.0,
0.01,
0.0,
0.22,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.09,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.04,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.46,
0.01,
0.0,
0.0,
0.82,
0.0,
0.0,
0.0,
0.0,
0.0,
0.2
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
97.75,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790718917.804988
}
}
@@ -0,0 +1,797 @@
{
"label": "native-v0.1.26-IQ3_S-2x3090-auto-two-turn",
"mode": "two-turn",
"ctx": "16k",
"target_tokens": 16384,
"run": 1,
"run_id": "2fd93144a29a",
"corpus_repeated": false,
"time": "2026-09-29T21:56:47",
"prompt_tokens": 15639,
"completion_tokens": 83,
"ttft_s": 21.242,
"e2e_s": 22.071,
"api_prompt_tps": 736.2,
"api_decode_tps": 98.8,
"engine_prompt_tps": 739.4,
"engine_decode_tps": 98.3,
"log_lines": [
"strata serve: prompt 15639 tokens = 0 reused + 15639 read in 21151 ms (739.4 tok/s), 83 generated in 844 ms (98.3 tok/s), drafts accepted 53 of 73, 1 checkpoints",
"strata serve: decode expert cache hit rate: 98.5% (48689 hits / 49415 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what's there.",
"turn2_ttft_s": 0.627,
"turn2_prompt_tokens": 15676,
"turn2_log_lines": [
"strata serve: prompt 15676 tokens = 15632 reused + 44 read in 521 ms (84.4 tok/s), 64 generated in 739 ms (86.6 tok/s), drafts accepted 37 of 52, 2 checkpoints",
"strata serve: decode expert cache hit rate: 97.1% (36768 hits / 37868 lookups)"
],
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_s",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 9376,
"expert_cache_mib": 17297,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 635,
"cvec": 0,
"arena_mib": 47962,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790719030.332211,
"duration_s": 1.3,
"finish": "length",
"prompt_tokens": 15676,
"reused": 15632,
"output_tokens": 64,
"engine_generated": 64,
"prompt_ms": 521.0,
"decode_ms": 739.1,
"decode_tok_s": 86.6,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790719007.7458334,
"duration_s": 22.0,
"finish": "stop",
"prompt_tokens": 15639,
"reused": 0,
"output_tokens": 83,
"engine_generated": 83,
"prompt_ms": 21150.9,
"decode_ms": 844.3,
"decode_tok_s": 98.3,
"hit_rate": 0.985
},
{
"projection": null,
"time": 1790718941.8879943,
"duration_s": 39.9,
"finish": "stop",
"prompt_tokens": 29827,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 39812.1,
"decode_ms": 93.1,
"decode_tok_s": 85.9,
"hit_rate": 0.962
},
{
"projection": null,
"time": 1790718917.8830457,
"duration_s": 23.4,
"finish": "stop",
"prompt_tokens": 17345,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 23292.2,
"decode_ms": 78.7,
"decode_tok_s": 101.7,
"hit_rate": 0.963
},
{
"projection": null,
"time": 1790718906.5660036,
"duration_s": 10.7,
"finish": "stop",
"prompt_tokens": 7491,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 10625.3,
"decode_ms": 109.4,
"decode_tok_s": 73.1,
"hit_rate": 0.902
},
{
"projection": null,
"time": 1790718828.4807332,
"duration_s": 42.6,
"finish": "stop",
"prompt_tokens": 31604,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 42110.8,
"decode_ms": 460.9,
"decode_tok_s": 106.3,
"hit_rate": 0.991
},
{
"projection": null,
"time": 1790718784.8375118,
"duration_s": 43.0,
"finish": "stop",
"prompt_tokens": 31633,
"reused": 0,
"output_tokens": 88,
"engine_generated": 88,
"prompt_ms": 42216.7,
"decode_ms": 776.7,
"decode_tok_s": 113.3,
"hit_rate": 0.978
},
{
"projection": null,
"time": 1790718743.8685048,
"duration_s": 40.3,
"finish": "stop",
"prompt_tokens": 28315,
"reused": 0,
"output_tokens": 84,
"engine_generated": 84,
"prompt_ms": 39286.5,
"decode_ms": 1011.1,
"decode_tok_s": 83.1,
"hit_rate": 0.949
}
],
"requests_kept": 8,
"totals": {
"since": 1790718725.4039552,
"requests": 8,
"prompt_tokens": 177530,
"reused": 15632,
"output_tokens": 392,
"prompt_ms": 219015.5,
"decode_ms": 4113.3
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 41,
"mem_used": 25212944384,
"mem_total": 25769803776,
"temp": 50,
"power": 209.466
},
{
"index": 1,
"util": 49,
"mem_used": 24227282944,
"mem_total": 25769803776,
"temp": 53,
"power": 186.867
}
],
"gpu_util": 45.0,
"gpu_mem_used": 49440227328,
"gpu_mem_total": 51539607552,
"gpu_temp": 53,
"gpu_power": 396.33299999999997,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 2090.7392578125,
"gpu_pcie_tx_mb": 103.1865234375,
"cpu": 82.0,
"ram_used": 70765735936,
"ram_total": 177175990272,
"disk_read_mb": 3.548661248401337,
"disk_write_mb": 0.003595401467478558,
"tok_s": 85.02069488627261,
"tok_s_mean": 85.60127593635436
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
57.5,
32.0,
26.0,
33.5,
25.0,
32.0,
32.5,
22.5,
36.0,
37.0,
36.5,
28.5,
42.5,
21.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
32.0,
30.5,
25.5,
63.5,
34.5,
24.5,
36.0,
38.0,
28.0,
33.0,
21.5,
25.0,
41.5,
33.0,
30.0,
22.0,
29.5,
19.5,
23.5,
48.0,
0.0,
45.0
],
"gpu_mem_used": [
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328
],
"gpu_temp": [
52,
51,
53,
52,
52,
52,
52,
53,
52,
53,
52,
53,
52,
53,
51,
50,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
47,
46,
46,
46,
46,
45,
45,
45,
51,
51,
51,
52,
51,
53,
52,
53,
52,
52,
53,
52,
53,
52,
52,
53,
53,
53,
53,
53,
51,
53
],
"gpu_power": [
383.68,
395.97,
381.79,
371.58,
387.34,
367.36,
390.18,
377.99,
404.54,
406.77,
371.21,
404.91,
389.57,
358.58,
310.16,
278.39,
242.88,
242.69,
242.56,
242.41,
242.25,
242.45,
242.44,
242.38,
242.25,
242.18,
242.52,
242.57,
242.25,
242.23,
197.61,
110.58,
65.55,
65.12,
65.0,
65.02,
65.01,
64.82,
155.28,
410.36,
361.72,
382.57,
404.0,
377.89,
389.35,
407.89,
389.48,
386.49,
371.41,
379.85,
411.79,
387.4,
395.89,
369.99,
400.03,
390.77,
393.61,
354.25,
413.98,
396.33
],
"gpu_pcie_rx_mb": [
5715.7,
6093.12,
89.88,
6215.57,
4331.35,
6045.63,
5971.19,
6178.04,
5846.59,
7484.53,
5744.65,
5095.67,
7809.07,
0.67,
0.71,
0.57,
0.67,
0.62,
0.62,
0.57,
0.71,
0.62,
0.57,
0.67,
0.62,
0.62,
0.57,
0.62,
0.62,
0.71,
0.91,
0.81,
0.76,
0.81,
0.76,
0.81,
0.86,
0.86,
6219.24,
5437.52,
6447.08,
6610.58,
6506.2,
88.93,
6106.14,
6218.53,
5297.85,
8021.88,
67.85,
4886.82,
6395.77,
5794.95,
5961.99,
92.79,
4561.42,
5886.93,
4115.39,
15.07,
6036.38,
2090.74
],
"cpu": [
6.2,
6.0,
9.3,
6.5,
6.1,
6.0,
14.5,
11.7,
5.6,
8.6,
7.7,
6.1,
6.7,
6.3,
15.2,
4.0,
11.7,
1.7,
0.8,
1.6,
10.1,
8.8,
1.8,
3.0,
2.0,
1.1,
3.9,
2.5,
1.2,
1.0,
4.4,
2.2,
2.1,
1.1,
9.2,
4.0,
0.7,
12.8,
6.2,
7.1,
6.6,
6.1,
5.7,
6.8,
7.9,
5.9,
6.1,
7.1,
16.6,
14.8,
6.4,
6.7,
6.6,
7.0,
6.5,
7.1,
6.4,
44.5,
46.9,
82.0
],
"ram_used": [
70371860480,
70366474240,
70373842944,
70374035456,
70365605888,
70363926528,
70340509696,
70341251072,
70340546560,
70343122944,
70346379264,
70347120640,
70345048064,
70479159296,
70572703744,
70652428288,
70736793600,
70729584640,
70733873152,
70729728000,
70753632256,
70894960640,
70882795520,
70887088128,
70877409280,
70896922624,
70917816320,
70944993280,
70949908480,
70948433920,
70969233408,
70968532992,
70973911040,
70965530624,
70981591040,
70982193152,
70979321856,
71007891456,
70533447680,
70536957952,
70444630016,
70438658048,
70435995648,
70428848128,
70422986752,
70424240128,
70404268032,
70411444224,
70518763520,
70541369344,
70539395072,
70538240000,
70528540672,
70514954240,
70316679168,
70304641024,
70310481920,
70539440128,
70546964480,
70765735936
],
"disk_read_mb": [
0.05,
0.0,
0.0,
0.03,
0.0,
0.04,
0.0,
0.0,
0.18,
0.0,
0.0,
0.0,
0.0,
0.0,
0.15,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.48,
0.01,
0.0,
0.0,
0.0,
0.0,
0.02,
0.0,
0.01,
0.0,
0.03,
0.0,
0.0,
0.21,
0.0,
0.0,
0.0,
0.0,
0.0,
0.21,
0.47,
3.55
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
106.42,
0.0,
85.02
]
},
"time": 1790719032.1000419
}
}
@@ -0,0 +1,648 @@
{
"label": "native-v0.1.26-IQ3_S-2x3090-auto",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 1,
"run_id": "e13c9cdd6797",
"corpus_repeated": false,
"time": "2026-09-29T21:52:23",
"prompt_tokens": 28315,
"completion_tokens": 84,
"ttft_s": 39.45,
"e2e_s": 40.422,
"api_prompt_tps": 717.7,
"api_decode_tps": 85.4,
"engine_prompt_tps": 720.7,
"engine_decode_tps": 83.1,
"log_lines": [
"strata serve: prompt 28315 tokens = 0 reused + 28315 read in 39287 ms (720.7 tok/s), 84 generated in 1011 ms (83.1 tok/s), drafts accepted 56 of 67, 2 checkpoints",
"strata serve: decode expert cache hit rate: 94.9% (43073 hits / 45377 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand the context and find the relevant files.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_s",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 9376,
"expert_cache_mib": 17297,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 635,
"cvec": 0,
"arena_mib": 47962,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790718743.8685048,
"duration_s": 40.3,
"finish": "stop",
"prompt_tokens": 28315,
"reused": 0,
"output_tokens": 84,
"engine_generated": 84,
"prompt_ms": 39286.5,
"decode_ms": 1011.1,
"decode_tok_s": 83.1,
"hit_rate": 0.949
}
],
"requests_kept": 1,
"totals": {
"since": 1790718725.4039552,
"requests": 1,
"prompt_tokens": 28315,
"reused": 0,
"output_tokens": 84,
"prompt_ms": 39286.5,
"decode_ms": 1011.1
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 39,
"mem_used": 25212944384,
"mem_total": 25769803776,
"temp": 45,
"power": 141.739
},
{
"index": 1,
"util": 48,
"mem_used": 24227282944,
"mem_total": 25769803776,
"temp": 50,
"power": 205.268
}
],
"gpu_util": 43.5,
"gpu_mem_used": 49440227328,
"gpu_mem_total": 51539607552,
"gpu_temp": 50,
"gpu_power": 347.007,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 6170.3671875,
"gpu_pcie_tx_mb": 126.7900390625,
"cpu": 85.9,
"ram_used": 70739390464,
"ram_total": 177175990272,
"disk_read_mb": 3.315986845192439,
"disk_write_mb": 0.09340808014626588,
"tok_s": 93.51552437654362,
"tok_s_mean": 85.24938371584437
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
57.0,
32.5,
23.5,
25.0,
22.0,
51.0,
35.5,
33.0,
27.5,
26.0,
41.0,
33.0,
23.5,
29.5,
27.5,
71.0,
31.5,
21.5,
64.0,
36.5,
20.5,
32.5,
30.5,
22.0,
29.0,
24.5,
30.0,
17.5,
76.0,
25.0,
20.5,
30.0,
23.0,
19.0,
24.0,
43.5
],
"gpu_mem_used": [
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49224220672,
49316495360,
49326981120,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49440227328
],
"gpu_temp": [
45,
45,
45,
45,
45,
45,
45,
45,
45,
45,
45,
45,
45,
45,
45,
45,
45,
42,
44,
47,
46,
49,
47,
49,
49,
49,
49,
48,
49,
48,
48,
49,
48,
48,
50,
48,
48,
48,
48,
49,
48,
48,
49,
48,
50,
49,
49,
51,
48,
50,
48,
49,
50,
50,
50
],
"gpu_power": [
239.92,
240.19,
239.81,
239.35,
239.3,
239.28,
239.24,
239.29,
239.41,
239.46,
239.45,
239.36,
239.21,
239.26,
239.32,
239.37,
225.06,
145.42,
158.12,
371.86,
384.05,
358.93,
405.61,
381.25,
384.16,
389.93,
395.3,
399.41,
384.35,
363.41,
386.79,
392.7,
344.05,
389.76,
383.66,
397.8,
373.05,
366.9,
391.72,
366.3,
381.76,
387.41,
366.67,
395.88,
403.84,
386.94,
392.83,
352.42,
402.48,
392.8,
357.94,
383.58,
359.24,
350.73,
347.01
],
"gpu_pcie_rx_mb": [
0.62,
0.67,
0.67,
0.62,
0.62,
0.57,
0.57,
0.57,
0.62,
0.67,
0.67,
0.62,
0.62,
0.62,
0.62,
0.62,
0.76,
14.92,
6198.41,
7236.0,
8724.26,
3654.86,
5959.32,
6449.94,
6329.34,
7285.26,
4763.84,
6812.52,
7321.69,
6494.14,
5619.86,
6789.97,
5793.67,
5562.64,
2331.69,
6177.52,
8354.0,
7435.75,
4811.38,
1.43,
7506.18,
7562.16,
2886.44,
7184.17,
6752.54,
7546.95,
7499.69,
4610.3,
6852.1,
6167.22,
5107.31,
7326.55,
4237.65,
0.67,
6170.37
],
"cpu": [
100.0,
1.4,
1.1,
0.9,
1.2,
2.3,
0.9,
1.3,
9.5,
5.4,
6.6,
4.7,
1.3,
1.2,
1.8,
2.0,
0.8,
11.3,
10.6,
10.4,
5.7,
6.8,
17.0,
10.2,
8.1,
7.1,
6.9,
7.6,
9.8,
9.9,
5.8,
6.7,
11.0,
6.0,
9.4,
6.2,
15.2,
12.9,
8.4,
7.2,
10.2,
6.1,
10.5,
6.4,
6.0,
9.0,
7.4,
8.9,
6.9,
8.7,
15.6,
12.0,
6.3,
6.8,
85.9
],
"ram_used": [
70239571968,
70088245248,
70096302080,
70097154048,
70103457792,
70078648320,
70084857856,
70088122368,
70148214784,
70162341888,
70191161344,
70190673920,
70184566784,
70184079360,
70179979264,
70173462528,
70171906048,
70119723008,
70266146816,
70263320576,
70263308288,
70262693888,
70372823040,
70378594304,
70380400640,
70383910912,
70389587968,
70366543872,
70385344512,
70382903296,
70379986944,
70372298752,
70358667264,
70367678464,
70356070400,
70353756160,
70321405952,
70284603392,
70262280192,
70387703808,
70314864640,
70312120320,
70299967488,
70299987968,
70294355968,
70301368320,
70293327872,
70290792448,
70280925184,
70300200960,
70377836544,
70448394240,
70448910336,
70574612480,
70739390464
],
"disk_read_mb": [
null,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
4.75,
124.76,
40.78,
0.0,
7.5,
16.84,
0.0,
55.72,
0.0,
13.03,
20.5,
0.0,
67.32,
0.0,
0.0,
83.74,
0.0,
80.89,
0.0,
0.0,
71.3,
0.0,
0.0,
79.43,
0.0,
72.4,
4.53,
0.0,
54.62,
0.0,
42.73,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
3.32
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
93.52
]
},
"time": 1790718784.6773934
}
}
@@ -0,0 +1,707 @@
{
"label": "native-v0.1.26-IQ3_S-2x3090-auto",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 2,
"run_id": "f953f67441b4",
"corpus_repeated": false,
"time": "2026-09-29T21:53:04",
"prompt_tokens": 31633,
"completion_tokens": 88,
"ttft_s": 42.403,
"e2e_s": 43.165,
"api_prompt_tps": 746.0,
"api_decode_tps": 114.2,
"engine_prompt_tps": 749.3,
"engine_decode_tps": 113.3,
"log_lines": [
"strata serve: prompt 31633 tokens = 0 reused + 31633 read in 42217 ms (749.3 tok/s), 88 generated in 777 ms (113.3 tok/s), drafts accepted 61 of 69, 2 checkpoints",
"strata serve: decode expert cache hit rate: 97.8% (45031 hits / 46048 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what's there and identify the \"last file\" being referenced.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_s",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 9376,
"expert_cache_mib": 17297,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 635,
"cvec": 0,
"arena_mib": 47962,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790718784.8375118,
"duration_s": 43.0,
"finish": "stop",
"prompt_tokens": 31633,
"reused": 0,
"output_tokens": 88,
"engine_generated": 88,
"prompt_ms": 42216.7,
"decode_ms": 776.7,
"decode_tok_s": 113.3,
"hit_rate": 0.978
},
{
"projection": null,
"time": 1790718743.8685048,
"duration_s": 40.3,
"finish": "stop",
"prompt_tokens": 28315,
"reused": 0,
"output_tokens": 84,
"engine_generated": 84,
"prompt_ms": 39286.5,
"decode_ms": 1011.1,
"decode_tok_s": 83.1,
"hit_rate": 0.949
}
],
"requests_kept": 2,
"totals": {
"since": 1790718725.4039552,
"requests": 2,
"prompt_tokens": 59948,
"reused": 0,
"output_tokens": 172,
"prompt_ms": 81503.2,
"decode_ms": 1787.8000000000002
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 43,
"mem_used": 25212944384,
"mem_total": 25769803776,
"temp": 46,
"power": 127.404
},
{
"index": 1,
"util": 22,
"mem_used": 24227282944,
"mem_total": 25769803776,
"temp": 50,
"power": 202.736
}
],
"gpu_util": 32.5,
"gpu_mem_used": 49440227328,
"gpu_mem_total": 51539607552,
"gpu_temp": 50,
"gpu_power": 330.14,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 50.97265625,
"gpu_pcie_tx_mb": 74.43359375,
"cpu": 47.4,
"ram_used": 70762872832,
"ram_total": 177175990272,
"disk_read_mb": 0.9085358249169909,
"disk_write_mb": 0.21546304148229034,
"tok_s": 110.51273259801776,
"tok_s_mean": 104.51731108020398
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
31.5,
21.5,
64.0,
36.5,
20.5,
32.5,
30.5,
22.0,
29.0,
24.5,
30.0,
17.5,
76.0,
25.0,
20.5,
30.0,
23.0,
19.0,
24.0,
43.5,
0.0,
41.5,
33.5,
27.5,
34.0,
22.0,
61.5,
37.0,
23.5,
24.5,
28.5,
54.0,
41.5,
89.5,
30.5,
21.0,
32.0,
33.5,
24.5,
26.0,
25.5,
38.5,
31.5,
24.5,
30.0,
26.0,
31.5,
19.0,
86.5,
28.0,
22.5,
32.0,
26.0,
77.5,
22.5,
22.5,
34.0,
26.0,
20.5,
32.5
],
"gpu_mem_used": [
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49333272576,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328
],
"gpu_temp": [
48,
48,
48,
48,
49,
48,
48,
49,
48,
50,
49,
49,
51,
48,
50,
48,
49,
50,
50,
50,
47,
48,
48,
50,
49,
50,
49,
49,
50,
49,
50,
49,
50,
51,
49,
50,
50,
49,
50,
50,
51,
50,
49,
50,
49,
51,
49,
50,
51,
49,
50,
50,
51,
52,
50,
50,
50,
51,
52,
50
],
"gpu_power": [
397.8,
373.05,
366.9,
391.72,
366.3,
381.76,
387.41,
366.67,
395.88,
403.84,
386.94,
392.83,
352.42,
402.48,
392.8,
357.94,
383.58,
359.24,
350.73,
347.01,
325.66,
372.55,
370.97,
352.05,
397.27,
391.66,
343.17,
403.13,
366.16,
402.14,
390.68,
396.82,
401.28,
360.7,
398.3,
366.48,
382.49,
395.03,
366.16,
401.29,
385.57,
368.88,
396.03,
374.4,
393.23,
385.24,
406.68,
391.86,
364.28,
409.58,
388.38,
389.1,
390.65,
372.81,
415.25,
390.44,
384.85,
382.05,
377.98,
330.14
],
"gpu_pcie_rx_mb": [
6177.52,
8354.0,
7435.75,
4811.38,
1.43,
7506.18,
7562.16,
2886.44,
7184.17,
6752.54,
7546.95,
7499.69,
4610.3,
6852.1,
6167.22,
5107.31,
7326.55,
4237.65,
0.67,
6170.37,
5107.54,
5192.28,
6336.26,
3422.45,
4911.8,
7759.14,
6146.0,
4671.1,
9668.92,
5712.17,
6061.89,
4888.06,
5886.08,
9090.42,
5683.33,
6294.68,
7625.39,
4995.82,
12979.6,
4392.43,
6062.41,
5581.95,
5691.53,
8234.83,
8344.89,
7880.73,
6094.07,
8294.58,
5858.85,
5465.17,
6922.82,
4432.29,
6296.59,
5837.44,
7103.97,
7604.84,
4756.35,
4899.02,
5517.96,
50.97
],
"cpu": [
6.2,
15.2,
12.9,
8.4,
7.2,
10.2,
6.1,
10.5,
6.4,
6.0,
9.0,
7.4,
8.9,
6.9,
8.7,
15.6,
12.0,
6.3,
6.8,
85.9,
9.8,
9.7,
6.7,
6.6,
6.8,
7.4,
7.1,
7.1,
12.2,
13.8,
6.7,
8.5,
6.5,
6.1,
6.4,
6.5,
6.1,
7.2,
6.6,
7.4,
6.1,
6.8,
12.8,
11.1,
6.2,
6.4,
6.4,
6.1,
6.3,
8.7,
7.4,
9.4,
6.3,
7.9,
6.5,
6.4,
15.4,
9.4,
6.3,
47.4
],
"ram_used": [
70353756160,
70321405952,
70284603392,
70262280192,
70387703808,
70314864640,
70312120320,
70299967488,
70299987968,
70294355968,
70301368320,
70293327872,
70290792448,
70280925184,
70300200960,
70377836544,
70448394240,
70448910336,
70574612480,
70739390464,
70512533504,
70533234688,
70513684480,
70496215040,
70484873216,
70469386240,
70452416512,
70445555712,
70424002560,
70434533376,
70424702976,
70408409088,
70395523072,
70388035584,
70353256448,
70333558784,
70326820864,
70357315584,
70361923584,
70355750912,
70357520384,
70490038272,
70530985984,
70524338176,
70524243968,
70525259776,
70528827392,
70526148608,
70526631936,
70541975552,
70541778944,
70536822784,
70537621504,
70537134080,
70534877184,
70532685824,
70529556480,
70530998272,
70534545408,
70762872832
],
"disk_read_mb": [
0.0,
0.0,
71.3,
0.0,
0.0,
79.43,
0.0,
72.4,
4.53,
0.0,
54.62,
0.0,
42.73,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
3.32,
0.6,
0.01,
0.0,
0.01,
0.0,
0.0,
0.02,
0.0,
0.02,
0.0,
0.0,
0.03,
0.0,
0.03,
0.0,
0.0,
0.73,
0.0,
0.01,
0.0,
0.0,
0.01,
0.0,
0.02,
0.0,
0.0,
0.0,
0.0,
12.58,
0.0,
0.0,
71.88,
0.0,
33.04,
0.0,
0.0,
0.0,
0.0,
0.0,
0.91
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
93.52,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
110.51
]
},
"time": 1790718828.3451
}
}
@@ -0,0 +1,721 @@
{
"label": "native-v0.1.26-IQ3_S-2x3090-auto",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 3,
"run_id": "4e71f26e7fd8",
"corpus_repeated": false,
"time": "2026-09-29T21:53:48",
"prompt_tokens": 31604,
"completion_tokens": 49,
"ttft_s": 42.269,
"e2e_s": 42.716,
"api_prompt_tps": 747.7,
"api_decode_tps": 107.5,
"engine_prompt_tps": 750.5,
"engine_decode_tps": 106.3,
"log_lines": [
"strata serve: prompt 31604 tokens = 0 reused + 31604 read in 42111 ms (750.5 tok/s), 49 generated in 461 ms (106.3 tok/s), drafts accepted 33 of 37, 2 checkpoints",
"strata serve: decode expert cache hit rate: 99.1% (26163 hits / 26396 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand what's there and identify the \"last file\" being referenced.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_s",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 9376,
"expert_cache_mib": 17297,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 635,
"cvec": 0,
"arena_mib": 47962,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790718828.4807332,
"duration_s": 42.6,
"finish": "stop",
"prompt_tokens": 31604,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 42110.8,
"decode_ms": 460.9,
"decode_tok_s": 106.3,
"hit_rate": 0.991
},
{
"projection": null,
"time": 1790718784.8375118,
"duration_s": 43.0,
"finish": "stop",
"prompt_tokens": 31633,
"reused": 0,
"output_tokens": 88,
"engine_generated": 88,
"prompt_ms": 42216.7,
"decode_ms": 776.7,
"decode_tok_s": 113.3,
"hit_rate": 0.978
},
{
"projection": null,
"time": 1790718743.8685048,
"duration_s": 40.3,
"finish": "stop",
"prompt_tokens": 28315,
"reused": 0,
"output_tokens": 84,
"engine_generated": 84,
"prompt_ms": 39286.5,
"decode_ms": 1011.1,
"decode_tok_s": 83.1,
"hit_rate": 0.949
}
],
"requests_kept": 3,
"totals": {
"since": 1790718725.4039552,
"requests": 3,
"prompt_tokens": 91552,
"reused": 0,
"output_tokens": 221,
"prompt_ms": 123614.0,
"decode_ms": 2248.7000000000003
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 39,
"mem_used": 25212944384,
"mem_total": 25769803776,
"temp": 47,
"power": 127.526
},
{
"index": 1,
"util": 2,
"mem_used": 24227282944,
"mem_total": 25769803776,
"temp": 50,
"power": 202.315
}
],
"gpu_util": 20.5,
"gpu_mem_used": 49440227328,
"gpu_mem_total": 51539607552,
"gpu_temp": 50,
"gpu_power": 329.841,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 19.740234375,
"gpu_pcie_tx_mb": 54.21484375,
"cpu": 32.2,
"ram_used": 70312075264,
"ram_total": 177175990272,
"disk_read_mb": 0.0,
"disk_write_mb": 0.09328657441898458,
"tok_s": 97.74566314411967,
"tok_s_mean": 97.74268443960047
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
25.5,
38.5,
31.5,
24.5,
30.0,
26.0,
31.5,
19.0,
86.5,
28.0,
22.5,
32.0,
26.0,
77.5,
22.5,
22.5,
34.0,
26.0,
20.5,
32.5,
0.0,
36.5,
37.0,
26.0,
32.0,
37.0,
24.0,
32.5,
20.5,
29.0,
25.0,
27.5,
30.5,
24.0,
35.0,
28.5,
29.0,
30.0,
29.5,
33.5,
44.5,
55.5,
36.0,
25.0,
33.5,
47.0,
15.5,
32.5,
24.0,
32.5,
29.0,
55.0,
34.0,
48.0,
33.0,
22.5,
31.5,
24.5,
20.0,
20.5
],
"gpu_mem_used": [
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328,
49440227328
],
"gpu_temp": [
51,
50,
49,
50,
49,
51,
49,
50,
51,
49,
50,
50,
51,
52,
50,
50,
50,
51,
52,
50,
49,
49,
49,
51,
50,
50,
50,
50,
51,
50,
50,
51,
50,
51,
50,
51,
51,
50,
52,
50,
51,
50,
50,
51,
50,
51,
51,
51,
51,
51,
51,
51,
50,
52,
52,
52,
51,
52,
52,
50
],
"gpu_power": [
385.57,
368.88,
396.03,
374.4,
393.23,
385.24,
406.68,
391.86,
364.28,
409.58,
388.38,
389.1,
390.65,
372.81,
415.25,
390.44,
384.85,
382.05,
377.98,
330.14,
415.76,
348.22,
407.06,
354.03,
392.05,
392.72,
370.96,
399.97,
402.84,
387.68,
394.33,
359.55,
419.05,
403.04,
384.68,
390.64,
393.93,
389.6,
362.93,
373.48,
405.22,
378.6,
399.07,
380.19,
386.69,
409.76,
359.41,
400.68,
368.54,
396.07,
393.99,
371.52,
407.92,
367.65,
416.33,
386.19,
394.79,
409.75,
373.56,
329.84
],
"gpu_pcie_rx_mb": [
6062.41,
5581.95,
5691.53,
8234.83,
8344.89,
7880.73,
6094.07,
8294.58,
5858.85,
5465.17,
6922.82,
4432.29,
6296.59,
5837.44,
7103.97,
7604.84,
4756.35,
4899.02,
5517.96,
50.97,
0.67,
11557.34,
5125.33,
6536.1,
6042.86,
7341.43,
5299.47,
6137.51,
6431.72,
5859.47,
4887.1,
5919.46,
5763.62,
94.17,
6438.59,
7535.84,
6171.89,
7355.36,
4306.32,
5857.37,
4681.59,
5568.03,
5823.33,
5368.61,
7806.78,
7675.93,
8469.58,
5669.88,
14723.06,
5790.85,
6188.01,
6980.23,
7332.23,
12898.87,
6754.21,
6340.74,
6000.61,
6420.09,
4455.66,
19.74
],
"cpu": [
6.1,
6.8,
12.8,
11.1,
6.2,
6.4,
6.4,
6.1,
6.3,
8.7,
7.4,
9.4,
6.3,
7.9,
6.5,
6.4,
15.4,
9.4,
6.3,
47.4,
36.1,
6.3,
6.7,
6.6,
5.7,
7.4,
6.2,
7.4,
6.0,
6.6,
15.5,
14.6,
5.8,
6.4,
6.5,
6.2,
11.6,
8.8,
7.8,
6.2,
6.9,
6.0,
5.5,
7.3,
17.5,
8.0,
7.9,
6.6,
6.2,
6.2,
6.1,
6.6,
5.7,
6.8,
7.1,
7.8,
6.2,
9.8,
15.0,
32.2
],
"ram_used": [
70357520384,
70490038272,
70530985984,
70524338176,
70524243968,
70525259776,
70528827392,
70526148608,
70526631936,
70541975552,
70541778944,
70536822784,
70537621504,
70537134080,
70534877184,
70532685824,
70529556480,
70530998272,
70534545408,
70762872832,
70460293120,
70452703232,
70444961792,
70428729344,
70420193280,
70418821120,
70406471680,
70396342272,
70389112832,
70380965888,
70312722432,
70348423168,
70338981888,
70328791040,
70326034432,
70312820736,
70085947392,
69987848192,
70072119296,
70060589056,
70056861696,
70179471360,
70176550912,
70159552512,
70270476288,
70270668800,
70271184896,
70263926784,
70264184832,
70264291328,
70265167872,
70267035648,
70267035648,
70264389632,
70261067776,
70265782272,
70268100608,
70275043328,
70091866112,
70312075264
],
"disk_read_mb": [
0.0,
0.01,
0.0,
0.02,
0.0,
0.0,
0.0,
0.0,
12.58,
0.0,
0.0,
71.88,
0.0,
33.04,
0.0,
0.0,
0.0,
0.0,
0.0,
0.91,
0.83,
0.04,
0.0,
0.0,
0.01,
0.0,
0.03,
0.0,
0.0,
0.03,
0.0,
0.05,
0.0,
0.0,
0.04,
0.0,
0.04,
0.0,
0.04,
0.0,
0.0,
0.04,
0.0,
0.0,
0.04,
0.0,
0.01,
0.0,
0.02,
0.0,
0.0,
0.01,
0.0,
0.22,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
110.51,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
97.75
]
},
"time": 1790718871.5639336
}
}
@@ -0,0 +1,830 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090-needle",
"mode": "needle",
"ctx": "16k",
"target_tokens": 16384,
"run": 1,
"run_id": "e39790e5649d",
"corpus_repeated": false,
"time": "2026-09-29T20:47:57",
"prompt_tokens": 17346,
"completion_tokens": 8,
"ttft_s": 9.075,
"e2e_s": 9.178,
"api_prompt_tps": 1911.3,
"api_decode_tps": 68.2,
"engine_prompt_tps": 1933.6,
"engine_decode_tps": 67.4,
"log_lines": [
"strata serve: prompt 17346 tokens = 0 reused + 17346 read in 8971 ms (1933.6 tok/s), 8 generated in 119 ms (67.4 tok/s), drafts accepted 6 of 6, 2 checkpoints",
"strata serve: decode expert cache hit rate: 80.6% (3014 hits / 3740 lookups)"
],
"answer_head": "37E3DB14",
"needle_found": true,
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714877.4157934,
"duration_s": 9.1,
"finish": "stop",
"prompt_tokens": 17346,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 8971.0,
"decode_ms": 118.7,
"decode_tok_s": 67.4,
"hit_rate": 0.806
},
{
"projection": null,
"time": 1790714872.57582,
"duration_s": 4.3,
"finish": "stop",
"prompt_tokens": 7493,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 4124.7,
"decode_ms": 123.2,
"decode_tok_s": 64.9,
"hit_rate": 0.748
},
{
"projection": null,
"time": 1790714759.725435,
"duration_s": 63.5,
"finish": "length",
"prompt_tokens": 129913,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 59900.8,
"decode_ms": 3556.3,
"decode_tok_s": 72.0,
"hit_rate": 0.956
},
{
"projection": null,
"time": 1790714695.4286683,
"duration_s": 63.2,
"finish": "length",
"prompt_tokens": 130360,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 59973.9,
"decode_ms": 3226.1,
"decode_tok_s": 79.4,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714636.537164,
"duration_s": 57.8,
"finish": "length",
"prompt_tokens": 119256,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 54577.1,
"decode_ms": 3229.8,
"decode_tok_s": 79.3,
"hit_rate": 0.955
},
{
"projection": null,
"time": 1790714507.7469585,
"duration_s": 17.4,
"finish": "length",
"prompt_tokens": 31602,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14617.7,
"decode_ms": 2785.2,
"decode_tok_s": 91.9,
"hit_rate": 0.965
},
{
"projection": null,
"time": 1790714489.1532733,
"duration_s": 17.9,
"finish": "length",
"prompt_tokens": 31582,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14618.7,
"decode_ms": 3270.7,
"decode_tok_s": 78.3,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714469.1007972,
"duration_s": 19.4,
"finish": "length",
"prompt_tokens": 34932,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 16553.9,
"decode_ms": 2826.7,
"decode_tok_s": 90.6,
"hit_rate": 0.941
},
{
"projection": null,
"time": 1790714463.1913157,
"duration_s": 5.2,
"finish": "length",
"prompt_tokens": 4201,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2365.6,
"decode_ms": 2868.4,
"decode_tok_s": 89.2,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714458.6299415,
"duration_s": 4.0,
"finish": "stop",
"prompt_tokens": 4200,
"reused": 0,
"output_tokens": 142,
"engine_generated": 142,
"prompt_ms": 2370.0,
"decode_ms": 1660.0,
"decode_tok_s": 85.5,
"hit_rate": 0.896
},
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
}
],
"requests_kept": 24,
"totals": {
"since": 1790713882.6043305,
"requests": 24,
"prompt_tokens": 631825,
"reused": 0,
"output_tokens": 4662,
"prompt_ms": 302982.9,
"decode_ms": 55029.19999999998
},
"hardware": {
"gpu_util": 100,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 49,
"gpu_power": 265.798,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 22367.23828125,
"gpu_pcie_tx_mb": 80.8232421875,
"cpu": 6.2,
"ram_used": 63624777728,
"ram_total": 177175990272,
"disk_read_mb": 0.0,
"disk_write_mb": 0.31474488451743216,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
99,
100,
99,
100,
0,
100,
99,
99,
100,
100,
99,
90,
100
],
"gpu_mem_used": [
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
46,
45,
45,
44,
45,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
42,
42,
42,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
47,
48,
49,
49,
46,
49,
49,
48,
49,
49,
49,
48,
49
],
"gpu_power": [
162.82,
148.08,
135.02,
121.86,
121.63,
121.78,
121.51,
121.24,
121.16,
121.27,
121.24,
121.23,
121.05,
121.06,
121.26,
121.23,
101.81,
59.35,
35.84,
35.18,
35.01,
35.2,
35.0,
34.94,
35.11,
35.02,
35.03,
35.11,
34.94,
34.9,
35.04,
35.01,
35.02,
35.13,
34.98,
34.93,
35.03,
34.9,
34.91,
35.06,
34.94,
34.94,
35.11,
35.01,
35.09,
34.99,
34.98,
69.69,
278.48,
278.38,
276.27,
201.82,
237.39,
277.05,
276.41,
278.18,
277.05,
276.73,
274.45,
265.8
],
"gpu_pcie_rx_mb": [
0.33,
0.33,
0.33,
0.29,
0.29,
0.29,
0.33,
0.33,
0.38,
0.33,
0.29,
0.29,
0.29,
0.33,
0.33,
0.43,
0.43,
0.43,
0.43,
0.48,
0.52,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.43,
0.43,
0.38,
0.38,
0.57,
0.43,
0.38,
0.43,
0.43,
0.38,
0.38,
0.43,
0.48,
0.43,
0.43,
0.67,
0.43,
0.43,
0.43,
0.43,
12932.54,
9.63,
46.83,
24945.45,
2343.61,
13238.91,
26700.59,
116.78,
454.76,
16.55,
25179.15,
16555.31,
22367.24
],
"cpu": [
1.7,
6.8,
2.8,
2.2,
1.5,
0.9,
1.8,
5.2,
2.3,
5.5,
8.8,
1.8,
3.7,
1.8,
2.8,
1.4,
3.7,
3.3,
1.7,
1.3,
4.2,
1.2,
1.6,
1.7,
9.9,
2.6,
0.5,
2.0,
1.8,
2.4,
1.5,
0.8,
1.6,
1.2,
0.7,
1.6,
1.6,
2.3,
9.4,
4.7,
1.1,
3.5,
10.5,
1.6,
1.2,
1.3,
4.9,
9.2,
6.2,
7.5,
8.5,
22.5,
12.5,
14.4,
12.6,
8.8,
6.5,
7.5,
6.4,
6.2
],
"ram_used": [
64108949504,
64264835072,
64269873152,
64217538560,
64220250112,
64209580032,
64204328960,
64140402688,
64131928064,
64163700736,
64240553984,
64240898048,
64248393728,
64243052544,
64234790912,
64233521152,
64232390656,
64308101120,
64309403648,
64297762816,
64329601024,
64305721344,
64307060736,
64304783360,
64363835392,
64356347904,
64354099200,
64356909056,
64359067648,
64329744384,
64330743808,
64332496896,
64325115904,
64319610880,
64320966656,
64320552960,
64315297792,
64318357504,
64285126656,
64085762048,
64088686592,
64091111424,
64247578624,
64251699200,
64241737728,
64244289536,
64283144192,
63581208576,
63583793152,
63583657984,
63716282368,
63680327680,
63688806400,
63692079104,
63653728256,
63611449344,
63604965376,
63573368832,
63636836352,
63624777728
],
"disk_read_mb": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.02,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
59.38,
0.0,
0.0,
0.0,
34.69,
51.95,
0.0,
0.0,
11.38,
0.0,
0.0,
0.0,
0.0
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790714887.0144231
}
}
@@ -0,0 +1,830 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090-needle",
"mode": "needle",
"ctx": "28k",
"target_tokens": 28672,
"run": 1,
"run_id": "94aa92e58ada",
"corpus_repeated": false,
"time": "2026-09-29T20:48:07",
"prompt_tokens": 29820,
"completion_tokens": 8,
"ttft_s": 14.138,
"e2e_s": 14.241,
"api_prompt_tps": 2109.2,
"api_decode_tps": 68.2,
"engine_prompt_tps": 2134.7,
"engine_decode_tps": 66.5,
"log_lines": [
"strata serve: prompt 29820 tokens = 0 reused + 29820 read in 13969 ms (2134.7 tok/s), 8 generated in 120 ms (66.5 tok/s), drafts accepted 6 of 6, 2 checkpoints",
"strata serve: decode expert cache hit rate: 80.6% (3033 hits / 3764 lookups)"
],
"answer_head": "64EC0999",
"needle_found": true,
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714887.1579242,
"duration_s": 14.1,
"finish": "stop",
"prompt_tokens": 29820,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 13969.3,
"decode_ms": 120.3,
"decode_tok_s": 66.5,
"hit_rate": 0.806
},
{
"projection": null,
"time": 1790714877.4157934,
"duration_s": 9.1,
"finish": "stop",
"prompt_tokens": 17346,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 8971.0,
"decode_ms": 118.7,
"decode_tok_s": 67.4,
"hit_rate": 0.806
},
{
"projection": null,
"time": 1790714872.57582,
"duration_s": 4.3,
"finish": "stop",
"prompt_tokens": 7493,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 4124.7,
"decode_ms": 123.2,
"decode_tok_s": 64.9,
"hit_rate": 0.748
},
{
"projection": null,
"time": 1790714759.725435,
"duration_s": 63.5,
"finish": "length",
"prompt_tokens": 129913,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 59900.8,
"decode_ms": 3556.3,
"decode_tok_s": 72.0,
"hit_rate": 0.956
},
{
"projection": null,
"time": 1790714695.4286683,
"duration_s": 63.2,
"finish": "length",
"prompt_tokens": 130360,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 59973.9,
"decode_ms": 3226.1,
"decode_tok_s": 79.4,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714636.537164,
"duration_s": 57.8,
"finish": "length",
"prompt_tokens": 119256,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 54577.1,
"decode_ms": 3229.8,
"decode_tok_s": 79.3,
"hit_rate": 0.955
},
{
"projection": null,
"time": 1790714507.7469585,
"duration_s": 17.4,
"finish": "length",
"prompt_tokens": 31602,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14617.7,
"decode_ms": 2785.2,
"decode_tok_s": 91.9,
"hit_rate": 0.965
},
{
"projection": null,
"time": 1790714489.1532733,
"duration_s": 17.9,
"finish": "length",
"prompt_tokens": 31582,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14618.7,
"decode_ms": 3270.7,
"decode_tok_s": 78.3,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714469.1007972,
"duration_s": 19.4,
"finish": "length",
"prompt_tokens": 34932,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 16553.9,
"decode_ms": 2826.7,
"decode_tok_s": 90.6,
"hit_rate": 0.941
},
{
"projection": null,
"time": 1790714463.1913157,
"duration_s": 5.2,
"finish": "length",
"prompt_tokens": 4201,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2365.6,
"decode_ms": 2868.4,
"decode_tok_s": 89.2,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714458.6299415,
"duration_s": 4.0,
"finish": "stop",
"prompt_tokens": 4200,
"reused": 0,
"output_tokens": 142,
"engine_generated": 142,
"prompt_ms": 2370.0,
"decode_ms": 1660.0,
"decode_tok_s": 85.5,
"hit_rate": 0.896
},
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
}
],
"requests_kept": 25,
"totals": {
"since": 1790713882.6043305,
"requests": 25,
"prompt_tokens": 661645,
"reused": 0,
"output_tokens": 4670,
"prompt_ms": 316952.2,
"decode_ms": 55149.499999999985
},
"hardware": {
"gpu_util": 99,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 49,
"gpu_power": 278.531,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 86.068359375,
"gpu_pcie_tx_mb": 76.1982421875,
"cpu": 6.7,
"ram_used": 63515471872,
"ram_total": 177175990272,
"disk_read_mb": 0.0,
"disk_write_mb": 0.08241686128693117,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
99,
100,
99,
100,
0,
100,
99,
99,
100,
100,
99,
90,
100,
0,
99,
99,
100,
96,
100,
99,
99,
99,
100,
99,
100,
99,
99
],
"gpu_mem_used": [
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
44,
44,
42,
42,
42,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
47,
48,
49,
49,
46,
49,
49,
48,
49,
49,
49,
48,
49,
46,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49
],
"gpu_power": [
121.26,
121.23,
101.81,
59.35,
35.84,
35.18,
35.01,
35.2,
35.0,
34.94,
35.11,
35.02,
35.03,
35.11,
34.94,
34.9,
35.04,
35.01,
35.02,
35.13,
34.98,
34.93,
35.03,
34.9,
34.91,
35.06,
34.94,
34.94,
35.11,
35.01,
35.09,
34.99,
34.98,
69.69,
278.48,
278.38,
276.27,
201.82,
237.39,
277.05,
276.41,
278.18,
277.05,
276.73,
274.45,
265.8,
225.08,
215.47,
277.53,
277.2,
277.77,
276.7,
277.63,
275.8,
266.11,
275.21,
277.53,
275.92,
279.07,
278.53
],
"gpu_pcie_rx_mb": [
0.33,
0.43,
0.43,
0.43,
0.43,
0.48,
0.52,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.43,
0.43,
0.38,
0.38,
0.57,
0.43,
0.38,
0.43,
0.43,
0.38,
0.38,
0.43,
0.48,
0.43,
0.43,
0.67,
0.43,
0.43,
0.43,
0.43,
12932.54,
9.63,
46.83,
24945.45,
2343.61,
13238.91,
26700.59,
116.78,
454.76,
16.55,
25179.15,
16555.31,
22367.24,
0.29,
6039.81,
15.31,
2050.78,
8.77,
51.02,
14.83,
11.11,
14.88,
25541.35,
21966.98,
22781.28,
20080.71,
86.07
],
"cpu": [
2.8,
1.4,
3.7,
3.3,
1.7,
1.3,
4.2,
1.2,
1.6,
1.7,
9.9,
2.6,
0.5,
2.0,
1.8,
2.4,
1.5,
0.8,
1.6,
1.2,
0.7,
1.6,
1.6,
2.3,
9.4,
4.7,
1.1,
3.5,
10.5,
1.6,
1.2,
1.3,
4.9,
9.2,
6.2,
7.5,
8.5,
22.5,
12.5,
14.4,
12.6,
8.8,
6.5,
7.5,
6.4,
6.2,
20.7,
7.5,
5.6,
6.7,
10.9,
6.4,
7.2,
16.4,
12.9,
5.7,
8.2,
6.5,
6.1,
6.7
],
"ram_used": [
64234790912,
64233521152,
64232390656,
64308101120,
64309403648,
64297762816,
64329601024,
64305721344,
64307060736,
64304783360,
64363835392,
64356347904,
64354099200,
64356909056,
64359067648,
64329744384,
64330743808,
64332496896,
64325115904,
64319610880,
64320966656,
64320552960,
64315297792,
64318357504,
64285126656,
64085762048,
64088686592,
64091111424,
64247578624,
64251699200,
64241737728,
64244289536,
64283144192,
63581208576,
63583793152,
63583657984,
63716282368,
63680327680,
63688806400,
63692079104,
63653728256,
63611449344,
63604965376,
63573368832,
63636836352,
63624777728,
63754727424,
63698673664,
63690715136,
63681667072,
63675179008,
63536058368,
63521837056,
63517446144,
63523024896,
63518388224,
63517155328,
63521734656,
63516585984,
63515471872
],
"disk_read_mb": [
0.0,
0.0,
0.02,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
59.38,
0.0,
0.0,
0.0,
34.69,
51.95,
0.0,
0.0,
11.38,
0.0,
0.0,
0.0,
0.0,
0.11,
4.58,
0.0,
0.0,
97.16,
0.0,
0.0,
0.0,
52.31,
0.0,
0.0,
0.0,
0.0,
0.0
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790714901.7591343
}
}
@@ -0,0 +1,830 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090-needle",
"mode": "needle",
"ctx": "8k",
"target_tokens": 8192,
"run": 1,
"run_id": "3c83d69c2581",
"corpus_repeated": false,
"time": "2026-09-29T20:47:52",
"prompt_tokens": 7493,
"completion_tokens": 8,
"ttft_s": 4.2,
"e2e_s": 4.307,
"api_prompt_tps": 1783.9,
"api_decode_tps": 65.8,
"engine_prompt_tps": 1816.6,
"engine_decode_tps": 64.9,
"log_lines": [
"strata serve: prompt 7493 tokens = 0 reused + 7493 read in 4125 ms (1816.6 tok/s), 8 generated in 123 ms (64.9 tok/s), drafts accepted 6 of 6, 1 checkpoints",
"strata serve: decode expert cache hit rate: 74.8% (2704 hits / 3615 lookups)"
],
"answer_head": "0E6415FF",
"needle_found": true,
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714872.57582,
"duration_s": 4.3,
"finish": "stop",
"prompt_tokens": 7493,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 4124.7,
"decode_ms": 123.2,
"decode_tok_s": 64.9,
"hit_rate": 0.748
},
{
"projection": null,
"time": 1790714759.725435,
"duration_s": 63.5,
"finish": "length",
"prompt_tokens": 129913,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 59900.8,
"decode_ms": 3556.3,
"decode_tok_s": 72.0,
"hit_rate": 0.956
},
{
"projection": null,
"time": 1790714695.4286683,
"duration_s": 63.2,
"finish": "length",
"prompt_tokens": 130360,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 59973.9,
"decode_ms": 3226.1,
"decode_tok_s": 79.4,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714636.537164,
"duration_s": 57.8,
"finish": "length",
"prompt_tokens": 119256,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 54577.1,
"decode_ms": 3229.8,
"decode_tok_s": 79.3,
"hit_rate": 0.955
},
{
"projection": null,
"time": 1790714507.7469585,
"duration_s": 17.4,
"finish": "length",
"prompt_tokens": 31602,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14617.7,
"decode_ms": 2785.2,
"decode_tok_s": 91.9,
"hit_rate": 0.965
},
{
"projection": null,
"time": 1790714489.1532733,
"duration_s": 17.9,
"finish": "length",
"prompt_tokens": 31582,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14618.7,
"decode_ms": 3270.7,
"decode_tok_s": 78.3,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714469.1007972,
"duration_s": 19.4,
"finish": "length",
"prompt_tokens": 34932,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 16553.9,
"decode_ms": 2826.7,
"decode_tok_s": 90.6,
"hit_rate": 0.941
},
{
"projection": null,
"time": 1790714463.1913157,
"duration_s": 5.2,
"finish": "length",
"prompt_tokens": 4201,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2365.6,
"decode_ms": 2868.4,
"decode_tok_s": 89.2,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714458.6299415,
"duration_s": 4.0,
"finish": "stop",
"prompt_tokens": 4200,
"reused": 0,
"output_tokens": 142,
"engine_generated": 142,
"prompt_ms": 2370.0,
"decode_ms": 1660.0,
"decode_tok_s": 85.5,
"hit_rate": 0.896
},
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
},
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
}
],
"requests_kept": 23,
"totals": {
"since": 1790713882.6043305,
"requests": 23,
"prompt_tokens": 614479,
"reused": 0,
"output_tokens": 4654,
"prompt_ms": 294011.9,
"decode_ms": 54910.499999999985
},
"hardware": {
"gpu_util": 100,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 49,
"gpu_power": 276.273,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 24945.44921875,
"gpu_pcie_tx_mb": 2986.287109375,
"cpu": 8.5,
"ram_used": 63716282368,
"ram_total": 177175990272,
"disk_read_mb": 0.0,
"disk_write_mb": 0.0,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
100,
99,
100,
99,
99,
85,
91,
96,
95,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
99,
100,
99,
100
],
"gpu_mem_used": [
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
49,
49,
49,
49,
49,
49,
49,
49,
49,
46,
45,
45,
44,
45,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
42,
42,
42,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
41,
47,
48,
49,
49
],
"gpu_power": [
277.85,
276.09,
278.51,
279.06,
278.13,
239.73,
262.71,
270.73,
273.54,
162.82,
148.08,
135.02,
121.86,
121.63,
121.78,
121.51,
121.24,
121.16,
121.27,
121.24,
121.23,
121.05,
121.06,
121.26,
121.23,
101.81,
59.35,
35.84,
35.18,
35.01,
35.2,
35.0,
34.94,
35.11,
35.02,
35.03,
35.11,
34.94,
34.9,
35.04,
35.01,
35.02,
35.13,
34.98,
34.93,
35.03,
34.9,
34.91,
35.06,
34.94,
34.94,
35.11,
35.01,
35.09,
34.99,
34.98,
69.69,
278.48,
278.38,
276.27
],
"gpu_pcie_rx_mb": [
12025.83,
22118.66,
18928.05,
18.36,
86.12,
284.24,
9240.67,
7805.97,
0.29,
0.33,
0.33,
0.33,
0.29,
0.29,
0.29,
0.33,
0.33,
0.38,
0.33,
0.29,
0.29,
0.29,
0.33,
0.33,
0.43,
0.43,
0.43,
0.43,
0.48,
0.52,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.43,
0.43,
0.38,
0.38,
0.57,
0.43,
0.38,
0.43,
0.43,
0.38,
0.38,
0.43,
0.48,
0.43,
0.43,
0.67,
0.43,
0.43,
0.43,
0.43,
12932.54,
9.63,
46.83,
24945.45
],
"cpu": [
8.2,
6.7,
6.2,
6.0,
13.2,
64.5,
99.9,
99.0,
86.8,
1.7,
6.8,
2.8,
2.2,
1.5,
0.9,
1.8,
5.2,
2.3,
5.5,
8.8,
1.8,
3.7,
1.8,
2.8,
1.4,
3.7,
3.3,
1.7,
1.3,
4.2,
1.2,
1.6,
1.7,
9.9,
2.6,
0.5,
2.0,
1.8,
2.4,
1.5,
0.8,
1.6,
1.2,
0.7,
1.6,
1.6,
2.3,
9.4,
4.7,
1.1,
3.5,
10.5,
1.6,
1.2,
1.3,
4.9,
9.2,
6.2,
7.5,
8.5
],
"ram_used": [
64100171776,
64087904256,
64069447680,
64067096576,
64095731712,
64224346112,
64185745408,
64170352640,
64157536256,
64108949504,
64264835072,
64269873152,
64217538560,
64220250112,
64209580032,
64204328960,
64140402688,
64131928064,
64163700736,
64240553984,
64240898048,
64248393728,
64243052544,
64234790912,
64233521152,
64232390656,
64308101120,
64309403648,
64297762816,
64329601024,
64305721344,
64307060736,
64304783360,
64363835392,
64356347904,
64354099200,
64356909056,
64359067648,
64329744384,
64330743808,
64332496896,
64325115904,
64319610880,
64320966656,
64320552960,
64315297792,
64318357504,
64285126656,
64085762048,
64088686592,
64091111424,
64247578624,
64251699200,
64241737728,
64244289536,
64283144192,
63581208576,
63583793152,
63583657984,
63716282368
],
"disk_read_mb": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.89,
2.52,
3.25,
2.83,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.02,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
59.38,
0.0,
0.0,
0.0
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
61.23,
76.01,
95.36,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790714877.3325372
}
}
@@ -0,0 +1,835 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090-two-turn",
"mode": "two-turn",
"ctx": "16k",
"target_tokens": 16384,
"run": 1,
"run_id": "7aed17dd03cd",
"corpus_repeated": false,
"time": "2026-09-29T20:48:48",
"prompt_tokens": 15636,
"completion_tokens": 256,
"ttft_s": 7.488,
"e2e_s": 10.882,
"api_prompt_tps": 2088.0,
"api_decode_tps": 75.1,
"engine_prompt_tps": 2114.8,
"engine_decode_tps": 75.1,
"log_lines": [
"strata serve: prompt 15636 tokens = 0 reused + 15636 read in 7394 ms (2114.8 tok/s), 256 generated in 3410 ms (75.1 tok/s), drafts accepted 152 of 215, 1 checkpoints",
"strata serve: decode expert cache hit rate: 93.0% (136865 hits / 147168 lookups)"
],
"answer_head": "## What `README.md` does\n\n`README.md` is the project's landing page and primary user-facing documentation. It serves several purposes:\n\n1. **Marketing/overview** \u2014 Opens with a headline claim (\"Run a 125-billion-parameter AI model on a normal gaming PC\") and a visual demo (the pagoda video) to immed",
"turn2_ttft_s": 0.438,
"turn2_prompt_tokens": 15915,
"turn2_log_lines": [
"strata serve: prompt 15915 tokens = 15892 reused + 23 read in 332 ms (69.3 tok/s), 46 generated in 661 ms (69.6 tok/s), drafts accepted 27 of 44, 2 checkpoints",
"strata serve: decode expert cache hit rate: 96.4% (29047 hits / 30124 lookups)"
],
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714939.7647502,
"duration_s": 1.0,
"finish": "stop",
"prompt_tokens": 15915,
"reused": 15892,
"output_tokens": 46,
"engine_generated": 46,
"prompt_ms": 331.9,
"decode_ms": 660.8,
"decode_tok_s": 69.6,
"hit_rate": 0.964
},
{
"projection": null,
"time": 1790714928.3706348,
"duration_s": 10.8,
"finish": "length",
"prompt_tokens": 15636,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 7393.6,
"decode_ms": 3409.5,
"decode_tok_s": 75.1,
"hit_rate": 0.93
},
{
"projection": null,
"time": 1790714887.1579242,
"duration_s": 14.1,
"finish": "stop",
"prompt_tokens": 29820,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 13969.3,
"decode_ms": 120.3,
"decode_tok_s": 66.5,
"hit_rate": 0.806
},
{
"projection": null,
"time": 1790714877.4157934,
"duration_s": 9.1,
"finish": "stop",
"prompt_tokens": 17346,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 8971.0,
"decode_ms": 118.7,
"decode_tok_s": 67.4,
"hit_rate": 0.806
},
{
"projection": null,
"time": 1790714872.57582,
"duration_s": 4.3,
"finish": "stop",
"prompt_tokens": 7493,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 4124.7,
"decode_ms": 123.2,
"decode_tok_s": 64.9,
"hit_rate": 0.748
},
{
"projection": null,
"time": 1790714759.725435,
"duration_s": 63.5,
"finish": "length",
"prompt_tokens": 129913,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 59900.8,
"decode_ms": 3556.3,
"decode_tok_s": 72.0,
"hit_rate": 0.956
},
{
"projection": null,
"time": 1790714695.4286683,
"duration_s": 63.2,
"finish": "length",
"prompt_tokens": 130360,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 59973.9,
"decode_ms": 3226.1,
"decode_tok_s": 79.4,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714636.537164,
"duration_s": 57.8,
"finish": "length",
"prompt_tokens": 119256,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 54577.1,
"decode_ms": 3229.8,
"decode_tok_s": 79.3,
"hit_rate": 0.955
},
{
"projection": null,
"time": 1790714507.7469585,
"duration_s": 17.4,
"finish": "length",
"prompt_tokens": 31602,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14617.7,
"decode_ms": 2785.2,
"decode_tok_s": 91.9,
"hit_rate": 0.965
},
{
"projection": null,
"time": 1790714489.1532733,
"duration_s": 17.9,
"finish": "length",
"prompt_tokens": 31582,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14618.7,
"decode_ms": 3270.7,
"decode_tok_s": 78.3,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714469.1007972,
"duration_s": 19.4,
"finish": "length",
"prompt_tokens": 34932,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 16553.9,
"decode_ms": 2826.7,
"decode_tok_s": 90.6,
"hit_rate": 0.941
},
{
"projection": null,
"time": 1790714463.1913157,
"duration_s": 5.2,
"finish": "length",
"prompt_tokens": 4201,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2365.6,
"decode_ms": 2868.4,
"decode_tok_s": 89.2,
"hit_rate": 0.96
}
],
"requests_kept": 27,
"totals": {
"since": 1790713882.6043305,
"requests": 27,
"prompt_tokens": 693196,
"reused": 15892,
"output_tokens": 4972,
"prompt_ms": 324677.7,
"decode_ms": 59219.79999999999
},
"hardware": {
"gpu_util": 94,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 48,
"gpu_power": 197.275,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 822.3525390625,
"gpu_pcie_tx_mb": 183.15234375,
"cpu": 52.4,
"ram_used": 63860678656,
"ram_total": 177175990272,
"disk_read_mb": 1.1632307226246328,
"disk_write_mb": 0.2954830452969325,
"tok_s": 50.58164583911189,
"tok_s_mean": 50.57911214220715
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
100,
99,
99,
100,
100,
99,
90,
100,
0,
99,
99,
100,
96,
100,
99,
99,
99,
100,
99,
100,
99,
99,
96,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
99,
99,
100,
99,
99,
100,
100,
100,
95,
97,
93,
94
],
"gpu_mem_used": [
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
49,
49,
48,
49,
49,
49,
48,
49,
46,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
48,
46,
45,
45,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
44,
42,
42,
42,
41,
41,
41,
41,
41,
41,
41,
47,
49,
49,
49,
49,
49,
49,
47,
48,
49,
49,
48
],
"gpu_power": [
237.39,
277.05,
276.41,
278.18,
277.05,
276.73,
274.45,
265.8,
225.08,
215.47,
277.53,
277.2,
277.77,
276.7,
277.63,
275.8,
266.11,
275.21,
277.53,
275.92,
279.07,
278.53,
241.13,
171.76,
147.92,
134.65,
121.43,
121.4,
121.36,
121.31,
121.11,
121.03,
121.2,
121.14,
120.8,
121.02,
121.17,
121.22,
102.94,
60.93,
36.12,
35.26,
35.35,
35.31,
35.23,
35.08,
35.09,
35.22,
69.73,
277.07,
276.87,
276.87,
278.61,
277.22,
278.12,
247.41,
259.45,
271.65,
275.28,
197.28
],
"gpu_pcie_rx_mb": [
13238.91,
26700.59,
116.78,
454.76,
16.55,
25179.15,
16555.31,
22367.24,
0.29,
6039.81,
15.31,
2050.78,
8.77,
51.02,
14.83,
11.11,
14.88,
25541.35,
21966.98,
22781.28,
20080.71,
86.07,
0.33,
0.29,
0.29,
0.33,
0.33,
0.29,
0.33,
0.29,
0.33,
0.33,
0.33,
0.33,
0.43,
0.33,
0.33,
0.29,
0.33,
0.38,
0.43,
0.38,
0.43,
0.38,
0.43,
0.43,
0.38,
0.43,
7494.78,
15213.11,
13.83,
86.31,
6.25,
4.48,
7.34,
1956.56,
3779.22,
10756.4,
0.33,
822.35
],
"cpu": [
12.5,
14.4,
12.6,
8.8,
6.5,
7.5,
6.4,
6.2,
20.7,
7.5,
5.6,
6.7,
10.9,
6.4,
7.2,
16.4,
12.9,
5.7,
8.2,
6.5,
6.1,
6.7,
20.8,
2.1,
8.1,
1.0,
2.4,
4.3,
1.2,
15.4,
6.0,
0.7,
1.7,
1.9,
1.9,
1.8,
1.1,
2.0,
2.0,
1.3,
1.6,
1.5,
3.7,
3.2,
9.8,
1.4,
4.8,
1.6,
8.9,
6.6,
7.0,
5.9,
5.6,
7.0,
10.7,
49.0,
100.0,
99.6,
87.8,
52.4
],
"ram_used": [
63688806400,
63692079104,
63653728256,
63611449344,
63604965376,
63573368832,
63636836352,
63624777728,
63754727424,
63698673664,
63690715136,
63681667072,
63675179008,
63536058368,
63521837056,
63517446144,
63523024896,
63518388224,
63517155328,
63521734656,
63516585984,
63515471872,
63598735360,
63575552000,
63746940928,
63743287296,
63744950272,
63746498560,
63748960256,
63781244928,
63777951744,
63778541568,
63778627584,
63784894464,
63788924928,
63789916160,
63785603072,
63778463744,
63786168320,
63781711872,
63785504768,
63775502336,
63798136832,
63833931776,
63825649664,
63827275776,
63826427904,
63833698304,
63620595712,
63618826240,
63602626560,
63602855936,
63603830784,
63609753600,
63610949632,
63683670016,
63692382208,
63679488000,
63682031616,
63860678656
],
"disk_read_mb": [
51.95,
0.0,
0.0,
11.38,
0.0,
0.0,
0.0,
0.0,
0.11,
4.58,
0.0,
0.0,
97.16,
0.0,
0.0,
0.0,
52.31,
0.0,
0.0,
0.0,
0.0,
0.0,
0.15,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.41,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.29,
3.18,
2.31,
2.73,
1.16
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
68.59,
62.69,
101.15,
0.0,
50.58
]
},
"time": 1790714941.2661076
}
}
@@ -0,0 +1,829 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "128k",
"target_tokens": 129792,
"run": 1,
"run_id": "183f9c0b2a25",
"corpus_repeated": false,
"time": "2026-09-29T20:43:56",
"prompt_tokens": 119256,
"completion_tokens": 256,
"ttft_s": 55.136,
"e2e_s": 58.347,
"api_prompt_tps": 2162.9,
"api_decode_tps": 79.4,
"engine_prompt_tps": 2185.1,
"engine_decode_tps": 79.3,
"log_lines": [
"strata serve: prompt 119256 tokens = 0 reused + 119256 read in 54577 ms (2185.1 tok/s), 256 generated in 3230 ms (79.3 tok/s), drafts accepted 151 of 208, 6 checkpoints",
"strata serve: decode expert cache hit rate: 95.5% (140181 hits / 146787 lookups)"
],
"answer_head": "The last file shown is `include/strata/kernels/cpu/pool.hpp`. It declares the CPU expert pool (`ExpertPool`), which is the engine's mechanism for computing the routed MoE experts that do not fit in VRAM.\n\n**What it does:**\n\n1. **Thread Management:** It creates a pool of worker threads pinned to phy",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714636.537164,
"duration_s": 57.8,
"finish": "length",
"prompt_tokens": 119256,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 54577.1,
"decode_ms": 3229.8,
"decode_tok_s": 79.3,
"hit_rate": 0.955
},
{
"projection": null,
"time": 1790714507.7469585,
"duration_s": 17.4,
"finish": "length",
"prompt_tokens": 31602,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14617.7,
"decode_ms": 2785.2,
"decode_tok_s": 91.9,
"hit_rate": 0.965
},
{
"projection": null,
"time": 1790714489.1532733,
"duration_s": 17.9,
"finish": "length",
"prompt_tokens": 31582,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14618.7,
"decode_ms": 3270.7,
"decode_tok_s": 78.3,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714469.1007972,
"duration_s": 19.4,
"finish": "length",
"prompt_tokens": 34932,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 16553.9,
"decode_ms": 2826.7,
"decode_tok_s": 90.6,
"hit_rate": 0.941
},
{
"projection": null,
"time": 1790714463.1913157,
"duration_s": 5.2,
"finish": "length",
"prompt_tokens": 4201,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2365.6,
"decode_ms": 2868.4,
"decode_tok_s": 89.2,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714458.6299415,
"duration_s": 4.0,
"finish": "stop",
"prompt_tokens": 4200,
"reused": 0,
"output_tokens": 142,
"engine_generated": 142,
"prompt_ms": 2370.0,
"decode_ms": 1660.0,
"decode_tok_s": 85.5,
"hit_rate": 0.896
},
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
},
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
},
{
"projection": null,
"time": 1790714377.2599747,
"duration_s": 17.6,
"finish": "length",
"prompt_tokens": 31605,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14608.5,
"decode_ms": 3015.6,
"decode_tok_s": 84.9,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714359.1307795,
"duration_s": 17.5,
"finish": "length",
"prompt_tokens": 31589,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14609.7,
"decode_ms": 2833.5,
"decode_tok_s": 90.3,
"hit_rate": 0.959
}
],
"requests_kept": 20,
"totals": {
"since": 1790713882.6043305,
"requests": 20,
"prompt_tokens": 346713,
"reused": 0,
"output_tokens": 4134,
"prompt_ms": 170012.5,
"decode_ms": 48004.89999999999
},
"hardware": {
"gpu_util": 0,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 45,
"gpu_power": 245.728,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.3330078125,
"gpu_pcie_tx_mb": 0.4765625,
"cpu": 55.3,
"ram_used": 63994736640,
"ram_total": 177175990272,
"disk_read_mb": 2.173699813344069,
"disk_write_mb": 0.07870292427625078,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0,
0,
0,
0,
100,
100,
99,
100,
99,
100,
99,
99,
100,
99,
99,
100,
99,
97,
96,
99,
99,
99,
100,
100,
97,
100,
100,
99,
97,
99,
100,
100,
99,
99,
98,
99,
99,
99,
98,
100,
100,
99,
99,
100,
100,
100,
99,
99,
99,
97,
100,
100,
100,
4,
100,
100,
89,
94,
95,
0
],
"gpu_mem_used": [
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
38,
38,
38,
38,
45,
46,
46,
46,
46,
46,
46,
47,
47,
47,
47,
46,
47,
47,
47,
47,
47,
47,
46,
46,
46,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
47,
46,
47,
47,
46,
47,
47,
45
],
"gpu_power": [
34.95,
35.05,
34.94,
34.95,
146.71,
278.26,
278.02,
277.13,
278.38,
277.26,
277.39,
265.55,
278.37,
277.81,
278.33,
277.55,
276.64,
268.76,
278.4,
278.09,
279.44,
277.89,
278.06,
278.94,
266.27,
278.02,
278.54,
277.25,
277.61,
278.51,
277.09,
267.68,
277.75,
277.97,
277.81,
277.03,
277.2,
278.97,
266.74,
277.84,
277.04,
277.08,
277.19,
277.7,
278.99,
275.31,
278.3,
278.49,
277.62,
278.02,
276.32,
276.96,
277.41,
263.19,
267.16,
277.12,
240.24,
275.77,
278.35,
245.73
],
"gpu_pcie_rx_mb": [
0.43,
0.38,
0.43,
0.62,
11.06,
10427.81,
2646.73,
383.9,
8262.3,
11.68,
24650.05,
893.64,
18094.54,
8958.05,
12.25,
6881.52,
17403.6,
4113.72,
25011.21,
21669.05,
15617.75,
11.78,
26451.63,
0.33,
5449.25,
2654.98,
14.88,
22.22,
15.59,
7.49,
1.29,
17076.97,
2352.29,
26573.8,
19.55,
15.45,
3977.3,
0.29,
16.07,
3622.44,
16839.27,
13.49,
13131.9,
19713.45,
26861.86,
17424.06,
12115.96,
5297.42,
26787.19,
12211.47,
5737.21,
18827.01,
8191.39,
15610.6,
18543.15,
81.97,
3906.87,
3778.6,
4665.28,
0.33
],
"cpu": [
1.5,
6.0,
1.8,
7.9,
6.4,
6.6,
16.7,
12.8,
7.5,
6.4,
5.6,
6.5,
6.9,
6.6,
17.4,
5.9,
5.5,
14.4,
12.9,
6.6,
19.0,
17.6,
6.4,
7.6,
15.3,
10.6,
6.2,
15.5,
14.7,
6.1,
5.9,
17.4,
8.8,
6.2,
15.9,
21.5,
7.2,
7.4,
16.6,
7.1,
6.6,
8.9,
14.9,
6.1,
5.8,
10.7,
14.6,
6.8,
5.9,
19.6,
12.3,
6.2,
7.7,
6.1,
5.9,
6.3,
64.3,
100.0,
100.0,
55.3
],
"ram_used": [
63599173632,
63581626368,
63584313344,
63628144640,
63383064576,
63385989120,
63410585600,
63420211200,
63412383744,
63414505472,
63524802560,
63511179264,
63497076736,
63495684096,
63489646592,
63487651840,
63472156672,
63594835968,
63578550272,
63580782592,
63599607808,
63609155584,
63609020416,
63658397696,
63611748352,
63599493120,
63591612416,
63610773504,
63607812096,
63605293056,
63719862272,
63720685568,
63714033664,
63716544512,
63707664384,
63700750336,
63700516864,
63791661056,
63808417792,
63809699840,
63813054464,
63809191936,
63809736704,
63785721856,
63788429312,
63899906048,
63903354880,
63885254656,
63887302656,
63919407104,
63917928448,
63921512448,
63919017984,
64030937088,
64033521664,
64022724608,
64014991360,
64020590592,
64011530240,
63994736640
],
"disk_read_mb": [
0.0,
0.0,
0.0,
0.0,
0.59,
0.0,
0.0,
0.18,
0.0,
0.0,
0.31,
0.0,
0.0,
5.59,
188.01,
0.0,
0.0,
123.58,
109.11,
0.0,
61.11,
110.87,
0.0,
0.0,
173.38,
90.91,
0.0,
90.3,
151.87,
0.0,
0.0,
198.92,
33.71,
0.0,
100.92,
100.99,
0.0,
0.0,
190.6,
21.65,
0.0,
46.97,
157.79,
0.0,
0.0,
54.2,
150.86,
0.0,
0.0,
89.37,
16.55,
0.0,
0.0,
0.0,
0.0,
0.0,
1.57,
4.0,
4.88,
2.17
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
80.35,
77.04,
74.05,
0.0
]
},
"time": 1790714694.882821
}
}
@@ -0,0 +1,829 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "128k",
"target_tokens": 129792,
"run": 2,
"run_id": "815c67976126",
"corpus_repeated": false,
"time": "2026-09-29T20:44:54",
"prompt_tokens": 130360,
"completion_tokens": 256,
"ttft_s": 60.567,
"e2e_s": 63.777,
"api_prompt_tps": 2152.3,
"api_decode_tps": 79.4,
"engine_prompt_tps": 2173.6,
"engine_decode_tps": 79.4,
"log_lines": [
"strata serve: prompt 130360 tokens = 0 reused + 130360 read in 59974 ms (2173.6 tok/s), 256 generated in 3226 ms (79.4 tok/s), drafts accepted 158 of 225, 6 checkpoints",
"strata serve: decode expert cache hit rate: 94.5% (142001 hits / 150326 lookups)"
],
"answer_head": "I'll analyze the last file in the repository listing.\n\n## What `include/strata/kernels/gdn.hpp` does\n\nThis header declares the **non-projection parts of the Gated Delta-Net (GDN) layer** \u2014 the \"mixer\" used in 36 of the model's 48 layers (the other 12 are QSA full-attention layers). It is the C++ cou",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714695.4286683,
"duration_s": 63.2,
"finish": "length",
"prompt_tokens": 130360,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 59973.9,
"decode_ms": 3226.1,
"decode_tok_s": 79.4,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714636.537164,
"duration_s": 57.8,
"finish": "length",
"prompt_tokens": 119256,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 54577.1,
"decode_ms": 3229.8,
"decode_tok_s": 79.3,
"hit_rate": 0.955
},
{
"projection": null,
"time": 1790714507.7469585,
"duration_s": 17.4,
"finish": "length",
"prompt_tokens": 31602,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14617.7,
"decode_ms": 2785.2,
"decode_tok_s": 91.9,
"hit_rate": 0.965
},
{
"projection": null,
"time": 1790714489.1532733,
"duration_s": 17.9,
"finish": "length",
"prompt_tokens": 31582,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14618.7,
"decode_ms": 3270.7,
"decode_tok_s": 78.3,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714469.1007972,
"duration_s": 19.4,
"finish": "length",
"prompt_tokens": 34932,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 16553.9,
"decode_ms": 2826.7,
"decode_tok_s": 90.6,
"hit_rate": 0.941
},
{
"projection": null,
"time": 1790714463.1913157,
"duration_s": 5.2,
"finish": "length",
"prompt_tokens": 4201,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2365.6,
"decode_ms": 2868.4,
"decode_tok_s": 89.2,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714458.6299415,
"duration_s": 4.0,
"finish": "stop",
"prompt_tokens": 4200,
"reused": 0,
"output_tokens": 142,
"engine_generated": 142,
"prompt_ms": 2370.0,
"decode_ms": 1660.0,
"decode_tok_s": 85.5,
"hit_rate": 0.896
},
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
},
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
},
{
"projection": null,
"time": 1790714377.2599747,
"duration_s": 17.6,
"finish": "length",
"prompt_tokens": 31605,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14608.5,
"decode_ms": 3015.6,
"decode_tok_s": 84.9,
"hit_rate": 0.966
}
],
"requests_kept": 21,
"totals": {
"since": 1790713882.6043305,
"requests": 21,
"prompt_tokens": 477073,
"reused": 0,
"output_tokens": 4390,
"prompt_ms": 229986.4,
"decode_ms": 51230.999999999985
},
"hardware": {
"gpu_util": 95,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 48,
"gpu_power": 278.59,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 1822.99609375,
"gpu_pcie_tx_mb": 282.4296875,
"cpu": 100.0,
"ram_used": 63968800768,
"ram_total": 177175990272,
"disk_read_mb": 3.7524610679737007,
"disk_write_mb": 0.06727519842980738,
"tok_s": 75.51795929153683,
"tok_s_mean": 78.52742680374247
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
99,
99,
100,
97,
99,
100,
3,
99,
100,
98,
100,
99,
100,
100,
99,
99,
98,
100,
100,
15,
99,
100,
100,
99,
100,
99,
100,
99,
100,
99,
98,
99,
100,
11,
99,
99,
100,
100,
99,
99,
99,
99,
100,
99,
100,
100,
100,
100,
99,
100,
99,
100,
99,
100,
100,
100,
49,
97,
93,
95
],
"gpu_mem_used": [
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
47,
47,
48,
48,
48,
47,
46,
47,
47,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
47,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
46,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
47,
48,
48,
48
],
"gpu_power": [
242.39,
277.2,
277.34,
277.65,
278.23,
277.3,
263.86,
266.5,
276.0,
277.29,
276.57,
277.42,
277.59,
268.12,
277.51,
276.99,
278.25,
276.6,
278.17,
261.67,
270.19,
277.42,
278.17,
277.12,
278.28,
277.75,
275.69,
267.25,
277.04,
278.86,
278.14,
276.63,
278.3,
265.62,
266.61,
278.07,
276.73,
277.66,
277.57,
279.3,
278.07,
267.14,
278.22,
278.47,
276.15,
278.64,
278.86,
277.69,
275.4,
267.11,
276.68,
277.32,
278.12,
277.19,
277.93,
278.16,
257.52,
253.15,
278.1,
278.59
],
"gpu_pcie_rx_mb": [
5309.2,
958.97,
17058.94,
14.64,
4.05,
3010.03,
8.39,
15.12,
15999.51,
15.07,
10772.8,
7160.47,
71.72,
850.39,
14.26,
26414.87,
26332.33,
24917.6,
18346.6,
6700.37,
20833.01,
48.73,
15.64,
11585.24,
10728.5,
4552.75,
22.55,
13.78,
18.55,
13.88,
3975.96,
21618.6,
14728.83,
12107.04,
17.45,
2833.51,
11.78,
14105.51,
21939.33,
26894.86,
0.33,
21545.12,
4351.66,
13.54,
21.36,
50.16,
22.7,
14.26,
24800.11,
17.12,
405.07,
24.65,
15145.21,
16473.29,
23109.39,
24054.19,
24291.28,
1098.68,
2094.22,
1823.0
],
"cpu": [
12.7,
5.7,
13.2,
17.8,
11.5,
8.3,
10.6,
6.0,
6.7,
8.3,
8.0,
5.8,
5.5,
10.0,
7.2,
6.7,
11.2,
15.8,
7.1,
9.4,
8.7,
6.2,
6.3,
10.1,
6.6,
8.2,
8.6,
6.9,
6.0,
6.4,
9.0,
16.5,
8.5,
8.3,
8.3,
6.3,
6.1,
9.9,
6.0,
7.2,
6.1,
8.2,
11.3,
7.1,
7.3,
16.3,
11.9,
6.5,
8.4,
17.1,
6.1,
6.2,
6.3,
6.4,
6.8,
7.5,
7.9,
100.0,
100.0,
100.0
],
"ram_used": [
63257399296,
63250329600,
63299825664,
63294885888,
63299862528,
63298265088,
63372304384,
63374991360,
63367077888,
63366172672,
63358062592,
63355240448,
63368228864,
63471902720,
63463698432,
63469293568,
63458623488,
63534329856,
63535923200,
63653580800,
63646789632,
63642984448,
63647580160,
63642767360,
63650861056,
63672475648,
63778967552,
63777734656,
63777472512,
63771406336,
63775264768,
63864942592,
63851782144,
63977308160,
63971295232,
63971143680,
63971721216,
63963795456,
63959093248,
63937032192,
64053448704,
64054136832,
63885062144,
63887245312,
63892475904,
63940841472,
63943122944,
63941619712,
64051613696,
64039284736,
64037093376,
64025649152,
64001216512,
63998476288,
63988797440,
63985102848,
64024535040,
64006193152,
63985057792,
63968800768
],
"disk_read_mb": [
82.45,
0.0,
0.0,
104.98,
0.0,
0.15,
86.65,
0.0,
0.0,
49.16,
30.63,
0.0,
0.0,
66.33,
0.0,
0.0,
49.25,
0.0,
0.0,
19.87,
53.0,
0.0,
0.0,
65.63,
0.0,
0.0,
49.27,
11.94,
0.0,
0.0,
53.35,
0.0,
0.0,
40.85,
14.45,
0.0,
0.0,
52.4,
0.0,
0.0,
0.0,
51.78,
0.0,
0.0,
14.03,
110.69,
0.0,
0.0,
0.19,
189.89,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.15,
2.91,
2.72,
3.75
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
80.44,
97.1,
75.52
]
},
"time": 1790714759.167411
}
}
@@ -0,0 +1,829 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "128k",
"target_tokens": 129792,
"run": 3,
"run_id": "317fbfabc24a",
"corpus_repeated": false,
"time": "2026-09-29T20:45:59",
"prompt_tokens": 129913,
"completion_tokens": 256,
"ttft_s": 60.534,
"e2e_s": 64.056,
"api_prompt_tps": 2146.1,
"api_decode_tps": 72.4,
"engine_prompt_tps": 2168.8,
"engine_decode_tps": 72.0,
"log_lines": [
"strata serve: prompt 129913 tokens = 0 reused + 129913 read in 59901 ms (2168.8 tok/s), 256 generated in 3556 ms (72.0 tok/s), drafts accepted 148 of 200, 6 checkpoints",
"strata serve: decode expert cache hit rate: 95.6% (138618 hits / 145073 lookups)"
],
"answer_head": "The last file is `include/strata/kernels/gdn.hpp`. It declares the non-projection parts of the gated delta-net (GDN) layer used by 36 of the model's 48 layers. It defines `GdnShapes` (S=128, h_k=16, h_v=48) and declares `gdn_step`, which performs one in-place step of the delta-rule recurrence: it de",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714759.725435,
"duration_s": 63.5,
"finish": "length",
"prompt_tokens": 129913,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 59900.8,
"decode_ms": 3556.3,
"decode_tok_s": 72.0,
"hit_rate": 0.956
},
{
"projection": null,
"time": 1790714695.4286683,
"duration_s": 63.2,
"finish": "length",
"prompt_tokens": 130360,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 59973.9,
"decode_ms": 3226.1,
"decode_tok_s": 79.4,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714636.537164,
"duration_s": 57.8,
"finish": "length",
"prompt_tokens": 119256,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 54577.1,
"decode_ms": 3229.8,
"decode_tok_s": 79.3,
"hit_rate": 0.955
},
{
"projection": null,
"time": 1790714507.7469585,
"duration_s": 17.4,
"finish": "length",
"prompt_tokens": 31602,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14617.7,
"decode_ms": 2785.2,
"decode_tok_s": 91.9,
"hit_rate": 0.965
},
{
"projection": null,
"time": 1790714489.1532733,
"duration_s": 17.9,
"finish": "length",
"prompt_tokens": 31582,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14618.7,
"decode_ms": 3270.7,
"decode_tok_s": 78.3,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714469.1007972,
"duration_s": 19.4,
"finish": "length",
"prompt_tokens": 34932,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 16553.9,
"decode_ms": 2826.7,
"decode_tok_s": 90.6,
"hit_rate": 0.941
},
{
"projection": null,
"time": 1790714463.1913157,
"duration_s": 5.2,
"finish": "length",
"prompt_tokens": 4201,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2365.6,
"decode_ms": 2868.4,
"decode_tok_s": 89.2,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714458.6299415,
"duration_s": 4.0,
"finish": "stop",
"prompt_tokens": 4200,
"reused": 0,
"output_tokens": 142,
"engine_generated": 142,
"prompt_ms": 2370.0,
"decode_ms": 1660.0,
"decode_tok_s": 85.5,
"hit_rate": 0.896
},
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
},
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
}
],
"requests_kept": 22,
"totals": {
"since": 1790713882.6043305,
"requests": 22,
"prompt_tokens": 606986,
"reused": 0,
"output_tokens": 4646,
"prompt_ms": 289887.2,
"decode_ms": 54787.29999999999
},
"hardware": {
"gpu_util": 95,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 49,
"gpu_power": 273.544,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.28515625,
"gpu_pcie_tx_mb": 0.4765625,
"cpu": 86.8,
"ram_used": 64157536256,
"ram_total": 177175990272,
"disk_read_mb": 2.8283858363947703,
"disk_write_mb": 0.0,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
99,
99,
99,
99,
100,
100,
99,
99,
100,
97,
99,
100,
98,
100,
100,
100,
100,
99,
100,
99,
99,
99,
100,
100,
100,
100,
100,
99,
100,
100,
100,
99,
100,
97,
100,
100,
100,
99,
99,
99,
99,
100,
100,
100,
97,
99,
99,
100,
100,
100,
99,
100,
99,
100,
99,
99,
85,
91,
96,
95
],
"gpu_mem_used": [
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
49,
48,
49,
49,
49,
49,
48,
49,
49,
49,
49,
48,
48,
49,
48,
49,
49,
49,
49,
48,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
48,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49
],
"gpu_power": [
277.4,
277.63,
276.55,
277.24,
277.6,
277.7,
267.41,
277.71,
277.73,
277.11,
277.47,
278.48,
265.62,
277.65,
278.51,
277.16,
277.8,
278.42,
276.76,
264.34,
277.83,
278.79,
277.39,
278.33,
279.04,
277.09,
266.43,
277.15,
279.09,
277.12,
278.21,
279.11,
276.87,
266.5,
277.59,
276.92,
277.76,
277.37,
277.95,
278.05,
266.15,
281.14,
276.88,
277.27,
277.03,
278.78,
277.01,
276.66,
264.08,
276.78,
278.41,
277.85,
276.09,
278.51,
279.06,
278.13,
239.73,
262.71,
270.73,
273.54
],
"gpu_pcie_rx_mb": [
11.44,
11737.44,
1061.11,
1303.05,
10.78,
20755.48,
892.69,
12802.27,
17290.83,
13.02,
669.76,
9859.75,
15.88,
26970.96,
27538.78,
8595.9,
10.82,
22491.22,
20098.16,
7703.26,
2655.31,
1810.74,
21.84,
656.7,
7.82,
17247.68,
12383.65,
14706.95,
18027.4,
14.64,
51.02,
23.94,
21140.67,
19852.11,
18272.88,
11345.43,
10748.2,
23.08,
3973.67,
14.35,
15.45,
12245.37,
13872.91,
2994.2,
10277.84,
51.35,
26547.62,
4842.76,
13126.71,
6178.52,
14.73,
12025.83,
22118.66,
18928.05,
18.36,
86.12,
284.24,
9240.67,
7805.97,
0.29
],
"cpu": [
7.6,
6.7,
9.9,
8.5,
6.7,
6.2,
11.3,
5.7,
6.1,
11.0,
7.2,
6.5,
20.9,
10.8,
5.8,
8.9,
8.5,
6.7,
6.4,
11.1,
6.7,
5.6,
11.4,
8.9,
6.1,
6.0,
17.0,
11.4,
6.6,
10.0,
7.3,
6.2,
6.6,
10.7,
6.4,
6.2,
6.7,
9.0,
6.2,
7.0,
9.7,
17.6,
7.3,
7.5,
10.4,
6.7,
6.4,
6.7,
8.5,
6.3,
5.8,
8.2,
6.7,
6.2,
6.0,
13.2,
64.5,
99.9,
99.0,
86.8
],
"ram_used": [
63275466752,
63276769280,
63271755776,
63272300544,
63263879168,
63359676416,
63357374464,
63357542400,
63358373888,
63359791104,
63361323008,
63363457024,
63494107136,
63494156288,
63489257472,
63490707456,
63488667648,
63458295808,
63462985728,
63580164096,
63581151232,
63584616448,
63609655296,
63608074240,
63610007552,
63607758848,
63749599232,
63745466368,
63718805504,
63722086400,
63728562176,
63731232768,
63729074176,
63842201600,
63847124992,
63850708992,
63853719552,
63846064128,
63846113280,
63848321024,
63970734080,
63991717888,
63989817344,
63985319936,
63983939584,
63975882752,
63976255488,
63973568512,
64091373568,
64083685376,
64078811136,
64100171776,
64087904256,
64069447680,
64067096576,
64095731712,
64224346112,
64185745408,
64170352640,
64157536256
],
"disk_read_mb": [
0.0,
0.0,
71.01,
35.58,
0.0,
2.93,
89.18,
0.0,
0.0,
92.41,
0.0,
0.0,
76.71,
3.39,
0.0,
12.48,
48.82,
0.0,
0.0,
92.22,
0.0,
0.0,
44.7,
41.48,
0.0,
0.0,
83.51,
0.0,
0.0,
52.65,
20.67,
0.0,
0.0,
77.14,
0.0,
0.0,
21.58,
52.7,
0.0,
0.0,
74.56,
0.0,
0.0,
0.0,
65.27,
0.0,
0.0,
0.0,
48.73,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.89,
2.52,
3.25,
2.83
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
61.23,
76.01,
95.36,
0.0
]
},
"time": 1790714823.7293081
}
}
@@ -0,0 +1,815 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "1k",
"target_tokens": 1024,
"run": 1,
"run_id": "56b3dec5f002",
"corpus_repeated": false,
"time": "2026-09-29T20:40:39",
"prompt_tokens": 1092,
"completion_tokens": 256,
"ttft_s": 1.378,
"e2e_s": 4.115,
"api_prompt_tps": 792.3,
"api_decode_tps": 93.2,
"engine_prompt_tps": 808.1,
"engine_decode_tps": 93.0,
"log_lines": [
"strata serve: prompt 1092 tokens = 0 reused + 1092 read in 1351 ms (808.1 tok/s), 256 generated in 2753 ms (93.0 tok/s), drafts accepted 159 of 210, 1 checkpoints",
"strata serve: decode expert cache hit rate: 95.4% (137036 hits / 143638 lookups)"
],
"answer_head": "Based on the content of `CMakeLists.txt`, here is an explanation of its function and a proposed improvement.\n\n### Explanation of `CMakeLists.txt`\n\nThis file serves as the top-level build configuration for the **Strata Engine** (version 0.1.26). Its primary responsibilities are:\n\n1. **Project Defini",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
},
{
"projection": null,
"time": 1790714377.2599747,
"duration_s": 17.6,
"finish": "length",
"prompt_tokens": 31605,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14608.5,
"decode_ms": 3015.6,
"decode_tok_s": 84.9,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714359.1307795,
"duration_s": 17.5,
"finish": "length",
"prompt_tokens": 31589,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14609.7,
"decode_ms": 2833.5,
"decode_tok_s": 90.3,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714338.0043592,
"duration_s": 20.5,
"finish": "length",
"prompt_tokens": 34942,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 17033.3,
"decode_ms": 3435.7,
"decode_tok_s": 74.5,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714334.3235514,
"duration_s": 3.0,
"finish": "stop",
"prompt_tokens": 4199,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 2369.7,
"decode_ms": 626.3,
"decode_tok_s": 78.2,
"hit_rate": 0.934
},
{
"projection": null,
"time": 1790714328.2723713,
"duration_s": 5.5,
"finish": "length",
"prompt_tokens": 4214,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2436.3,
"decode_ms": 3084.4,
"decode_tok_s": 83.0,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714324.3220718,
"duration_s": 3.4,
"finish": "stop",
"prompt_tokens": 3736,
"reused": 0,
"output_tokens": 56,
"engine_generated": 56,
"prompt_ms": 2700.1,
"decode_ms": 719.2,
"decode_tok_s": 77.9,
"hit_rate": 0.897
},
{
"projection": null,
"time": 1790714293.0977688,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1288.1,
"decode_ms": 2834.1,
"decode_tok_s": 90.3,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714290.8242896,
"duration_s": 1.8,
"finish": "stop",
"prompt_tokens": 1147,
"reused": 0,
"output_tokens": 40,
"engine_generated": 40,
"prompt_ms": 1304.0,
"decode_ms": 456.3,
"decode_tok_s": 87.7,
"hit_rate": 0.916
},
{
"projection": null,
"time": 1790714285.3293037,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 1094,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1899.7,
"decode_ms": 3080.2,
"decode_tok_s": 83.1,
"hit_rate": 0.946
},
{
"projection": null,
"time": 1790713900.001974,
"duration_s": 0.7,
"finish": "stop",
"prompt_tokens": 22,
"reused": 0,
"output_tokens": 7,
"engine_generated": 7,
"prompt_ms": 482.2,
"decode_ms": 197.4,
"decode_tok_s": 35.5,
"hit_rate": 0.707
}
],
"requests_kept": 11,
"totals": {
"since": 1790713882.6043305,
"requests": 11,
"prompt_tokens": 114775,
"reused": 0,
"output_tokens": 1944,
"prompt_ms": 60083.00000000001,
"decode_ms": 23035.299999999996
},
"hardware": {
"gpu_util": 94,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 45,
"gpu_power": 276.526,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.3330078125,
"gpu_pcie_tx_mb": 0.4765625,
"cpu": 87.0,
"ram_used": 63534440448,
"ram_total": 177175990272,
"disk_read_mb": 3.2598935177561885,
"disk_write_mb": 0.003747004043397918,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
99,
99,
99,
42,
99,
99,
100,
99,
99,
99,
94,
99,
95,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
100,
98,
94,
94
],
"gpu_mem_used": [
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
44,
45,
45,
45,
45,
45,
45,
45,
45,
45,
45,
45,
45,
42,
42,
41,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
39,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
45,
45,
45,
45
],
"gpu_power": [
277.8,
276.98,
276.99,
264.47,
274.0,
276.95,
276.96,
277.85,
278.23,
277.83,
242.91,
278.73,
277.1,
247.26,
164.95,
142.09,
130.43,
119.16,
119.05,
119.02,
118.92,
118.89,
118.85,
118.74,
118.81,
118.95,
118.87,
118.88,
119.01,
118.97,
113.29,
37.07,
35.2,
35.1,
35.04,
34.98,
34.86,
34.88,
34.97,
34.79,
34.76,
34.94,
34.9,
34.89,
35.0,
34.87,
34.82,
34.93,
34.86,
34.92,
34.99,
34.83,
34.88,
34.97,
34.89,
34.96,
172.41,
265.41,
275.33,
276.53
],
"gpu_pcie_rx_mb": [
20099.78,
18385.74,
52.36,
17363.88,
9102.54,
10.44,
87.17,
12174.99,
8.39,
78.63,
439.12,
1555.01,
511.84,
0.33,
0.29,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.29,
0.29,
0.29,
0.29,
0.33,
0.33,
0.33,
0.57,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.38,
0.38,
0.43,
0.38,
0.38,
9.97,
22329.52,
3689.24,
4264.07,
0.33
],
"cpu": [
6.7,
5.9,
12.5,
10.7,
6.6,
10.7,
6.2,
7.2,
6.5,
5.9,
52.8,
100.0,
100.0,
46.0,
2.5,
9.7,
2.8,
11.4,
13.4,
2.8,
1.5,
1.3,
2.8,
1.6,
1.6,
1.6,
2.2,
1.1,
5.2,
2.3,
1.3,
11.2,
3.6,
1.3,
11.5,
1.1,
1.9,
1.2,
1.3,
1.3,
1.0,
0.6,
2.3,
0.8,
1.2,
6.3,
8.9,
0.6,
1.9,
2.2,
2.1,
1.1,
2.2,
4.7,
1.2,
6.8,
7.3,
83.2,
99.8,
87.0
],
"ram_used": [
63341527040,
63336820736,
63366373376,
63501127680,
63474081792,
63398842368,
63397171200,
63396274176,
63387021312,
63380054016,
63501307904,
63504547840,
63499546624,
63490957312,
63502053376,
63600914432,
63612030976,
63779962880,
63785050112,
63794016256,
63795236864,
63794536448,
63786823680,
63781208064,
63760637952,
63756046336,
63757750272,
63751917568,
63784116224,
63784988672,
63783927808,
63781187584,
63772962816,
63781842944,
63808417792,
63797518336,
63793590272,
63788277760,
63788392448,
63791640576,
63791734784,
63793213440,
63793565696,
63794352128,
63793430528,
63799361536,
63590793216,
63591645184,
63583899648,
63571738624,
63579156480,
63572910080,
63581016064,
63625879552,
63626788864,
63427158016,
63429017600,
63532883968,
63535853568,
63534440448
],
"disk_read_mb": [
0.2,
0.0,
0.0,
0.22,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.41,
2.29,
3.94,
1.13,
0.0,
0.0,
0.0,
0.0,
0.1,
0.14,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.35,
0.0,
0.8,
3.91,
3.26
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
91.56,
92.69,
83.62,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
103.98,
98.22,
0.0
]
},
"time": 1790714443.884817
}
}
@@ -0,0 +1,829 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "1k",
"target_tokens": 1024,
"run": 2,
"run_id": "5da89525cd83",
"corpus_repeated": false,
"time": "2026-09-29T20:40:43",
"prompt_tokens": 1149,
"completion_tokens": 256,
"ttft_s": 1.323,
"e2e_s": 4.156,
"api_prompt_tps": 868.4,
"api_decode_tps": 90.0,
"engine_prompt_tps": 885.5,
"engine_decode_tps": 89.9,
"log_lines": [
"strata serve: prompt 1149 tokens = 0 reused + 1149 read in 1298 ms (885.5 tok/s), 256 generated in 2847 ms (89.9 tok/s), drafts accepted 156 of 215, 1 checkpoints",
"strata serve: decode expert cache hit rate: 97.1% (144603 hits / 148933 lookups)"
],
"answer_head": "Based on the content provided, here is an explanation of the `CMakeLists.txt` file and a proposed improvement.\n\n### Explanation of `CMakeLists.txt`\n\nThis file is the top-level build configuration for the **Strata Engine** (specifically Phase 1, Step 1). Its primary responsibilities are:\n\n1. **Proje",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
},
{
"projection": null,
"time": 1790714377.2599747,
"duration_s": 17.6,
"finish": "length",
"prompt_tokens": 31605,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14608.5,
"decode_ms": 3015.6,
"decode_tok_s": 84.9,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714359.1307795,
"duration_s": 17.5,
"finish": "length",
"prompt_tokens": 31589,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14609.7,
"decode_ms": 2833.5,
"decode_tok_s": 90.3,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714338.0043592,
"duration_s": 20.5,
"finish": "length",
"prompt_tokens": 34942,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 17033.3,
"decode_ms": 3435.7,
"decode_tok_s": 74.5,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714334.3235514,
"duration_s": 3.0,
"finish": "stop",
"prompt_tokens": 4199,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 2369.7,
"decode_ms": 626.3,
"decode_tok_s": 78.2,
"hit_rate": 0.934
},
{
"projection": null,
"time": 1790714328.2723713,
"duration_s": 5.5,
"finish": "length",
"prompt_tokens": 4214,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2436.3,
"decode_ms": 3084.4,
"decode_tok_s": 83.0,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714324.3220718,
"duration_s": 3.4,
"finish": "stop",
"prompt_tokens": 3736,
"reused": 0,
"output_tokens": 56,
"engine_generated": 56,
"prompt_ms": 2700.1,
"decode_ms": 719.2,
"decode_tok_s": 77.9,
"hit_rate": 0.897
},
{
"projection": null,
"time": 1790714293.0977688,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1288.1,
"decode_ms": 2834.1,
"decode_tok_s": 90.3,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714290.8242896,
"duration_s": 1.8,
"finish": "stop",
"prompt_tokens": 1147,
"reused": 0,
"output_tokens": 40,
"engine_generated": 40,
"prompt_ms": 1304.0,
"decode_ms": 456.3,
"decode_tok_s": 87.7,
"hit_rate": 0.916
},
{
"projection": null,
"time": 1790714285.3293037,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 1094,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1899.7,
"decode_ms": 3080.2,
"decode_tok_s": 83.1,
"hit_rate": 0.946
},
{
"projection": null,
"time": 1790713900.001974,
"duration_s": 0.7,
"finish": "stop",
"prompt_tokens": 22,
"reused": 0,
"output_tokens": 7,
"engine_generated": 7,
"prompt_ms": 482.2,
"decode_ms": 197.4,
"decode_tok_s": 35.5,
"hit_rate": 0.707
}
],
"requests_kept": 12,
"totals": {
"since": 1790713882.6043305,
"requests": 12,
"prompt_tokens": 115924,
"reused": 0,
"output_tokens": 2200,
"prompt_ms": 61380.600000000006,
"decode_ms": 25882.799999999996
},
"hardware": {
"gpu_util": 95,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 45,
"gpu_power": 273.597,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 1249.6943359375,
"gpu_pcie_tx_mb": 212.6689453125,
"cpu": 97.9,
"ram_used": 63536766976,
"ram_total": 177175990272,
"disk_read_mb": 2.8181744035205307,
"disk_write_mb": 0.014930725316665065,
"tok_s": 76.9743768862725,
"tok_s_mean": 90.24600065341676
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
99,
99,
100,
99,
99,
99,
94,
99,
95,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
100,
98,
94,
94,
100,
21,
98,
95
],
"gpu_mem_used": [
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
45,
45,
45,
45,
45,
45,
45,
45,
45,
42,
42,
41,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
39,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
45,
45,
45,
45,
45,
43,
45,
45
],
"gpu_power": [
274.0,
276.95,
276.96,
277.85,
278.23,
277.83,
242.91,
278.73,
277.1,
247.26,
164.95,
142.09,
130.43,
119.16,
119.05,
119.02,
118.92,
118.89,
118.85,
118.74,
118.81,
118.95,
118.87,
118.88,
119.01,
118.97,
113.29,
37.07,
35.2,
35.1,
35.04,
34.98,
34.86,
34.88,
34.97,
34.79,
34.76,
34.94,
34.9,
34.89,
35.0,
34.87,
34.82,
34.93,
34.86,
34.92,
34.99,
34.83,
34.88,
34.97,
34.89,
34.96,
172.41,
265.41,
275.33,
276.53,
216.14,
263.1,
264.26,
273.6
],
"gpu_pcie_rx_mb": [
9102.54,
10.44,
87.17,
12174.99,
8.39,
78.63,
439.12,
1555.01,
511.84,
0.33,
0.29,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.29,
0.29,
0.29,
0.29,
0.33,
0.33,
0.33,
0.57,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.38,
0.38,
0.43,
0.38,
0.38,
9.97,
22329.52,
3689.24,
4264.07,
0.33,
14955.09,
784.16,
3310.82,
1249.69
],
"cpu": [
6.6,
10.7,
6.2,
7.2,
6.5,
5.9,
52.8,
100.0,
100.0,
46.0,
2.5,
9.7,
2.8,
11.4,
13.4,
2.8,
1.5,
1.3,
2.8,
1.6,
1.6,
1.6,
2.2,
1.1,
5.2,
2.3,
1.3,
11.2,
3.6,
1.3,
11.5,
1.1,
1.9,
1.2,
1.3,
1.3,
1.0,
0.6,
2.3,
0.8,
1.2,
6.3,
8.9,
0.6,
1.9,
2.2,
2.1,
1.1,
2.2,
4.7,
1.2,
6.8,
7.3,
83.2,
99.8,
87.0,
14.8,
49.9,
100.0,
97.9
],
"ram_used": [
63474081792,
63398842368,
63397171200,
63396274176,
63387021312,
63380054016,
63501307904,
63504547840,
63499546624,
63490957312,
63502053376,
63600914432,
63612030976,
63779962880,
63785050112,
63794016256,
63795236864,
63794536448,
63786823680,
63781208064,
63760637952,
63756046336,
63757750272,
63751917568,
63784116224,
63784988672,
63783927808,
63781187584,
63772962816,
63781842944,
63808417792,
63797518336,
63793590272,
63788277760,
63788392448,
63791640576,
63791734784,
63793213440,
63793565696,
63794352128,
63793430528,
63799361536,
63590793216,
63591645184,
63583899648,
63571738624,
63579156480,
63572910080,
63581016064,
63625879552,
63626788864,
63427158016,
63429017600,
63532883968,
63535853568,
63534440448,
63490953216,
63544176640,
63529631744,
63536766976
],
"disk_read_mb": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.41,
2.29,
3.94,
1.13,
0.0,
0.0,
0.0,
0.0,
0.1,
0.14,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.35,
0.0,
0.8,
3.91,
3.26,
0.6,
0.0,
1.08,
2.82
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
91.56,
92.69,
83.62,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
103.98,
98.22,
0.0,
0.0,
112.83,
83.57,
76.97
]
},
"time": 1790714448.544591
}
}
@@ -0,0 +1,829 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "1k",
"target_tokens": 1024,
"run": 3,
"run_id": "3ad6050d1d4c",
"corpus_repeated": false,
"time": "2026-09-29T20:40:48",
"prompt_tokens": 1135,
"completion_tokens": 256,
"ttft_s": 1.33,
"e2e_s": 4.007,
"api_prompt_tps": 853.1,
"api_decode_tps": 95.3,
"engine_prompt_tps": 869.7,
"engine_decode_tps": 95.1,
"log_lines": [
"strata serve: prompt 1135 tokens = 0 reused + 1135 read in 1305 ms (869.7 tok/s), 256 generated in 2691 ms (95.1 tok/s), drafts accepted 159 of 217, 1 checkpoints",
"strata serve: decode expert cache hit rate: 97.2% (145229 hits / 149472 lookups)"
],
"answer_head": "The `CMakeLists.txt` file defines the top-level build configuration for the **Strata Engine** project. Its primary responsibilities include:\n\n1. **Project Definition**: Sets the project name (`strata`), version (`0.1.26`), and language standard (C++20).\n2. **Target Management**: Conditionally adds",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
},
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
},
{
"projection": null,
"time": 1790714377.2599747,
"duration_s": 17.6,
"finish": "length",
"prompt_tokens": 31605,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14608.5,
"decode_ms": 3015.6,
"decode_tok_s": 84.9,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714359.1307795,
"duration_s": 17.5,
"finish": "length",
"prompt_tokens": 31589,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14609.7,
"decode_ms": 2833.5,
"decode_tok_s": 90.3,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714338.0043592,
"duration_s": 20.5,
"finish": "length",
"prompt_tokens": 34942,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 17033.3,
"decode_ms": 3435.7,
"decode_tok_s": 74.5,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714334.3235514,
"duration_s": 3.0,
"finish": "stop",
"prompt_tokens": 4199,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 2369.7,
"decode_ms": 626.3,
"decode_tok_s": 78.2,
"hit_rate": 0.934
},
{
"projection": null,
"time": 1790714328.2723713,
"duration_s": 5.5,
"finish": "length",
"prompt_tokens": 4214,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2436.3,
"decode_ms": 3084.4,
"decode_tok_s": 83.0,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714324.3220718,
"duration_s": 3.4,
"finish": "stop",
"prompt_tokens": 3736,
"reused": 0,
"output_tokens": 56,
"engine_generated": 56,
"prompt_ms": 2700.1,
"decode_ms": 719.2,
"decode_tok_s": 77.9,
"hit_rate": 0.897
},
{
"projection": null,
"time": 1790714293.0977688,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1288.1,
"decode_ms": 2834.1,
"decode_tok_s": 90.3,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714290.8242896,
"duration_s": 1.8,
"finish": "stop",
"prompt_tokens": 1147,
"reused": 0,
"output_tokens": 40,
"engine_generated": 40,
"prompt_ms": 1304.0,
"decode_ms": 456.3,
"decode_tok_s": 87.7,
"hit_rate": 0.916
},
{
"projection": null,
"time": 1790714285.3293037,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 1094,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1899.7,
"decode_ms": 3080.2,
"decode_tok_s": 83.1,
"hit_rate": 0.946
}
],
"requests_kept": 13,
"totals": {
"since": 1790713882.6043305,
"requests": 13,
"prompt_tokens": 117059,
"reused": 0,
"output_tokens": 2456,
"prompt_ms": 62685.700000000004,
"decode_ms": 28573.599999999995
},
"hardware": {
"gpu_util": 21,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 43,
"gpu_power": 268.452,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.28515625,
"gpu_pcie_tx_mb": 0.4287109375,
"cpu": 63.3,
"ram_used": 63492075520,
"ram_total": 177175990272,
"disk_read_mb": 1.6601509757982635,
"disk_write_mb": 0.022485114796364742,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
99,
94,
99,
95,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
100,
98,
94,
94,
100,
21,
98,
95,
53,
100,
94,
96,
21
],
"gpu_mem_used": [
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
45,
45,
45,
45,
42,
42,
41,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
39,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
45,
45,
45,
45,
45,
43,
45,
45,
44,
45,
45,
45,
43
],
"gpu_power": [
277.83,
242.91,
278.73,
277.1,
247.26,
164.95,
142.09,
130.43,
119.16,
119.05,
119.02,
118.92,
118.89,
118.85,
118.74,
118.81,
118.95,
118.87,
118.88,
119.01,
118.97,
113.29,
37.07,
35.2,
35.1,
35.04,
34.98,
34.86,
34.88,
34.97,
34.79,
34.76,
34.94,
34.9,
34.89,
35.0,
34.87,
34.82,
34.93,
34.86,
34.92,
34.99,
34.83,
34.88,
34.97,
34.89,
34.96,
172.41,
265.41,
275.33,
276.53,
216.14,
263.1,
264.26,
273.6,
211.21,
274.12,
265.58,
276.31,
268.45
],
"gpu_pcie_rx_mb": [
78.63,
439.12,
1555.01,
511.84,
0.33,
0.29,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.29,
0.29,
0.29,
0.29,
0.33,
0.33,
0.33,
0.57,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.38,
0.38,
0.43,
0.38,
0.38,
9.97,
22329.52,
3689.24,
4264.07,
0.33,
14955.09,
784.16,
3310.82,
1249.69,
15874.15,
18357.04,
4099.13,
485.18,
0.29
],
"cpu": [
5.9,
52.8,
100.0,
100.0,
46.0,
2.5,
9.7,
2.8,
11.4,
13.4,
2.8,
1.5,
1.3,
2.8,
1.6,
1.6,
1.6,
2.2,
1.1,
5.2,
2.3,
1.3,
11.2,
3.6,
1.3,
11.5,
1.1,
1.9,
1.2,
1.3,
1.3,
1.0,
0.6,
2.3,
0.8,
1.2,
6.3,
8.9,
0.6,
1.9,
2.2,
2.1,
1.1,
2.2,
4.7,
1.2,
6.8,
7.3,
83.2,
99.8,
87.0,
14.8,
49.9,
100.0,
97.9,
33.3,
7.4,
99.9,
100.0,
63.3
],
"ram_used": [
63380054016,
63501307904,
63504547840,
63499546624,
63490957312,
63502053376,
63600914432,
63612030976,
63779962880,
63785050112,
63794016256,
63795236864,
63794536448,
63786823680,
63781208064,
63760637952,
63756046336,
63757750272,
63751917568,
63784116224,
63784988672,
63783927808,
63781187584,
63772962816,
63781842944,
63808417792,
63797518336,
63793590272,
63788277760,
63788392448,
63791640576,
63791734784,
63793213440,
63793565696,
63794352128,
63793430528,
63799361536,
63590793216,
63591645184,
63583899648,
63571738624,
63579156480,
63572910080,
63581016064,
63625879552,
63626788864,
63427158016,
63429017600,
63532883968,
63535853568,
63534440448,
63490953216,
63544176640,
63529631744,
63536766976,
63443234816,
63502606336,
63508336640,
63509970944,
63492075520
],
"disk_read_mb": [
0.0,
1.41,
2.29,
3.94,
1.13,
0.0,
0.0,
0.0,
0.0,
0.1,
0.14,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.35,
0.0,
0.8,
3.91,
3.26,
0.6,
0.0,
1.08,
2.82,
1.34,
0.0,
1.55,
2.4,
1.66
],
"tok_s": [
0.0,
91.56,
92.69,
83.62,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
103.98,
98.22,
0.0,
0.0,
112.83,
83.57,
76.97,
0.0,
0.0,
97.69,
87.72,
0.0
]
},
"time": 1790714453.0546403
}
}
@@ -0,0 +1,675 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "262k",
"target_tokens": 260864,
"run": 1,
"run_id": "459ef0e5c155",
"corpus_repeated": false,
"time": "2026-09-29T20:52:28",
"prompt_tokens": 232183,
"completion_tokens": 256,
"ttft_s": 131.32,
"e2e_s": 135.339,
"api_prompt_tps": 1768.1,
"api_decode_tps": 63.4,
"engine_prompt_tps": 1784.6,
"engine_decode_tps": 63.0,
"log_lines": [
"strata serve: prompt 232183 tokens = 0 reused + 232183 read in 130101 ms (1784.6 tok/s), 256 generated in 4061 ms (63.0 tok/s), drafts accepted 150 of 240, 6 checkpoints",
"strata serve: decode expert cache hit rate: 93.7% (149829 hits / 159942 lookups)"
],
"answer_head": "The last file is `serve/server.py` (the listing is truncated at the very end, in the `main()` function where it assigns `svc.gpu_index`).\n\n## What it does\n\nIt is the HTTP API layer of Strata: a pure-Python bridge between OpenAI/Anthropic-style clients and the C++ engine. Concretely:\n\n- **Engine adap",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 262144,
"images": false,
"version": "0.1.26",
"context": 262144,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10451,
"expert_cache_mib": 17355,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 385,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790715149.1813676,
"duration_s": 134.2,
"finish": "length",
"prompt_tokens": 232183,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 130101.1,
"decode_ms": 4061.2,
"decode_tok_s": 63.0,
"hit_rate": 0.937
}
],
"requests_kept": 1,
"totals": {
"since": 1790715131.4670517,
"requests": 1,
"prompt_tokens": 232183,
"reused": 0,
"output_tokens": 256,
"prompt_ms": 130101.1,
"decode_ms": 4061.2
},
"hardware": {
"gpu_util": 93,
"gpu_mem_used": 25512837120,
"gpu_mem_total": 25769803776,
"gpu_temp": 50,
"gpu_power": 278.227,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 1220.75,
"gpu_pcie_tx_mb": 478.41015625,
"cpu": 100.0,
"ram_used": 65694810112,
"ram_total": 177175990272,
"disk_read_mb": 3.754966568441275,
"disk_write_mb": 0.0,
"tok_s": 74.58045953935934,
"tok_s_mean": 62.37130450720771
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
99,
100,
99,
100,
99,
100,
98,
100,
100,
100,
100,
100,
99,
99,
100,
99,
99,
100,
99,
100,
100,
98,
100,
100,
100,
97,
100,
100,
99,
99,
98,
97,
100,
100,
100,
99,
100,
100,
99,
99,
99,
100,
100,
100,
100,
100,
99,
100,
100,
100,
100,
100,
100,
3,
100,
100,
93,
94,
96,
93
],
"gpu_mem_used": [
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25412173824,
25512837120,
25512837120,
25512837120,
25512837120
],
"gpu_temp": [
49,
49,
49,
50,
49,
49,
49,
49,
49,
49,
49,
49,
49,
50,
49,
49,
49,
49,
50,
50,
49,
49,
50,
49,
50,
50,
50,
50,
50,
50,
50,
50,
50,
49,
50,
50,
50,
50,
50,
50,
50,
50,
49,
50,
50,
50,
51,
49,
49,
49,
49,
49,
49,
49,
50,
50,
47,
50,
50,
50
],
"gpu_power": [
279.11,
266.12,
276.9,
277.46,
279.35,
277.6,
278.96,
278.2,
276.29,
279.45,
275.58,
268.64,
275.16,
277.98,
275.78,
278.17,
279.67,
276.04,
279.46,
275.1,
265.27,
279.22,
280.54,
276.07,
280.55,
278.32,
274.82,
275.85,
280.08,
279.93,
266.81,
277.79,
274.52,
274.38,
279.74,
277.72,
274.64,
279.65,
280.34,
278.34,
277.27,
274.99,
265.64,
277.06,
278.38,
279.64,
279.6,
273.86,
273.12,
273.61,
275.7,
275.96,
276.36,
266.12,
265.34,
275.53,
242.04,
256.98,
274.43,
278.23
],
"gpu_pcie_rx_mb": [
28.08,
16676.85,
27.75,
7942.58,
15.78,
16.36,
19454.0,
15911.58,
26.8,
41.1,
28.75,
15.21,
24.79,
15.5,
12903.17,
15722.66,
13615.27,
5212.5,
21571.11,
9259.8,
29.85,
15.5,
9701.01,
153.35,
15.64,
30.23,
25023.46,
14.5,
29.71,
26217.94,
17128.85,
9320.26,
28.28,
28.94,
13.54,
87.12,
1377.34,
10125.25,
29.04,
30.52,
15905.0,
8753.63,
7850.26,
26.85,
27.04,
15.31,
3817.42,
27.99,
26.89,
26269.48,
26779.27,
20418.6,
6900.17,
6532.96,
1637.36,
26114.94,
1472.71,
1607.46,
3050.8,
1220.75
],
"cpu": [
6.4,
10.7,
11.7,
16.5,
8.6,
6.3,
18.6,
6.0,
5.9,
5.7,
8.8,
12.7,
5.6,
5.9,
6.6,
12.9,
11.3,
13.4,
13.0,
9.8,
14.3,
23.4,
6.3,
5.9,
7.9,
13.4,
9.7,
6.5,
6.7,
5.9,
10.3,
17.8,
14.9,
7.1,
8.8,
5.8,
16.3,
7.3,
5.7,
7.3,
5.7,
8.0,
14.4,
7.4,
6.6,
5.9,
15.4,
12.5,
6.2,
6.9,
7.8,
7.2,
6.8,
7.1,
5.7,
6.0,
44.6,
99.9,
99.9,
100.0
],
"ram_used": [
65760505856,
65825771520,
65805475840,
65899847680,
65884385280,
65881726976,
65877250048,
65865695232,
65856700416,
65843732480,
65918058496,
65911185408,
65901252608,
65896804352,
65888411648,
65880047616,
65859633152,
65903091712,
65906130944,
65929789440,
65996169216,
65697763328,
65680461824,
65660788736,
65639858176,
65624662016,
65614233600,
65604620288,
65594793984,
65589379072,
65666322432,
65661911040,
65706741760,
65701203968,
65697587200,
65691623424,
65677221888,
65665282048,
65657679872,
65628098560,
65621381120,
65695760384,
65678503936,
65672011776,
65665482752,
65658216448,
65673232384,
65655951360,
65646583808,
65641152512,
65659457536,
65656025088,
65651355648,
65716195328,
65703702528,
65693274112,
65702584320,
65687781376,
65690525696,
65694810112
],
"disk_read_mb": [
0.0,
84.11,
102.3,
0.0,
0.0,
0.0,
175.14,
0.0,
0.0,
0.0,
43.72,
150.32,
0.0,
0.0,
0.0,
118.91,
69.66,
0.0,
0.0,
0.0,
128.82,
137.4,
0.0,
0.0,
0.0,
143.2,
89.93,
0.0,
0.0,
0.0,
81.49,
154.61,
0.0,
0.0,
0.0,
0.0,
196.96,
31.0,
0.0,
0.0,
0.0,
22.35,
158.36,
0.0,
0.0,
0.0,
0.0,
63.48,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.53,
4.38,
2.32,
3.75
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
41.84,
65.33,
69.08,
74.58
]
},
"time": 1790715283.9323688
}
}
@@ -0,0 +1,689 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "262k",
"target_tokens": 260864,
"run": 2,
"run_id": "fbabd65a593d",
"corpus_repeated": false,
"time": "2026-09-29T20:54:43",
"prompt_tokens": 259589,
"completion_tokens": 92,
"ttft_s": 152.099,
"e2e_s": 153.446,
"api_prompt_tps": 1706.7,
"api_decode_tps": 67.5,
"engine_prompt_tps": 1721.6,
"engine_decode_tps": 67.3,
"log_lines": [
"strata serve: prompt 259589 tokens = 0 reused + 259589 read in 150784 ms (1721.6 tok/s), 92 generated in 1367 ms (67.3 tok/s), drafts accepted 61 of 75, 6 checkpoints",
"strata serve: decode expert cache hit rate: 90.0% (43983 hits / 48863 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand the codebase and the last file in detail.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 262144,
"images": false,
"version": "0.1.26",
"context": 262144,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10451,
"expert_cache_mib": 17355,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 385,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790715285.1507986,
"duration_s": 152.2,
"finish": "stop",
"prompt_tokens": 259589,
"reused": 0,
"output_tokens": 92,
"engine_generated": 92,
"prompt_ms": 150783.8,
"decode_ms": 1366.8,
"decode_tok_s": 67.3,
"hit_rate": 0.9
},
{
"projection": null,
"time": 1790715149.1813676,
"duration_s": 134.2,
"finish": "length",
"prompt_tokens": 232183,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 130101.1,
"decode_ms": 4061.2,
"decode_tok_s": 63.0,
"hit_rate": 0.937
}
],
"requests_kept": 2,
"totals": {
"since": 1790715131.4670517,
"requests": 2,
"prompt_tokens": 491772,
"reused": 0,
"output_tokens": 348,
"prompt_ms": 280884.9,
"decode_ms": 5428.0
},
"hardware": {
"gpu_util": 96,
"gpu_mem_used": 25512837120,
"gpu_mem_total": 25769803776,
"gpu_temp": 52,
"gpu_power": 277.319,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 5709.8388671875,
"gpu_pcie_tx_mb": 1049.041015625,
"cpu": 99.9,
"ram_used": 65638817792,
"ram_total": 177175990272,
"disk_read_mb": 3.1622365794124767,
"disk_write_mb": 0.03737868297177868,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
99,
100,
100,
99,
100,
100,
100,
99,
100,
100,
99,
99,
97,
100,
100,
100,
99,
99,
97,
100,
100,
100,
100,
60,
100,
100,
99,
99,
100,
98,
99,
99,
100,
100,
100,
100,
100,
100,
100,
100,
100,
98,
100,
100,
99,
99,
100,
98,
100,
99,
100,
100,
100,
100,
100,
99,
100,
99,
96,
96
],
"gpu_mem_used": [
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120
],
"gpu_temp": [
51,
52,
52,
51,
51,
52,
51,
50,
51,
52,
51,
51,
51,
51,
51,
52,
51,
51,
51,
51,
51,
51,
52,
50,
52,
51,
52,
52,
51,
51,
51,
51,
51,
51,
51,
51,
52,
52,
52,
52,
52,
52,
51,
51,
51,
52,
51,
52,
52,
52,
52,
52,
52,
52,
52,
52,
52,
52,
51,
52
],
"gpu_power": [
280.1,
277.72,
269.31,
279.51,
276.6,
277.19,
280.46,
278.19,
275.14,
276.45,
280.49,
278.01,
265.6,
274.96,
274.76,
278.94,
279.21,
278.77,
277.22,
274.11,
273.93,
275.55,
279.88,
274.53,
278.22,
280.08,
279.56,
277.48,
275.9,
276.58,
275.74,
275.62,
274.27,
272.69,
272.53,
276.33,
279.54,
279.3,
279.1,
279.0,
278.24,
279.57,
276.45,
276.52,
276.57,
276.89,
273.45,
267.54,
275.91,
275.91,
277.91,
276.31,
276.26,
279.97,
276.73,
278.79,
274.29,
278.64,
241.5,
277.32
],
"gpu_pcie_rx_mb": [
24.6,
11576.41,
14790.49,
31.66,
20927.76,
28.32,
23015.64,
14269.26,
27.42,
9814.79,
27090.45,
28.08,
29.28,
30.8,
22511.15,
22487.21,
30.47,
74.67,
20330.0,
20889.04,
27.89,
31.8,
55.55,
14868.74,
15.35,
20128.63,
27.13,
26.56,
53.21,
24118.71,
16327.71,
9496.97,
20100.59,
27.75,
15.97,
14788.58,
13.49,
13957.07,
26.13,
27.75,
26181.89,
48.68,
16340.3,
5056.67,
25172.95,
16.36,
87.55,
33.81,
31.28,
31.66,
35.0,
35.09,
8309.17,
6276.99,
31.14,
13669.87,
18489.17,
29.47,
2057.6,
5709.84
],
"cpu": [
6.6,
7.6,
11.4,
12.8,
6.6,
6.0,
6.6,
11.6,
10.6,
6.8,
5.6,
6.1,
9.8,
25.0,
9.1,
5.9,
6.8,
6.1,
16.7,
7.0,
8.8,
6.9,
5.9,
12.8,
11.2,
5.6,
6.5,
14.2,
10.7,
16.4,
8.1,
7.0,
6.2,
5.9,
7.4,
13.8,
6.0,
5.7,
7.0,
6.1,
6.2,
15.3,
15.5,
12.5,
6.3,
6.3,
6.0,
14.9,
7.3,
9.6,
6.6,
6.1,
6.6,
8.6,
5.9,
6.2,
16.0,
9.9,
42.7,
99.9
],
"ram_used": [
65829687296,
65809809408,
65878708224,
65862221824,
65854197760,
65848958976,
65840418816,
65838673920,
65828872192,
65821380608,
65813520384,
65804607488,
65870708736,
65884573696,
65869344768,
65860734976,
65835606016,
65825009664,
65818324992,
65817894912,
65821642752,
65816698880,
65812000768,
65862680576,
65843482624,
65833279488,
65827409920,
65838510080,
65830367232,
65803018240,
65796870144,
65792782336,
65785704448,
65781006336,
65859014656,
65839325184,
65832935424,
65818849280,
65813626880,
65805553664,
65796202496,
65790906368,
65792847872,
65822486528,
65813880832,
65796804608,
65786474496,
65854476288,
65841573888,
65829576704,
65816891392,
65810354176,
65800015872,
65793110016,
65783308288,
65776508928,
65580986368,
65575313408,
65644572672,
65638817792
],
"disk_read_mb": [
0.0,
0.0,
99.27,
135.95,
0.0,
0.0,
0.0,
113.06,
91.94,
0.0,
0.0,
0.0,
46.52,
161.04,
0.0,
0.0,
0.0,
0.0,
199.72,
0.0,
0.0,
0.0,
0.0,
91.5,
66.56,
0.0,
0.0,
0.0,
0.0,
191.98,
0.0,
0.0,
0.0,
0.0,
13.73,
127.69,
0.0,
0.0,
0.0,
0.0,
1.52,
125.36,
0.0,
0.0,
0.0,
0.0,
0.0,
171.54,
7.82,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.75,
3.16
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
69.44,
0.0
]
},
"time": 1790715437.8967788
}
}
@@ -0,0 +1,703 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "262k",
"target_tokens": 260864,
"run": 3,
"run_id": "40a721fd9a17",
"corpus_repeated": false,
"time": "2026-09-29T20:57:17",
"prompt_tokens": 261068,
"completion_tokens": 256,
"ttft_s": 152.605,
"e2e_s": 156.279,
"api_prompt_tps": 1710.7,
"api_decode_tps": 69.4,
"engine_prompt_tps": 1725.6,
"engine_decode_tps": 69.3,
"log_lines": [
"strata serve: prompt 261068 tokens = 0 reused + 261068 read in 151288 ms (1725.6 tok/s), 256 generated in 3693 ms (69.3 tok/s), drafts accepted 151 of 231, 6 checkpoints",
"strata serve: decode expert cache hit rate: 96.3% (153481 hits / 159304 lookups)"
],
"answer_head": "I'll analyze the last file in the repository listing and then propose a concrete improvement.\n\n## What `serve/web/app.js` does\n\nThis file is the **entire client-side logic of the Strata web application** \u2014 a framework-free, single-file JavaScript app that talks only to the local Strata server. It po",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 262144,
"images": false,
"version": "0.1.26",
"context": 262144,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10451,
"expert_cache_mib": 17355,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 385,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790715439.1095636,
"duration_s": 155.1,
"finish": "length",
"prompt_tokens": 261068,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 151288.5,
"decode_ms": 3693.0,
"decode_tok_s": 69.3,
"hit_rate": 0.963
},
{
"projection": null,
"time": 1790715285.1507986,
"duration_s": 152.2,
"finish": "stop",
"prompt_tokens": 259589,
"reused": 0,
"output_tokens": 92,
"engine_generated": 92,
"prompt_ms": 150783.8,
"decode_ms": 1366.8,
"decode_tok_s": 67.3,
"hit_rate": 0.9
},
{
"projection": null,
"time": 1790715149.1813676,
"duration_s": 134.2,
"finish": "length",
"prompt_tokens": 232183,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 130101.1,
"decode_ms": 4061.2,
"decode_tok_s": 63.0,
"hit_rate": 0.937
}
],
"requests_kept": 3,
"totals": {
"since": 1790715131.4670517,
"requests": 3,
"prompt_tokens": 752840,
"reused": 0,
"output_tokens": 604,
"prompt_ms": 432173.4,
"decode_ms": 9121.0
},
"hardware": {
"gpu_util": 92,
"gpu_mem_used": 25512837120,
"gpu_mem_total": 25769803776,
"gpu_temp": 53,
"gpu_power": 277.576,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 3810.1669921875,
"gpu_pcie_tx_mb": 299.7392578125,
"cpu": 100.0,
"ram_used": 65843089408,
"ram_total": 177175990272,
"disk_read_mb": 4.922097648659462,
"disk_write_mb": 0.0,
"tok_s": 68.55526509763148,
"tok_s_mean": 69.76955378630859
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
99,
100,
99,
99,
100,
100,
100,
100,
100,
100,
100,
100,
99,
100,
100,
100,
100,
100,
99,
100,
98,
99,
99,
100,
100,
100,
100,
100,
100,
100,
100,
98,
100,
100,
100,
99,
99,
100,
100,
100,
100,
100,
100,
88,
100,
100,
100,
99,
99,
99,
100,
100,
100,
100,
100,
100,
97,
95,
95,
92
],
"gpu_mem_used": [
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120,
25512837120
],
"gpu_temp": [
53,
52,
53,
52,
52,
52,
53,
53,
52,
52,
53,
53,
53,
52,
52,
53,
53,
53,
53,
53,
53,
53,
53,
52,
52,
53,
53,
53,
53,
53,
53,
52,
52,
52,
52,
53,
53,
53,
53,
53,
53,
53,
53,
52,
53,
53,
52,
53,
53,
53,
53,
53,
53,
53,
53,
53,
53,
53,
53,
53
],
"gpu_power": [
279.28,
276.25,
280.52,
280.21,
276.32,
278.64,
280.39,
275.19,
275.3,
267.01,
278.7,
279.27,
280.07,
277.82,
274.89,
273.96,
277.23,
280.24,
279.4,
277.21,
266.21,
276.82,
277.27,
274.7,
272.68,
273.87,
273.33,
275.44,
276.56,
276.53,
276.52,
263.9,
276.06,
275.76,
276.06,
275.68,
275.74,
273.79,
276.62,
276.84,
276.88,
276.17,
275.71,
273.17,
265.54,
275.78,
273.31,
275.66,
275.72,
276.2,
275.38,
273.99,
273.72,
275.56,
276.07,
276.57,
245.75,
278.73,
277.86,
277.58
],
"gpu_pcie_rx_mb": [
4135.46,
6890.58,
13.64,
3437.09,
30.71,
20378.88,
15.64,
30.99,
20391.65,
19570.21,
4926.97,
27.94,
28.08,
26564.6,
4245.0,
29.13,
28.94,
7148.27,
17857.03,
28.51,
11700.44,
28.28,
27.51,
26015.42,
14.3,
16.36,
11904.38,
29.71,
29.99,
33.33,
14.83,
30.04,
28.8,
28.18,
26.08,
17.07,
26755.14,
31.04,
30.14,
30.8,
29.04,
30.8,
33.24,
27187.54,
19414.33,
9223.17,
54.17,
12.68,
24.32,
33.43,
12868.02,
32.04,
29.66,
34.62,
20107.13,
84.11,
1655.15,
10931.06,
1614.47,
3810.17
],
"cpu": [
12.6,
5.5,
6.4,
6.8,
13.7,
9.3,
10.4,
12.8,
12.2,
11.8,
13.0,
6.1,
6.4,
6.3,
8.4,
15.9,
9.1,
6.5,
7.0,
5.8,
13.8,
18.7,
8.2,
6.0,
7.7,
8.1,
14.9,
5.8,
6.5,
6.5,
5.9,
9.5,
9.8,
6.4,
6.2,
13.8,
11.5,
9.4,
9.4,
6.0,
7.2,
5.8,
6.6,
6.5,
15.9,
8.9,
7.4,
6.0,
6.1,
9.0,
13.9,
6.6,
8.0,
6.2,
6.0,
7.2,
56.6,
100.0,
100.0,
100.0
],
"ram_used": [
65659777024,
65650483200,
65649508352,
65644490752,
65632600064,
65621151744,
65675010048,
65661538304,
65681547264,
65747542016,
65735454720,
65723609088,
65715372032,
65702187008,
65677402112,
65653993472,
65667379200,
65663696896,
65657884672,
65648963584,
65722257408,
65791442944,
65798762496,
65787301888,
65781350400,
65659375616,
65646817280,
65635090432,
65627262976,
65615314944,
65606516736,
65678639104,
65669410816,
65663270912,
65656647680,
65739636736,
65798643712,
65792847872,
65780387840,
65772281856,
65774555136,
65768087552,
65765552128,
65838772224,
65833267200,
65850757120,
65824538624,
65812451328,
65801834496,
65796722688,
65808052224,
65799196672,
65796362240,
65791713280,
65787756544,
65798152192,
65876860928,
65866027008,
65852674048,
65843089408
],
"disk_read_mb": [
116.54,
0.0,
0.0,
0.0,
150.82,
68.05,
0.0,
0.0,
0.0,
84.44,
137.56,
0.0,
0.0,
0.0,
19.83,
193.88,
0.0,
0.0,
0.0,
0.0,
143.92,
24.87,
0.0,
0.0,
0.0,
25.89,
153.9,
0.0,
0.0,
0.0,
0.0,
69.98,
56.36,
0.0,
0.0,
0.0,
0.0,
48.96,
64.15,
0.0,
0.0,
0.0,
0.0,
0.0,
206.65,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.78,
4.65,
4.44,
4.92
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
74.98,
63.75,
72.35,
68.56
]
},
"time": 1790715594.6843412
}
}
@@ -0,0 +1,829 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 1,
"run_id": "563f1c703ebe",
"corpus_repeated": false,
"time": "2026-09-29T20:41:08",
"prompt_tokens": 34932,
"completion_tokens": 256,
"ttft_s": 16.748,
"e2e_s": 19.56,
"api_prompt_tps": 2085.7,
"api_decode_tps": 90.7,
"engine_prompt_tps": 2110.2,
"engine_decode_tps": 90.6,
"log_lines": [
"strata serve: prompt 34932 tokens = 0 reused + 34932 read in 16554 ms (2110.2 tok/s), 256 generated in 2827 ms (90.6 tok/s), drafts accepted 167 of 216, 3 checkpoints",
"strata serve: decode expert cache hit rate: 94.1% (133137 hits / 141416 lookups)"
],
"answer_head": "I'll analyze the last file in the repository listing and propose an improvement.\n\n## What `docs/DETAILS.md` does\n\nThis is the comprehensive technical documentation file for the Strata project. It serves as the single source of truth for:\n\n1. **Performance benchmarks** \u2014 Detailed tables of prompt-pro",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714469.1007972,
"duration_s": 19.4,
"finish": "length",
"prompt_tokens": 34932,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 16553.9,
"decode_ms": 2826.7,
"decode_tok_s": 90.6,
"hit_rate": 0.941
},
{
"projection": null,
"time": 1790714463.1913157,
"duration_s": 5.2,
"finish": "length",
"prompt_tokens": 4201,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2365.6,
"decode_ms": 2868.4,
"decode_tok_s": 89.2,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714458.6299415,
"duration_s": 4.0,
"finish": "stop",
"prompt_tokens": 4200,
"reused": 0,
"output_tokens": 142,
"engine_generated": 142,
"prompt_ms": 2370.0,
"decode_ms": 1660.0,
"decode_tok_s": 85.5,
"hit_rate": 0.896
},
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
},
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
},
{
"projection": null,
"time": 1790714377.2599747,
"duration_s": 17.6,
"finish": "length",
"prompt_tokens": 31605,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14608.5,
"decode_ms": 3015.6,
"decode_tok_s": 84.9,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714359.1307795,
"duration_s": 17.5,
"finish": "length",
"prompt_tokens": 31589,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14609.7,
"decode_ms": 2833.5,
"decode_tok_s": 90.3,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714338.0043592,
"duration_s": 20.5,
"finish": "length",
"prompt_tokens": 34942,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 17033.3,
"decode_ms": 3435.7,
"decode_tok_s": 74.5,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714334.3235514,
"duration_s": 3.0,
"finish": "stop",
"prompt_tokens": 4199,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 2369.7,
"decode_ms": 626.3,
"decode_tok_s": 78.2,
"hit_rate": 0.934
},
{
"projection": null,
"time": 1790714328.2723713,
"duration_s": 5.5,
"finish": "length",
"prompt_tokens": 4214,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2436.3,
"decode_ms": 3084.4,
"decode_tok_s": 83.0,
"hit_rate": 0.959
}
],
"requests_kept": 17,
"totals": {
"since": 1790713882.6043305,
"requests": 17,
"prompt_tokens": 164273,
"reused": 0,
"output_tokens": 3366,
"prompt_ms": 86199.0,
"decode_ms": 38719.19999999999
},
"hardware": {
"gpu_util": 97,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 46,
"gpu_power": 278.81,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 5630.111328125,
"gpu_pcie_tx_mb": 76.2939453125,
"cpu": 100.0,
"ram_used": 63789760512,
"ram_total": 177175990272,
"disk_read_mb": 2.3587450688100042,
"disk_write_mb": 0.1268945131954749,
"tok_s": 96.52070218780436,
"tok_s_mean": 91.25774344883004
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
100,
98,
94,
94,
100,
21,
98,
95,
53,
100,
94,
96,
21,
99,
99,
92,
97,
97,
0,
98,
99,
98,
0,
99,
100,
99,
96,
96,
0,
100,
99,
100,
100,
99,
100,
100,
99,
100,
99,
100,
99,
99,
99,
100,
98,
99,
97
],
"gpu_mem_used": [
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
38,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
45,
45,
45,
45,
45,
43,
45,
45,
44,
45,
45,
45,
43,
45,
45,
45,
45,
46,
42,
46,
45,
46,
42,
45,
45,
45,
46,
46,
42,
46,
46,
46,
46,
46,
45,
46,
46,
46,
46,
46,
46,
46,
46,
46,
46,
46,
46
],
"gpu_power": [
34.89,
35.0,
34.87,
34.82,
34.93,
34.86,
34.92,
34.99,
34.83,
34.88,
34.97,
34.89,
34.96,
172.41,
265.41,
275.33,
276.53,
216.14,
263.1,
264.26,
273.6,
211.21,
274.12,
265.58,
276.31,
268.45,
217.39,
278.78,
252.44,
278.12,
278.79,
215.59,
278.37,
251.8,
276.73,
219.4,
271.43,
276.62,
251.66,
277.46,
278.06,
194.1,
265.98,
277.8,
274.38,
278.56,
277.99,
277.15,
264.89,
276.96,
277.37,
277.24,
276.83,
276.94,
278.15,
264.71,
273.73,
243.99,
277.71,
278.81
],
"gpu_pcie_rx_mb": [
0.38,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.38,
0.38,
0.43,
0.38,
0.38,
9.97,
22329.52,
3689.24,
4264.07,
0.33,
14955.09,
784.16,
3310.82,
1249.69,
15874.15,
18357.04,
4099.13,
485.18,
0.29,
11.78,
84.59,
865.12,
8675.62,
0.33,
3342.49,
34.05,
7461.5,
4551.6,
6961.73,
24513.15,
26324.56,
679.21,
426.48,
0.33,
10.87,
10442.35,
23162.22,
22324.94,
24878.6,
26870.2,
14619.68,
11419.68,
893.4,
13515.52,
20953.08,
7.87,
14.59,
23972.7,
9329.51,
82.11,
7527.59,
4538.68,
5630.11
],
"cpu": [
0.8,
1.2,
6.3,
8.9,
0.6,
1.9,
2.2,
2.1,
1.1,
2.2,
4.7,
1.2,
6.8,
7.3,
83.2,
99.8,
87.0,
14.8,
49.9,
100.0,
97.9,
33.3,
7.4,
99.9,
100.0,
63.3,
5.7,
6.4,
81.2,
100.0,
93.8,
14.8,
15.8,
37.5,
100.0,
32.6,
6.8,
6.6,
96.7,
100.0,
83.5,
5.1,
7.7,
6.8,
5.8,
11.1,
14.6,
9.1,
8.4,
7.3,
7.4,
7.0,
7.1,
6.5,
5.9,
6.0,
6.9,
72.2,
100.0,
100.0
],
"ram_used": [
63794352128,
63793430528,
63799361536,
63590793216,
63591645184,
63583899648,
63571738624,
63579156480,
63572910080,
63581016064,
63625879552,
63626788864,
63427158016,
63429017600,
63532883968,
63535853568,
63534440448,
63490953216,
63544176640,
63529631744,
63536766976,
63443234816,
63502606336,
63508336640,
63509970944,
63492075520,
63440269312,
63431364608,
63482470400,
63473512448,
63471906816,
63401848832,
63554486272,
63453114368,
63441051648,
63399321600,
63389306880,
63427080192,
63418408960,
63417094144,
63416299520,
63358083072,
63351615488,
63342723072,
63336611840,
63371808768,
63426170880,
63504416768,
63594704896,
63611879424,
63612047360,
63599980544,
63573508096,
63570501632,
63568433152,
63702056960,
63700324352,
63800950784,
63801184256,
63789760512
],
"disk_read_mb": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.35,
0.0,
0.8,
3.91,
3.26,
0.6,
0.0,
1.08,
2.82,
1.34,
0.0,
1.55,
2.4,
1.66,
0.64,
0.0,
2.25,
2.98,
2.66,
0.64,
0.0,
0.21,
2.1,
1.17,
0.0,
0.0,
1.29,
3.73,
2.96,
0.82,
0.0,
0.0,
0.35,
0.0,
0.0,
0.0,
0.23,
0.0,
0.0,
0.22,
0.0,
0.0,
0.0,
0.0,
0.0,
0.7,
0.31,
2.36
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
103.98,
98.22,
0.0,
0.0,
112.83,
83.57,
76.97,
0.0,
0.0,
97.69,
87.72,
0.0,
0.0,
0.0,
102.14,
97.9,
0.0,
0.0,
0.0,
89.96,
98.26,
0.0,
0.0,
0.0,
93.47,
116.21,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
97.18,
97.71,
96.52
]
},
"time": 1790714488.9946597
}
}
@@ -0,0 +1,829 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 2,
"run_id": "283cb867e188",
"corpus_repeated": false,
"time": "2026-09-29T20:41:28",
"prompt_tokens": 31582,
"completion_tokens": 256,
"ttft_s": 14.807,
"e2e_s": 18.058,
"api_prompt_tps": 2132.9,
"api_decode_tps": 78.4,
"engine_prompt_tps": 2160.4,
"engine_decode_tps": 78.3,
"log_lines": [
"strata serve: prompt 31582 tokens = 0 reused + 31582 read in 14619 ms (2160.4 tok/s), 256 generated in 3271 ms (78.3 tok/s), drafts accepted 161 of 240, 2 checkpoints",
"strata serve: decode expert cache hit rate: 96.0% (151459 hits / 157708 lookups)"
],
"answer_head": "The last file in the provided list is `docs/DETAILS.md`.\n\n### What it does\nThis file serves as the **comprehensive technical manual and reference guide** for the Strata engine. While the `README.md` focuses on quick installation and high-level marketing, `DETAILS.md` provides the deep technical spec",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714489.1532733,
"duration_s": 17.9,
"finish": "length",
"prompt_tokens": 31582,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14618.7,
"decode_ms": 3270.7,
"decode_tok_s": 78.3,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714469.1007972,
"duration_s": 19.4,
"finish": "length",
"prompt_tokens": 34932,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 16553.9,
"decode_ms": 2826.7,
"decode_tok_s": 90.6,
"hit_rate": 0.941
},
{
"projection": null,
"time": 1790714463.1913157,
"duration_s": 5.2,
"finish": "length",
"prompt_tokens": 4201,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2365.6,
"decode_ms": 2868.4,
"decode_tok_s": 89.2,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714458.6299415,
"duration_s": 4.0,
"finish": "stop",
"prompt_tokens": 4200,
"reused": 0,
"output_tokens": 142,
"engine_generated": 142,
"prompt_ms": 2370.0,
"decode_ms": 1660.0,
"decode_tok_s": 85.5,
"hit_rate": 0.896
},
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
},
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
},
{
"projection": null,
"time": 1790714377.2599747,
"duration_s": 17.6,
"finish": "length",
"prompt_tokens": 31605,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14608.5,
"decode_ms": 3015.6,
"decode_tok_s": 84.9,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714359.1307795,
"duration_s": 17.5,
"finish": "length",
"prompt_tokens": 31589,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14609.7,
"decode_ms": 2833.5,
"decode_tok_s": 90.3,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714338.0043592,
"duration_s": 20.5,
"finish": "length",
"prompt_tokens": 34942,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 17033.3,
"decode_ms": 3435.7,
"decode_tok_s": 74.5,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714334.3235514,
"duration_s": 3.0,
"finish": "stop",
"prompt_tokens": 4199,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 2369.7,
"decode_ms": 626.3,
"decode_tok_s": 78.2,
"hit_rate": 0.934
}
],
"requests_kept": 18,
"totals": {
"since": 1790713882.6043305,
"requests": 18,
"prompt_tokens": 195855,
"reused": 0,
"output_tokens": 3622,
"prompt_ms": 100817.7,
"decode_ms": 41989.89999999999
},
"hardware": {
"gpu_util": 94,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 47,
"gpu_power": 276.188,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.380859375,
"gpu_pcie_tx_mb": 0.4287109375,
"cpu": 84.0,
"ram_used": 63683891200,
"ram_total": 177175990272,
"disk_read_mb": 2.12697518787369,
"disk_write_mb": 0.05242544477153462,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
21,
98,
95,
53,
100,
94,
96,
21,
99,
99,
92,
97,
97,
0,
98,
99,
98,
0,
99,
100,
99,
96,
96,
0,
100,
99,
100,
100,
99,
100,
100,
99,
100,
99,
100,
99,
99,
99,
100,
98,
99,
97,
0,
99,
99,
99,
99,
99,
99,
98,
100,
99,
100,
99,
99,
99,
73,
98,
97,
94
],
"gpu_mem_used": [
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
43,
45,
45,
44,
45,
45,
45,
43,
45,
45,
45,
45,
46,
42,
46,
45,
46,
42,
45,
45,
45,
46,
46,
42,
46,
46,
46,
46,
46,
45,
46,
46,
46,
46,
46,
46,
46,
46,
46,
46,
46,
46,
43,
46,
47,
46,
46,
46,
47,
46,
47,
46,
47,
46,
46,
46,
44,
46,
46,
47
],
"gpu_power": [
263.1,
264.26,
273.6,
211.21,
274.12,
265.58,
276.31,
268.45,
217.39,
278.78,
252.44,
278.12,
278.79,
215.59,
278.37,
251.8,
276.73,
219.4,
271.43,
276.62,
251.66,
277.46,
278.06,
194.1,
265.98,
277.8,
274.38,
278.56,
277.99,
277.15,
264.89,
276.96,
277.37,
277.24,
276.83,
276.94,
278.15,
264.71,
273.73,
243.99,
277.71,
278.81,
203.42,
258.01,
277.13,
277.38,
277.05,
276.55,
275.55,
267.16,
280.52,
277.94,
278.68,
277.45,
276.52,
278.47,
255.06,
250.07,
273.21,
276.19
],
"gpu_pcie_rx_mb": [
784.16,
3310.82,
1249.69,
15874.15,
18357.04,
4099.13,
485.18,
0.29,
11.78,
84.59,
865.12,
8675.62,
0.33,
3342.49,
34.05,
7461.5,
4551.6,
6961.73,
24513.15,
26324.56,
679.21,
426.48,
0.33,
10.87,
10442.35,
23162.22,
22324.94,
24878.6,
26870.2,
14619.68,
11419.68,
893.4,
13515.52,
20953.08,
7.87,
14.59,
23972.7,
9329.51,
82.11,
7527.59,
4538.68,
5630.11,
6.67,
11788.08,
773.91,
87.02,
13.59,
4.53,
50.21,
7.15,
6744.72,
14.45,
115.11,
2575.49,
26114.03,
3364.04,
3375.15,
957.73,
2766.08,
0.38
],
"cpu": [
49.9,
100.0,
97.9,
33.3,
7.4,
99.9,
100.0,
63.3,
5.7,
6.4,
81.2,
100.0,
93.8,
14.8,
15.8,
37.5,
100.0,
32.6,
6.8,
6.6,
96.7,
100.0,
83.5,
5.1,
7.7,
6.8,
5.8,
11.1,
14.6,
9.1,
8.4,
7.3,
7.4,
7.0,
7.1,
6.5,
5.9,
6.0,
6.9,
72.2,
100.0,
100.0,
19.3,
8.8,
6.1,
7.1,
6.6,
7.1,
6.0,
6.8,
5.6,
5.5,
6.6,
7.8,
6.1,
6.2,
41.1,
99.9,
99.4,
84.0
],
"ram_used": [
63544176640,
63529631744,
63536766976,
63443234816,
63502606336,
63508336640,
63509970944,
63492075520,
63440269312,
63431364608,
63482470400,
63473512448,
63471906816,
63401848832,
63554486272,
63453114368,
63441051648,
63399321600,
63389306880,
63427080192,
63418408960,
63417094144,
63416299520,
63358083072,
63351615488,
63342723072,
63336611840,
63371808768,
63426170880,
63504416768,
63594704896,
63611879424,
63612047360,
63599980544,
63573508096,
63570501632,
63568433152,
63702056960,
63700324352,
63800950784,
63801184256,
63789760512,
63567470592,
63559606272,
63544537088,
63536496640,
63529500672,
63515496448,
63496245248,
63530811392,
63529254912,
63530737664,
63536521216,
63543078912,
63537020928,
63539232768,
63659114496,
63677952000,
63679279104,
63683891200
],
"disk_read_mb": [
0.0,
1.08,
2.82,
1.34,
0.0,
1.55,
2.4,
1.66,
0.64,
0.0,
2.25,
2.98,
2.66,
0.64,
0.0,
0.21,
2.1,
1.17,
0.0,
0.0,
1.29,
3.73,
2.96,
0.82,
0.0,
0.0,
0.35,
0.0,
0.0,
0.0,
0.23,
0.0,
0.0,
0.22,
0.0,
0.0,
0.0,
0.0,
0.0,
0.7,
0.31,
2.36,
0.74,
0.0,
0.0,
0.0,
0.35,
0.0,
0.0,
0.34,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.15,
1.22,
1.87,
2.13
],
"tok_s": [
112.83,
83.57,
76.97,
0.0,
0.0,
97.69,
87.72,
0.0,
0.0,
0.0,
102.14,
97.9,
0.0,
0.0,
0.0,
89.96,
98.26,
0.0,
0.0,
0.0,
93.47,
116.21,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
97.18,
97.71,
96.52,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
80.68,
75.74,
112.93,
0.0
]
},
"time": 1790714507.5571826
}
}
@@ -0,0 +1,829 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 3,
"run_id": "1aba3d88be7a",
"corpus_repeated": false,
"time": "2026-09-29T20:41:47",
"prompt_tokens": 31602,
"completion_tokens": 256,
"ttft_s": 14.833,
"e2e_s": 17.604,
"api_prompt_tps": 2130.5,
"api_decode_tps": 92.0,
"engine_prompt_tps": 2161.9,
"engine_decode_tps": 91.9,
"log_lines": [
"strata serve: prompt 31602 tokens = 0 reused + 31602 read in 14618 ms (2161.9 tok/s), 256 generated in 2785 ms (91.9 tok/s), drafts accepted 160 of 207, 2 checkpoints",
"strata serve: decode expert cache hit rate: 96.5% (137828 hits / 142765 lookups)"
],
"answer_head": "The last file in the provided list is `docs/DETAILS.md`.\n\n### What it does\nThis file serves as the comprehensive technical documentation and user manual for the \"Strata\" engine. It bridges the gap between the high-level marketing pitch in `README.md` and the raw source code. Specifically, it:\n\n1. *",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714507.7469585,
"duration_s": 17.4,
"finish": "length",
"prompt_tokens": 31602,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14617.7,
"decode_ms": 2785.2,
"decode_tok_s": 91.9,
"hit_rate": 0.965
},
{
"projection": null,
"time": 1790714489.1532733,
"duration_s": 17.9,
"finish": "length",
"prompt_tokens": 31582,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14618.7,
"decode_ms": 3270.7,
"decode_tok_s": 78.3,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714469.1007972,
"duration_s": 19.4,
"finish": "length",
"prompt_tokens": 34932,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 16553.9,
"decode_ms": 2826.7,
"decode_tok_s": 90.6,
"hit_rate": 0.941
},
{
"projection": null,
"time": 1790714463.1913157,
"duration_s": 5.2,
"finish": "length",
"prompt_tokens": 4201,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2365.6,
"decode_ms": 2868.4,
"decode_tok_s": 89.2,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714458.6299415,
"duration_s": 4.0,
"finish": "stop",
"prompt_tokens": 4200,
"reused": 0,
"output_tokens": 142,
"engine_generated": 142,
"prompt_ms": 2370.0,
"decode_ms": 1660.0,
"decode_tok_s": 85.5,
"hit_rate": 0.896
},
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
},
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
},
{
"projection": null,
"time": 1790714377.2599747,
"duration_s": 17.6,
"finish": "length",
"prompt_tokens": 31605,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14608.5,
"decode_ms": 3015.6,
"decode_tok_s": 84.9,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714359.1307795,
"duration_s": 17.5,
"finish": "length",
"prompt_tokens": 31589,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14609.7,
"decode_ms": 2833.5,
"decode_tok_s": 90.3,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714338.0043592,
"duration_s": 20.5,
"finish": "length",
"prompt_tokens": 34942,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 17033.3,
"decode_ms": 3435.7,
"decode_tok_s": 74.5,
"hit_rate": 0.945
}
],
"requests_kept": 19,
"totals": {
"since": 1790713882.6043305,
"requests": 19,
"prompt_tokens": 227457,
"reused": 0,
"output_tokens": 3878,
"prompt_ms": 115435.4,
"decode_ms": 44775.099999999984
},
"hardware": {
"gpu_util": 94,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 47,
"gpu_power": 277.644,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 3986.787109375,
"gpu_pcie_tx_mb": 397.443359375,
"cpu": 99.9,
"ram_used": 63539171328,
"ram_total": 177175990272,
"disk_read_mb": 3.5686025775501298,
"disk_write_mb": 0.3811491758221081,
"tok_s": 96.24470767975828,
"tok_s_mean": 94.09593644569512
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0,
99,
100,
99,
96,
96,
0,
100,
99,
100,
100,
99,
100,
100,
99,
100,
99,
100,
99,
99,
99,
100,
98,
99,
97,
0,
99,
99,
99,
99,
99,
99,
98,
100,
99,
100,
99,
99,
99,
73,
98,
97,
94,
100,
100,
99,
99,
99,
99,
99,
100,
99,
100,
100,
100,
99,
99,
97,
97,
94
],
"gpu_mem_used": [
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
42,
45,
45,
45,
46,
46,
42,
46,
46,
46,
46,
46,
45,
46,
46,
46,
46,
46,
46,
46,
46,
46,
46,
46,
46,
43,
46,
47,
46,
46,
46,
47,
46,
47,
46,
47,
46,
46,
46,
44,
46,
46,
47,
46,
46,
47,
46,
46,
47,
47,
47,
47,
47,
47,
47,
47,
47,
46,
47,
47
],
"gpu_power": [
219.4,
271.43,
276.62,
251.66,
277.46,
278.06,
194.1,
265.98,
277.8,
274.38,
278.56,
277.99,
277.15,
264.89,
276.96,
277.37,
277.24,
276.83,
276.94,
278.15,
264.71,
273.73,
243.99,
277.71,
278.81,
203.42,
258.01,
277.13,
277.38,
277.05,
276.55,
275.55,
267.16,
280.52,
277.94,
278.68,
277.45,
276.52,
278.47,
255.06,
250.07,
273.21,
276.19,
200.05,
276.81,
276.45,
275.4,
277.81,
277.45,
277.14,
266.34,
281.85,
279.13,
278.52,
278.21,
279.47,
278.62,
244.74,
278.38,
277.64
],
"gpu_pcie_rx_mb": [
6961.73,
24513.15,
26324.56,
679.21,
426.48,
0.33,
10.87,
10442.35,
23162.22,
22324.94,
24878.6,
26870.2,
14619.68,
11419.68,
893.4,
13515.52,
20953.08,
7.87,
14.59,
23972.7,
9329.51,
82.11,
7527.59,
4538.68,
5630.11,
6.67,
11788.08,
773.91,
87.02,
13.59,
4.53,
50.21,
7.15,
6744.72,
14.45,
115.11,
2575.49,
26114.03,
3364.04,
3375.15,
957.73,
2766.08,
0.38,
16.21,
26374.96,
15489.62,
25149.82,
11.68,
14.21,
14.21,
5900.76,
15.35,
3692.53,
87.59,
8.2,
25347.8,
80.63,
5132.53,
22.03,
3986.79
],
"cpu": [
32.6,
6.8,
6.6,
96.7,
100.0,
83.5,
5.1,
7.7,
6.8,
5.8,
11.1,
14.6,
9.1,
8.4,
7.3,
7.4,
7.0,
7.1,
6.5,
5.9,
6.0,
6.9,
72.2,
100.0,
100.0,
19.3,
8.8,
6.1,
7.1,
6.6,
7.1,
6.0,
6.8,
5.6,
5.5,
6.6,
7.8,
6.1,
6.2,
41.1,
99.9,
99.4,
84.0,
4.7,
8.8,
7.4,
6.1,
6.1,
5.7,
6.3,
7.3,
6.8,
5.8,
8.4,
15.2,
18.1,
6.8,
56.4,
100.0,
99.9
],
"ram_used": [
63399321600,
63389306880,
63427080192,
63418408960,
63417094144,
63416299520,
63358083072,
63351615488,
63342723072,
63336611840,
63371808768,
63426170880,
63504416768,
63594704896,
63611879424,
63612047360,
63599980544,
63573508096,
63570501632,
63568433152,
63702056960,
63700324352,
63800950784,
63801184256,
63789760512,
63567470592,
63559606272,
63544537088,
63536496640,
63529500672,
63515496448,
63496245248,
63530811392,
63529254912,
63530737664,
63536521216,
63543078912,
63537020928,
63539232768,
63659114496,
63677952000,
63679279104,
63683891200,
63526555648,
63547674624,
63533957120,
63515795456,
63502536704,
63493373952,
63485927424,
63556431872,
63548153856,
63549214720,
63593517056,
63649341440,
63479009280,
63476772864,
63577780224,
63546908672,
63539171328
],
"disk_read_mb": [
1.17,
0.0,
0.0,
1.29,
3.73,
2.96,
0.82,
0.0,
0.0,
0.35,
0.0,
0.0,
0.0,
0.23,
0.0,
0.0,
0.22,
0.0,
0.0,
0.0,
0.0,
0.0,
0.7,
0.31,
2.36,
0.74,
0.0,
0.0,
0.0,
0.35,
0.0,
0.0,
0.34,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.15,
1.22,
1.87,
2.13,
0.67,
0.0,
0.0,
0.27,
0.0,
0.0,
0.0,
0.35,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.45,
0.74,
3.57
],
"tok_s": [
0.0,
0.0,
0.0,
93.47,
116.21,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
97.18,
97.71,
96.52,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
80.68,
75.74,
112.93,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
108.5,
87.33,
96.24
]
},
"time": 1790714525.664817
}
}
@@ -0,0 +1,829 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "4k",
"target_tokens": 4096,
"run": 1,
"run_id": "6c6e9cb15bc9",
"corpus_repeated": false,
"time": "2026-09-29T20:40:53",
"prompt_tokens": 3881,
"completion_tokens": 256,
"ttft_s": 2.267,
"e2e_s": 5.041,
"api_prompt_tps": 1711.6,
"api_decode_tps": 91.9,
"engine_prompt_tps": 1745.2,
"engine_decode_tps": 91.7,
"log_lines": [
"strata serve: prompt 3881 tokens = 0 reused + 3881 read in 2224 ms (1745.2 tok/s), 256 generated in 2791 ms (91.7 tok/s), drafts accepted 155 of 215, 1 checkpoints",
"strata serve: decode expert cache hit rate: 97.3% (146401 hits / 150495 lookups)"
],
"answer_head": "The `CMakeLists.txt` file is the top-level build configuration for the **Strata Engine**. It orchestrates the compilation of the project, handling complex dependencies between CPU-only components, GPU kernels (CUDA/HIP), and testing infrastructure.\n\n### What the file does:\n\n1. **Project Configurati",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
},
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
},
{
"projection": null,
"time": 1790714377.2599747,
"duration_s": 17.6,
"finish": "length",
"prompt_tokens": 31605,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14608.5,
"decode_ms": 3015.6,
"decode_tok_s": 84.9,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714359.1307795,
"duration_s": 17.5,
"finish": "length",
"prompt_tokens": 31589,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14609.7,
"decode_ms": 2833.5,
"decode_tok_s": 90.3,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714338.0043592,
"duration_s": 20.5,
"finish": "length",
"prompt_tokens": 34942,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 17033.3,
"decode_ms": 3435.7,
"decode_tok_s": 74.5,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714334.3235514,
"duration_s": 3.0,
"finish": "stop",
"prompt_tokens": 4199,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 2369.7,
"decode_ms": 626.3,
"decode_tok_s": 78.2,
"hit_rate": 0.934
},
{
"projection": null,
"time": 1790714328.2723713,
"duration_s": 5.5,
"finish": "length",
"prompt_tokens": 4214,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2436.3,
"decode_ms": 3084.4,
"decode_tok_s": 83.0,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714324.3220718,
"duration_s": 3.4,
"finish": "stop",
"prompt_tokens": 3736,
"reused": 0,
"output_tokens": 56,
"engine_generated": 56,
"prompt_ms": 2700.1,
"decode_ms": 719.2,
"decode_tok_s": 77.9,
"hit_rate": 0.897
},
{
"projection": null,
"time": 1790714293.0977688,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1288.1,
"decode_ms": 2834.1,
"decode_tok_s": 90.3,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714290.8242896,
"duration_s": 1.8,
"finish": "stop",
"prompt_tokens": 1147,
"reused": 0,
"output_tokens": 40,
"engine_generated": 40,
"prompt_ms": 1304.0,
"decode_ms": 456.3,
"decode_tok_s": 87.7,
"hit_rate": 0.916
}
],
"requests_kept": 14,
"totals": {
"since": 1790713882.6043305,
"requests": 14,
"prompt_tokens": 120940,
"reused": 0,
"output_tokens": 2712,
"prompt_ms": 64909.50000000001,
"decode_ms": 31364.099999999995
},
"hardware": {
"gpu_util": 97,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 46,
"gpu_power": 278.792,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.3330078125,
"gpu_pcie_tx_mb": 0.5244140625,
"cpu": 93.8,
"ram_used": 63471906816,
"ram_total": 177175990272,
"disk_read_mb": 2.6609869128828647,
"disk_write_mb": 0.0037478688913843163,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
100,
98,
94,
94,
100,
21,
98,
95,
53,
100,
94,
96,
21,
99,
99,
92,
97,
97
],
"gpu_mem_used": [
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
42,
41,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
39,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
45,
45,
45,
45,
45,
43,
45,
45,
44,
45,
45,
45,
43,
45,
45,
45,
45,
46
],
"gpu_power": [
164.95,
142.09,
130.43,
119.16,
119.05,
119.02,
118.92,
118.89,
118.85,
118.74,
118.81,
118.95,
118.87,
118.88,
119.01,
118.97,
113.29,
37.07,
35.2,
35.1,
35.04,
34.98,
34.86,
34.88,
34.97,
34.79,
34.76,
34.94,
34.9,
34.89,
35.0,
34.87,
34.82,
34.93,
34.86,
34.92,
34.99,
34.83,
34.88,
34.97,
34.89,
34.96,
172.41,
265.41,
275.33,
276.53,
216.14,
263.1,
264.26,
273.6,
211.21,
274.12,
265.58,
276.31,
268.45,
217.39,
278.78,
252.44,
278.12,
278.79
],
"gpu_pcie_rx_mb": [
0.29,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.33,
0.29,
0.29,
0.29,
0.29,
0.33,
0.33,
0.33,
0.57,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.38,
0.38,
0.43,
0.38,
0.38,
9.97,
22329.52,
3689.24,
4264.07,
0.33,
14955.09,
784.16,
3310.82,
1249.69,
15874.15,
18357.04,
4099.13,
485.18,
0.29,
11.78,
84.59,
865.12,
8675.62,
0.33
],
"cpu": [
2.5,
9.7,
2.8,
11.4,
13.4,
2.8,
1.5,
1.3,
2.8,
1.6,
1.6,
1.6,
2.2,
1.1,
5.2,
2.3,
1.3,
11.2,
3.6,
1.3,
11.5,
1.1,
1.9,
1.2,
1.3,
1.3,
1.0,
0.6,
2.3,
0.8,
1.2,
6.3,
8.9,
0.6,
1.9,
2.2,
2.1,
1.1,
2.2,
4.7,
1.2,
6.8,
7.3,
83.2,
99.8,
87.0,
14.8,
49.9,
100.0,
97.9,
33.3,
7.4,
99.9,
100.0,
63.3,
5.7,
6.4,
81.2,
100.0,
93.8
],
"ram_used": [
63502053376,
63600914432,
63612030976,
63779962880,
63785050112,
63794016256,
63795236864,
63794536448,
63786823680,
63781208064,
63760637952,
63756046336,
63757750272,
63751917568,
63784116224,
63784988672,
63783927808,
63781187584,
63772962816,
63781842944,
63808417792,
63797518336,
63793590272,
63788277760,
63788392448,
63791640576,
63791734784,
63793213440,
63793565696,
63794352128,
63793430528,
63799361536,
63590793216,
63591645184,
63583899648,
63571738624,
63579156480,
63572910080,
63581016064,
63625879552,
63626788864,
63427158016,
63429017600,
63532883968,
63535853568,
63534440448,
63490953216,
63544176640,
63529631744,
63536766976,
63443234816,
63502606336,
63508336640,
63509970944,
63492075520,
63440269312,
63431364608,
63482470400,
63473512448,
63471906816
],
"disk_read_mb": [
0.0,
0.0,
0.0,
0.0,
0.1,
0.14,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.35,
0.0,
0.8,
3.91,
3.26,
0.6,
0.0,
1.08,
2.82,
1.34,
0.0,
1.55,
2.4,
1.66,
0.64,
0.0,
2.25,
2.98,
2.66
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
103.98,
98.22,
0.0,
0.0,
112.83,
83.57,
76.97,
0.0,
0.0,
97.69,
87.72,
0.0,
0.0,
0.0,
102.14,
97.9,
0.0
]
},
"time": 1790714458.598403
}
}
@@ -0,0 +1,829 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "4k",
"target_tokens": 4096,
"run": 2,
"run_id": "1df8c923675b",
"corpus_repeated": false,
"time": "2026-09-29T20:40:58",
"prompt_tokens": 4200,
"completion_tokens": 142,
"ttft_s": 2.418,
"e2e_s": 4.063,
"api_prompt_tps": 1736.7,
"api_decode_tps": 85.7,
"engine_prompt_tps": 1772.2,
"engine_decode_tps": 85.5,
"log_lines": [
"strata serve: prompt 4200 tokens = 0 reused + 4200 read in 2370 ms (1772.2 tok/s), 142 generated in 1660 ms (85.5 tok/s), drafts accepted 96 of 114, 1 checkpoints",
"strata serve: decode expert cache hit rate: 89.6% (64163 hits / 71608 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand the context better.",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714458.6299415,
"duration_s": 4.0,
"finish": "stop",
"prompt_tokens": 4200,
"reused": 0,
"output_tokens": 142,
"engine_generated": 142,
"prompt_ms": 2370.0,
"decode_ms": 1660.0,
"decode_tok_s": 85.5,
"hit_rate": 0.896
},
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
},
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
},
{
"projection": null,
"time": 1790714377.2599747,
"duration_s": 17.6,
"finish": "length",
"prompt_tokens": 31605,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14608.5,
"decode_ms": 3015.6,
"decode_tok_s": 84.9,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714359.1307795,
"duration_s": 17.5,
"finish": "length",
"prompt_tokens": 31589,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14609.7,
"decode_ms": 2833.5,
"decode_tok_s": 90.3,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714338.0043592,
"duration_s": 20.5,
"finish": "length",
"prompt_tokens": 34942,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 17033.3,
"decode_ms": 3435.7,
"decode_tok_s": 74.5,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714334.3235514,
"duration_s": 3.0,
"finish": "stop",
"prompt_tokens": 4199,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 2369.7,
"decode_ms": 626.3,
"decode_tok_s": 78.2,
"hit_rate": 0.934
},
{
"projection": null,
"time": 1790714328.2723713,
"duration_s": 5.5,
"finish": "length",
"prompt_tokens": 4214,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2436.3,
"decode_ms": 3084.4,
"decode_tok_s": 83.0,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714324.3220718,
"duration_s": 3.4,
"finish": "stop",
"prompt_tokens": 3736,
"reused": 0,
"output_tokens": 56,
"engine_generated": 56,
"prompt_ms": 2700.1,
"decode_ms": 719.2,
"decode_tok_s": 77.9,
"hit_rate": 0.897
},
{
"projection": null,
"time": 1790714293.0977688,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1288.1,
"decode_ms": 2834.1,
"decode_tok_s": 90.3,
"hit_rate": 0.966
}
],
"requests_kept": 15,
"totals": {
"since": 1790713882.6043305,
"requests": 15,
"prompt_tokens": 125140,
"reused": 0,
"output_tokens": 2854,
"prompt_ms": 67279.5,
"decode_ms": 33024.09999999999
},
"hardware": {
"gpu_util": 98,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 46,
"gpu_power": 276.727,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 4551.6005859375,
"gpu_pcie_tx_mb": 1681.041015625,
"cpu": 100.0,
"ram_used": 63441051648,
"ram_total": 177175990272,
"disk_read_mb": 2.097570021071815,
"disk_write_mb": 0.10077293695540748,
"tok_s": 98.25687730909294,
"tok_s_mean": 85.16861474502441
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
100,
98,
94,
94,
100,
21,
98,
95,
53,
100,
94,
96,
21,
99,
99,
92,
97,
97,
0,
98,
99,
98
],
"gpu_mem_used": [
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
40,
39,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
45,
45,
45,
45,
45,
43,
45,
45,
44,
45,
45,
45,
43,
45,
45,
45,
45,
46,
42,
46,
45,
46
],
"gpu_power": [
119.05,
119.02,
118.92,
118.89,
118.85,
118.74,
118.81,
118.95,
118.87,
118.88,
119.01,
118.97,
113.29,
37.07,
35.2,
35.1,
35.04,
34.98,
34.86,
34.88,
34.97,
34.79,
34.76,
34.94,
34.9,
34.89,
35.0,
34.87,
34.82,
34.93,
34.86,
34.92,
34.99,
34.83,
34.88,
34.97,
34.89,
34.96,
172.41,
265.41,
275.33,
276.53,
216.14,
263.1,
264.26,
273.6,
211.21,
274.12,
265.58,
276.31,
268.45,
217.39,
278.78,
252.44,
278.12,
278.79,
215.59,
278.37,
251.8,
276.73
],
"gpu_pcie_rx_mb": [
0.33,
0.33,
0.33,
0.33,
0.33,
0.29,
0.29,
0.29,
0.29,
0.33,
0.33,
0.33,
0.57,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.38,
0.38,
0.43,
0.38,
0.38,
9.97,
22329.52,
3689.24,
4264.07,
0.33,
14955.09,
784.16,
3310.82,
1249.69,
15874.15,
18357.04,
4099.13,
485.18,
0.29,
11.78,
84.59,
865.12,
8675.62,
0.33,
3342.49,
34.05,
7461.5,
4551.6
],
"cpu": [
13.4,
2.8,
1.5,
1.3,
2.8,
1.6,
1.6,
1.6,
2.2,
1.1,
5.2,
2.3,
1.3,
11.2,
3.6,
1.3,
11.5,
1.1,
1.9,
1.2,
1.3,
1.3,
1.0,
0.6,
2.3,
0.8,
1.2,
6.3,
8.9,
0.6,
1.9,
2.2,
2.1,
1.1,
2.2,
4.7,
1.2,
6.8,
7.3,
83.2,
99.8,
87.0,
14.8,
49.9,
100.0,
97.9,
33.3,
7.4,
99.9,
100.0,
63.3,
5.7,
6.4,
81.2,
100.0,
93.8,
14.8,
15.8,
37.5,
100.0
],
"ram_used": [
63785050112,
63794016256,
63795236864,
63794536448,
63786823680,
63781208064,
63760637952,
63756046336,
63757750272,
63751917568,
63784116224,
63784988672,
63783927808,
63781187584,
63772962816,
63781842944,
63808417792,
63797518336,
63793590272,
63788277760,
63788392448,
63791640576,
63791734784,
63793213440,
63793565696,
63794352128,
63793430528,
63799361536,
63590793216,
63591645184,
63583899648,
63571738624,
63579156480,
63572910080,
63581016064,
63625879552,
63626788864,
63427158016,
63429017600,
63532883968,
63535853568,
63534440448,
63490953216,
63544176640,
63529631744,
63536766976,
63443234816,
63502606336,
63508336640,
63509970944,
63492075520,
63440269312,
63431364608,
63482470400,
63473512448,
63471906816,
63401848832,
63554486272,
63453114368,
63441051648
],
"disk_read_mb": [
0.1,
0.14,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.35,
0.0,
0.8,
3.91,
3.26,
0.6,
0.0,
1.08,
2.82,
1.34,
0.0,
1.55,
2.4,
1.66,
0.64,
0.0,
2.25,
2.98,
2.66,
0.64,
0.0,
0.21,
2.1
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
103.98,
98.22,
0.0,
0.0,
112.83,
83.57,
76.97,
0.0,
0.0,
97.69,
87.72,
0.0,
0.0,
0.0,
102.14,
97.9,
0.0,
0.0,
0.0,
89.96,
98.26
]
},
"time": 1790714463.1652913
}
}
@@ -0,0 +1,829 @@
{
"label": "native-v0.1.26-IQ3_XXS-1x3090",
"mode": "speed",
"ctx": "4k",
"target_tokens": 4096,
"run": 3,
"run_id": "777f84f22df4",
"corpus_repeated": false,
"time": "2026-09-29T20:41:03",
"prompt_tokens": 4201,
"completion_tokens": 256,
"ttft_s": 2.409,
"e2e_s": 5.262,
"api_prompt_tps": 1744.1,
"api_decode_tps": 89.4,
"engine_prompt_tps": 1775.8,
"engine_decode_tps": 89.2,
"log_lines": [
"strata serve: prompt 4201 tokens = 0 reused + 4201 read in 2366 ms (1775.8 tok/s), 256 generated in 2868 ms (89.2 tok/s), drafts accepted 161 of 222, 1 checkpoints",
"strata serve: decode expert cache hit rate: 96.0% (144002 hits / 149996 lookups)"
],
"answer_head": "The `CMakeLists.txt` file is the top-level build configuration for the **Strata Engine**. Its primary responsibilities are:\n\n1. **Project Definition**: Sets up the project name (`strata`), version (`0.1.26`), and C++20 standard.\n2. **Backend Selection**: Manages mutually exclusive GPU backends (CU",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 131072,
"images": false,
"version": "0.1.26",
"context": 131072,
"kv": "int8",
"kv_resident": 32768,
"expert_slots": 10584,
"expert_cache_mib": 17583,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 389,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790714463.1913157,
"duration_s": 5.2,
"finish": "length",
"prompt_tokens": 4201,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2365.6,
"decode_ms": 2868.4,
"decode_tok_s": 89.2,
"hit_rate": 0.96
},
{
"projection": null,
"time": 1790714458.6299415,
"duration_s": 4.0,
"finish": "stop",
"prompt_tokens": 4200,
"reused": 0,
"output_tokens": 142,
"engine_generated": 142,
"prompt_ms": 2370.0,
"decode_ms": 1660.0,
"decode_tok_s": 85.5,
"hit_rate": 0.896
},
{
"projection": null,
"time": 1790714453.0791314,
"duration_s": 5.0,
"finish": "length",
"prompt_tokens": 3881,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2223.8,
"decode_ms": 2790.5,
"decode_tok_s": 91.7,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790714448.5537117,
"duration_s": 4.0,
"finish": "length",
"prompt_tokens": 1135,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1305.1,
"decode_ms": 2690.8,
"decode_tok_s": 95.1,
"hit_rate": 0.972
},
{
"projection": null,
"time": 1790714443.8943996,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1149,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1297.6,
"decode_ms": 2847.5,
"decode_tok_s": 89.9,
"hit_rate": 0.971
},
{
"projection": null,
"time": 1790714439.2770011,
"duration_s": 4.1,
"finish": "length",
"prompt_tokens": 1092,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 1351.4,
"decode_ms": 2752.6,
"decode_tok_s": 93.0,
"hit_rate": 0.954
},
{
"projection": null,
"time": 1790714377.2599747,
"duration_s": 17.6,
"finish": "length",
"prompt_tokens": 31605,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14608.5,
"decode_ms": 3015.6,
"decode_tok_s": 84.9,
"hit_rate": 0.966
},
{
"projection": null,
"time": 1790714359.1307795,
"duration_s": 17.5,
"finish": "length",
"prompt_tokens": 31589,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 14609.7,
"decode_ms": 2833.5,
"decode_tok_s": 90.3,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714338.0043592,
"duration_s": 20.5,
"finish": "length",
"prompt_tokens": 34942,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 17033.3,
"decode_ms": 3435.7,
"decode_tok_s": 74.5,
"hit_rate": 0.945
},
{
"projection": null,
"time": 1790714334.3235514,
"duration_s": 3.0,
"finish": "stop",
"prompt_tokens": 4199,
"reused": 0,
"output_tokens": 49,
"engine_generated": 49,
"prompt_ms": 2369.7,
"decode_ms": 626.3,
"decode_tok_s": 78.2,
"hit_rate": 0.934
},
{
"projection": null,
"time": 1790714328.2723713,
"duration_s": 5.5,
"finish": "length",
"prompt_tokens": 4214,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 2436.3,
"decode_ms": 3084.4,
"decode_tok_s": 83.0,
"hit_rate": 0.959
},
{
"projection": null,
"time": 1790714324.3220718,
"duration_s": 3.4,
"finish": "stop",
"prompt_tokens": 3736,
"reused": 0,
"output_tokens": 56,
"engine_generated": 56,
"prompt_ms": 2700.1,
"decode_ms": 719.2,
"decode_tok_s": 77.9,
"hit_rate": 0.897
}
],
"requests_kept": 16,
"totals": {
"since": 1790713882.6043305,
"requests": 16,
"prompt_tokens": 129341,
"reused": 0,
"output_tokens": 3110,
"prompt_ms": 69645.1,
"decode_ms": 35892.49999999999
},
"hardware": {
"gpu_util": 96,
"gpu_mem_used": 25517031424,
"gpu_mem_total": 25769803776,
"gpu_temp": 46,
"gpu_power": 278.057,
"gpu_power_limit": 280.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.3330078125,
"gpu_pcie_tx_mb": 0.4287109375,
"cpu": 83.5,
"ram_used": 63416299520,
"ram_total": 177175990272,
"disk_read_mb": 2.956676951508761,
"disk_write_mb": 0.16488439273306146,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090",
"gpu_count": 1,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
100,
98,
94,
94,
100,
21,
98,
95,
53,
100,
94,
96,
21,
99,
99,
92,
97,
97,
0,
98,
99,
98,
0,
99,
100,
99,
96,
96
],
"gpu_mem_used": [
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25514934272,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424,
25517031424
],
"gpu_temp": [
40,
40,
40,
40,
40,
40,
39,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
38,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
37,
45,
45,
45,
45,
45,
43,
45,
45,
44,
45,
45,
45,
43,
45,
45,
45,
45,
46,
42,
46,
45,
46,
42,
45,
45,
45,
46,
46
],
"gpu_power": [
118.81,
118.95,
118.87,
118.88,
119.01,
118.97,
113.29,
37.07,
35.2,
35.1,
35.04,
34.98,
34.86,
34.88,
34.97,
34.79,
34.76,
34.94,
34.9,
34.89,
35.0,
34.87,
34.82,
34.93,
34.86,
34.92,
34.99,
34.83,
34.88,
34.97,
34.89,
34.96,
172.41,
265.41,
275.33,
276.53,
216.14,
263.1,
264.26,
273.6,
211.21,
274.12,
265.58,
276.31,
268.45,
217.39,
278.78,
252.44,
278.12,
278.79,
215.59,
278.37,
251.8,
276.73,
219.4,
271.43,
276.62,
251.66,
277.46,
278.06
],
"gpu_pcie_rx_mb": [
0.29,
0.29,
0.29,
0.33,
0.33,
0.33,
0.57,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.43,
0.43,
0.43,
0.38,
0.38,
0.43,
0.43,
0.38,
0.38,
0.38,
0.43,
0.38,
0.38,
0.43,
0.38,
0.38,
9.97,
22329.52,
3689.24,
4264.07,
0.33,
14955.09,
784.16,
3310.82,
1249.69,
15874.15,
18357.04,
4099.13,
485.18,
0.29,
11.78,
84.59,
865.12,
8675.62,
0.33,
3342.49,
34.05,
7461.5,
4551.6,
6961.73,
24513.15,
26324.56,
679.21,
426.48,
0.33
],
"cpu": [
1.6,
1.6,
2.2,
1.1,
5.2,
2.3,
1.3,
11.2,
3.6,
1.3,
11.5,
1.1,
1.9,
1.2,
1.3,
1.3,
1.0,
0.6,
2.3,
0.8,
1.2,
6.3,
8.9,
0.6,
1.9,
2.2,
2.1,
1.1,
2.2,
4.7,
1.2,
6.8,
7.3,
83.2,
99.8,
87.0,
14.8,
49.9,
100.0,
97.9,
33.3,
7.4,
99.9,
100.0,
63.3,
5.7,
6.4,
81.2,
100.0,
93.8,
14.8,
15.8,
37.5,
100.0,
32.6,
6.8,
6.6,
96.7,
100.0,
83.5
],
"ram_used": [
63760637952,
63756046336,
63757750272,
63751917568,
63784116224,
63784988672,
63783927808,
63781187584,
63772962816,
63781842944,
63808417792,
63797518336,
63793590272,
63788277760,
63788392448,
63791640576,
63791734784,
63793213440,
63793565696,
63794352128,
63793430528,
63799361536,
63590793216,
63591645184,
63583899648,
63571738624,
63579156480,
63572910080,
63581016064,
63625879552,
63626788864,
63427158016,
63429017600,
63532883968,
63535853568,
63534440448,
63490953216,
63544176640,
63529631744,
63536766976,
63443234816,
63502606336,
63508336640,
63509970944,
63492075520,
63440269312,
63431364608,
63482470400,
63473512448,
63471906816,
63401848832,
63554486272,
63453114368,
63441051648,
63399321600,
63389306880,
63427080192,
63418408960,
63417094144,
63416299520
],
"disk_read_mb": [
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.35,
0.0,
0.8,
3.91,
3.26,
0.6,
0.0,
1.08,
2.82,
1.34,
0.0,
1.55,
2.4,
1.66,
0.64,
0.0,
2.25,
2.98,
2.66,
0.64,
0.0,
0.21,
2.1,
1.17,
0.0,
0.0,
1.29,
3.73,
2.96
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
103.98,
98.22,
0.0,
0.0,
112.83,
83.57,
76.97,
0.0,
0.0,
97.69,
87.72,
0.0,
0.0,
0.0,
102.14,
97.9,
0.0,
0.0,
0.0,
89.96,
98.26,
0.0,
0.0,
0.0,
93.47,
116.21,
0.0
]
},
"time": 1790714468.9308503
}
}
@@ -0,0 +1,501 @@
{
"label": "native-v0.1.26-IQ3_XXS-2x3090-auto-needle",
"mode": "needle",
"ctx": "16k",
"target_tokens": 16384,
"run": 1,
"run_id": "8f89dfed9af3",
"corpus_repeated": false,
"time": "2026-09-29T22:00:26",
"prompt_tokens": 17344,
"completion_tokens": 8,
"ttft_s": 15.582,
"e2e_s": 15.663,
"api_prompt_tps": 1113.1,
"api_decode_tps": 86.5,
"engine_prompt_tps": 1119.9,
"engine_decode_tps": 83.8,
"log_lines": [
"strata serve: prompt 17344 tokens = 0 reused + 17344 read in 15487 ms (1119.9 tok/s), 8 generated in 96 ms (83.8 tok/s), drafts accepted 6 of 6, 2 checkpoints",
"strata serve: decode expert cache hit rate: 97.3% (4205 hits / 4320 lookups)"
],
"answer_head": "05449BFC",
"needle_found": true,
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 11883,
"expert_cache_mib": 17564,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 645,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790719226.530526,
"duration_s": 15.6,
"finish": "stop",
"prompt_tokens": 17344,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 15486.8,
"decode_ms": 95.5,
"decode_tok_s": 83.8,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790719217.9333243,
"duration_s": 8.0,
"finish": "stop",
"prompt_tokens": 7493,
"reused": 0,
"output_tokens": 9,
"engine_generated": 9,
"prompt_ms": 7861.5,
"decode_ms": 153.7,
"decode_tok_s": 58.6,
"hit_rate": 0.94
}
],
"requests_kept": 2,
"totals": {
"since": 1790719202.7795203,
"requests": 2,
"prompt_tokens": 24837,
"reused": 0,
"output_tokens": 17,
"prompt_ms": 23348.3,
"decode_ms": 249.2
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 0,
"mem_used": 25171001344,
"mem_total": 25769803776,
"temp": 47,
"power": 148.05
},
{
"index": 1,
"util": 40,
"mem_used": 24185339904,
"mem_total": 25769803776,
"temp": 54,
"power": 237.219
}
],
"gpu_util": 20.0,
"gpu_mem_used": 49356341248,
"gpu_mem_total": 51539607552,
"gpu_temp": 54,
"gpu_power": 385.269,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 1.7626953125,
"gpu_pcie_tx_mb": 0.9052734375,
"cpu": 9.1,
"ram_used": 62596341760,
"ram_total": 177175990272,
"disk_read_mb": 0.0,
"disk_write_mb": 0.0,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.0,
73.5,
23.5,
31.0,
56.5,
23.5,
20.5,
0.5,
70.5,
22.5,
26.5,
56.0,
29.0,
77.0,
11.0,
28.5,
59.5,
28.5,
19.5,
17.0,
27.0,
20.0
],
"gpu_mem_used": [
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49274552320,
49291329536,
49291329536,
49291329536,
49291329536,
49291329536,
49291329536,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248
],
"gpu_temp": [
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
51,
53,
52,
52,
52,
53,
49,
51,
52,
52,
53,
53,
53,
52,
53,
51,
53,
53,
53,
53,
54
],
"gpu_power": [
257.56,
245.14,
244.59,
244.41,
244.51,
244.45,
244.36,
244.36,
244.26,
244.16,
244.27,
244.18,
244.09,
243.92,
243.88,
245.24,
443.06,
409.13,
432.67,
433.1,
400.92,
389.08,
278.03,
383.36,
392.74,
440.94,
403.62,
421.29,
427.09,
407.67,
422.11,
423.13,
417.76,
440.15,
377.19,
403.8,
385.27
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
0.57,
0.62,
0.67,
0.57,
0.62,
0.62,
0.67,
0.62,
0.62,
0.67,
0.62,
0.57,
0.62,
2169.46,
6179.19,
3838.3,
4927.82,
4008.2,
7314.58,
0.95,
1338.19,
7892.51,
3024.72,
5741.74,
2921.96,
5454.83,
5667.49,
3768.87,
6803.13,
8164.64,
2711.1,
5725.29,
6417.89,
0.67,
1.76
],
"cpu": [
0.0,
15.8,
15.7,
6.4,
8.0,
8.1,
4.7,
6.7,
0.9,
1.5,
5.3,
12.5,
1.6,
3.2,
8.4,
14.2,
13.2,
10.5,
10.5,
13.4,
9.0,
12.2,
23.9,
8.1,
16.5,
13.0,
13.0,
9.0,
9.7,
12.8,
8.6,
12.9,
10.4,
8.6,
9.0,
9.4,
9.1
],
"ram_used": [
61827047424,
61871300608,
61941383168,
61960540160,
61978361856,
61977542656,
61984432128,
61992636416,
61992636416,
62000824320,
62002450432,
62005186560,
62006108160,
62014894080,
62023741440,
62230065152,
62246010880,
62250319872,
62234144768,
62227582976,
62226890752,
62392664064,
62490071040,
62486704128,
62515294208,
62517342208,
62467452928,
62510080000,
62495842304,
62471684096,
62463819776,
62459879424,
62443171840,
62374465536,
62303469568,
62390607872,
62596341760
],
"disk_read_mb": [
null,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
0.0,
28.33,
101.36,
41.6,
10.77,
0.0,
0.01,
0.0,
0.0,
1.06,
0.0,
14.72,
0.0,
56.04,
0.0,
33.79,
66.18,
16.29,
83.86,
33.38,
0.0,
0.0,
0.0,
0.0
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790719242.619913
}
}
@@ -0,0 +1,722 @@
{
"label": "native-v0.1.26-IQ3_XXS-2x3090-auto-needle",
"mode": "needle",
"ctx": "28k",
"target_tokens": 28672,
"run": 1,
"run_id": "93a9a0e32114",
"corpus_repeated": false,
"time": "2026-09-29T22:00:42",
"prompt_tokens": 29825,
"completion_tokens": 9,
"ttft_s": 26.19,
"e2e_s": 26.262,
"api_prompt_tps": 1138.8,
"api_decode_tps": 110.5,
"engine_prompt_tps": 1146.7,
"engine_decode_tps": 103.9,
"log_lines": [
"strata serve: prompt 29825 tokens = 0 reused + 29825 read in 26009 ms (1146.7 tok/s), 9 generated in 87 ms (103.9 tok/s), drafts accepted 6 of 6, 2 checkpoints",
"strata serve: decode expert cache hit rate: 98.2% (4241 hits / 4320 lookups)"
],
"answer_head": "98C00B03",
"needle_found": true,
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 11883,
"expert_cache_mib": 17564,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 645,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790719242.7790127,
"duration_s": 26.1,
"finish": "stop",
"prompt_tokens": 29825,
"reused": 0,
"output_tokens": 9,
"engine_generated": 9,
"prompt_ms": 26008.5,
"decode_ms": 86.6,
"decode_tok_s": 103.9,
"hit_rate": 0.982
},
{
"projection": null,
"time": 1790719226.530526,
"duration_s": 15.6,
"finish": "stop",
"prompt_tokens": 17344,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 15486.8,
"decode_ms": 95.5,
"decode_tok_s": 83.8,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790719217.9333243,
"duration_s": 8.0,
"finish": "stop",
"prompt_tokens": 7493,
"reused": 0,
"output_tokens": 9,
"engine_generated": 9,
"prompt_ms": 7861.5,
"decode_ms": 153.7,
"decode_tok_s": 58.6,
"hit_rate": 0.94
}
],
"requests_kept": 3,
"totals": {
"since": 1790719202.7795203,
"requests": 3,
"prompt_tokens": 54662,
"reused": 0,
"output_tokens": 26,
"prompt_ms": 49356.8,
"decode_ms": 335.79999999999995
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 6,
"mem_used": 25171001344,
"mem_total": 25769803776,
"temp": 47,
"power": 141.832
},
{
"index": 1,
"util": 20,
"mem_used": 24185339904,
"mem_total": 25769803776,
"temp": 52,
"power": 243.782
}
],
"gpu_util": 13.0,
"gpu_mem_used": 49356341248,
"gpu_mem_total": 51539607552,
"gpu_temp": 52,
"gpu_power": 385.61400000000003,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.666015625,
"gpu_pcie_tx_mb": 0.857421875,
"cpu": 16.6,
"ram_used": 62951010304,
"ram_total": 177175990272,
"disk_read_mb": 0.08651659039933747,
"disk_write_mb": 0.0,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.0,
73.5,
23.5,
31.0,
56.5,
23.5,
20.5,
0.5,
70.5,
22.5,
26.5,
56.0,
29.0,
77.0,
11.0,
28.5,
59.5,
28.5,
19.5,
17.0,
27.0,
20.0,
0.0,
60.5,
25.5,
71.0,
67.0,
26.5,
26.5,
85.0,
26.0,
73.5,
49.5,
25.0,
48.0,
32.0,
76.5,
9.0,
27.5,
47.5,
30.0,
62.5,
15.5,
31.5,
29.0,
39.5,
13.0
],
"gpu_mem_used": [
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49274552320,
49291329536,
49291329536,
49291329536,
49291329536,
49291329536,
49291329536,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248
],
"gpu_temp": [
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
51,
53,
52,
52,
52,
53,
49,
51,
52,
52,
53,
53,
53,
52,
53,
51,
53,
53,
53,
53,
54,
50,
51,
53,
53,
52,
54,
52,
52,
53,
53,
53,
53,
52,
53,
54,
52,
53,
52,
53,
52,
52,
54,
53,
54,
52
],
"gpu_power": [
244.59,
244.41,
244.51,
244.45,
244.36,
244.36,
244.26,
244.16,
244.27,
244.18,
244.09,
243.92,
243.88,
245.24,
443.06,
409.13,
432.67,
433.1,
400.92,
389.08,
278.03,
383.36,
392.74,
440.94,
403.62,
421.29,
427.09,
407.67,
422.11,
423.13,
417.76,
440.15,
377.19,
403.8,
385.27,
299.57,
398.78,
401.71,
449.87,
430.87,
402.83,
439.43,
401.46,
455.62,
425.18,
404.39,
417.35,
406.87,
423.67,
422.86,
404.6,
421.5,
402.4,
422.71,
432.67,
398.05,
455.72,
434.46,
403.83,
385.61
],
"gpu_pcie_rx_mb": [
0.57,
0.62,
0.67,
0.57,
0.62,
0.62,
0.67,
0.62,
0.62,
0.67,
0.62,
0.57,
0.62,
2169.46,
6179.19,
3838.3,
4927.82,
4008.2,
7314.58,
0.95,
1338.19,
7892.51,
3024.72,
5741.74,
2921.96,
5454.83,
5667.49,
3768.87,
6803.13,
8164.64,
2711.1,
5725.29,
6417.89,
0.67,
1.76,
1343.92,
7796.67,
10809.8,
5598.92,
3013.99,
91.89,
4693.79,
5621.38,
5381.87,
7487.25,
2228.12,
7344.77,
3943.44,
0.81,
5476.19,
2437.4,
6693.74,
3836.63,
7843.59,
5638.65,
2853.11,
8215.43,
8500.96,
4445.79,
0.67
],
"cpu": [
15.7,
6.4,
8.0,
8.1,
4.7,
6.7,
0.9,
1.5,
5.3,
12.5,
1.6,
3.2,
8.4,
14.2,
13.2,
10.5,
10.5,
13.4,
9.0,
12.2,
23.9,
8.1,
16.5,
13.0,
13.0,
9.0,
9.7,
12.8,
8.6,
12.9,
10.4,
8.6,
9.0,
9.4,
9.1,
16.9,
17.1,
22.7,
7.5,
10.8,
8.9,
7.3,
7.3,
8.3,
7.7,
9.8,
6.9,
12.4,
6.4,
12.2,
20.6,
19.9,
11.0,
8.1,
10.3,
9.8,
7.6,
8.1,
7.3,
16.6
],
"ram_used": [
61941383168,
61960540160,
61978361856,
61977542656,
61984432128,
61992636416,
61992636416,
62000824320,
62002450432,
62005186560,
62006108160,
62014894080,
62023741440,
62230065152,
62246010880,
62250319872,
62234144768,
62227582976,
62226890752,
62392664064,
62490071040,
62486704128,
62515294208,
62517342208,
62467452928,
62510080000,
62495842304,
62471684096,
62463819776,
62459879424,
62443171840,
62374465536,
62303469568,
62390607872,
62596341760,
62489825280,
62562496512,
62577270784,
62577836032,
62576951296,
62564986880,
62553812992,
62539886592,
62533107712,
62521810944,
62503256064,
62503677952,
62490673152,
62492131328,
62495432704,
62503706624,
62769029120,
62766465024,
62765707264,
62747688960,
62726733824,
62717767680,
62722011136,
62728314880,
62951010304
],
"disk_read_mb": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
0.0,
28.33,
101.36,
41.6,
10.77,
0.0,
0.01,
0.0,
0.0,
1.06,
0.0,
14.72,
0.0,
56.04,
0.0,
33.79,
66.18,
16.29,
83.86,
33.38,
0.0,
0.0,
0.0,
0.0,
0.73,
0.0,
0.0,
0.0,
0.22,
0.0,
0.0,
0.14,
0.0,
0.53,
47.85,
0.0,
71.37,
0.0,
78.98,
55.42,
22.25,
53.69,
0.0,
54.32,
39.07,
0.0,
0.0,
0.0,
0.09
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790719269.3852785
}
}
@@ -0,0 +1,352 @@
{
"label": "native-v0.1.26-IQ3_XXS-2x3090-auto-needle",
"mode": "needle",
"ctx": "8k",
"target_tokens": 8192,
"run": 1,
"run_id": "d1d745f05911",
"corpus_repeated": false,
"time": "2026-09-29T22:00:17",
"prompt_tokens": 7493,
"completion_tokens": 9,
"ttft_s": 7.948,
"e2e_s": 8.057,
"api_prompt_tps": 942.8,
"api_decode_tps": 73.4,
"engine_prompt_tps": 953.1,
"engine_decode_tps": 58.6,
"log_lines": [
"strata serve: prompt 7493 tokens = 0 reused + 7493 read in 7861 ms (953.1 tok/s), 9 generated in 154 ms (58.6 tok/s), drafts accepted 6 of 6, 1 checkpoints",
"strata serve: decode expert cache hit rate: 94.0% (4062 hits / 4320 lookups)"
],
"answer_head": "69231569",
"needle_found": true,
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 11883,
"expert_cache_mib": 17564,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 645,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790719217.9333243,
"duration_s": 8.0,
"finish": "stop",
"prompt_tokens": 7493,
"reused": 0,
"output_tokens": 9,
"engine_generated": 9,
"prompt_ms": 7861.5,
"decode_ms": 153.7,
"decode_tok_s": 58.6,
"hit_rate": 0.94
}
],
"requests_kept": 1,
"totals": {
"since": 1790719202.7795203,
"requests": 1,
"prompt_tokens": 7493,
"reused": 0,
"output_tokens": 9,
"prompt_ms": 7861.5,
"decode_ms": 153.7
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 0,
"mem_used": 25139544064,
"mem_total": 25769803776,
"temp": 46,
"power": 145.526
},
{
"index": 1,
"util": 41,
"mem_used": 24151785472,
"mem_total": 25769803776,
"temp": 53,
"power": 243.553
}
],
"gpu_util": 20.5,
"gpu_mem_used": 49291329536,
"gpu_mem_total": 51539607552,
"gpu_temp": 53,
"gpu_power": 389.079,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.9521484375,
"gpu_pcie_tx_mb": 4154.1572265625,
"cpu": 12.2,
"ram_used": 62392664064,
"ram_total": 177175990272,
"disk_read_mb": 0.0036010722333241606,
"disk_write_mb": 0.0,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.5,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2.0,
73.5,
23.5,
31.0,
56.5,
23.5,
20.5
],
"gpu_mem_used": [
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49274552320,
49291329536,
49291329536,
49291329536,
49291329536,
49291329536,
49291329536
],
"gpu_temp": [
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
48,
51,
53,
52,
52,
52,
53
],
"gpu_power": [
257.56,
245.14,
244.59,
244.41,
244.51,
244.45,
244.36,
244.36,
244.26,
244.16,
244.27,
244.18,
244.09,
243.92,
243.88,
245.24,
443.06,
409.13,
432.67,
433.1,
400.92,
389.08
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
0.57,
0.62,
0.67,
0.57,
0.62,
0.62,
0.67,
0.62,
0.62,
0.67,
0.62,
0.57,
0.62,
2169.46,
6179.19,
3838.3,
4927.82,
4008.2,
7314.58,
0.95
],
"cpu": [
0.0,
15.8,
15.7,
6.4,
8.0,
8.1,
4.7,
6.7,
0.9,
1.5,
5.3,
12.5,
1.6,
3.2,
8.4,
14.2,
13.2,
10.5,
10.5,
13.4,
9.0,
12.2
],
"ram_used": [
61827047424,
61871300608,
61941383168,
61960540160,
61978361856,
61977542656,
61984432128,
61992636416,
61992636416,
62000824320,
62002450432,
62005186560,
62006108160,
62014894080,
62023741440,
62230065152,
62246010880,
62250319872,
62234144768,
62227582976,
62226890752,
62392664064
],
"disk_read_mb": [
null,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.01,
0.0,
0.0,
0.0,
0.0,
28.33,
101.36,
41.6,
10.77,
0.0,
0.01,
0.0,
0.0
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
]
},
"time": 1790719226.4537745
}
}
@@ -0,0 +1,755 @@
{
"label": "native-v0.1.26-IQ3_XXS-2x3090-auto-two-turn",
"mode": "two-turn",
"ctx": "16k",
"target_tokens": 16384,
"run": 1,
"run_id": "dedda4f9d6be",
"corpus_repeated": false,
"time": "2026-09-29T22:01:09",
"prompt_tokens": 15635,
"completion_tokens": 44,
"ttft_s": 13.63,
"e2e_s": 14.13,
"api_prompt_tps": 1147.1,
"api_decode_tps": 86.1,
"engine_prompt_tps": 1154.6,
"engine_decode_tps": 85.6,
"log_lines": [
"strata serve: prompt 15635 tokens = 0 reused + 15635 read in 13541 ms (1154.6 tok/s), 44 generated in 514 ms (85.6 tok/s), drafts accepted 30 of 36, 1 checkpoints",
"strata serve: decode expert cache hit rate: 97.9% (24433 hits / 24957 lookups)"
],
"answer_head": "I'll start by exploring the repository structure to understand the context better.",
"turn2_ttft_s": 0.577,
"turn2_prompt_tokens": 15672,
"turn2_log_lines": [
"strata serve: prompt 15672 tokens = 15628 reused + 44 read in 490 ms (89.8 tok/s), 48 generated in 567 ms (84.6 tok/s), drafts accepted 28 of 43, 2 checkpoints",
"strata serve: decode expert cache hit rate: 98.6% (31236 hits / 31679 lookups)"
],
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 11883,
"expert_cache_mib": 17564,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 645,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790719284.681533,
"duration_s": 1.1,
"finish": "stop",
"prompt_tokens": 15672,
"reused": 15628,
"output_tokens": 48,
"engine_generated": 48,
"prompt_ms": 490.1,
"decode_ms": 567.1,
"decode_tok_s": 84.6,
"hit_rate": 0.986
},
{
"projection": null,
"time": 1790719270.0522854,
"duration_s": 14.1,
"finish": "stop",
"prompt_tokens": 15635,
"reused": 0,
"output_tokens": 44,
"engine_generated": 44,
"prompt_ms": 13541.4,
"decode_ms": 513.7,
"decode_tok_s": 85.7,
"hit_rate": 0.979
},
{
"projection": null,
"time": 1790719242.7790127,
"duration_s": 26.1,
"finish": "stop",
"prompt_tokens": 29825,
"reused": 0,
"output_tokens": 9,
"engine_generated": 9,
"prompt_ms": 26008.5,
"decode_ms": 86.6,
"decode_tok_s": 103.9,
"hit_rate": 0.982
},
{
"projection": null,
"time": 1790719226.530526,
"duration_s": 15.6,
"finish": "stop",
"prompt_tokens": 17344,
"reused": 0,
"output_tokens": 8,
"engine_generated": 8,
"prompt_ms": 15486.8,
"decode_ms": 95.5,
"decode_tok_s": 83.8,
"hit_rate": 0.973
},
{
"projection": null,
"time": 1790719217.9333243,
"duration_s": 8.0,
"finish": "stop",
"prompt_tokens": 7493,
"reused": 0,
"output_tokens": 9,
"engine_generated": 9,
"prompt_ms": 7861.5,
"decode_ms": 153.7,
"decode_tok_s": 58.6,
"hit_rate": 0.94
}
],
"requests_kept": 5,
"totals": {
"since": 1790719202.7795203,
"requests": 5,
"prompt_tokens": 85969,
"reused": 15628,
"output_tokens": 118,
"prompt_ms": 63388.3,
"decode_ms": 1416.6
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 15,
"mem_used": 25191972864,
"mem_total": 25769803776,
"temp": 48,
"power": 148.771
},
{
"index": 1,
"util": 0,
"mem_used": 24206311424,
"mem_total": 25769803776,
"temp": 51,
"power": 169.566
}
],
"gpu_util": 7.5,
"gpu_mem_used": 49398284288,
"gpu_mem_total": 51539607552,
"gpu_temp": 51,
"gpu_power": 318.337,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 26.1298828125,
"gpu_pcie_tx_mb": 56.265625,
"cpu": 39.7,
"ram_used": 63088369664,
"ram_total": 177175990272,
"disk_read_mb": 1.2843527404984159,
"disk_write_mb": 0.0035875774874257423,
"tok_s": 52.0,
"tok_s_mean": 89.37171592337687
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
23.5,
31.0,
56.5,
23.5,
20.5,
0.5,
70.5,
22.5,
26.5,
56.0,
29.0,
77.0,
11.0,
28.5,
59.5,
28.5,
19.5,
17.0,
27.0,
20.0,
0.0,
60.5,
25.5,
71.0,
67.0,
26.5,
26.5,
85.0,
26.0,
73.5,
49.5,
25.0,
48.0,
32.0,
76.5,
9.0,
27.5,
47.5,
30.0,
62.5,
15.5,
31.5,
29.0,
39.5,
13.0,
0.0,
69.5,
24.0,
30.5,
61.5,
27.0,
62.5,
17.0,
26.5,
53.5,
23.5,
29.5,
29.0,
41.0,
7.5
],
"gpu_mem_used": [
49291329536,
49291329536,
49291329536,
49291329536,
49291329536,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49356341248,
49398284288,
49398284288
],
"gpu_temp": [
53,
52,
52,
52,
53,
49,
51,
52,
52,
53,
53,
53,
52,
53,
51,
53,
53,
53,
53,
54,
50,
51,
53,
53,
52,
54,
52,
52,
53,
53,
53,
53,
52,
53,
54,
52,
53,
52,
53,
52,
52,
54,
53,
54,
52,
50,
51,
53,
54,
52,
54,
53,
53,
54,
53,
53,
54,
55,
53,
51
],
"gpu_power": [
409.13,
432.67,
433.1,
400.92,
389.08,
278.03,
383.36,
392.74,
440.94,
403.62,
421.29,
427.09,
407.67,
422.11,
423.13,
417.76,
440.15,
377.19,
403.8,
385.27,
299.57,
398.78,
401.71,
449.87,
430.87,
402.83,
439.43,
401.46,
455.62,
425.18,
404.39,
417.35,
406.87,
423.67,
422.86,
404.6,
421.5,
402.4,
422.71,
432.67,
398.05,
455.72,
434.46,
403.83,
385.61,
282.41,
360.22,
446.82,
449.66,
410.55,
427.9,
441.96,
389.46,
451.44,
439.2,
402.13,
441.82,
408.98,
365.37,
318.34
],
"gpu_pcie_rx_mb": [
3838.3,
4927.82,
4008.2,
7314.58,
0.95,
1338.19,
7892.51,
3024.72,
5741.74,
2921.96,
5454.83,
5667.49,
3768.87,
6803.13,
8164.64,
2711.1,
5725.29,
6417.89,
0.67,
1.76,
1343.92,
7796.67,
10809.8,
5598.92,
3013.99,
91.89,
4693.79,
5621.38,
5381.87,
7487.25,
2228.12,
7344.77,
3943.44,
0.81,
5476.19,
2437.4,
6693.74,
3836.63,
7843.59,
5638.65,
2853.11,
8215.43,
8500.96,
4445.79,
0.67,
0.62,
4431.82,
4655.12,
7505.13,
4915.86,
7990.69,
6352.23,
3326.13,
3696.82,
7077.12,
4858.06,
5613.99,
7732.68,
0.67,
26.13
],
"cpu": [
10.5,
10.5,
13.4,
9.0,
12.2,
23.9,
8.1,
16.5,
13.0,
13.0,
9.0,
9.7,
12.8,
8.6,
12.9,
10.4,
8.6,
9.0,
9.4,
9.1,
16.9,
17.1,
22.7,
7.5,
10.8,
8.9,
7.3,
7.3,
8.3,
7.7,
9.8,
6.9,
12.4,
6.4,
12.2,
20.6,
19.9,
11.0,
8.1,
10.3,
9.8,
7.6,
8.1,
7.3,
16.6,
7.1,
8.3,
7.7,
7.5,
19.7,
13.3,
9.8,
12.2,
12.2,
11.3,
11.1,
11.3,
11.7,
49.6,
39.7
],
"ram_used": [
62250319872,
62234144768,
62227582976,
62226890752,
62392664064,
62490071040,
62486704128,
62515294208,
62517342208,
62467452928,
62510080000,
62495842304,
62471684096,
62463819776,
62459879424,
62443171840,
62374465536,
62303469568,
62390607872,
62596341760,
62489825280,
62562496512,
62577270784,
62577836032,
62576951296,
62564986880,
62553812992,
62539886592,
62533107712,
62521810944,
62503256064,
62503677952,
62490673152,
62492131328,
62495432704,
62503706624,
62769029120,
62766465024,
62765707264,
62747688960,
62726733824,
62717767680,
62722011136,
62728314880,
62951010304,
62691995648,
62677225472,
62661165056,
62640271360,
62636351488,
62633791488,
62731657216,
62747160576,
62744502272,
62746267648,
62732316672,
62762123264,
62711451648,
62861885440,
63088369664
],
"disk_read_mb": [
10.77,
0.0,
0.01,
0.0,
0.0,
1.06,
0.0,
14.72,
0.0,
56.04,
0.0,
33.79,
66.18,
16.29,
83.86,
33.38,
0.0,
0.0,
0.0,
0.0,
0.73,
0.0,
0.0,
0.0,
0.22,
0.0,
0.0,
0.14,
0.0,
0.53,
47.85,
0.0,
71.37,
0.0,
78.98,
55.42,
22.25,
53.69,
0.0,
54.32,
39.07,
0.0,
0.0,
0.0,
0.09,
0.58,
0.02,
0.01,
0.0,
0.03,
0.0,
2.6,
6.44,
7.35,
8.08,
4.14,
2.09,
0.01,
2.47,
1.28
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
52.0
]
},
"time": 1790719286.2452984
}
}
@@ -0,0 +1,612 @@
{
"label": "native-v0.1.26-IQ3_XXS-2x3090-auto",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 1,
"run_id": "cfa75b59eb61",
"corpus_repeated": false,
"time": "2026-09-29T21:39:52",
"prompt_tokens": 28314,
"completion_tokens": 256,
"ttft_s": 26.573,
"e2e_s": 29.595,
"api_prompt_tps": 1065.5,
"api_decode_tps": 84.4,
"engine_prompt_tps": 1071.8,
"engine_decode_tps": 83.7,
"log_lines": [
"strata serve: prompt 28314 tokens = 0 reused + 28314 read in 26417 ms (1071.8 tok/s), 256 generated in 3058 ms (83.7 tok/s), drafts accepted 147 of 251, 2 checkpoints",
"strata serve: decode expert cache hit rate: 98.9% (171443 hits / 173268 lookups)"
],
"answer_head": "The last file in the repository listing is `docs/DETAILS.md`.\n\n### What `docs/DETAILS.md` does\n\nIt is the comprehensive technical documentation and reference manual for the Strata engine. While the `README.md` focuses on quick installation and high-level usage, `DETAILS.md` provides the deep technic",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 11883,
"expert_cache_mib": 17564,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 645,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790717992.6885722,
"duration_s": 29.5,
"finish": "length",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 26416.6,
"decode_ms": 3057.9,
"decode_tok_s": 83.7,
"hit_rate": 0.989
}
],
"requests_kept": 1,
"totals": {
"since": 1790717968.2500567,
"requests": 1,
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 256,
"prompt_ms": 26416.6,
"decode_ms": 3057.9
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 44,
"mem_used": 25196167168,
"mem_total": 25769803776,
"temp": 52,
"power": 244.795
},
{
"index": 1,
"util": 0,
"mem_used": 24208408576,
"mem_total": 25769803776,
"temp": 52,
"power": 218.413
}
],
"gpu_util": 22.0,
"gpu_mem_used": 49404575744,
"gpu_mem_total": 51539607552,
"gpu_temp": 52,
"gpu_power": 463.20799999999997,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 0.666015625,
"gpu_pcie_tx_mb": 0.857421875,
"cpu": 60.1,
"ram_used": 62328995840,
"ram_total": 177175990272,
"disk_read_mb": 3.420667733965059,
"disk_write_mb": 0.02523147959721329,
"tok_s": 0.0,
"tok_s_mean": 0.0
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
49.5,
21.5,
58.5,
25.5,
31.5,
24.0,
25.0,
35.0,
27.0,
64.5,
29.0,
24.5,
24.5,
27.0,
16.0,
26.0,
59.5,
24.5,
28.5,
48.0,
26.5,
29.0,
31.0,
3.0,
46.0,
46.0,
22.0
],
"gpu_mem_used": [
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49205346304,
49278746624,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49383604224,
49404575744,
49404575744,
49404575744
],
"gpu_temp": [
50,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
49,
50,
49,
46,
46,
46,
46,
46,
46,
48,
52,
53,
53,
53,
53,
54,
54,
53,
54,
53,
53,
54,
54,
54,
52,
55,
53,
54,
55,
54,
54,
54,
55,
53,
55,
55,
52
],
"gpu_power": [
260.95,
248.93,
247.54,
246.62,
246.82,
246.65,
246.9,
246.83,
246.8,
246.68,
246.72,
246.75,
246.63,
246.53,
246.57,
246.83,
236.89,
159.99,
79.32,
65.35,
64.71,
64.62,
64.91,
91.65,
314.3,
428.65,
367.67,
455.67,
441.66,
390.44,
440.16,
375.92,
453.54,
370.98,
401.8,
438.74,
379.04,
440.69,
353.57,
419.67,
435.26,
406.67,
447.91,
390.07,
459.5,
448.73,
405.61,
374.45,
407.02,
468.77,
463.21
],
"gpu_pcie_rx_mb": [
0.67,
0.62,
0.62,
0.67,
0.57,
7.87,
0.62,
0.62,
0.67,
0.62,
0.62,
0.57,
0.62,
0.62,
1.38,
0.57,
0.76,
0.86,
0.91,
0.81,
0.86,
0.86,
0.81,
539.92,
4704.14,
5432.94,
3021.19,
4790.88,
4142.71,
2301.69,
8161.88,
3244.83,
5099.68,
7126.09,
2825.64,
6742.29,
2064.18,
5534.93,
4369.31,
7614.9,
4834.13,
2332.54,
7141.88,
4942.8,
3514.62,
5720.52,
6970.74,
14.21,
15.78,
30.52,
0.67
],
"cpu": [
0.0,
14.3,
2.7,
0.9,
1.7,
1.5,
2.1,
1.3,
1.5,
1.3,
1.2,
2.2,
1.2,
0.9,
1.2,
19.1,
3.1,
3.2,
2.2,
1.9,
2.8,
2.0,
4.5,
12.1,
9.2,
7.1,
7.5,
5.5,
13.3,
15.7,
18.9,
15.5,
7.4,
9.3,
7.1,
10.1,
9.1,
6.1,
9.7,
7.4,
9.1,
9.2,
13.5,
15.4,
6.6,
8.7,
6.0,
28.4,
94.8,
99.5,
60.1
],
"ram_used": [
61824409600,
61846106112,
61853241344,
61854605312,
61855711232,
61855694848,
61853442048,
61858058240,
61861154816,
61861928960,
61862432768,
61867282432,
61861072896,
61856456704,
61880406016,
61890236416,
61890191360,
61887963136,
61887766528,
61882646528,
61870043136,
61879148544,
61934235648,
61984825344,
62089637888,
62090121216,
62098157568,
62098403328,
62088568832,
62106021888,
61750501376,
61766746112,
61776080896,
61778165760,
61779779584,
61908017152,
61907206144,
61910032384,
62031020032,
62033805312,
62032531456,
61967249408,
61974036480,
61990858752,
61985890304,
61979660288,
61980233728,
62277226496,
62302523392,
62302191616,
62328995840
],
"disk_read_mb": [
null,
0.01,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
103.38,
66.8,
0.0,
24.38,
0.0,
55.65,
33.54,
0.11,
67.43,
0.0,
83.76,
1.78,
79.2,
71.21,
0.0,
79.44,
0.0,
77.02,
53.81,
0.7,
42.73,
0.0,
0.0,
0.0,
1.02,
5.65,
4.98,
3.42
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
48.0,
86.94,
102.06,
0.0
]
},
"time": 1790718022.6741135
}
}
@@ -0,0 +1,707 @@
{
"label": "native-v0.1.26-IQ3_XXS-2x3090-auto",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 2,
"run_id": "c27c8adc0b65",
"corpus_repeated": false,
"time": "2026-09-29T21:40:22",
"prompt_tokens": 31633,
"completion_tokens": 256,
"ttft_s": 26.904,
"e2e_s": 29.536,
"api_prompt_tps": 1175.8,
"api_decode_tps": 96.9,
"engine_prompt_tps": 1185.2,
"engine_decode_tps": 96.7,
"log_lines": [
"strata serve: prompt 31633 tokens = 0 reused + 31633 read in 26691 ms (1185.2 tok/s), 256 generated in 2648 ms (96.7 tok/s), drafts accepted 160 of 214, 2 checkpoints",
"strata serve: decode expert cache hit rate: 99.1% (147426 hits / 148799 lookups)"
],
"answer_head": "I cannot analyze the last file because the provided repository content is truncated. The `docs/DETAILS.md` file cuts off mid-sentence in the \"Using it\" section (`...if y`), and no subsequent files are shown.\n\nHowever, I can analyze the **`chat.py`** file, which is the last *complete* file provided i",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 11883,
"expert_cache_mib": 17564,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 645,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790718022.860633,
"duration_s": 29.4,
"finish": "length",
"prompt_tokens": 31633,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 26690.6,
"decode_ms": 2648.4,
"decode_tok_s": 96.7,
"hit_rate": 0.991
},
{
"projection": null,
"time": 1790717992.6885722,
"duration_s": 29.5,
"finish": "length",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 26416.6,
"decode_ms": 3057.9,
"decode_tok_s": 83.7,
"hit_rate": 0.989
}
],
"requests_kept": 2,
"totals": {
"since": 1790717968.2500567,
"requests": 2,
"prompt_tokens": 59947,
"reused": 0,
"output_tokens": 512,
"prompt_ms": 53107.2,
"decode_ms": 5706.3
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 37,
"mem_used": 25196167168,
"mem_total": 25769803776,
"temp": 51,
"power": 209.254
},
{
"index": 1,
"util": 55,
"mem_used": 24208408576,
"mem_total": 25769803776,
"temp": 55,
"power": 248.664
}
],
"gpu_util": 46.0,
"gpu_mem_used": 49404575744,
"gpu_mem_total": 51539607552,
"gpu_temp": 55,
"gpu_power": 457.918,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 30.46875,
"gpu_pcie_tx_mb": 164.2216796875,
"cpu": 97.1,
"ram_used": 62326792192,
"ram_total": 177175990272,
"disk_read_mb": 4.657722192080744,
"disk_write_mb": 0.11106875996500236,
"tok_s": 102.58306863780025,
"tok_s_mean": 98.12574884260572
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
49.5,
21.5,
58.5,
25.5,
31.5,
24.0,
25.0,
35.0,
27.0,
64.5,
29.0,
24.5,
24.5,
27.0,
16.0,
26.0,
59.5,
24.5,
28.5,
48.0,
26.5,
29.0,
31.0,
3.0,
46.0,
46.0,
22.0,
59.5,
29.0,
60.0,
26.0,
31.5,
71.0,
32.5,
28.0,
66.0,
23.5,
24.5,
18.5,
29.0,
28.0,
78.0,
30.0,
73.5,
16.0,
28.0,
25.0,
28.0,
29.0,
66.0,
26.5,
18.5,
43.5,
46.0
],
"gpu_mem_used": [
49192763392,
49192763392,
49192763392,
49192763392,
49192763392,
49205346304,
49278746624,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49295523840,
49383604224,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744
],
"gpu_temp": [
46,
46,
46,
46,
46,
48,
52,
53,
53,
53,
53,
54,
54,
53,
54,
53,
53,
54,
54,
54,
52,
55,
53,
54,
55,
54,
54,
54,
55,
53,
55,
55,
52,
52,
54,
54,
54,
55,
55,
55,
54,
54,
54,
54,
54,
54,
54,
55,
55,
55,
54,
55,
54,
55,
55,
55,
55,
53,
55,
55
],
"gpu_power": [
79.32,
65.35,
64.71,
64.62,
64.91,
91.65,
314.3,
428.65,
367.67,
455.67,
441.66,
390.44,
440.16,
375.92,
453.54,
370.98,
401.8,
438.74,
379.04,
440.69,
353.57,
419.67,
435.26,
406.67,
447.91,
390.07,
459.5,
448.73,
405.61,
374.45,
407.02,
468.77,
463.21,
376.39,
436.62,
444.21,
398.6,
447.75,
406.3,
391.79,
452.85,
427.37,
418.5,
444.64,
378.02,
407.95,
435.96,
404.27,
456.87,
440.61,
401.93,
421.84,
438.49,
398.65,
446.07,
421.03,
422.3,
368.39,
434.33,
457.92
],
"gpu_pcie_rx_mb": [
0.91,
0.81,
0.86,
0.86,
0.81,
539.92,
4704.14,
5432.94,
3021.19,
4790.88,
4142.71,
2301.69,
8161.88,
3244.83,
5099.68,
7126.09,
2825.64,
6742.29,
2064.18,
5534.93,
4369.31,
7614.9,
4834.13,
2332.54,
7141.88,
4942.8,
3514.62,
5720.52,
6970.74,
14.21,
15.78,
30.52,
0.67,
4175.19,
7742.45,
4905.89,
4411.55,
4744.0,
6063.36,
4488.9,
7846.78,
7336.33,
4790.3,
4790.26,
4959.82,
3664.44,
6053.92,
4708.72,
5601.93,
6957.58,
5201.77,
7840.16,
7413.0,
3656.91,
7095.34,
5569.93,
6273.89,
9.44,
21.46,
30.47
],
"cpu": [
2.2,
1.9,
2.8,
2.0,
4.5,
12.1,
9.2,
7.1,
7.5,
5.5,
13.3,
15.7,
18.9,
15.5,
7.4,
9.3,
7.1,
10.1,
9.1,
6.1,
9.7,
7.4,
9.1,
9.2,
13.5,
15.4,
6.6,
8.7,
6.0,
28.4,
94.8,
99.5,
60.1,
6.9,
5.7,
6.7,
6.1,
6.3,
13.9,
10.0,
6.4,
7.2,
5.7,
6.4,
6.6,
6.1,
5.5,
6.3,
6.6,
7.5,
6.5,
6.4,
17.9,
10.2,
6.4,
7.9,
6.6,
24.8,
93.3,
97.1
],
"ram_used": [
61887766528,
61882646528,
61870043136,
61879148544,
61934235648,
61984825344,
62089637888,
62090121216,
62098157568,
62098403328,
62088568832,
62106021888,
61750501376,
61766746112,
61776080896,
61778165760,
61779779584,
61908017152,
61907206144,
61910032384,
62031020032,
62033805312,
62032531456,
61967249408,
61974036480,
61990858752,
61985890304,
61979660288,
61980233728,
62277226496,
62302523392,
62302191616,
62328995840,
62040481792,
62030888960,
62024949760,
62010191872,
62003638272,
62026113024,
62011977728,
61980151808,
61970239488,
61954445312,
61954318336,
61948420096,
61997678592,
62080253952,
62075203584,
62075965440,
62076403712,
62076399616,
62070407168,
62091988992,
62091988992,
62093479936,
62097862656,
62095917056,
62331494400,
62325518336,
62326792192
],
"disk_read_mb": [
0.0,
0.0,
0.0,
0.0,
0.0,
103.38,
66.8,
0.0,
24.38,
0.0,
55.65,
33.54,
0.11,
67.43,
0.0,
83.76,
1.78,
79.2,
71.21,
0.0,
79.44,
0.0,
77.02,
53.81,
0.7,
42.73,
0.0,
0.0,
0.0,
1.02,
5.65,
4.98,
3.42,
0.54,
0.0,
0.01,
0.02,
0.0,
0.02,
0.03,
0.0,
0.03,
0.02,
0.0,
0.01,
0.0,
0.01,
0.02,
0.0,
0.0,
12.64,
0.0,
71.65,
32.97,
0.0,
0.0,
0.0,
0.99,
5.21,
4.66
],
"tok_s": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
48.0,
86.94,
102.06,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
56.0,
103.48,
102.58
]
},
"time": 1790718052.712857
}
}
@@ -0,0 +1,721 @@
{
"label": "native-v0.1.26-IQ3_XXS-2x3090-auto",
"mode": "speed",
"ctx": "32k",
"target_tokens": 31488,
"run": 3,
"run_id": "60c6cbe1b14a",
"corpus_repeated": false,
"time": "2026-09-29T21:40:52",
"prompt_tokens": 31603,
"completion_tokens": 256,
"ttft_s": 27.476,
"e2e_s": 30.102,
"api_prompt_tps": 1150.2,
"api_decode_tps": 97.1,
"engine_prompt_tps": 1158.9,
"engine_decode_tps": 96.9,
"log_lines": [
"strata serve: prompt 31603 tokens = 0 reused + 31603 read in 27271 ms (1158.9 tok/s), 256 generated in 2641 ms (96.9 tok/s), drafts accepted 154 of 209, 2 checkpoints",
"strata serve: decode expert cache hit rate: 99.6% (148622 hits / 149275 lookups)"
],
"answer_head": "An analysis of the last file (`docs/DETAILS.md`) and a proposed improvement follows.\n\n### What the file does\n\n`docs/DETAILS.md` serves as the comprehensive technical manual for the Strata engine. It bridges the gap between the high-level marketing in the `README.md` and the raw source code. Specific",
"metrics_after": {
"engine": {
"model": "qwen3.8-flash-next-iq3_xxs",
"max_context": 32768,
"images": false,
"version": "0.1.26",
"context": 32768,
"kv": "int8",
"kv_resident": 0,
"expert_slots": 11883,
"expert_cache_mib": 17564,
"spec": 6,
"mtp_max": 4,
"lookup": 3,
"vram_free_mib": 645,
"cvec": 0,
"arena_mib": 40925,
"pool_workers": 19,
"pcie_frac": "0.55",
"spec_min_p": "0.50",
"engine": "0.1.26"
},
"live": {
"state": "idle",
"queued": 0,
"phase": null,
"prompt_tokens": null,
"prompt_read": null,
"prompt_total": null,
"generated": null,
"max_tokens": null,
"elapsed_s": null,
"tok_s": null,
"tok_s_mean": null,
"tok_s_window_s": null
},
"requests": [
{
"projection": null,
"time": 1790718052.8930452,
"duration_s": 29.9,
"finish": "length",
"prompt_tokens": 31603,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 27270.7,
"decode_ms": 2641.1,
"decode_tok_s": 96.9,
"hit_rate": 0.996
},
{
"projection": null,
"time": 1790718022.860633,
"duration_s": 29.4,
"finish": "length",
"prompt_tokens": 31633,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 26690.6,
"decode_ms": 2648.4,
"decode_tok_s": 96.7,
"hit_rate": 0.991
},
{
"projection": null,
"time": 1790717992.6885722,
"duration_s": 29.5,
"finish": "length",
"prompt_tokens": 28314,
"reused": 0,
"output_tokens": 256,
"engine_generated": 256,
"prompt_ms": 26416.6,
"decode_ms": 3057.9,
"decode_tok_s": 83.7,
"hit_rate": 0.989
}
],
"requests_kept": 3,
"totals": {
"since": 1790717968.2500567,
"requests": 3,
"prompt_tokens": 91550,
"reused": 0,
"output_tokens": 768,
"prompt_ms": 80377.9,
"decode_ms": 8347.4
},
"hardware": {
"gpus": [
{
"index": 0,
"util": 43,
"mem_used": 25196167168,
"mem_total": 25769803776,
"temp": 52,
"power": 242.95
},
{
"index": 1,
"util": 65,
"mem_used": 24208408576,
"mem_total": 25769803776,
"temp": 55,
"power": 253.875
}
],
"gpu_util": 54.0,
"gpu_mem_used": 49404575744,
"gpu_mem_total": 51539607552,
"gpu_temp": 55,
"gpu_power": 496.825,
"gpu_power_limit": 560.0,
"gpu_pcie_gen": 4,
"gpu_pcie_gen_max": 4,
"gpu_pcie_width": 16,
"gpu_pcie_rx_mb": 11.77734375,
"gpu_pcie_tx_mb": 120.830078125,
"cpu": 85.4,
"ram_used": 62122582016,
"ram_total": 177175990272,
"disk_read_mb": 2.9330443322466575,
"disk_write_mb": 0.08616042102070966,
"tok_s": 82.32972941826796,
"tok_s_mean": 95.05553044960695
},
"hardware_static": {
"gpu_name": "NVIDIA GeForce RTX 3090 + NVIDIA GeForce RTX 3090",
"gpu_count": 2,
"cpu_name": "AMD EPYC 7453 28-Core Processor",
"cores": 20,
"threads": 20,
"psutil": true
},
"history": {
"gpu_util": [
31.0,
3.0,
46.0,
46.0,
22.0,
59.5,
29.0,
60.0,
26.0,
31.5,
71.0,
32.5,
28.0,
66.0,
23.5,
24.5,
18.5,
29.0,
28.0,
78.0,
30.0,
73.5,
16.0,
28.0,
25.0,
28.0,
29.0,
66.0,
26.5,
18.5,
43.5,
46.0,
0.0,
64.5,
26.0,
23.0,
72.5,
27.0,
66.0,
24.5,
76.5,
60.5,
27.5,
57.5,
24.5,
32.0,
66.5,
26.0,
27.0,
64.5,
29.5,
52.5,
65.5,
24.0,
23.5,
85.0,
30.5,
9.5,
46.0,
54.0
],
"gpu_mem_used": [
49295523840,
49383604224,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744,
49404575744
],
"gpu_temp": [
55,
53,
55,
55,
52,
52,
54,
54,
54,
55,
55,
55,
54,
54,
54,
54,
54,
54,
54,
55,
55,
55,
54,
55,
54,
55,
55,
55,
55,
53,
55,
55,
53,
54,
55,
55,
54,
55,
55,
55,
56,
54,
55,
55,
55,
55,
55,
55,
55,
54,
55,
55,
55,
55,
56,
55,
56,
54,
56,
55
],
"gpu_power": [
405.61,
374.45,
407.02,
468.77,
463.21,
376.39,
436.62,
444.21,
398.6,
447.75,
406.3,
391.79,
452.85,
427.37,
418.5,
444.64,
378.02,
407.95,
435.96,
404.27,
456.87,
440.61,
401.93,
421.84,
438.49,
398.65,
446.07,
421.03,
422.3,
368.39,
434.33,
457.92,
400.91,
379.28,
435.92,
440.53,
380.92,
451.07,
408.21,
436.33,
435.94,
414.69,
425.45,
442.33,
389.05,
457.45,
433.14,
411.6,
454.98,
417.2,
434.56,
447.81,
430.75,
413.26,
446.25,
404.97,
437.77,
402.11,
426.81,
496.82
],
"gpu_pcie_rx_mb": [
6970.74,
14.21,
15.78,
30.52,
0.67,
4175.19,
7742.45,
4905.89,
4411.55,
4744.0,
6063.36,
4488.9,
7846.78,
7336.33,
4790.3,
4790.26,
4959.82,
3664.44,
6053.92,
4708.72,
5601.93,
6957.58,
5201.77,
7840.16,
7413.0,
3656.91,
7095.34,
5569.93,
6273.89,
9.44,
21.46,
30.47,
0.67,
4040.72,
6771.71,
4774.76,
3710.08,
6013.11,
4218.43,
89.64,
5065.25,
4264.21,
7538.94,
3521.39,
1962.57,
7673.88,
4194.59,
12185.76,
7580.33,
5805.73,
5337.71,
5530.07,
5019.52,
94.17,
4176.62,
7140.59,
4804.28,
0.62,
11.11,
11.78
],
"cpu": [
6.0,
28.4,
94.8,
99.5,
60.1,
6.9,
5.7,
6.7,
6.1,
6.3,
13.9,
10.0,
6.4,
7.2,
5.7,
6.4,
6.6,
6.1,
5.5,
6.3,
6.6,
7.5,
6.5,
6.4,
17.9,
10.2,
6.4,
7.9,
6.6,
24.8,
93.3,
97.1,
28.6,
7.9,
6.3,
6.6,
5.7,
7.6,
16.1,
12.3,
6.8,
6.9,
6.2,
7.1,
5.6,
6.4,
6.7,
5.7,
7.5,
6.5,
6.0,
8.4,
15.8,
7.4,
8.5,
6.1,
5.7,
7.0,
74.1,
85.4
],
"ram_used": [
61980233728,
62277226496,
62302523392,
62302191616,
62328995840,
62040481792,
62030888960,
62024949760,
62010191872,
62003638272,
62026113024,
62011977728,
61980151808,
61970239488,
61954445312,
61954318336,
61948420096,
61997678592,
62080253952,
62075203584,
62075965440,
62076403712,
62076399616,
62070407168,
62091988992,
62091988992,
62093479936,
62097862656,
62095917056,
62331494400,
62325518336,
62326792192,
62020993024,
62018838528,
62010839040,
62003871744,
61990277120,
61970149376,
61773103104,
61820641280,
61810376704,
61790760960,
61782196224,
61814075392,
61809737728,
61808422912,
61930074112,
61927755776,
61912608768,
61800587264,
61798178816,
61793333248,
61882507264,
61882978304,
61885661184,
61886173184,
61886357504,
62129778688,
62122844160,
62122582016
],
"disk_read_mb": [
0.0,
1.02,
5.65,
4.98,
3.42,
0.54,
0.0,
0.01,
0.02,
0.0,
0.02,
0.03,
0.0,
0.03,
0.02,
0.0,
0.01,
0.0,
0.01,
0.02,
0.0,
0.0,
12.64,
0.0,
71.65,
32.97,
0.0,
0.0,
0.0,
0.99,
5.21,
4.66,
2.02,
0.04,
0.0,
0.02,
0.04,
0.0,
0.04,
0.0,
0.05,
0.05,
0.0,
0.05,
0.04,
0.0,
0.04,
0.04,
0.0,
0.02,
0.03,
0.0,
0.01,
0.0,
0.16,
0.0,
0.0,
0.0,
3.86,
2.93
],
"tok_s": [
0.0,
48.0,
86.94,
102.06,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
56.0,
103.48,
102.58,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
114.9,
82.33
]
},
"time": 1790718083.3185816
}
}
@@ -0,0 +1,304 @@
#!/usr/bin/env python3
"""Strata benchmark harness (contribution plan, PR 1 step 1.2).
Follows the upstream method (bench/results/2026-09-28-speed-0114): one code-agent prompt per
length, greedy, 256 generated tokens, MTP as configured by setup. Every run gets a unique
prefix, so conversation checkpoints cannot skip the prompt. Numbers come from the engine log
lines the owner asks for in issue #74. /metrics and API timing are stored as cross-checks.
Stdlib only. Examples:
./strata-bench.py --label IQ3_XXS-1x3090 --log ./strata-iq3_xxs.log
./strata-bench.py --label Coder-2x3090-auto --contexts 16k,28k --mode needle
./strata-bench.py --url http://127.0.0.1:9292 --model flash-next-strata --label via-llama-swap
"""
import argparse
import json
import os
import re
import statistics
import sys
import time
import urllib.error
import urllib.request
import uuid
from datetime import datetime
from pathlib import Path
NOMINAL = {"1k": 1024, "2.7k": 2765, "4k": 4096, "8k": 8192, "16k": 16384, "28k": 28672,
"32k": 32768, "64k": 65536, "128k": 131072, "262k": 262144}
CODE_EXT = {".py", ".cpp", ".cc", ".h", ".hpp", ".cu", ".cuh", ".js", ".md", ".txt", ".cmake"}
SKIP_DIRS = {".git", ".venv", "build", "engine", "third_party", "node_modules", "models",
"packs", "mtp", "bench", "data", "__pycache__", "Strata-data"}
LOG_PATTERNS = [
re.compile(r"decode expert cache hit rate", re.I),
re.compile(r"\bPCIe\b"),
re.compile(r"prompt .*tok/s.*generated .*tok/s", re.I),
re.compile(r"reus|checkpoint", re.I),
re.compile(r"layer split", re.I),
]
TOKS_PER_S = re.compile(r"([\d][\d,]*(?:\.\d+)?)\s*tok(?:ens)?/s", re.I)
def load_corpus(dirs):
parts = []
for d in dirs:
root = Path(d)
for p in sorted(root.rglob("*")):
if p.suffix.lower() not in CODE_EXT or not p.is_file():
continue
if any(s in SKIP_DIRS for s in p.relative_to(root).parts[:-1]):
continue
text = p.read_text(encoding="utf-8", errors="ignore")
if text.strip():
parts.append(f"### {p.relative_to(root).as_posix()}\n```\n{text}\n```\n")
if not parts:
sys.exit(f"no source files found in {dirs}")
return parts
def build_text(parts, n_chars):
out, size, i, repeated = [], 0, 0, False
while size < n_chars:
if i and i % len(parts) == 0:
repeated = True
chunk = parts[i % len(parts)]
out.append(chunk)
size += len(chunk)
i += 1
return "".join(out)[:n_chars], repeated
def post_stream(url, payload, api_key, timeout):
req = urllib.request.Request(
f"{url}/v1/chat/completions", data=json.dumps(payload).encode(),
headers={"Content-Type": "application/json", "Authorization": f"Bearer {api_key or 'none'}"})
t0 = time.perf_counter()
t_first, text, reasoning, usage, chunks = None, [], [], {}, 0
with urllib.request.urlopen(req, timeout=timeout) as resp:
for raw in resp:
line = raw.decode("utf-8", errors="ignore").strip()
if not line.startswith("data:"):
continue
data = line[5:].strip()
if data == "[DONE]":
break
try:
chunk = json.loads(data)
except json.JSONDecodeError:
continue
if chunk.get("usage"):
usage = chunk["usage"]
for ch in chunk.get("choices") or []:
delta = ch.get("delta") or {}
piece = delta.get("content") or ""
rpiece = delta.get("reasoning_content") or ""
if (piece or rpiece) and t_first is None:
t_first = time.perf_counter()
if piece or rpiece:
chunks += 1
text.append(piece)
reasoning.append(rpiece)
t_end = time.perf_counter()
return {"t_start": t0, "t_first": t_first or t_end, "t_end": t_end, "text": "".join(text),
"reasoning": "".join(reasoning), "usage": usage, "chunks": chunks}
def get_json(url, path, api_key, timeout=10):
try:
req = urllib.request.Request(f"{url}{path}", headers={"Authorization": f"Bearer {api_key or 'none'}"})
with urllib.request.urlopen(req, timeout=timeout) as r:
body = r.read().decode("utf-8", errors="ignore")
try:
return json.loads(body)
except json.JSONDecodeError:
return body
except (urllib.error.URLError, TimeoutError) as e:
return {"error": str(e)}
def wait_healthy(url, api_key, timeout):
deadline = time.time() + timeout
while time.time() < deadline:
h = get_json(url, "/health", api_key, timeout=5)
if not (isinstance(h, dict) and "error" in h):
return True
time.sleep(5)
return False
def log_offset(log):
return log.stat().st_size if log and log.exists() else 0
def log_lines_since(log, offset):
if not log or not log.exists():
return []
time.sleep(0.5)
with log.open("r", encoding="utf-8", errors="ignore") as f:
f.seek(offset)
new = f.read().splitlines()
return [ln for ln in new if any(p.search(ln) for p in LOG_PATTERNS)]
def engine_numbers(lines):
"""Best effort: the last 'prompt ... tok/s ... generated ... tok/s' line -> (prompt, decode)."""
for ln in reversed(lines):
if LOG_PATTERNS[2].search(ln):
vals = [float(v.replace(",", "")) for v in TOKS_PER_S.findall(ln)]
if len(vals) >= 2:
return vals[0], vals[1]
return None, None
def target_tokens(key, max_tokens):
n = NOMINAL[key]
# leave room for the answer, like upstream's 259,943-token "262K" prompt
return n - max_tokens - 1024 if n >= 32768 else n
def make_messages(mode, parts, n_chars, run_id):
body, repeated = build_text(parts, n_chars)
system = f"[bench run {run_id}] You are a coding agent working in the repository shown below."
if mode == "needle":
word = uuid.uuid4().hex[:8].upper()
mid = len(body) // 2
body = f"{body[:mid]}\n# NOTE: the secret code word is {word}.\n{body[mid:]}"
task = "What is the secret code word mentioned in the files above? Answer with the word only."
else:
word = None
task = ("Task: explain what the last file above does, then propose one concrete improvement "
"as a unified diff.")
msgs = [{"role": "system", "content": system},
{"role": "user", "content": f"Repository files:\n\n{body}\n\n{task}"}]
return msgs, word, repeated
def run_once(a, parts, key, run, cpt):
tgt = target_tokens(key, a.max_tokens)
run_id = uuid.uuid4().hex[:12]
msgs, word, repeated = make_messages(a.mode, parts, int(tgt * cpt), run_id)
payload = {"model": a.model, "messages": msgs, "max_tokens": a.max_tokens, "stream": True,
"stream_options": {"include_usage": True}, "temperature": 0,
"reasoning_effort": a.reasoning_effort}
off = log_offset(a.log)
rec = {"label": a.label, "mode": a.mode, "ctx": key, "target_tokens": tgt, "run": run,
"run_id": run_id, "corpus_repeated": repeated, "time": datetime.now().isoformat(timespec="seconds")}
try:
r = post_stream(a.url, payload, a.api_key, a.timeout)
except Exception as e: # noqa: BLE001 - record and continue with the next cell
rec["error"] = str(e)[:300]
return rec, cpt
pt = r["usage"].get("prompt_tokens")
ct = r["usage"].get("completion_tokens") or r["chunks"]
ttft = r["t_first"] - r["t_start"]
dec_t = r["t_end"] - r["t_first"]
lines = log_lines_since(a.log, off)
e_prompt, e_decode = engine_numbers(lines)
rec.update({
"prompt_tokens": pt, "completion_tokens": ct,
"ttft_s": round(ttft, 3), "e2e_s": round(r["t_end"] - r["t_start"], 3),
"api_prompt_tps": round(pt / ttft, 1) if pt and ttft > 0 else None,
"api_decode_tps": round((ct - 1) / dec_t, 1) if ct and ct > 1 and dec_t > 0 else None,
"engine_prompt_tps": e_prompt, "engine_decode_tps": e_decode,
"log_lines": lines, "answer_head": r["text"][:300],
})
if word:
rec["needle_found"] = word in r["text"].upper() or word in r["reasoning"].upper()
if a.mode == "two-turn":
follow = msgs + [{"role": "assistant", "content": r["text"]},
{"role": "user", "content": "Summarize your answer in one sentence."}]
off2 = log_offset(a.log)
r2 = post_stream(a.url, {**payload, "messages": follow, "max_tokens": 64}, a.api_key, a.timeout)
rec["turn2_ttft_s"] = round(r2["t_first"] - r2["t_start"], 3)
rec["turn2_prompt_tokens"] = r2["usage"].get("prompt_tokens")
rec["turn2_log_lines"] = log_lines_since(a.log, off2)
if pt:
cpt = (int(tgt * cpt) + 400) / pt # refine chars per token for the next cells
return rec, cpt
def write_md(path, recs, label):
def med(vals):
vals = [v for v in vals if v is not None]
return round(statistics.median(vals), 1) if vals else None
rows = ["| ctx | prompt tokens | runs | TTFT s (med) | prompt tok/s engine / API (med) "
"| decode tok/s engine / API (run 1) | decode tok/s engine / API (med) | needle |",
"|---|---|---|---|---|---|---|---|"]
for key in dict.fromkeys(r["ctx"] for r in recs):
rs = [r for r in recs if r["ctx"] == key and "error" not in r]
errs = sum(1 for r in recs if r["ctx"] == key and "error" in r)
if not rs:
rows.append(f"| {key} | - | 0 ({errs} errors) | | | | | |")
continue
first = rs[0]
needle = "" if rs[0].get("needle_found") is None else f"{sum(r['needle_found'] for r in rs)}/{len(rs)}"
rows.append(
f"| {key} | {rs[0]['prompt_tokens']} | {len(rs)}{f' ({errs} err)' if errs else ''} "
f"| {med(r['ttft_s'] for r in rs)} "
f"| {med(r['engine_prompt_tps'] for r in rs)} / {med(r['api_prompt_tps'] for r in rs)} "
f"| {first['engine_decode_tps']} / {first['api_decode_tps']} "
f"| {med(r['engine_decode_tps'] for r in rs)} / {med(r['api_decode_tps'] for r in rs)} | {needle} |")
path.write_text(f"# {label}\n\n" + "\n".join(rows) + "\n", encoding="utf-8")
def main():
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
ap.add_argument("--url", default="http://127.0.0.1:8090")
ap.add_argument("--model", default="strata", help="model name sent (llama-swap: the model id)")
ap.add_argument("--api-key", default=os.environ.get("STRATA_API_KEY", ""))
ap.add_argument("--label", required=True, help="e.g. IQ3_XXS-1x3090-calibrated")
ap.add_argument("--contexts", default="1k,4k,32k,128k", help=f"comma list of {','.join(NOMINAL)}")
ap.add_argument("--repeats", type=int, default=3)
ap.add_argument("--max-tokens", type=int, default=256)
ap.add_argument("--reasoning-effort", default="none")
ap.add_argument("--mode", choices=["speed", "needle", "two-turn"], default="speed")
ap.add_argument("--source-dir", action="append", default=None,
help="code corpus for the prompts (default: current directory, the Strata repo)")
ap.add_argument("--log", type=Path, default=None,
help="engine log, e.g. ./strata-iq3_xxs.log")
ap.add_argument("--out", type=Path, default=Path(f"./benchmark-output/{datetime.now():%Y-%m-%d}"))
ap.add_argument("--timeout", type=float, default=1800, help="per request, seconds (262K prefill takes minutes)")
ap.add_argument("--chars-per-token", type=float, default=3.4, help="start value, refined after each run")
a = ap.parse_args()
keys = [k.strip().lower() for k in a.contexts.split(",") if k.strip()]
bad = [k for k in keys if k not in NOMINAL]
if bad:
sys.exit(f"unknown context(s): {bad}")
parts = load_corpus(a.source_dir or ["."])
if a.log and not a.log.exists():
print(f"warning: log {a.log} not found; engine numbers will be empty", file=sys.stderr)
if not wait_healthy(a.url, a.api_key, 900):
sys.exit(f"{a.url}/health not reachable")
out = a.out / a.label
(out / "data").mkdir(parents=True, exist_ok=True)
recs, cpt = [], a.chars_per_token
for key in keys:
for run in range(1, a.repeats + 1):
rec, cpt = run_once(a, parts, key, run, cpt)
rec["metrics_after"] = get_json(a.url, "/metrics", a.api_key)
recs.append(rec)
(out / "data" / f"{a.mode}-{key}-{run}.json").write_text(json.dumps(rec, indent=1), encoding="utf-8")
status = rec.get("error") or (f"prompt {rec['prompt_tokens']} tok, TTFT {rec['ttft_s']} s, "
f"decode engine {rec['engine_decode_tps']} / API {rec['api_decode_tps']} tok/s")
print(f"[{a.label}] {a.mode} {key} run {run}: {status}", flush=True)
matrix_path = out / "matrix.json"
merged = {}
if matrix_path.exists():
for record in json.loads(matrix_path.read_text(encoding="utf-8")):
merged[(record["mode"], record["ctx"], record["run"])] = record
for record in recs:
key = (record["mode"], record["ctx"], record["run"])
merged[key] = {k: v for k, v in record.items() if k != "metrics_after"}
combined = list(merged.values())
matrix_path.write_text(json.dumps(combined, indent=1), encoding="utf-8")
write_md(out / "matrix.md", combined, f"{a.label} ({a.mode})")
print(f"written: {out}/matrix.md, matrix.json, data/")
if __name__ == "__main__":
main()
@@ -0,0 +1,86 @@
## date (UTC)
2026-09-29T22:07:24Z
## strata version
v0.1.26
## os
PRETTY_NAME="Ubuntu 24.04.5 LTS"
VERSION_ID="24.04"
6.8.0-139-generic
## virtualization
kvm
## cpu
CPU(s): 20
Model name: AMD EPYC 7453 28-Core Processor
Thread(s) per core: 1
Core(s) per socket: 20
Socket(s): 1
L3 cache: 320 MiB (20 instances)
NUMA node(s): 1
## cpu flags (relevant)
avx2 f16c fma
## numa
available: 1 nodes (0)
node 0 cpus: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
node 0 size: 168968 MB
node 0 free: 47460 MB
node distances:
node 0
0: 10
## memory
total used free shared buff/cache available
Mem: 165 14 46 0 105 150
Swap: 0 0 0
## dimms
run as root for dmidecode
(in a VM these are virtual DIMMs: fill in the host section below by hand)
## memlock limit
21627928
## gpu
index, name, driver_version, memory.total [MiB], pcie.link.gen.current, pcie.link.gen.max, pcie.link.width.current, pcie.link.width.max, power.limit [W], power.default_limit [W], power.max_limit [W], power.draw [W], clocks.max.sm [MHz]
0, NVIDIA GeForce RTX 3090, 595.91.07, 24576 MiB, 1, 4, 16, 16, 280.00 W, 350.00 W, 366.00 W, 35.23 W, 2130 MHz
1, NVIDIA GeForce RTX 3090, 595.91.07, 24576 MiB, 1, 4, 16, 16, 280.00 W, 420.00 W, 450.00 W, 28.60 W, 2100 MHz
## gpu topology
GPU0 GPU1 CPU Affinity NUMA Affinity GPU NUMA ID
GPU0 X PHB 0-19 0 N/A
GPU1 PHB X 0-19 0 N/A
Legend:
X = Self
SYS = Connection traversing PCIe as well as the SMP interconnect between NUMA nodes (e.g., QPI/UPI)
NODE = Connection traversing PCIe as well as the interconnect between PCIe Host Bridges within a NUMA node
PHB = Connection traversing PCIe as well as a PCIe Host Bridge (typically the CPU)
PXB = Connection traversing multiple PCIe bridges (without traversing the PCIe Host Bridge)
PIX = Connection traversing at most a single PCIe bridge
NV# = Connection traversing a bonded set of # NVLinks
## gpu processes (must be empty before benchmarking)
pid, process_name, used_gpu_memory [MiB]
## docker
Docker version 29.8.1, build 4a63305
NVIDIA Container Toolkit CLI version 1.18.1
## disk (model data)
Filesystem Size Used Avail Use% Mounted on
/dev/sdb1 541G 409G 106G 80% <storage>
## host (fill in manually)
- Hypervisor: Proxmox VE (KVM guest; host version not visible inside the VM)
- CPU: AMD EPYC 7453 28-Core Processor (Milan); 20 vCPU exposed, AVX2, no AVX-512 visible
- RAM: 165 GiB visible to the guest; physical DIMM layout and bandwidth not measured
- VM: 20 vCPU, 1 socket x 20 cores x 1 thread, 1 NUMA node; ballooning and pinning not verified
- GPUs: 2x RTX 3090 24 GB; PCIe Gen4 x16 maximum reported for each (current idle link generation varies); configured power limit 280 W each
- Storage: ext4 guest data disk, 541 GiB; host storage layout not verified from the guest
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,48 @@
# Native benchmark matrix (v0.1.26)
Prompt speeds are engine tok/s medians; output lists the first-run value and the three-run median. `prompt tokens` is the median measured count. Draft acceptance is the mean of per-run accepted/offered values from engine logs.
## IQ3_XXS, one RTX 3090
| Context | Prompt tokens | Prompt tok/s | Decode first / median tok/s | TTFT median | Draft acceptance |
|---|---:|---:|---:|---:|---:|
| 1K | 1,135 | 869.7 | 93.0 / 93.0 | 1.33 s | 0.738 |
| 4K | 4,200 | 1,772.2 | 91.7 / 89.2 | 2.41 s | 0.763 |
| 32K | 31,602 | 2,160.4 | 90.6 / 90.6 | 14.83 s | 0.739 |
| 128K | 129,913 | 2,173.6 | 79.3 / 79.3 | 60.53 s | 0.723 |
| 262K | 259,589 | 1,725.6 | 63.0 / 67.3 | 152.10 s | 0.697 |
## 32K model and GPU comparison
| Model | GPUs / split | Prompt tokens | Prompt tok/s median | Decode first / median tok/s | TTFT median | Draft acceptance |
|---|---|---:|---:|---:|---:|---:|
| Coder IQ1_M | 1x 3090 | 31,601 | 2,502.4 | 52.7 / 66.8 | 12.80 s | 0.760 |
| Coder IQ1_M | 2x 3090, auto K=19 | 31,601 | 2,704.3 | 88.5 / 98.6 | 11.85 s | 0.908 |
| IQ3_XXS | 2x 3090, auto K=24 | 31,603 | 1,158.9 | 83.7 / 96.7 | 26.90 s | 0.690 |
| IQ3_S | 2x 3090, auto K=24 | 31,604 | 749.3 | 83.1 / 106.3 | 42.27 s | 0.871 |
## Coder IQ1_M fixed layer split
One initial 32K run per K, then three-run repeats for K=22–30. Prompts are independent and adaptive-cache behavior varies; compare the medians cautiously.
| Split | Successful runs | Prompt tok/s median | Decode tok/s median | Notes |
|---|---:|---:|---:|---|
| Auto (K=19) | 3 | 2,704.3 | 98.6 | Layers 0–18 / 19–47 |
| K=18 | 1 | 2,324.6 | 83.1 | Repeat startup OOM while uploading a dense weight |
| K=22 | 3 | 2,951.6 | 103.3 | Layers 0–21 / 22–47 |
| K=24 | 3 | 3,123.2 | 100.2 | Layers 0–23 / 24–47 |
| K=26 | 3 | 3,205.2 | 93.5 | Layers 0–25 / 26–47 |
| K=28 | 3 | 3,034.9 | 96.6 | Layers 0–27 / 28–47 |
| K=30 | 3 | 2,920.6 | 96.1 | Layers 0–29 / 30–47 |
## Correctness
| Model / setup | Check | Result |
|---|---|---|
| IQ3_XXS, 1x 3090 | Needles 8K / 16K / 28K | 3/3 found |
| IQ3_XXS, 1x 3090 | 16K two-turn chat | 15,892 / 15,915 prompt tokens reused on turn two |
| IQ3_XXS, 2x 3090 auto K=24 | Needles 8K / 16K / 28K | 3/3 found |
| IQ3_XXS, 2x 3090 auto K=24 | 16K two-turn chat | 15,628 / 15,672 prompt tokens reused on turn two |
| IQ3_S, 2x 3090 auto K=24 | Needles 8K / 16K / 28K | 3/3 found |
| IQ3_S, 2x 3090 auto K=24 | 16K two-turn chat | 15,632 / 15,676 prompt tokens reused on turn two |
| Coder, 2x 3090 | Needles / two-turn | Not run |
@@ -0,0 +1,14 @@
{
"source": "local",
"version": "0.1.29",
"archs": [
120
],
"vision": "gpu",
"cuda_dirs": [
"/usr/local/cuda/bin",
"/usr/local/cuda/lib64"
],
"src": "1437bc9455f7c0af",
"vision_src": "4b80385716918cce"
}
@@ -0,0 +1,4 @@
FROM nvidia/cuda@sha256:5dc1bca23d05bd37b011be68ec470c03b403a5da07ec3a86e41af9470e9d0cc6
RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends build-essential cmake ninja-build git ca-certificates curl python3 python3-venv python3-dev pkg-config && rm -rf /var/lib/apt/lists/*
ENV HOME=/workspace/home PYTHONUNBUFFERED=1
WORKDIR /workspace/Strata
@@ -0,0 +1,167 @@
# Community benchmark: RTX 5090, Core Ultra 9 285K
Measured on 2026-09-30 by [hagope](https://github.com/hagope), on a Linux
machine called OMAN. This tests Strata 0.1.29 with the original Flash-Next
IQ2_XS, one GPU, and a 131,072-token context limit.
Median decode throughput was **179.4 tok/s at 4,096 prompt tokens, 175.7 tok/s
at 32,768, and 165.0 tok/s at 128,000**. These are synthetic code-explanation
requests with greedy decoding and a 256-token output cap. They do not establish
general answer quality or performance on other workloads.
## Hardware and software
- NVIDIA GeForce RTX 5090; 32,607 MiB reported VRAM; 575 W power limit.
PCIe capability: Gen 5, x16. The engine's startup transfer probe reported
50.0 GB/s host-to-device. GPU clocks were not fixed for this test.
- Intel Core Ultra 9 285K; 24 logical CPUs. The engine selected AVX2 and
23 expert-pool workers plus its host thread.
- 64 GB installed RAM; Linux reported 62.19 GiB usable. Local NVMe storage:
WDC WDS200T2B0C-00PXH0. 8 GiB system swap.
- Ubuntu 24.04.4 LTS, kernel 6.8.0-142-generic, NVIDIA driver 595.84.
- Source commit `d6708a4aae15b4860000d54c8af9e84d684bce09`; engine 0.1.29.
Locally compiled CUDA architecture 120, including the GPU vision helper.
See [BUILD.json](BUILD.json).
- CUDA 13.0.2 container; NVCC 13.0.88; GCC 13.3.0; Python 3.12.3.
Base image: `nvidia/cuda@sha256:5dc1bca23d05bd37b011be68ec470c03b403a5da07ec3a86e41af9470e9d0cc6`.
Installed Python dependencies are listed in [python-packages.txt](python-packages.txt).
- The regular inference server, GPU TTS, and GPU embedding service were paused.
Other CPU services remained running. The GPU was dedicated to Strata and its
vision helper; this was not a completely isolated operating system.
## Model and configuration
Model: `ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF`, revision
`ed59f92082b1e93c0e96d60a8b11aab089b52f09`:
- `IQ2_XS/Qwen3.8-Flash-Next-GSQ-RCO-IQ2_XS-00001-of-00002.gguf`
- `IQ2_XS/Qwen3.8-Flash-Next-GSQ-RCO-IQ2_XS-00002-of-00002.gguf`
- `mmproj-Qwen3.8-Flash-Next-BF16.gguf`
All three local GGUF SHA-256 hashes matched the revision's published LFS hashes.
[model-provenance.json](model-provenance.json) contains filenames, byte sizes,
revisions, and verified hashes. MTP was fetched by the installer from
`Qwen/Qwen3.8-Flash-Next`; its API reported revision
`de4b8e4d43b917e7706784d8bb445c9af86a3540` at verification time. The installer
uses `main` for those tensor-range downloads. Their individual output hashes
are retained in [mtp-manifest.json](mtp-manifest.json); the full BF16 upstream
shards were not downloaded or independently hash-verified.
The unmodified installer prepared the native IQ2_XS pack and Q2_0 MTP experts.
[artifact-hashes.json](artifact-hashes.json) identifies the executables,
default expert profile, tokenizer, pack metadata/dense weights, and draft pack.
- Context 131,072; INT8 KV; 32,768 KV cells per attention layer resident on GPU.
- Expert cache `auto`: 17,463 slots, 23.44 GiB VRAM, profile-prefilled with
**no eviction**. The bundled expert profile was used without calibration.
- Prefill `auto` selected chunks of 8,192 tokens, borrowing 3,421 expert-cache
slots during prompt processing.
- MTP `--spec 4 --spec-min-p 0.5`; built-in suffix drafting remained enabled.
- Low-RAM mode off; GPU vision enabled, 1,024 image tokens and a 700 MiB VRAM
reserve. The vision helper warmed up; benchmark requests contained no images.
- Experimental speed projection off; no custom control vectors or calibration.
- Reasoning disabled, temperature 0, maximum 256 generated tokens per speed run.
The complete measured configuration is [strata-iq2_xs.json](strata-iq2_xs.json).
Startup choices and every request's timing/draft statistics are in
[engine.log](engine.log).
## Method and reproduction
Use the attached [Dockerfile](Dockerfile), the pinned source commit, and an empty
data directory. Mount a working directory as `/workspace`, with the checkout
at `/workspace/Strata`. Run setup inside the CUDA container with GPU access,
host IPC, and unlimited memlock:
```bash
bash ./setup.sh --family qwen --model IQ2_XS --context 131072 --kv int8 \
--vision gpu --experimental-speed-projection off --gpu 0 --low-ram off \
--build --yes --no-start --port 18080 --data-dir /workspace/Strata-data
```
Launch the prepared server on loopback inside a container using host networking:
```bash
/workspace/Strata/.venv/bin/python serve/server.py --engine strata \
--config strata-iq2_xs.json --host 127.0.0.1 --port 18080
```
Run [benchmark.py](benchmark.py) inside that container, after placing the script
at `/workspace/benchmark.py`. It generates deterministic synthetic Python
functions, adds a different nonce near the start of each request, and counts the
complete rendered chat prompt using Strata's tokenizer. It adjusts the filler
to the target token count and verifies the count against the server afterward.
The resulting request hashes are in [results.json](results.json).
```bash
/workspace/Strata/.venv/bin/python /workspace/benchmark.py
/workspace/Strata/.venv/bin/python tools/needle_bench.py \
--url http://127.0.0.1:18080 --lengths 32k,128k --depths 10,50,90 \
--out /workspace/results/needles.json
```
One short warm-up request was excluded. Three runs at each length were executed
serially in increasing-length order on the same loaded engine. All nine speed
requests processed their entire prompt: **zero reused tokens**. The GPU expert
cache was filled at startup and retained between requests; no engine restart or
OS page-cache reset separated them. Downloads and file verification had already
warmed the filesystem cache. Loading time is excluded.
The script measures streaming TTFT from immediately before the HTTP request
until the first nonempty text delta, ignoring empty role chunks and keep-alives.
With reasoning off, that delta contains answer text. Total latency ends at
stream completion. Both timings include HTTP and frontend tokenization on OMAN
over loopback. Engine prompt throughput uses freshly read tokens divided by
`prompt_ms`; decode throughput uses `engine_generated / decode_ms`. The JSON
preserves the engine timing values and output text for each run.
## Results
Each cell below is the median **[minimum–maximum]** of three runs. Every request
generated 256 tokens and stopped at the output limit, with no failed or cancelled
speed requests.
| Prompt tokens | Reused | Prompt tok/s | Decode tok/s | TTFT seconds | Total seconds |
| ---: | ---: | ---: | ---: | ---: | ---: |
| 4,096 | 0 | 4,269.8 [3,510.2–4,273.3] | 179.4 [161.3–184.8] | 0.974 [0.973–1.183] | 2.392 [2.351–2.761] |
| 32,768 | 0 | 5,543.2 [5,527.1–5,549.6] | 175.7 [166.1–181.8] | 5.950 [5.942–5.968] | 7.390 [7.348–7.498] |
| 128,000 | 0 | 5,778.7 [5,767.0–5,791.9] | 165.0 [154.8–169.3] | 22.262 [22.212–22.308] | 23.850 [23.765–23.856] |
Raw per-run records: [results.json](results.json). Calculated aggregates:
[summary.json](summary.json). The lower first 4K run is retained in the range.
Decode expert-cache hit rates were 97.8–99.7% for these nine requests.
[monitor.py](monitor.py) sampled the host once per second, starting before model
load and ending after the recall checks. [telemetry.jsonl](telemetry.jsonl)
contains 250 samples over 255.9 seconds, with the following observed peaks:
- GPU memory: **31,785 MiB (31.04 GiB)**, system-wide on the selected GPU.
- Host RAM: **45.54 GiB**, calculated as `MemTotal - MemAvailable`. This includes
Strata, other services, and non-reclaimable system memory; it is not process RSS.
- Swap allocation increased from **0.25 MiB to 425.50 MiB**, including increases
during the speed suite. Swap I/O rates were not measured, so this is not a
claim that inference ran without paging. No out-of-memory error occurred.
Sampling and the server's own telemetry were active during inference. These
are sampled peaks; brief allocation spikes between samples may be missed.
Aggregates are also recorded in [memory-summary.json](memory-summary.json).
## Recall and limitations
The repository's unchanged `tools/needle_bench.py` found **all six needles**:
depths 10%, 50%, and 90% at both requested lengths. Actual prompt lengths were
30,804–30,805 tokens for `32k` and 126,318–126,320 for `128k`. All answers exactly
matched the expected code words. See [needles.json](needles.json).
The final 128K recall case reused 16,384 prompt tokens; the other five reused
zero. Recall latency is therefore not used in the fresh-prompt speed table.
The script chooses needle depth by character position, not token position.
This is one machine, one quantization, one configuration, and a small synthetic
workload. Long output, sampled decoding, thinking, coding-task correctness,
vision, tool use, multi-request concurrency, and a sustained thermal run were
not evaluated. The built-in needle check measures recall on these six inputs,
not general model accuracy. No same-workload baseline on another engine or GPU
was run; do not interpret the README's different-hardware numbers as a controlled
comparison. The 128,000-token speed prompt also does not fill every token of the
131,072-token context window.
@@ -0,0 +1,82 @@
[
{
"file": "Strata-data/mtp/mtp-q2_0.gguf",
"bytes": 889017216,
"sha256": "a22206a4d74eafbf31063a84610292535fb3b49af9a339963817fd04aed81e4d"
},
{
"file": "Strata-data/mtp/rt/dense.bin",
"bytes": 116099072,
"sha256": "c724dc0b0822ada5d2977bf5bde821605feabaa64ea2e0045b67ca656329070a"
},
{
"file": "Strata-data/mtp/rt/dense.txt",
"bytes": 1851,
"sha256": "991456cf4eb266eb8a888c349e548d11bc640f5dbd9149439aa9786af0f732fd"
},
{
"file": "Strata-data/mtp/rt/draft_vocab.bin",
"bytes": 425196,
"sha256": "b1e1d3a7a9e4bf862dcd5923ce661fb59bbd07907e594df5cf86a62ac235cb91"
},
{
"file": "Strata-data/mtp/rt/experts.bin",
"bytes": 707788800,
"sha256": "09398406be61f1f54c93861f449e48b8df0bfccbc9ec9b2b7636775a6ea9244f"
},
{
"file": "Strata-data/packs/iq2_xs/dense.bin",
"bytes": 1538035200,
"sha256": "d2af3d8331e5c7a1985d1d589747230f9d56719a6d33c7cddc9ee6b81cde6b13"
},
{
"file": "Strata-data/packs/iq2_xs/index.txt",
"bytes": 93686,
"sha256": "19e781af360ca3b83fd90fe09e757ac9aa2a9dcada26810ddc9e933bdb112091"
},
{
"file": "Strata-data/packs/iq2_xs/native_experts.txt",
"bytes": 3289,
"sha256": "48df605acb89c7e8c3176a51cec777c2ed344ea439e8f3a37e5ce4f9dcb6946c"
},
{
"file": "Strata-data/packs/iq2_xs/tokenizer/chat_template.jinja",
"bytes": 9993,
"sha256": "12827f24b742ea4e80cdc12dbcf9622227056b9f797252a3149263d4f9aaadce"
},
{
"file": "Strata-data/packs/iq2_xs/tokenizer/merges.txt",
"bytes": 3353258,
"sha256": "4ba698529766c7a2f5052083ea10cdf2485577f5237a332ee291054eb11e3332"
},
{
"file": "Strata-data/packs/iq2_xs/tokenizer/token_type.json",
"bytes": 744960,
"sha256": "5088c8c298fc06af8382ddb3b76c888703ac2634e82263b97eedcc2ad202738b"
},
{
"file": "Strata-data/packs/iq2_xs/tokenizer/tokenizer.json",
"bytes": 541,
"sha256": "c0bd435efbc6c3b28964b47999afe16c4ad268c7c7c4e8cb3af410796a6f30bf"
},
{
"file": "Strata-data/packs/iq2_xs/tokenizer/vocab.json",
"bytes": 5737005,
"sha256": "4ba64f0332abcfb0b600b7df1537d1e836e68009d5fb7cdb77339738dc6365c4"
},
{
"file": "Strata/data/expert-profile.bin",
"bytes": 196632,
"sha256": "8f59b4aa8873209dff11c11e37bcda9529a1335b724a1afeea37bf6388975baf"
},
{
"file": "Strata/engine/strata",
"bytes": 43158256,
"sha256": "b7f18df1314ad438952ca11bb5ce5f23b41e7a572462426383d2ad8209fcf367"
},
{
"file": "Strata/engine/strata-vision",
"bytes": 74993888,
"sha256": "0d4c955f255ba4c3a9f6f456d63292754fae440a8a39cb13b9b6564938448e19"
}
]
@@ -0,0 +1,135 @@
#!/usr/bin/env python3
"""Serial, fresh-prompt Strata benchmark. Run inside its prepared environment."""
import argparse
import hashlib
import json
import statistics
import sys
import time
import urllib.request
from pathlib import Path
def get(url):
with urllib.request.urlopen(url, timeout=30) as response:
return json.load(response)
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--root", type=Path, default=Path("/workspace/Strata"))
parser.add_argument("--pack", type=Path, default=Path("/workspace/Strata-data/packs/iq2_xs"))
parser.add_argument("--url", default="http://127.0.0.1:18080")
parser.add_argument("--out", type=Path, default=Path("/workspace/results"))
parser.add_argument("--targets", default="4096,32768,128000")
parser.add_argument("--runs", type=int, default=3)
args = parser.parse_args()
args.out.mkdir(parents=True, exist_ok=True)
sys.path[:0] = [str(args.root), str(args.root / "tools")]
from strata_tokenizer import Tokenizer
from serve.frontend import ChatTemplate, openai_to_messages
directory = args.pack / "tokenizer"
vocab = json.loads((directory / "vocab.json").read_text())
tokens = [None] * len(vocab)
for token, number in vocab.items():
tokens[number] = token
tokenizer = Tokenizer(tokens, (directory / "merges.txt").read_text().splitlines(),
json.loads((directory / "token_type.json").read_text()))
template = ChatTemplate(directory / "chat_template.jinja")
initial = get(args.url + "/v1/status")
(args.out / "initial-status.json").write_text(json.dumps(initial, indent=2) + "\n")
rows = []
def request(content, maximum=256):
return {"model": "strata", "messages": [{"role": "user", "content": content}],
"temperature": 0, "reasoning_effort": "none", "max_tokens": maximum,
"stream": True, "stream_options": {"include_usage": True}}
def count(req):
messages, tools, kwargs = openai_to_messages(req)
return len(tokenizer.encode(template.render(messages, tools, **kwargs), parse_special=True))
def perform(label, req, expected=None):
body = json.dumps(req).encode()
(args.out / (label + "-request.json")).write_bytes(body + b"\n")
print("start", label, "tokens", expected, flush=True)
chunks, texts, first, finish = [], [], None, None
started = time.perf_counter()
wire = urllib.request.Request(args.url + "/v1/chat/completions", data=body,
headers={"Content-Type": "application/json"})
with urllib.request.urlopen(wire, timeout=1800) as response:
for line in response:
if not line.startswith(b"data: "):
continue
payload = line[6:].strip()
if payload == b"[DONE]":
break
chunk = json.loads(payload)
chunks.append(chunk)
for choice in chunk.get("choices", []):
delta = choice.get("delta", {})
text = (delta.get("content") or "") + (delta.get("reasoning_content") or "")
if text:
first = first if first is not None else time.perf_counter() - started
texts.append(text)
finish = choice.get("finish_reason") or finish
elapsed = time.perf_counter() - started
metrics = get(args.url + "/metrics")
engine = metrics["requests"][0]
usage = next((chunk["usage"] for chunk in reversed(chunks) if "usage" in chunk), {})
row = {"label": label, "expected_prompt_tokens": expected,
"request_sha256": hashlib.sha256(body).hexdigest(),
"client_ttft_s": first, "client_elapsed_s": elapsed, "finish_reason": finish,
"usage": usage, "engine": engine, "text": "".join(texts)}
if expected is not None and engine["prompt_tokens"] != expected:
raise RuntimeError(f"token count mismatch: {expected} vs {engine['prompt_tokens']}")
if not texts:
raise RuntimeError(f"no text received for {label}")
(args.out / (label + "-raw.json")).write_text(json.dumps({"chunks": chunks, "row": row}, indent=2) + "\n")
rows.append(row)
(args.out / "results.json").write_text(json.dumps(rows, indent=2) + "\n")
print("done", label, json.dumps({"ttft_s": first, "elapsed_s": elapsed, "engine": engine}), flush=True)
return row
perform("warmup", request("Reply with exactly the word READY.", 16))
# Each nonce occurs before the filler so previous long prompts cannot be reused.
filler = "\n".join(f"def task_{i:05d}(value: int) -> int: return (value * {(i % 97) + 1} + {i}) % 100003"
for i in range(12000))
ending = ("\n\nWrite a detailed explanation of the code above. Discuss deterministic integer transforms, "
"modulo arithmetic, testing, naming, complexity, and maintainability. Write at least 600 words.")
for target in map(int, args.targets.split(",")):
for run in range(1, args.runs + 1):
prefix = f"Benchmark nonce: series-{target}-trial-{run}.\nReview this synthetic Python module:\n"
lo, hi = 0, len(filler)
while lo < hi:
middle = (lo + hi + 1) // 2
if count(request(prefix + filler[:middle] + ending)) <= target:
lo = middle
else:
hi = middle - 1
req = request(prefix + filler[:lo] + ending)
actual = count(req)
if actual < target - 20 or actual > target:
raise RuntimeError(f"could not construct target {target}: {actual}")
perform(f"tokens-{target}-run-{run}", req, actual)
measured = [row for row in rows if row["label"] != "warmup"]
groups = {}
for target in map(int, args.targets.split(",")):
subset = [r for r in measured if r["label"].startswith(f"tokens-{target}-")]
values = {
"prompt_tokens": [r["engine"]["prompt_tokens"] for r in subset],
"cached_tokens": [r["engine"].get("reused", 0) for r in subset],
"output_tokens": [r["engine"]["engine_generated"] for r in subset],
"client_ttft_s": [r["client_ttft_s"] for r in subset],
"client_elapsed_s": [r["client_elapsed_s"] for r in subset],
"prefill_tok_s": [(r["engine"]["prompt_tokens"] - (r["engine"].get("reused") or 0)) / (r["engine"]["prompt_ms"] / 1000) for r in subset],
"decode_tok_s": [r["engine"]["engine_generated"] / (r["engine"]["decode_ms"] / 1000) for r in subset],
}
groups[str(target)] = {key: {"median": statistics.median(v), "min": min(v), "max": max(v)}
for key, v in values.items()}
(args.out / "summary.json").write_text(json.dumps(groups, indent=2) + "\n")
print("summary", json.dumps(groups), flush=True)
if __name__ == "__main__":
main()
@@ -0,0 +1,91 @@
load_hparams: Qwen-VL models require at minimum 1024 image tokens to function correctly on grounding tasks
load_hparams: if you encounter problems with accuracy, try adding --image-min-tokens 1024
load_hparams: more info: https://github.com/ggml-org/llama.cpp/issues/16842
strata-vision: warmed up at 1024 image tokens
strata generate: PCIe probe: 50.0 GB/s host->device -> pcie_frac 0.55 (default 0.55)
strata generate: this CPU has no AVX-512: the expert kernels run on AVX-2 (multi-token for the i-quant gate/up rows)
strata generate: native pack: /workspace/Strata-data/packs/iq2_xs experts (largest blob 1.51 MB), token embedding type 23 in mapped host memory (322 MiB)
strata generate: 1466 MiB of weights loaded from /workspace/Strata-data/packs/iq2_xs (302 canonical tensors skipped: served natively)
strata generate: 300 native projection matrices, 1474.85 MiB of weights
strata generate: KV streaming: 32768 of 131072 cells per QSA layer in VRAM, the K/V in 1.55 GiB of pinned RAM
strata generate: PLE on, table 320001536 rows of /workspace/Strata-data/models/IQ2_XS/Qwen3.8-Flash-Next-GSQ-RCO-IQ2_XS-00002-of-00002.gguf
strata mtp: draft layer loaded, 835 MiB of VRAM (experts 675, dense 111), files read in 0.23 s (3441 MiB/s)
strata generate: expert arena: cudaHostRegister PORTABLE ok; MAP_HUGETLB unavailable (no hugetlb pool configured?); using 4 KB pages
strata generate: loaded 33.02 GiB at 2.21 GiB/s
strata generate: profile /workspace/Strata/data/expert-profile.bin: 24576 ranked pairs, built for 24576 slots
strata generate: experimental native Q5_K head, 337715200 bytes
strata generate: expert cache auto: 24.26 GiB free, 700 MiB reserved (+143 MiB for the draft head) -> 16663 slots
strata generate: expert cache 17463 slots, 23.44 GiB of VRAM; policy is
strata generate: the GPU computes the experts in the cache; it rounds differently from the CPU,
so a reply can differ slightly from a run without the cache (same quality:
bench/results/2026-09-27-cache-parity).
PROFILE, ranked by routing frequency, no eviction.
strata generate: pre-filled 17463 of 17463 slots from the profile; slot 0 verified
strata generate: R4 hit path ON - resident experts are computed on the GPU
strata generate: 23 expert-pool workers + the host thread
strata generate: session is up (engine 0.1.29)
strata generate: token graph hit path: 17463 resident experts, decided on the device
strata serve: prompt chunk auto: 8192 tokens
strata serve: the prompt path borrows 3421 cache slots (4.62 GiB)
strata verify: window up to 6 tokens, 57.1 MiB of device buffers
strata mtp: draft head over 106299 tokens (137.9 MiB)
strata serve: 412 MiB of VRAM free with everything loaded
strata verify: captured the 6-token window (upload no error, sync no error)
strata verify: captured the 1-token window (upload no error, sync no error)
strata verify: captured the 4-token window (upload no error, sync no error)
strata serve: prompt 19 tokens = 0 reused + 19 read in 135 ms (140.9 tok/s), 2 generated in 57 ms (34.9 tok/s), drafts accepted 3 of 3, 1 checkpoints
strata serve: decode expert cache hit rate: 90.8% (2037 hits / 2244 lookups)
strata serve: KV streaming: 92.31% of 936 block reads hit VRAM, 0.3 MiB read from RAM
strata verify: captured the 3-token window (upload no error, sync no error)
strata verify: captured the 2-token window (upload no error, sync no error)
strata serve: prompt 4096 tokens = 0 reused + 4096 read in 1167 ms (3510.2 tok/s), 256 generated in 1587 ms (161.3 tok/s), drafts accepted 149 of 226, 1 checkpoints
strata serve: decode expert cache hit rate: 97.8% (155423 hits / 158942 lookups)
strata serve: KV streaming: 99.39% of 2095092 block reads hit VRAM, 51.8 MiB read from RAM
strata serve: suffix drafts: 3 windows, 6 of 9 drafts accepted
strata serve: prompt 4096 tokens = 0 reused + 4096 read in 959 ms (4269.7 tok/s), 256 generated in 1385 ms (184.8 tok/s), drafts accepted 158 of 221, 1 checkpoints
strata serve: decode expert cache hit rate: 99.3% (151655 hits / 152786 lookups)
strata serve: KV streaming: 99.36% of 2002680 block reads hit VRAM, 51.7 MiB read from RAM
strata serve: suffix drafts: 1 windows, 2 of 3 drafts accepted
strata serve: prompt 4096 tokens = 0 reused + 4096 read in 958 ms (4273.4 tok/s), 256 generated in 1427 ms (179.4 tok/s), drafts accepted 160 of 226, 1 checkpoints
strata serve: decode expert cache hit rate: 98.9% (153580 hits / 155293 lookups)
strata serve: KV streaming: 99.37% of 2039616 block reads hit VRAM, 52.0 MiB read from RAM
strata serve: suffix drafts: 2 windows, 2 of 8 drafts accepted
strata serve: prompt 32768 tokens = 0 reused + 32768 read in 5929 ms (5527.1 tok/s), 256 generated in 1541 ms (166.1 tok/s), drafts accepted 148 of 218, 2 checkpoints
strata serve: decode expert cache hit rate: 99.4% (155252 hits / 156260 lookups)
strata serve: KV streaming: 97.72% of 2045772 block reads hit VRAM, 187.5 MiB read from RAM
strata serve: prompt 32768 tokens = 0 reused + 32768 read in 5911 ms (5543.1 tok/s), 256 generated in 1408 ms (181.8 tok/s), drafts accepted 160 of 212, 2 checkpoints
strata serve: decode expert cache hit rate: 99.4% (147298 hits / 148150 lookups)
strata serve: KV streaming: 97.53% of 1941048 block reads hit VRAM, 193.2 MiB read from RAM
strata serve: prompt 32768 tokens = 0 reused + 32768 read in 5905 ms (5549.6 tok/s), 256 generated in 1457 ms (175.7 tok/s), drafts accepted 153 of 206, 2 checkpoints
strata serve: decode expert cache hit rate: 99.5% (148308 hits / 149107 lookups)
strata serve: KV streaming: 97.56% of 1953372 block reads hit VRAM, 191.7 MiB read from RAM
strata serve: suffix drafts: 2 windows, 3 of 8 drafts accepted
strata serve: prompt 128000 tokens = 0 reused + 128000 read in 22100 ms (5791.9 tok/s), 256 generated in 1654 ms (154.8 tok/s), drafts accepted 149 of 218, 6 checkpoints
strata serve: decode expert cache hit rate: 99.4% (155334 hits / 156245 lookups)
strata serve: KV streaming: 96.13% of 2045748 block reads hit VRAM, 318.7 MiB read from RAM
strata serve: prompt 128000 tokens = 0 reused + 128000 read in 22151 ms (5778.7 tok/s), 256 generated in 1512 ms (169.3 tok/s), drafts accepted 159 of 228, 6 checkpoints
strata serve: decode expert cache hit rate: 99.7% (155406 hits / 155913 lookups)
strata serve: KV streaming: 96.26% of 2039616 block reads hit VRAM, 307.0 MiB read from RAM
strata serve: prompt 128000 tokens = 0 reused + 128000 read in 22195 ms (5767.0 tok/s), 256 generated in 1551 ms (165.0 tok/s), drafts accepted 154 of 221, 6 checkpoints
strata serve: decode expert cache hit rate: 99.7% (155405 hits / 155914 lookups)
strata serve: KV streaming: 96.22% of 2039628 block reads hit VRAM, 310.9 MiB read from RAM
strata serve: suffix drafts: 1 windows, 1 of 2 drafts accepted
strata serve: prompt 30804 tokens = 0 reused + 30804 read in 6382 ms (4826.8 tok/s), 9 generated in 55 ms (163.1 tok/s), drafts accepted 6 of 6, 2 checkpoints
strata serve: decode expert cache hit rate: 92.6% (3832 hits / 4139 lookups)
strata serve: KV streaming: 78.28% of 92424 block reads hit VRAM, 80.8 MiB read from RAM
strata serve: prompt 30804 tokens = 0 reused + 30804 read in 5709 ms (5395.4 tok/s), 9 generated in 61 ms (147.0 tok/s), drafts accepted 6 of 6, 2 checkpoints
strata serve: decode expert cache hit rate: 94.7% (3971 hits / 4192 lookups)
strata serve: KV streaming: 78.55% of 92424 block reads hit VRAM, 79.9 MiB read from RAM
strata serve: prompt 30805 tokens = 0 reused + 30805 read in 5718 ms (5387.6 tok/s), 10 generated in 66 ms (150.4 tok/s), drafts accepted 9 of 9, 2 checkpoints
strata serve: decode expert cache hit rate: 96.3% (5885 hits / 6108 lookups)
strata serve: KV streaming: 82.56% of 117072 block reads hit VRAM, 82.3 MiB read from RAM
strata serve: prompt 126320 tokens = 0 reused + 126320 read in 22281 ms (5669.4 tok/s), 10 generated in 65 ms (154.9 tok/s), drafts accepted 7 of 7, 6 checkpoints
strata serve: decode expert cache hit rate: 97.7% (5115 hits / 5233 lookups)
strata serve: KV streaming: 77.02% of 104760 block reads hit VRAM, 97.0 MiB read from RAM
strata serve: prompt 126318 tokens = 0 reused + 126318 read in 22453 ms (5626.0 tok/s), 9 generated in 105 ms (86.0 tok/s), drafts accepted 6 of 14, 6 checkpoints
strata serve: decode expert cache hit rate: 97.4% (9224 hits / 9474 lookups)
strata serve: KV streaming: 82.65% of 160212 block reads hit VRAM, 112.0 MiB read from RAM
strata serve: prompt 126318 tokens = 16384 reused + 109934 read in 19791 ms (5554.7 tok/s), 9 generated in 78 ms (115.2 tok/s), drafts accepted 7 of 9, 6 checkpoints
strata serve: decode expert cache hit rate: 98.1% (6539 hits / 6669 lookups)
strata serve: KV streaming: 87.22% of 283464 block reads hit VRAM, 146.0 MiB read from RAM
@@ -0,0 +1 @@
{"service": "strata", "model": "qwen3.8-flash-next-iq2_xs", "engine": "0.1.29", "started": 1790772696, "uptime_s": 196, "cache_max_tokens": 131072, "context": {"native": 131072, "max_positions": 131072}, "concurrency": {"serving": 1, "requested": 1}, "dialects": ["/v1/chat/completions", "/v1/messages"], "vision": {"enabled": true, "available": true, "error": null}, "activity": {"requests": 16, "in_flight": 0, "last_request_at": 1790772892}, "last_timings": {"cache_n": 16384, "prompt_n": 109934, "prompt_ms": 19791.2, "prompt_per_token_ms": 0.18, "prompt_per_second": 5554.7, "predicted_n": 9, "predicted_ms": 78.1, "predicted_per_token_ms": 8.678, "predicted_per_second": 115.2, "draft_n": 9, "draft_n_accepted": 7, "at": 1790772892}, "machine": {"at": 1790772892, "gpu": {"name": "NVIDIA GeForce RTX 5090", "used_mib": 32281.0, "total_mib": 32607.0, "util_pct": 100, "temp_c": 72, "power_w": 528.823}, "ram": {"used_gib": 45.4, "total_gib": 62.2}}}
@@ -0,0 +1,46 @@
{
"service": "strata",
"model": "qwen3.8-flash-next-iq2_xs",
"engine": "0.1.29",
"started": 1790772696,
"uptime_s": 2,
"cache_max_tokens": 131072,
"context": {
"native": 131072,
"max_positions": 131072
},
"concurrency": {
"serving": 1,
"requested": 1
},
"dialects": [
"/v1/chat/completions",
"/v1/messages"
],
"vision": {
"enabled": true,
"available": true,
"error": null
},
"activity": {
"requests": 0,
"in_flight": 0,
"last_request_at": null
},
"last_timings": null,
"machine": {
"at": 1790772698,
"gpu": {
"name": "NVIDIA GeForce RTX 5090",
"used_mib": 32195.0,
"total_mib": 32607.0,
"util_pct": 0,
"temp_c": 36,
"power_w": 83.403
},
"ram": {
"used_gib": 44.4,
"total_gib": 62.2
}
}
}
@@ -0,0 +1,10 @@
{
"samples": 250,
"sample_duration_s": 255.8539924621582,
"sampling_method": "nominal 1 s; /proc/meminfo and nvidia-smi; startup through recall checks",
"ram_peak_GiB": 45.54487228393555,
"gpu_peak_MiB": 31785.0,
"swap_start_MiB": 0.25,
"swap_peak_MiB": 425.5,
"swap_end_MiB": 425.5
}
@@ -0,0 +1,46 @@
[
{
"repository": "ISTA-DASLab/Qwen3.8-Flash-Next-GSQ-RCO-GGUF",
"revision": "ed59f92082b1e93c0e96d60a8b11aab089b52f09",
"gguf_files": [
{
"filename": "IQ2_XS/Qwen3.8-Flash-Next-GSQ-RCO-IQ2_XS-00001-of-00002.gguf",
"lfs": {
"sha256": "92cee27ae5bbadcd732416a0f7a7f0acc092399dbbe8f5a5efa707c2ec0a49d7",
"size": 39225954592,
"pointerSize": 136
},
"size": 39225954592,
"actual_sha256": "92cee27ae5bbadcd732416a0f7a7f0acc092399dbbe8f5a5efa707c2ec0a49d7",
"verified": true
},
{
"filename": "IQ2_XS/Qwen3.8-Flash-Next-GSQ-RCO-IQ2_XS-00002-of-00002.gguf",
"lfs": {
"sha256": "316b46f3a2dbd68c900f43136ab9449f9dcc3725dfd8c794847c204bc161e113",
"size": 28800138432,
"pointerSize": 136
},
"size": 28800138432,
"actual_sha256": "316b46f3a2dbd68c900f43136ab9449f9dcc3725dfd8c794847c204bc161e113",
"verified": true
},
{
"filename": "mmproj-Qwen3.8-Flash-Next-BF16.gguf",
"lfs": {
"sha256": "b1a82259702816a5330d7bd7607cd9676b11780e79ff7348c21103ff3ce49bd0",
"size": 907543008,
"pointerSize": 134
},
"size": 907543008,
"actual_sha256": "b1a82259702816a5330d7bd7607cd9676b11780e79ff7348c21103ff3ce49bd0",
"verified": true
}
]
},
{
"repository": "Qwen/Qwen3.8-Flash-Next",
"revision": "de4b8e4d43b917e7706784d8bb445c9af86a3540",
"gguf_files": []
}
]
@@ -0,0 +1,18 @@
"""Sample system RAM, swap and GPU memory once per second during the trial."""
import json
import subprocess
import sys
import time
from pathlib import Path
with Path(sys.argv[1] if len(sys.argv) > 1 else 'telemetry.jsonl').open('a') as output:
while True:
memory = {}
for line in Path('/proc/meminfo').read_text().splitlines():
key, value = line.split(':', 1)
if key in ('MemTotal', 'MemAvailable', 'SwapTotal', 'SwapFree'):
memory[key + '_KiB'] = int(value.strip().split()[0])
gpu = subprocess.check_output(['nvidia-smi', '--query-gpu=memory.used,memory.total,utilization.gpu,power.draw,temperature.gpu', '--format=csv,noheader,nounits'], text=True).strip()
output.write(json.dumps({'epoch_s': time.time(), 'memory': memory, 'gpu': gpu}) + '\n')
output.flush()
time.sleep(1)
@@ -0,0 +1,429 @@
[
{
"name": "mtp.fc_embedding.weight",
"shard": "model-00120-of-00131.safetensors",
"dtype": "BF16",
"shape": [
2560,
2560
],
"start": 1935412640,
"end": 1948519839,
"bytes": 13107200,
"file": "tensors/mtp.fc_embedding.weight.bin",
"sha256": "241d6e87ded317a61b1aeb3ca4e28c53f1caba09ad5be66092e91fe5e3e14751"
},
{
"name": "mtp.fc_hidden.weight",
"shard": "model-00124-of-00131.safetensors",
"dtype": "BF16",
"shape": [
2560,
2560
],
"start": 1716599928,
"end": 1729707127,
"bytes": 13107200,
"file": "tensors/mtp.fc_hidden.weight.bin",
"sha256": "97c8e427ad0177e2c713ed24a397d815b523eda15ef453f1ae6463f6c70a8f96"
},
{
"name": "mtp.hyper_connection_mixer.hc_norm.weight",
"shard": "model-00037-of-00131.safetensors",
"dtype": "BF16",
"shape": [
10240
],
"start": 1742326680,
"end": 1742347159,
"bytes": 20480,
"file": "tensors/mtp.hyper_connection_mixer.hc_norm.weight.bin",
"sha256": "ce948a398e15aeaa403c424cda34e6eed296ab2570d591bb5ff3da642b255d64"
},
{
"name": "mtp.hyper_connection_mixer.input_mix_weight_down.weight",
"shard": "model-00041-of-00131.safetensors",
"dtype": "BF16",
"shape": [
320,
10240
],
"start": 1935412688,
"end": 1941966287,
"bytes": 6553600,
"file": "tensors/mtp.hyper_connection_mixer.input_mix_weight_down.weight.bin",
"sha256": "c633d2841fda463e82045e0b93fb8cb8d511ec0c9eda616020f01aca18d71947"
},
{
"name": "mtp.hyper_connection_mixer.input_mix_weight_up.weight",
"shard": "model-00043-of-00131.safetensors",
"dtype": "BF16",
"shape": [
10240,
320
],
"start": 1832518416,
"end": 1839072015,
"bytes": 6553600,
"file": "tensors/mtp.hyper_connection_mixer.input_mix_weight_up.weight.bin",
"sha256": "6565285f0ba2923703252763cfc11d8a9bda40ab42e7548e12464b04dbdbec13"
},
{
"name": "mtp.layers.0.attn_hyper_connection.block_inject_weight.weight",
"shard": "model-00047-of-00131.safetensors",
"dtype": "BF16",
"shape": [
4,
10240
],
"start": 1716599984,
"end": 1716681903,
"bytes": 81920,
"file": "tensors/mtp.layers.0.attn_hyper_connection.block_inject_weight.weight.bin",
"sha256": "c8afff64e7f54412d02120097c4255033c55245e1c1eed84cc630d428ccb864c"
},
{
"name": "mtp.layers.0.attn_hyper_connection.hc_norm.weight",
"shard": "model-00049-of-00131.safetensors",
"dtype": "BF16",
"shape": [
10240
],
"start": 1935412672,
"end": 1935433151,
"bytes": 20480,
"file": "tensors/mtp.layers.0.attn_hyper_connection.hc_norm.weight.bin",
"sha256": "1fb619aeaaf637ccd70f46f1f8f8116e6a46448cb43026b246de8ee8286ed809"
},
{
"name": "mtp.layers.0.attn_hyper_connection.input_mix_weight_down.weight",
"shard": "model-00053-of-00131.safetensors",
"dtype": "BF16",
"shape": [
320,
10240
],
"start": 1832518424,
"end": 1839072023,
"bytes": 6553600,
"file": "tensors/mtp.layers.0.attn_hyper_connection.input_mix_weight_down.weight.bin",
"sha256": "e80ac8bf3e270e9d5a949ec7c913329dc8de017d69851334820fae7b8c86a7f5"
},
{
"name": "mtp.layers.0.attn_hyper_connection.input_mix_weight_up.weight",
"shard": "model-00057-of-00131.safetensors",
"dtype": "BF16",
"shape": [
10240,
320
],
"start": 1935412680,
"end": 1941966279,
"bytes": 6553600,
"file": "tensors/mtp.layers.0.attn_hyper_connection.input_mix_weight_up.weight.bin",
"sha256": "f80f1fd44e1183e7764ea496b11ff89ead9dd758f861d4e79a770bf54956b1a5"
},
{
"name": "mtp.layers.0.mlp.experts.down_proj",
"shard": "model-00062-of-00131.safetensors",
"dtype": "BF16",
"shape": [
512,
2560,
640
],
"start": 1832518400,
"end": 3510239999,
"bytes": 1677721600,
"file": "tensors/mtp.layers.0.mlp.experts.down_proj.bin",
"sha256": "539c46234f73bac70450f731f40e715f77ac32faf77def0f3f800e58aaabbbc0"
},
{
"name": "mtp.layers.0.mlp.experts.gate_up_proj",
"shard": "model-00060-of-00131.safetensors",
"dtype": "BF16",
"shape": [
512,
1280,
2560
],
"start": 115918328,
"end": 3471361527,
"bytes": 3355443200,
"file": "tensors/mtp.layers.0.mlp.experts.gate_up_proj.bin",
"sha256": "839e98f9642ebc884b178abd2090b6dc8b0bcd81ed92d7f7a08314c6a68f96d5"
},
{
"name": "mtp.layers.0.mlp.gate.weight",
"shard": "model-00066-of-00131.safetensors",
"dtype": "BF16",
"shape": [
512,
2560
],
"start": 1716599952,
"end": 1719221391,
"bytes": 2621440,
"file": "tensors/mtp.layers.0.mlp.gate.weight.bin",
"sha256": "f0d35fa41b360a08bc0c5b1e5766aa42df960291716ee189208b5d2599462c20"
},
{
"name": "mtp.layers.0.mlp.shared_expert.down_proj.weight",
"shard": "model-00076-of-00131.safetensors",
"dtype": "BF16",
"shape": [
2560,
640
],
"start": 1935412680,
"end": 1938689479,
"bytes": 3276800,
"file": "tensors/mtp.layers.0.mlp.shared_expert.down_proj.weight.bin",
"sha256": "d2ced8c81367cc494599d1a8cdc279c3dd6579b628ded05acd7495e99cee01d8"
},
{
"name": "mtp.layers.0.mlp.shared_expert.gate_proj.weight",
"shard": "model-00072-of-00131.safetensors",
"dtype": "BF16",
"shape": [
640,
2560
],
"start": 1832518528,
"end": 1835795327,
"bytes": 3276800,
"file": "tensors/mtp.layers.0.mlp.shared_expert.gate_proj.weight.bin",
"sha256": "f4a81109165853b3b64f36d809f98094b599763364070f5fa079200e1c386d4c"
},
{
"name": "mtp.layers.0.mlp.shared_expert.up_proj.weight",
"shard": "model-00072-of-00131.safetensors",
"dtype": "BF16",
"shape": [
640,
2560
],
"start": 1835795328,
"end": 1839072127,
"bytes": 3276800,
"file": "tensors/mtp.layers.0.mlp.shared_expert.up_proj.weight.bin",
"sha256": "172586861eea53efbff10afc43ded5b6e49c83879e9efc01e089c652bbb0a156"
},
{
"name": "mtp.layers.0.mlp.shared_expert_gate.weight",
"shard": "model-00070-of-00131.safetensors",
"dtype": "BF16",
"shape": [
1,
2560
],
"start": 1832518400,
"end": 1832523519,
"bytes": 5120,
"file": "tensors/mtp.layers.0.mlp.shared_expert_gate.weight.bin",
"sha256": "acdd306d9996d356e4667a16ff63af6fef086fc7f570f1bc00bbe882a2a93f6e"
},
{
"name": "mtp.layers.0.mlp_hyper_connection.block_inject_weight.weight",
"shard": "model-00078-of-00131.safetensors",
"dtype": "BF16",
"shape": [
4,
10240
],
"start": 1832518424,
"end": 1832600343,
"bytes": 81920,
"file": "tensors/mtp.layers.0.mlp_hyper_connection.block_inject_weight.weight.bin",
"sha256": "c5782dd92b479a1f8ef43d683fe9c917fd9e8fba81f23c1aae8817bfe4b476a6"
},
{
"name": "mtp.layers.0.mlp_hyper_connection.hc_norm.weight",
"shard": "model-00082-of-00131.safetensors",
"dtype": "BF16",
"shape": [
10240
],
"start": 1935412656,
"end": 1935433135,
"bytes": 20480,
"file": "tensors/mtp.layers.0.mlp_hyper_connection.hc_norm.weight.bin",
"sha256": "21a504876b5e7b788301557c68dfb757999430eba36c66ec8ab96a63604dbfd1"
},
{
"name": "mtp.layers.0.mlp_hyper_connection.input_mix_weight_down.weight",
"shard": "model-00086-of-00131.safetensors",
"dtype": "BF16",
"shape": [
320,
10240
],
"start": 1935412696,
"end": 1941966295,
"bytes": 6553600,
"file": "tensors/mtp.layers.0.mlp_hyper_connection.input_mix_weight_down.weight.bin",
"sha256": "b71240036dea954e034d5ae04e097bcd7ac51cb28a44e4c93d198af3447278a1"
},
{
"name": "mtp.layers.0.mlp_hyper_connection.input_mix_weight_up.weight",
"shard": "model-00088-of-00131.safetensors",
"dtype": "BF16",
"shape": [
10240,
320
],
"start": 1832518424,
"end": 1839072023,
"bytes": 6553600,
"file": "tensors/mtp.layers.0.mlp_hyper_connection.input_mix_weight_up.weight.bin",
"sha256": "40756866bf2a5e82c28e407f717b6fa07614d593f78e79c7ceb2cd4ffe6dda94"
},
{
"name": "mtp.layers.0.self_attn.indexer.index_qk_proj.weight",
"shard": "model-00090-of-00131.safetensors",
"dtype": "BF16",
"shape": [
640,
2560
],
"start": 1832518416,
"end": 1835795215,
"bytes": 3276800,
"file": "tensors/mtp.layers.0.self_attn.indexer.index_qk_proj.weight.bin",
"sha256": "2befafae6e944c1fc651fd73d4d527eb6f138a6c1679065b003128ee3150e859"
},
{
"name": "mtp.layers.0.self_attn.indexer.k_layernorm.weight",
"shard": "model-00094-of-00131.safetensors",
"dtype": "BF16",
"shape": [
128
],
"start": 1935412672,
"end": 1935412927,
"bytes": 256,
"file": "tensors/mtp.layers.0.self_attn.indexer.k_layernorm.weight.bin",
"sha256": "2db621f6a08b4085756fc69d60a4a1bd1d7fbf5d406456d2477075842efaae54"
},
{
"name": "mtp.layers.0.self_attn.indexer.q_layernorm.weight",
"shard": "model-00100-of-00131.safetensors",
"dtype": "BF16",
"shape": [
128
],
"start": 1716599968,
"end": 1716600223,
"bytes": 256,
"file": "tensors/mtp.layers.0.self_attn.indexer.q_layernorm.weight.bin",
"sha256": "afaf59f68e251939970ffdeacad0667dffc657a522bea62cdc44a52816fc49d6"
},
{
"name": "mtp.layers.0.self_attn.k_norm.weight",
"shard": "model-00102-of-00131.safetensors",
"dtype": "BF16",
"shape": [
256
],
"start": 1935412648,
"end": 1935413159,
"bytes": 512,
"file": "tensors/mtp.layers.0.self_attn.k_norm.weight.bin",
"sha256": "8f924b0357cf936e14fc34518205d000e1423aa60626827df81b0804fae8cdfd"
},
{
"name": "mtp.layers.0.self_attn.k_proj.weight",
"shard": "model-00108-of-00131.safetensors",
"dtype": "BF16",
"shape": [
512,
2560
],
"start": 1832518624,
"end": 1835140063,
"bytes": 2621440,
"file": "tensors/mtp.layers.0.self_attn.k_proj.weight.bin",
"sha256": "1a295dc2d6e633e808aeb19e00c97856a1817bbfcc83f5b610e2bfcacfcb8c38"
},
{
"name": "mtp.layers.0.self_attn.o_proj.weight",
"shard": "model-00106-of-00131.safetensors",
"dtype": "BF16",
"shape": [
2560,
6144
],
"start": 1832518400,
"end": 1863975679,
"bytes": 31457280,
"file": "tensors/mtp.layers.0.self_attn.o_proj.weight.bin",
"sha256": "9d2fcf0ac6ac19de87f638f710cfd1af6ad14141e75b7d3d5d29fbd06f374219"
},
{
"name": "mtp.layers.0.self_attn.q_norm.weight",
"shard": "model-00112-of-00131.safetensors",
"dtype": "BF16",
"shape": [
256
],
"start": 1935412664,
"end": 1935413175,
"bytes": 512,
"file": "tensors/mtp.layers.0.self_attn.q_norm.weight.bin",
"sha256": "57957aa1e7c5a3ac628bff0ec5522ad55a39b8c0b8bd2d324ae640e3771617ef"
},
{
"name": "mtp.layers.0.self_attn.q_proj.weight",
"shard": "model-00108-of-00131.safetensors",
"dtype": "BF16",
"shape": [
12288,
2560
],
"start": 1835140064,
"end": 1898054623,
"bytes": 62914560,
"file": "tensors/mtp.layers.0.self_attn.q_proj.weight.bin",
"sha256": "5220aef3d288f40759f7356af9ef453e5ac0256a38749a9bb803a4e9db58150d"
},
{
"name": "mtp.layers.0.self_attn.v_proj.weight",
"shard": "model-00108-of-00131.safetensors",
"dtype": "BF16",
"shape": [
512,
2560
],
"start": 1898054624,
"end": 1900676063,
"bytes": 2621440,
"file": "tensors/mtp.layers.0.self_attn.v_proj.weight.bin",
"sha256": "39cb12f5424e965fa71fb81db0ee230c701b7b1e0b72c36641fde7e0e41bff41"
},
{
"name": "mtp.pre_fc_norm_embedding.weight",
"shard": "model-00114-of-00131.safetensors",
"dtype": "BF16",
"shape": [
2560
],
"start": 1832518392,
"end": 1832523511,
"bytes": 5120,
"file": "tensors/mtp.pre_fc_norm_embedding.weight.bin",
"sha256": "04c4a570850e06f2d8913da8220d54d4c7f87db6eb6d45480b938e8ba41d6a86"
},
{
"name": "mtp.pre_fc_norm_hidden.weight",
"shard": "model-00118-of-00131.safetensors",
"dtype": "BF16",
"shape": [
10240
],
"start": 1716599944,
"end": 1716620423,
"bytes": 20480,
"file": "tensors/mtp.pre_fc_norm_hidden.weight.bin",
"sha256": "b933b44559879449b1baf2af8385c5c237347307e3fd452394870cb53e6eab6d"
}
]
@@ -0,0 +1,56 @@
[
{
"length": "32k",
"depth": 10,
"prompt_tokens": 30804,
"seconds": 6.5,
"found": true,
"word": "meadow-copper-504",
"answer": "meadow-copper-504"
},
{
"length": "32k",
"depth": 50,
"prompt_tokens": 30804,
"seconds": 5.8,
"found": true,
"word": "falcon-quartz-940",
"answer": "falcon-quartz-940"
},
{
"length": "32k",
"depth": 90,
"prompt_tokens": 30805,
"seconds": 5.8,
"found": true,
"word": "willow-cobalt-696",
"answer": "willow-cobalt-696"
},
{
"length": "128k",
"depth": 10,
"prompt_tokens": 126320,
"seconds": 22.5,
"found": true,
"word": "falcon-saffron-138",
"answer": "falcon-saffron-138"
},
{
"length": "128k",
"depth": 50,
"prompt_tokens": 126318,
"seconds": 22.8,
"found": true,
"word": "quartz-tundra-528",
"answer": "quartz-tundra-528"
},
{
"length": "128k",
"depth": 90,
"prompt_tokens": 126318,
"seconds": 20.1,
"found": true,
"word": "quartz-glacier-192",
"answer": "quartz-glacier-192"
}
]
Loaded 100 of 743 files, more files were not shown because too many files have changed in this diff. Show more