From 1ea57758a6a897341bed0f59731bfbac932921bc Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Thu, 27 Aug 2026 13:40:29 -0700 Subject: [PATCH 01/10] dasLLAMA metal: deep-dense dev-W tiling - tile counts to 32, no occupancy floor The dev-W N-tile search capped at 8 tiles, so a 24B-class FFN panel (335MB up/gate/down at dim 5120 x ffn 32768) never fit the 32MB knee and the whole FFN fell back to the kq-tg twin at every prompt size. Extending the search to 32 tiles engages dev-W on all three FFN matrices; the occupancy floor probed for tc>8 measured OUT (a 20-tg tile dispatch still beats the kq-tg fallback at 512 rows, +3.8%). Mistral-Small-24B Q4_K_M pp512: 685 -> 889 tok/s (+29.7%, 0.684x -> 0.897x upstream); pp2048 ~+25%. Qwen 27Bs, gemma 12B/26B: flat (picks unchanged). Sanity argmax logit-exact vs the pre-fix path; kq parity arm token-exact. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014fKJGuUL8tP58Y6NvoVeSn --- modules/dasLLAMA/dasllama/dasllama_metal_prefill.das | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das index 033fc2b3f0..62dd7eb2b2 100644 --- a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das +++ b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das @@ -3088,7 +3088,7 @@ def private pf_devw_tiles(rows, d, kdim : int64; slow_fb : bool = false) : int64 let tile_floor = slow_fb ? DEVW_WIDE_N_ROWS : DEVW_LONG_K_ROWS let tile_over = slow_fb ? DEVW_SMALL_PANEL : DEVW_BIG_PANEL if (pb > tile_over && rows >= tile_floor) { - for (tc in range64(2l, 9l)) { + for (tc in range64(2l, DEVW_MAX_TILES + 1l)) { if (d % (tc * 64l) == 0l && pb / uint64(tc) <= DEVW_SMALL_PANEL && uint64(d / tc * kdim * 2l) <= g_pf_bwh_bytes) { return tc @@ -4900,6 +4900,10 @@ let DEVW_BIG_ROWS = 2048l // small M — engaged there it LOSES e2e despite winning its isolated site race let DEVW_LONG_K = 4096l let DEVW_LONG_K_ROWS = 1024l +// deep-dense panels (24B+: 300MB+ up/gate/down) need tile counts far past the 8 the first +// knee map raced; narrow tiles measured fine (a 20-tg tile dispatch still beat the kq-tg +// fallback at 512 rows), so the only tile bars are divisibility, the knee, and the pool +let DEVW_MAX_TILES = 32l var private g_pf_env_span = true var private g_pf_env_logits = true var private g_pf_env_attn = true From c898c71e36e67d7086444db9c0ed41e443eca152 Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Thu, 27 Aug 2026 14:02:28 -0700 Subject: [PATCH 02/10] dasLLAMA metal: MoE q5_1 tensor twin family (T/TH/TH128/THR) gemma-4-26B-A4B's expert down-projections are Q5_1 (expert_ffn 704 is not 256-divisible, so K-quants cannot apply) and were the last MoE format with no tensor twin - 29 of 30 layers rode the legacy monolithic-tg kernel, the board's 0.880x pp512 red. The new family stamps the K45 twins' expert fold with the legacy kernel's 32-block d/m decode; the pick guards kdim % 64 (the twins walk 64-deep K chunks) and falls back to the legacy form. gemma-26B pp512: 3041 -> 3652 tok/s (+20%, 0.880x -> 1.055x upstream). Gates: kernels-suite twin + tall-pair legs, bit-exact on the exact- arithmetic q51 planes, with a poisoned negative control; fam-gemma4moe support-matrix engage/logits cells pass on the twin path. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014fKJGuUL8tP58Y6NvoVeSn --- .../dasllama/dasllama_metal_prefill.das | 128 +++++++++++++++++- .../tests/test_metal_prefill_kernels.das | 116 ++++++++++++++++ 2 files changed, 238 insertions(+), 6 deletions(-) diff --git a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das index 62dd7eb2b2..4e81e8b856 100644 --- a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das +++ b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das @@ -1126,6 +1126,93 @@ class MetalMoeMulMmK5THR : MetalMoeMulMmK45TensorT { override REM = true } +// Metal-4 staged-tile twin of the MoE Q5_1 form — the legacy kernel's 32-block d/m decode +// (d at 2*blk, m at 2*blk+1; 5 uints/block: 4 nibble words + qh) with the MoeQ8 twin's +// expert fold. CONTIGUOUS rows only. +[ |> template_struct_instance] +class template MetalMoeMulMmQ51TensorT { + @template_constant MT : uint = 32u + @template_constant REM : bool = false + @ssbo @binding = 0 @role = "weight" @off = "soff" wsh : array + @ssbo @binding = 1 @role = "weight" @off = "qoff" wqu : array + @ssbo @binding = 3 xf : array + @ssbo @binding = 4 y : array + @uniform @binding = 5 ka : MoeMmArgs + @ssbo @binding = 6 cnt : array + @ssbo @binding = 7 basep : array + @workgroup twb : float16[4096] + + [metal_kernel(float_a_ok=true)] + def metal_moe_mulmm_q51_t { + let e = gl_WorkGroupID.z + let ce = cnt[e] + let mBase = gl_WorkGroupID.x * MT + (REM ? ce / 128u * 128u : 0u) + let lim = MT == 128u ? ce / 128u * 128u : (ce + 31u) / 32u * 32u + if (mBase >= lim) { // threadgroup-uniform exit — cooperative-safe + return + } + let rbase = basep[e] + let nBase = gl_WorkGroupID.y * 64u + let nkb = ka.kdim / 32u + let lid = gl_LocalInvocationID.x + var acc : float[8192] + var cp = unsafe(addr(y[(rbase + mBase) * ka.ndim + nBase])) + tmm2d_tg_begin_deva(acc, unsafe(addr(xf[0])), MT, 64u, 4u, 64u) + var kb = 0u + while (kb < nkb) { + // one work item = one (wrow, 16-element half) of the 64-deep chunk — jsl names + // its 32-block; d/m load once per item + var work = lid + while (work < 256u) { + let j = work >> 2u + let sub = work & 3u + let jsl = kb + (sub >> 1u) + let kh = (sub & 1u) * 16u + let blk = e * ka.eplane + (nBase + j) * nkb + jsl + let d = float(wsh[blk * 2u]) + let m = float(wsh[blk * 2u + 1u]) + let qb = blk * 5u + let qh = wqu[qb + 4u] + let nsh = (sub & 1u) * 4u + for [unroll_full] (t in range(16)) { + let el = kh + uint(t) + let u = wqu[qb + uint(t) / 4u] + let q = ((u >> (8u * (uint(t) % 4u) + nsh)) & 15u) | (((qh >> el) & 1u) << 4u) + twb[j * 64u + (sub >> 1u) * 32u + el] = float16(d * float(q) + m) + } + work += gl_WorkGroupSize.x + } + barrier() + tmm2d_tg_step_deva(acc, unsafe(addr(xf[(rbase + mBase) * ka.kdim + kb * 32u])), ka.kdim, twb, MT, 64u, 64u) + barrier() + kb += 2u + } + tmm2d_tg_store(acc, cp, MT, 64u, ka.ndim) + } +} + +[metal_dispatch(name = "pf_enc_moe_mm_q51_t_c", pso = "g_pf_pso_moe_mm_q51_t", tgmem = "MetalMoeMulMmQ51T_metal_moe_mulmm_q51_t_msl_tgmem", tg = 128, grid = "npos/32, rows/64, ne", params = "rows : int64, npos : int64, ne : int64")] +class MetalMoeMulMmQ51T : MetalMoeMulMmQ51TensorT { + typedef XT = float +} + +[metal_dispatch(name = "pf_enc_moe_mm_q51_th_c", pso = "g_pf_pso_moe_mm_q51_th", tgmem = "MetalMoeMulMmQ51TH_metal_moe_mulmm_q51_t_msl_tgmem", tg = 128, grid = "npos/32, rows/64, ne", params = "rows : int64, npos : int64, ne : int64")] +class MetalMoeMulMmQ51TH : MetalMoeMulMmQ51TensorT { + typedef XT = float16 +} + +[metal_dispatch(name = "pf_enc_moe_mm_q51_th128_c", pso = "g_pf_pso_moe_mm_q51_th128", tgmem = "MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl_tgmem", tg = 128, grid = "npos/128, rows/64, ne", params = "rows : int64, npos : int64, ne : int64")] +class MetalMoeMulMmQ51TH128 : MetalMoeMulMmQ51TensorT { + typedef XT = float16 + override MT = 128u +} + +[metal_dispatch(name = "pf_enc_moe_mm_q51_thr_c", pso = "g_pf_pso_moe_mm_q51_thr", tgmem = "MetalMoeMulMmQ51THR_metal_moe_mulmm_q51_t_msl_tgmem", tg = 128, grid = "4, rows/64, ne", params = "rows : int64, ne : int64")] +class MetalMoeMulMmQ51THR : MetalMoeMulMmQ51TensorT { + typedef XT = float16 + override REM = true +} + [ |> template_struct_instance] class template MetalMoeMulMmK6TensorT { @template_constant MT : uint = 32u @@ -2360,6 +2447,10 @@ var private g_pf_moe_mm_mx4_tensor : bool // "moe_mulmm_mx4" crowned (contiguous var private g_pf_pso_moe_mm_mx4_t : MetalComputePipeline? var private g_pf_pso_moe_mm_mx4_th : MetalComputePipeline? var private g_pf_pso_moe_gx : MetalComputePipeline? // gather-X materialization (up/gate contiguous form) +var private g_pf_pso_moe_mm_q51_t : MetalComputePipeline? // moe q5_1 twins (contiguous rows; the k4 crown proxies — same staging form class) +var private g_pf_pso_moe_mm_q51_th : MetalComputePipeline? +var private g_pf_pso_moe_mm_q51_th128 : MetalComputePipeline? +var private g_pf_pso_moe_mm_q51_thr : MetalComputePipeline? var private g_pf_pso_moe_mm_k4_t : MetalComputePipeline? // moe kq twins (contiguous rows; dense kq crowns gate) var private g_pf_pso_moe_mm_k4_th : MetalComputePipeline? var private g_pf_pso_moe_mm_k5_t : MetalComputePipeline? @@ -2571,7 +2662,8 @@ def public metal_prefill_shutdown { // nolint:STYLE037,STYLE038 — flat one-r g_pf_pso_moe_mm_k5_thr = null g_pf_pso_moe_mm_k6_th128 = null g_pf_pso_moe_mm_k6_thr = null - for (pp in [g_pf_pso_moe_mm_k4_t, g_pf_pso_moe_mm_k4_th, g_pf_pso_moe_mm_k5_t, g_pf_pso_moe_mm_k5_th, g_pf_pso_moe_mm_k6_t, g_pf_pso_moe_mm_k6_th]) { + for (pp in [g_pf_pso_moe_mm_k4_t, g_pf_pso_moe_mm_k4_th, g_pf_pso_moe_mm_k5_t, g_pf_pso_moe_mm_k5_th, g_pf_pso_moe_mm_k6_t, g_pf_pso_moe_mm_k6_th, + g_pf_pso_moe_mm_q51_t, g_pf_pso_moe_mm_q51_th, g_pf_pso_moe_mm_q51_th128, g_pf_pso_moe_mm_q51_thr]) { if (pp != null) { metal_release(pp) } @@ -2582,6 +2674,10 @@ def public metal_prefill_shutdown { // nolint:STYLE037,STYLE038 — flat one-r g_pf_pso_moe_mm_k5_th = null g_pf_pso_moe_mm_k6_t = null g_pf_pso_moe_mm_k6_th = null + g_pf_pso_moe_mm_q51_t = null + g_pf_pso_moe_mm_q51_th = null + g_pf_pso_moe_mm_q51_th128 = null + g_pf_pso_moe_mm_q51_thr = null if (g_pf_pso_moe_mm_mx4_th != null) { metal_release(g_pf_pso_moe_mm_mx4_th) g_pf_pso_moe_mm_mx4_th = null @@ -2756,6 +2852,11 @@ def public metal_prefill_shutdown { // nolint:STYLE037,STYLE038 — flat one-r // class; own tune families are an arc-end candidate) def private pf_compile_moe_kq_twins(var ok : bool&) { if (g_pf_kq_mm4_tensor) { + // q5_1 has no dense crown; the k4 crown proxies (same file, non-256-divisible axes) + g_pf_pso_moe_mm_q51_t = compile_pso(MetalMoeMulMmQ51T_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51T_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51T_metal_moe_mulmm_q51_t_msl_fastmath, ok) + g_pf_pso_moe_mm_q51_th = compile_pso(MetalMoeMulMmQ51TH_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51TH_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51TH_metal_moe_mulmm_q51_t_msl_fastmath, ok) + g_pf_pso_moe_mm_q51_th128 = compile_pso(MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl_fastmath, ok) + g_pf_pso_moe_mm_q51_thr = compile_pso(MetalMoeMulMmQ51THR_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51THR_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51THR_metal_moe_mulmm_q51_t_msl_fastmath, ok) g_pf_pso_moe_mm_k4_t = compile_pso(MetalMoeMulMmK4T_metal_moe_mulmm_k45_t_msl, MetalMoeMulMmK4T_metal_moe_mulmm_k45_t_msl_entry, MetalMoeMulMmK4T_metal_moe_mulmm_k45_t_msl_fastmath, ok) g_pf_pso_moe_mm_k4_th = compile_pso(MetalMoeMulMmK4TH_metal_moe_mulmm_k45_t_msl, MetalMoeMulMmK4TH_metal_moe_mulmm_k45_t_msl_entry, MetalMoeMulMmK4TH_metal_moe_mulmm_k45_t_msl_fastmath, ok) g_pf_pso_moe_mm_k4_th128 = compile_pso(MetalMoeMulMmK4TH128_metal_moe_mulmm_k45_t_msl, MetalMoeMulMmK4TH128_metal_moe_mulmm_k45_t_msl_entry, MetalMoeMulMmK4TH128_metal_moe_mulmm_k45_t_msl_fastmath, ok) @@ -3382,7 +3483,7 @@ def private kn_moe_mm_family_tail(enc : MetalComputeEncoder?; bx, by, bcnt, bbas // one gathered expert mul_mm site: grid (ceil(npos/32) tiles, rows/64, ne experts); the twin // exits tiles past the expert's padded count. Per-format generated builders; the tensor twins // keep their own compact binding layout (contiguous-only) so the pick swaps builders. -def private pf_enc_moe_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; stack_off, rows, npos : int64; +def private pf_enc_moe_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; stack_off, rows, npos : int64; // nolint:STYLE037,STYLE038 — flat per-format twin-pick ladder, one arm per weight format bx, by, bcnt, bbase, bbkt : MetalBuffer?; var ka : MoeMmArgs; contiguous : bool = false; bxh : MetalBuffer? = null) { return if (g_pf_skip == "moe_mm_disp") // attribution: gather+cvt kept, mm dispatches out @@ -3405,7 +3506,21 @@ def private pf_enc_moe_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; st } } elif (fmt == KqFmt.q51) { let qp = q51_planes_of(g_dev, t, stack_off) - pf_enc_moe_mm_q51_c(enc, qp.sbuf, qp.soff, qp.qbuf, qp.qoff, bx, by, ka, bcnt, bbase, bbkt, rows, npos, ne) + // the twin walks 64-deep K chunks (2 blocks/step) — an odd 32-block count stays legacy + if (contiguous && (ka.kdim & 63u) == 0u && g_pf_pso_moe_mm_q51_t != null) { + if (bxh != null && g_pf_pso_moe_mm_q51_th != null) { + if (g_pf_env_tall && npos * int64(ka.nk) >= 128l * ne && g_pf_pso_moe_mm_q51_th128 != null && g_pf_pso_moe_mm_q51_thr != null) { + pf_enc_moe_mm_q51_th128_c(enc, qp.sbuf, qp.soff, qp.qbuf, qp.qoff, bxh, by, ka, bcnt, bbase, rows, npos, ne) + pf_enc_moe_mm_q51_thr_c(enc, qp.sbuf, qp.soff, qp.qbuf, qp.qoff, bxh, by, ka, bcnt, bbase, rows, ne) + } else { + pf_enc_moe_mm_q51_th_c(enc, qp.sbuf, qp.soff, qp.qbuf, qp.qoff, bxh, by, ka, bcnt, bbase, rows, npos, ne) + } + } else { + pf_enc_moe_mm_q51_t_c(enc, qp.sbuf, qp.soff, qp.qbuf, qp.qoff, bx, by, ka, bcnt, bbase, rows, npos, ne) + } + } else { + pf_enc_moe_mm_q51_c(enc, qp.sbuf, qp.soff, qp.qbuf, qp.qoff, bx, by, ka, bcnt, bbase, bbkt, rows, npos, ne) + } } elif (fmt == KqFmt.k6) { let bq = kq_quants_of(g_dev, t, fmt, stack_off) let bs = kq_scales_of(g_dev, t, fmt, stack_off) @@ -4376,8 +4491,8 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : pf_enc_moe_mm_mx4(enc, t, t.we3_offs[l], c.n_ff_exp, npos, g4moe ? bxb2 : bxb, bmg2, bmcnt, bmbase, bmbkt, bwb3, kaup, contiguous = bxg1 != null, bxh = bxg1) } else { - let gx_th1 = fe1 == KqFmt.q8 ? g_pf_pso_moe_mm_q8_th : (fe1 == KqFmt.k4 ? g_pf_pso_moe_mm_k4_th : (fe1 == KqFmt.k5 ? g_pf_pso_moe_mm_k5_th : (fe1 == KqFmt.k6 ? g_pf_pso_moe_mm_k6_th : null))) - let gx_th3 = fe3 == KqFmt.q8 ? g_pf_pso_moe_mm_q8_th : (fe3 == KqFmt.k4 ? g_pf_pso_moe_mm_k4_th : (fe3 == KqFmt.k5 ? g_pf_pso_moe_mm_k5_th : (fe3 == KqFmt.k6 ? g_pf_pso_moe_mm_k6_th : null))) + let gx_th1 = fe1 == KqFmt.q8 ? g_pf_pso_moe_mm_q8_th : (fe1 == KqFmt.k4 ? g_pf_pso_moe_mm_k4_th : (fe1 == KqFmt.k5 ? g_pf_pso_moe_mm_k5_th : (fe1 == KqFmt.k6 ? g_pf_pso_moe_mm_k6_th : (fe1 == KqFmt.q51 ? g_pf_pso_moe_mm_q51_th : null)))) + let gx_th3 = fe3 == KqFmt.q8 ? g_pf_pso_moe_mm_q8_th : (fe3 == KqFmt.k4 ? g_pf_pso_moe_mm_k4_th : (fe3 == KqFmt.k5 ? g_pf_pso_moe_mm_k5_th : (fe3 == KqFmt.k6 ? g_pf_pso_moe_mm_k6_th : (fe3 == KqFmt.q51 ? g_pf_pso_moe_mm_q51_th : null)))) let gx_q8 = gx_th1 != null && gx_th3 != null let bxg1 = pf_moe_gather_panel(enc, bmbkt, g4moe ? bxb2 : bxb, bmxg, gx_q8, dim, c.n_expert_used, c.n_expert, mpad, npos) @@ -4421,7 +4536,8 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : fe2 == KqFmt.q8 ? g_pf_pso_moe_mm_q8_th != null : ( fe2 == KqFmt.k4 ? g_pf_pso_moe_mm_k4_th != null : ( fe2 == KqFmt.k5 ? g_pf_pso_moe_mm_k5_th != null : ( - fe2 == KqFmt.k6 && g_pf_pso_moe_mm_k6_th != null)))) + fe2 == KqFmt.k6 ? g_pf_pso_moe_mm_k6_th != null : ( + fe2 == KqFmt.q51 && g_pf_pso_moe_mm_q51_th != null))))) // the bucket panel is PADDED — the twin indexes rows via basep, so the // convert must cover mpad rows, not the mtot prefix (tail experts read f16) let bxh_mg = down_th ? pf_cvt_panel(enc, bmg, mpad, c.n_ff_exp, g_pf_skip == "moe_cvt") : null diff --git a/modules/dasLLAMA/tests/test_metal_prefill_kernels.das b/modules/dasLLAMA/tests/test_metal_prefill_kernels.das index a8b711918a..4956d7c8df 100644 --- a/modules/dasLLAMA/tests/test_metal_prefill_kernels.das +++ b/modules/dasLLAMA/tests/test_metal_prefill_kernels.das @@ -618,6 +618,7 @@ def test_metal_prefill_kernels(t : T?) { moe_gemv_q51_gate(t, dev, queue, 64, 24, 5, 3, 3, true) // batch streams, down form moe_mulmm_q51_gate(t, dev, queue, 64, 64, [32, 40, 64]) // padded tail on expert 1 moe_mulmm_q51_gate(t, dev, queue, 96, 128, [8, 96]) // 2 col tiles, tiny run + multi-tile + moe_mulmm_q51_gate(t, dev, queue, 64, 64, [136, 32]) // counts crossing 128 — both tall-pair stamps live // ===== mx4 expert GEMV (reworked to the q51 shape — gpt-oss's decode kernel) ===== moe_gemv_mx4_gate(t, dev, queue, 96, 24, 5, 3, 1, false, false) // gate/up (shared x) @@ -2214,6 +2215,22 @@ def private moe_gemv_mx4_gate(t : T?; dev, queue; n, d, net, k, nst : int; persl // The gathered q51 mul_mm: ne experts with padded-CSR row runs (gather = 0 bucket-rows mode); // exact-arithmetic planes (the A tile's f16(d*q + m) values are dyadic <= 63.25 — f16-exact), // int x rows — every simdgroup accumulate is exact, so the whole padded y compares BIT-exact. +// Metal-4 tensor toolchain probe (the gemm file's twin, file-private there): one crowned +// twin PSO compiling proves the toolchain, so a later twin compile failure is a RED +var private g_m4_probed = false +var private g_m4_ok = false + +def private metal4_tensor_available(dev) : bool { + if (!g_m4_probed) { + g_m4_probed = true + var err : string + var p1 = pipeline_from_source(dev, MetalQ8MulMmT_metal_q8_mulmm_t_msl, MetalQ8MulMmT_metal_q8_mulmm_t_msl_entry, MetalQ8MulMmT_metal_q8_mulmm_t_msl_fastmath, err) + g_m4_ok = p1 != null + metal_release(p1) + } + return g_m4_ok +} + def private moe_mulmm_q51_gate(t : T?; dev, queue; kdim, ndim : int; counts : array) { var err : string var pso = pipeline_from_source(dev, metal_moe_mulmm_q51_msl, metal_moe_mulmm_q51_msl_entry, metal_moe_mulmm_q51_msl_fastmath, err) @@ -2285,6 +2302,105 @@ def private moe_mulmm_q51_gate(t : T?; dev, queue; kdim, ndim : int; counts : ar } t |> success(ran, "moe q51 mulmm dispatch kdim={kdim} ndim={ndim} ne={ne} pad={pad}: {err}") t |> equal(buf_mismatch_exact(by, want), 0) + // the contiguous tensor twin (TH stamp over an f16 X): same exact-arithmetic oracle — + // pow2 d / quarter m / int x all stage to f16 losslessly, so the twin is BIT-exact too. + // The twin walks 64-deep K chunks, so kdim % 64 != 0 fixtures cover the legacy form only + // (the pick guards the same bound). + if (kdim % 64 != 0) { + metal_release(bw) + metal_release(bs) + metal_release(bx) + metal_release(by) + metal_release(bcnt) + metal_release(bbase) + metal_release(bbkt) + metal_release(pso) + delete qp + delete sp + delete wref + delete cnt + delete basep + delete xv + delete want + return + } + var terr : string + var tw_pso = pipeline_from_source(dev, MetalMoeMulMmQ51TH_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51TH_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51TH_metal_moe_mulmm_q51_t_msl_fastmath, terr) + if (tw_pso == null && !metal4_tensor_available(dev)) { + to_log(LOG_INFO, "moe q51 mulmm twin: no Metal-4 tensor toolchain - twin leg skipped\n") + } else { + t |> success(tw_pso != null, "moe q51 mulmm twin: pipeline: {terr}") + } + if (tw_pso != null) { + var xh <- [for (v in xv); float16(v)] + var bxh = buf_upload(dev, xh) + var by_t = buf_fill(dev, pad * ndim, -500.0) + let rant = with_compute_encoder(queue, terr) $(enc : MetalComputeEncoder?) { + metal_set_pipeline(enc, tw_pso) + metal_set_threadgroup_memory_length(enc, MetalMoeMulMmQ51TH_metal_moe_mulmm_q51_t_msl_tgmem, 0) + metal_set_buffer(enc, bs, 0ul, 0) + metal_set_buffer(enc, bw, 0ul, 1) + metal_set_buffer(enc, bxh, 0ul, 3) + metal_set_buffer(enc, by_t, 0ul, 4) + metal_set_bytes(enc, unsafe(addr(ka)), uint64(typeinfo sizeof(ka)), 5) + metal_set_buffer(enc, bcnt, 0ul, 6) + metal_set_buffer(enc, bbase, 0ul, 7) + metal_dispatch_threadgroups(enc, uint3(uint(tiles), uint(ndim / 64), uint(ne)), uint3(128u, 1u, 1u)) + } + t |> success(rant, "moe q51 mulmm twin: encode: {terr}") + if (rant) { + t |> equal(buf_mismatch_exact(by_t, want), 0) + } + // the tall pair: 128-floor stamp + remainder stamp over the same fixtures — the + // toolchain is proven (tw_pso compiled), so a pair PSO that fails to compile is a RED + var tl_pso = pipeline_from_source(dev, MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl_fastmath, terr) + var rm_pso = pipeline_from_source(dev, MetalMoeMulMmQ51THR_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51THR_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51THR_metal_moe_mulmm_q51_t_msl_fastmath, terr) + t |> success(tl_pso != null && rm_pso != null, "moe q51 mulmm tall pair: pipeline: {terr}") + if (tl_pso != null && rm_pso != null) { + var maxce = 0 + for (c in cnt) { + maxce = max(maxce, int(c)) + } + var by_p = buf_fill(dev, pad * ndim, -700.0) + let ranp = with_compute_encoder(queue, terr) $(enc : MetalComputeEncoder?) { + metal_set_pipeline(enc, tl_pso) + metal_set_threadgroup_memory_length(enc, MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl_tgmem, 0) + metal_set_buffer(enc, bs, 0ul, 0) + metal_set_buffer(enc, bw, 0ul, 1) + metal_set_buffer(enc, bxh, 0ul, 3) + metal_set_buffer(enc, by_p, 0ul, 4) + metal_set_bytes(enc, unsafe(addr(ka)), uint64(typeinfo sizeof(ka)), 5) + metal_set_buffer(enc, bcnt, 0ul, 6) + metal_set_buffer(enc, bbase, 0ul, 7) + metal_dispatch_threadgroups(enc, uint3(uint((maxce + 127) / 128), uint(ndim / 64), uint(ne)), uint3(128u, 1u, 1u)) + metal_set_pipeline(enc, rm_pso) + metal_set_threadgroup_memory_length(enc, MetalMoeMulMmQ51THR_metal_moe_mulmm_q51_t_msl_tgmem, 0) + metal_set_buffer(enc, bs, 0ul, 0) + metal_set_buffer(enc, bw, 0ul, 1) + metal_set_buffer(enc, bxh, 0ul, 3) + metal_set_buffer(enc, by_p, 0ul, 4) + metal_set_bytes(enc, unsafe(addr(ka)), uint64(typeinfo sizeof(ka)), 5) + metal_set_buffer(enc, bcnt, 0ul, 6) + metal_set_buffer(enc, bbase, 0ul, 7) + metal_dispatch_threadgroups(enc, uint3(4u, uint(ndim / 64), uint(ne)), uint3(128u, 1u, 1u)) + } + t |> success(ranp, "moe q51 mulmm tall pair: encode: {terr}") + if (ranp) { + t |> equal(buf_mismatch_exact(by_p, want), 0) + } + metal_release(by_p) + } + if (tl_pso != null) { + metal_release(tl_pso) + } + if (rm_pso != null) { + metal_release(rm_pso) + } + metal_release(bxh) + metal_release(by_t) + metal_release(tw_pso) + delete xh + } metal_release(bw) metal_release(bs) metal_release(bx) From 084ef28e65f1c4b6ac195b3f9c952f63307c9631 Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Thu, 27 Aug 2026 14:38:03 -0700 Subject: [PATCH 03/10] dasLLAMA: harvest dasllama_metal_prefill.das into the document system The first harvest-on-first-touch of the [arch] experiment. 511 comments: 17 RULE -> 9 new REVIEW_GPU.md rules (pad-row B-operand ban, K/V panel sizing, GEMV-peel stride, pf_p_weight<->rowstat mirror duty, cooperative uniform-exit, bucket sentinel test, @span column-tile ban, aliased-KV ownership, race shape rule); 62 FACT -> ARCHITECTURE_GPU_PREFILL.md, a new companion carrying sec.2.2c-2.2i (GEMM form ladder, dev-W knee map, GEMV tail peel, attention slab, MoE bucket rail, pad rows, chunked submission) split out at the 300-line gate; 7 anchors cited by 10 [arch] annotations on the driver's pick/encode functions - arch_sites reports no dead anchor and no dangling citation. 4 renames (dsc_sh8/16/24, in_rotary, skip_convert, null_kv_panel); 87 drops; KEEPs compressed to //! one-liners; 1 TODO -> PERF_LEDGER (MoE twin tune families). File 5662 -> 5297 lines, comment-stripped diff byte-identical before the renames. Kernel suites green (prefill/rope/gemm); Mistral pp512 argmax logit-exact, perf unchanged (885.6 vs 889). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014fKJGuUL8tP58Y6NvoVeSn --- modules/dasLLAMA/ARCHITECTURE.md | 2 + modules/dasLLAMA/ARCHITECTURE_GPU.md | 1 - modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md | 145 +++ modules/dasLLAMA/PERF_LEDGER.md | 7 + modules/dasLLAMA/REVIEW_GPU.md | 40 + .../dasllama/dasllama_metal_prefill.das | 1142 ++++++----------- 6 files changed, 585 insertions(+), 752 deletions(-) create mode 100644 modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md diff --git a/modules/dasLLAMA/ARCHITECTURE.md b/modules/dasLLAMA/ARCHITECTURE.md index b4d33a415a..bf898004ea 100644 --- a/modules/dasLLAMA/ARCHITECTURE.md +++ b/modules/dasLLAMA/ARCHITECTURE.md @@ -38,6 +38,8 @@ re-transcoding `$LCPP/src/unicode-data.cpp`). - `ARCHITECTURE_IMAGE.md` - sec.2.1-2.1g: the prepared-image rail. - `ARCHITECTURE_GPU.md` - sec.2.2b: the tensor-GEMM and fused-attention shapes that measured out. +- `ARCHITECTURE_GPU_PREFILL.md` - sec.2.2c-2.2i: the Metal prefill driver's GEMM form ladder, + dev-W knee map, attention slab, MoE bucket rail, and chunked submission. - `ARCHITECTURE_RUNTIME.md` - sec.2.2-2.4, 2.6-2.9, 2.11, 2.12: kernel shape, caches, lint policy, knobs, coverage, the GPU ramp. - `ARCHITECTURE_MEASUREMENT.md` - sec.2.5, 2.10: the benchmark rig, the tune gate, and the diff --git a/modules/dasLLAMA/ARCHITECTURE_GPU.md b/modules/dasLLAMA/ARCHITECTURE_GPU.md index ca8c58cd42..90661b10af 100644 --- a/modules/dasLLAMA/ARCHITECTURE_GPU.md +++ b/modules/dasLLAMA/ARCHITECTURE_GPU.md @@ -189,4 +189,3 @@ The positive laws these races established - half operands, stage-only-to-transfo consecutive staging runs, relaxed_precision always - are `REVIEW_GPU.md` rules and the `modules/dasMetal/REVIEW.das` descriptor gate; this section keeps only the refuted shapes and why they lose. - diff --git a/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md b/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md new file mode 100644 index 0000000000..c9415220d5 --- /dev/null +++ b/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md @@ -0,0 +1,145 @@ +# dasLLAMA Architecture - the Metal prefill driver + +Companion to `ARCHITECTURE.md`; section numbers are that document's. + +### 2.2c The prefill GEMM form ladder {#prefill-gemm-ladder} + +Every weight GEMM in `dasllama_metal_prefill.das` picks one of four forms, in this order, per site +per forward: + +1. **dev-W all-device** - the weight plane is dequantized into a device f16 panel and multiplied + half x half. No threadgroup staging and no barriers, so the staged-operand tax is gone; the + dequant pass is paid once per site per forward against a GEMM that re-reads the operand `d/64` + times. sec.2.2d carries the panel size rules. +2. **tall 128-row M-tile** - the stamp streams W `M/128` times over a 128-row tile, taken on the + row count's 128-floor with the 32-row stamp on the remainder. The remainder arm strides X by + `kdim`, so a caller that passes no `kdim` stays whole-dispatch 32-tile. +3. **32-row tile** - the default stamp. +4. **GEMV tail peel** - sec.2.2e. + +**Half operands ride an f16 activation panel.** One pass converts the f32 panel; the GEMM then +re-reads it at half the bytes `d/64` times, so the convert amortizes above a row floor +(`CVT_MIN_ROWS`, default 256) and loses under it. The panel is double-buffered so a consumer's +GEMM overlaps the next twin's producer, and a producer that dual-stores the f16 form takes a panel +ungated by rows because its twin is free. + +**The bf16-A stamp widens without dequantizing** - a bf16 row widens by an exact bit shift and +rounds to the f16 tile - so the E-series `per_layer_model_proj` GEMM serves straight off the +kept-bf16 blob with no resident f32 copy. + +**The staging form that wins is per format, not universal.** The gathered q8 mul_mm carries its +scale and quant pointers across k-blocks; the stateless index form measured 3.4-3.6% slower in the +gmm8 lab. The gathered Q6_K goes the other way: the superblock-scalar cache the standalone kernel +carried measured 2.4% slower per mm than reloading per k-block in the gmm6 lab, so its stage is +stateless. + +**The occupancy floor guards the tall stamp.** A tall grid is taken only when +`rows/128 * (d/64) >= TALL_OCC_FLOOR` (default 64, a sidecar knob). An under-occupied tall grid +starves the GPU and small prompts regress hard without the floor; 32 adds nothing over 64, raced +at mid-M across three dense families. + +### 2.2d The dev-W panel knee map {#devw-panel-knees} + +Panel SIZE dominates the dev-W decision, not shape: a panel at or under 32 MiB wins at every row +count, 47 MiB wins only from 2048 rows, and 112 MiB loses everywhere - the f16 panel's W stream is +2 bytes an element against the q8 blob's 1.06 once it leaves cache. Wide-N panels pay a dequant +tax that only deep M repays. The grid these rules come from is +`benchmarks/matmul/bench_metal_nax_probe.das`. + +Three clauses the isolated grid cannot see, because it races one site while production overlaps +sites: + +- **A long-K (down-projection) dequant serializes** on the panel pair behind the up/gate GEMM + chain at small M, so it loses end to end there despite winning its isolated site race. The + long-K floor is 1024 rows; the isolated tiled win at 512 rows read flat-negative end to end. +- **An over-knee panel runs as N-column TILES**, each under the small-panel knee, with the tile + count bounded only by divisibility, the knee and the pool. Deep-dense models (300 MB+ + up/gate/down planes) need far more tiles than the first knee map raced, and narrow tiles measure + fine - a 20-threadgroup tile dispatch still beat the tg-staged fallback at 512 rows. +- **A k-quant tg fallback is about 1.28x the q8 half-panel form**, so a k-quant site lowers both + the over-knee bar and the tiled-rows floor: a tiled read still beats THAT fallback. + +The knee constants are box-raced and cached at init from the sidecar (`metal_cvt_min_rows`, +`metal_tall_floor`, `metal_devw_small_panel_mb`). + +### 2.2e The GEMV tail peel {#gemv-tail-peel} + +A prefill panel pads to `mp = ceil32(npos)`, so `npos % 32` rows of every GEMM are padding. Up to +`MM_TAIL_MAX` (8) remainder rows peel off the padded tile onto the fixed-B mv family instead; +above that the padded tile is cheaper than three or more weight streams. One peeled row rides the +reduction-split GEMV, two or more ride the b4 form only - the reduction-split GEMV walks per +block and needs `kdim % 32`, while the b4 stripe reads whole 128-quant rounds. + +### 2.2f The prefill attention slab {#prefill-attn-slab} + +Prefill attention is a three-kernel pipeline over one per-head f16 score slab padded to +`np32 = ceil32(npos)` columns: QK writes the raw scores half once, rowstat mints each row's max +and reciprocal sum, and AV applies `exp` while it stages P. The slab is written once and read +once, and no separate softmax pass touches it. Every stage and every stamp of every stage binds +ONE `AttnArgs` value, derived once per layer, and ignores the fields it does not read. Two forms +serve it: the tiled QK/AV GEMM pair (the default, needing `head_size % 64` on BOTH attention +classes) and the scalar 32x32 trio, which serves when that gate fails or `DASLLAMA_METAL_ATTN=0` +pins it. + +- **A pad row of K or V stages as 0.** Pad rows carry recycled pool bytes and may hold NaN, and + `0 * NaN` poisons a whole cooperative tile. `pf_p_weight` zeroes P columns past each row's live + length exactly, so the P side needs no guard; the K and V sides do. +- **The PADFREE stamps drop that guard**, and an encoder may pick one only when the whole WALK + stays inside live rows - `qoff + qrows == npos` as well as the divisibility. A padded query + chunk walks pad-query tiles past `npos`, where a real row's read poisons the tile. +- **A block skip lifts to `uend` only where the tile holds span rows.** A causal-only tile above + the uniform span keeps its short causal walk, and a tile below every row's sliding window is + skipped whole because `pf_p_weight` zeroes P over the skipped region. +- **The softmax scale rides the staged K side, not Q**, because `(q*s).k == q.(k*s)` and Q streams + from device raw. + +**Two attention classes.** The config fields describe the GLOBAL class and the `_swa` twins the +SLIDING class; the loader guarantees at most two. Buffers size to the class maxima and each layer +binds its own class's uniform set - a uniform model leaves the sliding twins null and binds the +base set everywhere. + +### 2.2g The prefill MoE bucket rail {#prefill-moe-buckets} + +Routing is atomics-free: count (one threadgroup per expert) -> in-threadgroup prefix -> bucket +fill. Each expert's bucket PADS to a whole 32-row tile, every threadgroup computes the same padded +prefix, and threadgroup `e` publishes `basep[e]` for the mm and activation consumers. The bucket +fill splits the entry range into contiguous ascending per-lane chunks and scans the chunk counts, +which reproduces the serial entry order exactly, so the ordered weighted reduce is bit-stable +against the CPU park-and-accumulate. The selection is read GPU-side by the kernels; nothing reads +back to the CPU, so encode-ahead and speculation stay compatible. + +Pad bucket rows carry a stamped sentinel and the reduce never references them. The gather-X pass +copies the bucket's token rows into a CONTIGUOUS f16 panel with pad rows zeroed, which lets the up +and gate sites ride the contiguous tensor twins instead of the in-kernel gather form; the panel is +minted once per layer and shared by both sites. A bkt-indirect X can never form a tensor view, +which is why every tensor twin of the MoE family serves contiguous rows only. + +### 2.2h Pad rows and cooperative-op constraints {#prefill-pad-rows-and-coop} + +Activation panels size to `mp = ceil32(npos)` rows because every kernel's M grid is `mp/32`; a +64-row pad would bill a dead 32-row GEMM block on every short prefill. The GEMM has no edge +masking, so pad rows are written with whatever the tile computes. That is safe because C-block +rows are independent and no pad row is read back: the norm, rope, attention and elementwise +kernels all bound at `npos`, and rowstat writes `[0, npos)` only. + +A continuation chunk (`start_pos > 0`) attends the session's existing rows: the K/V panels hold +`[0, start_pos)` gathered rows plus the chunk at the `start_pos` offset, keys pad to the QK key +grid's 64-tile, and the score slabs widen to `nk64` columns while the rows stay the `mp` queries. + +Cooperative matmul ops constrain the kernel bodies two ways. The accumulate loop is spelled ROLLED +over matrix arrays with pointer tile bumps: the hand-unrolled spelling hoists sixteen tile +addresses into loop-lifetime registers and costs an occupancy tier (measured `max_threads` 704). +And an early exit inside such a body must be threadgroup-uniform. + +### 2.2i Chunked submission and interleaved readback {#prefill-chunked-submit} + +A prefill encodes into `DASLLAMA_METAL_NCB` command buffers (default about four layers each) and +commits each chunk as soon as it is encoded, so the scheduler analyzes chunk k while chunk k-1 +executes; `DASLLAMA_METAL_UNRETAINED=1` drops per-dispatch retain/release on top. Inside a chunk +the `kn_*` calls record a step graph that `graph_flush_sched` replays on a CONCURRENT encoder, +which auto-schedules and inserts barriers only at real hazards (`DASLLAMA_METAL_SCHED=0` keeps +capture order, `DASLLAMA_METAL_PF_CAPTURE=0` is the serial-encode rollback). + +Completion and readback interleave: chunks complete in commit order and each completed chunk's +roped-K and raw-V rows stream into the CPU K/V codec while later chunks keep the GPU busy. The +residual-stream copy waits for the LAST chunk. diff --git a/modules/dasLLAMA/PERF_LEDGER.md b/modules/dasLLAMA/PERF_LEDGER.md index 847f618364..848842dc94 100644 --- a/modules/dasLLAMA/PERF_LEDGER.md +++ b/modules/dasLLAMA/PERF_LEDGER.md @@ -1066,3 +1066,10 @@ group; wording kept. paste funnel; the server replaces that funnel. - **OPEN - v2: select-two compare widget (maybe)** on the leaderboard, and publishing the depth/batch test variants (`pp512@d4096`, `tg128@b4`, ...) that stay internal-only under v1. + +### From the prefill-driver harvest (2026-08-27) + +- **OPEN - MoE k-quant twin tune families.** The moe k4/k5/k6/q51 tensor twins are gated by + the DENSE k-quant crowns rather than raced on their own; give each its own + `metal_tensor_race` family and crown so the gate stops proxying. Instrument: + `metal_tensor_race` on an M5 box, one q8 and one k-quant MoE model. diff --git a/modules/dasLLAMA/REVIEW_GPU.md b/modules/dasLLAMA/REVIEW_GPU.md index 3485a2d1a0..7c514e0935 100644 --- a/modules/dasLLAMA/REVIEW_GPU.md +++ b/modules/dasLLAMA/REVIEW_GPU.md @@ -42,12 +42,39 @@ arrays - read the one per-row entry instead.** The bucket-building kernel writes entry. The scan repeats on every thread of every row's threadgroup, and it grows with the bucket count. +**Never test a bucket row's validity by comparing it with the pad sentinel - compare it with +the live entry count instead.** Stale bytes past the last expert's stamped tail are not the +sentinel, and an equality test sends their token index out of bounds. + +**An early `return` in a kernel body that runs a cooperative op is threadgroup-uniform - never +gate it on a per-thread value.** A per-thread exit leaves the threadgroup unable to complete +the cooperative op. + **An encoder that picks a kernel's guard-free instance shows that every address the instance touches stays inside rows holding real data.** The guard-free instance is the one stamped without the loop's bounds or tail guard. One extent dividing evenly is not that showing. A padded chunk's walk can run past the live extent, and one poisoned read in a shared tile corrupts real rows. +**Never let a prefill pad output row reach a matmul as a B operand - stage it as zero, or +bound the walk at the live row count.** Pad rows hold recycled pool bytes, so a pad row used +as B multiplies stale values (NaN included) into every real row of the tile. Pad rows read as +row-confined A operands are safe. + +**A prefill K/V panel is sized from the padded write extent, never from the live key count.** +The K/V GEMMs write full M-tile rows at the chunk's row offset, so a panel sized to the live +count is overrun silently into whatever the pool put next to it. + +**Never route a GEMM site through the GEMV tail peel when its output row stride differs from +the dispatch width it passes - dispatch the padded tile instead.** The peel writes y rows at +that width, so a fused-row site whose rows are wider lands its tail rows on top of the row +beside them. + +**A diff that changes the mask, window, live-length or softcap math of `pf_p_weight` +(`dasllama/dasllama_metal_prefill.das`) changes `metal_attn_rowstat`'s copy in the same +change, and the reverse.** Rowstat mints each row's max and reciprocal sum; the AV kernels +apply the weight. Rows renormalize against the wrong max when the two disagree. + **Never leave a pipeline of dispatches with fewer scratch buffers than it has dispatches in flight - give each dispatch site its own instead.** One shared scratch serializes the whole chain through its write-after-read hazards. @@ -92,6 +119,11 @@ defect; a per-encode field either omits `@role` or names the access its body per generated builder reads - per-field `@binding` / `@role` / `@off` / `@span` / `@default`, `@workgroup` state with its `tgmem=` dispatch key.** +**Never give a `@span` to a kernel field whose callers bind a COLUMN TILE of a wider output +row - omit the span instead.** A column-tile caller passes the tile width as the kernel's n +while its rows stride the full output width, so a span computed from the tile width leaves +the rest of every row outside the tracked hazard range. + **A NEW hand-written `enc_*` body is a defect unless it is a wrapper - a format or twin pick, a default-filling wrapper, or a composite over generated builders.** @@ -125,6 +157,10 @@ that owns its kernel class** - it goes through that file's own init/release pair `dasllama/dasllama__common.das`.** Race code is the in-engine base-vs-twin check that times both kernels on one queue and compares their outputs. +**A kernel A/B race sizes its operands at a real model shape - never at a small square slab.** +A slab small enough to sit in cache ranks the kernels by an effect production never sees, and +crowns the loser. + **A string-typed Metal decline reason is a defect - a Metal decline reason is an enum value in `dasllama/dasllama_metal_shapes.das`, one enum per driver.** @@ -193,6 +229,10 @@ serves both codecs, so a codec no kernel covers silently drops that codec's GPU **An f16 store into any GPU-resident K/V that does not clamp to the f16 finite range (+/-65504) is a defect.** +**A per-layer K/V panel that aliases another layer's is gathered, stored and released only +through its source layer.** An aliasing layer that gathers, stores or releases a second time +double-frees the panel or overwrites the source's rows. + **A resident override that touches the mirror before gating the session on the armed mirror codec and on the flat (non-paged) cache is a defect** - a resident override is a decode/prefill hook the whole-model residency rail registers in diff --git a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das index 4e81e8b856..8fd5894db2 100644 --- a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das +++ b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das @@ -6,16 +6,16 @@ module dasllama_metal_prefill shared public require dasllama/dasllama_lint public require math -require daslib/math_bits // uint_bits_to_float in the mx4 GEMV (msl_emit as_type) -require dasllama/dasllama_env // the g_env_* knob globals ([EnvConfig] declarations; ENVIRONMENT.md is generated from them) +require daslib/math_bits +require dasllama/dasllama_env require metal/msl_shader require metal/das_metal_boost -require daslib/typemacro_boost // [template_struct_instance] — the tensor-twin template below +require daslib/typemacro_boost require dasllama/dasllama_common require dasllama/dasllama_math -require dasllama/dasllama_metal_common // decline enums/tables + the shared block_q8_0 blob cache (W1 split) -require dasllama/dasllama_metal_kernels // the family-shared [metal_kernel] classes both drivers dispatch (M1 move) -require dasllama/dasllama_metal_lens // [metal_dispatch] builders + census policing (lensed classes live next to their use) +require dasllama/dasllama_metal_common +require dasllama/dasllama_metal_kernels +require dasllama/dasllama_metal_lens // Phase-6 dasMetal: the full-GPU-resident prefill kernel set — everything between the GEMMs: // rmsnorm, table-driven RoPE, fused causal-softmax attention scores, the P·V gather, fused @@ -35,13 +35,10 @@ require dasllama/dasllama_metal_lens // [metal_dispatch] builders + census pol // (modules/dasLLAMA/tests/test_metal_prefill_kernels.das). -// MetalQ8MulMm with the A stage swapped to native BF16 rows (no dequant: widen = exact bit -// shift, then RNE to the f16 tile). Serves the E-series per_layer_model_proj GEMM straight off -// the kept-bf16 blob — no resident f32 copy. Same %64 shape gates, kdim % 32. [metal_dispatch(name = "pf_enc_bf16_mm_c", pso = "g_pf_pso_bf16_mm", tgmem = "metal_bf16_mulmm_msl_tgmem", tg = 128, grid = "mp/32, nd/64", params = "mp : int64, nd : int64")] class MetalBf16MulMm : MetalMmTileBase { - @ssbo @binding = 0 @role = "weight" @off = "wboff" wbh : array // bf16 W rows, ushort4 view (row r elem k at (r*kdim+k)/4) - @ssbo @binding = 2 @role = "read" xf : array // raw f32 activations, float4 view + @ssbo @binding = 0 @role = "weight" @off = "wboff" wbh : array //!< bf16 W rows, ushort4 view (row r elem k at (r*kdim+k)/4) + @ssbo @binding = 2 @role = "read" xf : array //!< raw f32 activations, float4 view @ssbo @binding = 3 @role = "write" y : array @uniform @binding = 4 kdim : uint @uniform @binding = 5 ndim : uint @@ -101,19 +98,16 @@ class MetalBf16MulMm : MetalMmTileBase { } } -// Metal-4 tensor twin of MetalQ8MulMm (same binds, blob bound twice): tmm2d_q8u_f32 stages W -// to a tg f16 tile per K-chunk, streams activations, holds one multiply_accumulate C (crown -// "mulmm_q8"). XT = the A stream codec: a float A operand is off the native half path. [ |> template_struct_instance] class template MetalQ8MulMmTensorT { - @template_constant MT : uint = 32u // M-tile rows: W re-streams M/MT times (128 = upstream's tall tile) - @ssbo @binding = 0 @role = "weight" @off = "wboff" wsh : array // 34B-block W blob, half-scale view - @ssbo @binding = 1 @role = "weight" @off = "wboff" wqb : array // the SAME blob buffer, byte view - @ssbo @binding = 2 @off = "xoff" xf : array // raw activations (float, or the converted f16 panel) + @template_constant MT : uint = 32u //!< M-tile rows: W re-streams M/MT times + @ssbo @binding = 0 @role = "weight" @off = "wboff" wsh : array //!< 34B-block W blob, half-scale view + @ssbo @binding = 1 @role = "weight" @off = "wboff" wqb : array //!< the SAME blob buffer, byte view + @ssbo @binding = 2 @off = "xoff" xf : array //!< raw activations (float, or the converted f16 panel) @ssbo @binding = 3 @off = "yoff" @span = "mp*d*4" y : array @uniform @binding = 4 kdim : uint @uniform @binding = 5 ndim : uint - @workgroup twb : float16[4096] // W chunk: 64 wcols x 64 k (bk=64), dequant-staged by the helper + @workgroup twb : float16[4096] //!< W chunk: 64 wcols x 64 k (bk=64), dequant-staged by the helper [metal_kernel(float_a_ok=true)] def metal_q8_mulmm_t { @@ -150,8 +144,6 @@ class MetalQ8MulMmTH128 : MetalQ8MulMmTensorT { override MT = 128u } -// The f32 -> f16 activation panel conversion feeding the half-X mul_mm stamp: one pass over -// the panel (paid once) against the GEMM's d/64 re-reads of it at half the bytes. struct CvtArgs { total : uint } @@ -172,14 +164,11 @@ class MetalCvtHalf { } } -// The q8 blob -> device f16 W panel pass feeding the all-device mul_mm form: one thread per -// 34B block, scale folds at dequant, output offset blk*32 stays contiguous in both layouts. -// Paid per site per forward against the GEMM escaping the tg-staged-operand tax (probe arm D). [metal_dispatch(name = "enc_dequant_q8h", pso = "g_pf_pso_dq_q8", tg = 256, grid = "total/256", params = "total : int64")] class MetalDequantQ8H { - @ssbo @binding = 0 @role = "weight" @off = "wboff" wsh : array // 34B-block W blob, half-scale view - @ssbo @binding = 1 @role = "weight" @off = "wboff" wqb : array // the SAME blob buffer, byte view - @ssbo @binding = 2 @role = "write" wh : array // the dequantized W panel, d x kdim + @ssbo @binding = 0 @role = "weight" @off = "wboff" wsh : array //!< 34B-block W blob, half-scale view + @ssbo @binding = 1 @role = "weight" @off = "wboff" wqb : array //!< the SAME blob buffer, byte view + @ssbo @binding = 2 @role = "write" wh : array //!< the dequantized W panel, d x kdim @uniform @binding = 3 ka : CvtArgs [metal_kernel(name="metal_dequant_q8h_msl")] @@ -195,14 +184,11 @@ class MetalDequantQ8H { } } -// K4/K5 superblock dequant -> panel twin of the q8 pass: one thread per 32-quant sub-block -// (blk = gid/8 superblock, js = gid%8 — the kmask decode and nibble/qh compose are the -// mul_mm twin's staging verbatim), output offset blk*256 + js*32 contiguous in both layouts. [ |> template_struct_instance] class template MetalDequantK45T { - @ssbo @binding = 0 @role = "weight" @off = "s0off" ksh : array // 16B scale blocks, half view - @ssbo @binding = 1 @role = "weight" @off = "soff" ks4 : array // the same buffer, uint4 view - @ssbo @binding = 2 @role = "weight" @off = "qoff" kqu : array // quant plane, uint view + @ssbo @binding = 0 @role = "weight" @off = "s0off" ksh : array //!< 16B scale blocks, half view + @ssbo @binding = 1 @role = "weight" @off = "soff" ks4 : array //!< the same buffer, uint4 view + @ssbo @binding = 2 @role = "weight" @off = "qoff" kqu : array //!< quant plane, uint view @ssbo @binding = 3 @role = "write" wh : array @uniform @binding = 4 ka : CvtArgs @template_constant BLK : uint = 32u @@ -254,13 +240,11 @@ class MetalDequantK5H : MetalDequantK45T { override QH = true } -// the K6 twin: per-sub-block signed sub-scale, two 16-element halves (ile) per sub-block — -// the ql|qh compose is MetalKqMulMmK6TensorT's staging verbatim [metal_dispatch(name = "enc_dequant_k6h", pso = "g_pf_pso_dq_k6", tg = 256, grid = "total/256", params = "total : int64")] class MetalDequantK6H { - @ssbo @binding = 0 @role = "weight" @off = "s0off" kdh : array // d plane (f16 tail at doff) - @ssbo @binding = 1 @role = "weight" @off = "soff" ksc : array // 16B sub-scale blocks - @ssbo @binding = 2 @role = "weight" @off = "qoff" kqu : array // ql at 48*blk, qh at 48*blk+32 + @ssbo @binding = 0 @role = "weight" @off = "s0off" kdh : array //!< d plane (f16 tail at doff) + @ssbo @binding = 1 @role = "weight" @off = "soff" ksc : array //!< 16B sub-scale blocks + @ssbo @binding = 2 @role = "weight" @off = "qoff" kqu : array //!< ql at 48*blk, qh at 48*blk+32 @ssbo @binding = 3 @role = "write" wh : array @uniform @binding = 4 ka : CvtArgs @@ -296,14 +280,12 @@ class MetalDequantK6H { } } -// The all-device half x half mul_mm form: A = the half-X activation panel, W = the dequant -// panel above — no threadgroup staging, no barriers (the staged-operand tax is out). [ |> template_struct_instance] class template MetalHalfMulMmTensorT { - @template_constant MT : uint = 32u // M-tile rows: the panel re-reads M/MT times - @ssbo @binding = 0 @role = "read" wh : array // pre-dequantized W panel, d x kdim - @ssbo @binding = 1 @role = "read" @off = "xoff" xf : array // the f16 activation panel (half-X) - @ssbo @binding = 2 @off = "yoff" y : array // no @span: the dev-W N-tiled callers pass td as d while rows stride the FULL ndim — an exact span would under-cover the hazard range + @template_constant MT : uint = 32u //!< M-tile rows: the panel re-reads M/MT times + @ssbo @binding = 0 @role = "read" wh : array //!< pre-dequantized W panel, d x kdim + @ssbo @binding = 1 @role = "read" @off = "xoff" xf : array //!< the f16 activation panel (half-X) + @ssbo @binding = 2 @off = "yoff" y : array @uniform @binding = 3 kdim : uint @uniform @binding = 4 ndim : uint @@ -326,14 +308,11 @@ class MetalHalfMulMmTH128 : MetalHalfMulMmTensorT { override MT = 128u } -// Metal-4 tensor twin of MetalBf16MulMm: the SAME tile shape off the same binds, lowered to -// mpp matmul2d over tensor_inline views (tuner crown "mulmm_bf16"). XT = the A stream codec, -// same contract as MetalQ8MulMmTensorT; MT = M-tile rows (all-device W streams M/MT times). [ |> template_struct_instance] class template MetalBf16MulMmTensorT { @template_constant MT : uint = 32u - @ssbo @binding = 0 @role = "weight" @off = "wboff" wbh : array // bf16 W rows, halfword view - @ssbo @binding = 2 @off = "xoff" xf : array // raw activations (float, or the converted f16 panel) + @ssbo @binding = 0 @role = "weight" @off = "wboff" wbh : array //!< bf16 W rows, halfword view + @ssbo @binding = 2 @off = "xoff" xf : array //!< raw activations (float, or the converted f16 panel) @ssbo @binding = 3 @off = "yoff" y : array @uniform @binding = 4 kdim : uint @uniform @binding = 5 ndim : uint @@ -371,39 +350,33 @@ class MetalBf16MulMmTH128 : MetalBf16MulMmTensorT { override MT = 128u } -// The E-series PLE pre-step's two device stages walk the SAME [n_layers x npos x ple] panel, so -// one kargs at slot 4 serves both — the gather reads sc0, the finish reads inv_sd/eps/inv_s2, and -// each ignores the other's. Every field derives from the config, hence the one builder below. struct PleArgs { npos : uint ple : uint nlayers : uint - sc0 : float // sqrt(ple), folded into the gather's dequant - inv_sd : float // 1/sqrt(dim) + sc0 : float //!< sqrt(ple), folded into the gather's dequant + inv_sd : float //!< 1/sqrt(dim) eps : float - inv_s2 : float // 1/sqrt(2) + inv_s2 : float //!< 1/sqrt(2) } def private ple_ka(npos, ple, nlayers, dim : int64; eps : float) : PleArgs => ( PleArgs(npos = uint(npos), ple = uint(ple), nlayers = uint(nlayers), sc0 = sqrt(float(ple)), inv_sd = 1.0 / sqrt(float(dim)), eps = eps, inv_s2 = 1.0 / sqrt(2.0))) -// E-series PLE gather (GPU pre-step, stage 1): dequant token row slices of the Q8_0 -// per_layer_token_embd region straight into the LAYER-major side-input panel, sqrt(ple) folded. -// One tg per (layer, position) slice; binds ride blob_of's q8 pair at the region base. [metal_dispatch(name = "pf_enc_ple_gather", pso = "g_pf_pso_ple_gather", tg = "ple", grid = "nlayers, npos", params = "nlayers : int64, npos : int64, ple : int64")] class MetalPleGatherQ8 { - @ssbo @binding = 0 @role = "weight" @off = "eoff" wsh : array // ple_emb q8 region, half-scale view (block b at 17*b) - @ssbo @binding = 1 @role = "weight" @off = "eoff" wqb : array // the SAME region, byte view (quants at 34*b + 2) - @ssbo @binding = 2 @role = "read" tok : array // [npos] token ids - @ssbo @binding = 3 @role = "write" y : array // [n_layers x npos x ple] layer-major side input + @ssbo @binding = 0 @role = "weight" @off = "eoff" wsh : array //!< ple_emb q8 region, half-scale view (block b at 17*b) + @ssbo @binding = 1 @role = "weight" @off = "eoff" wqb : array //!< the SAME region, byte view (quants at 34*b + 2) + @ssbo @binding = 2 @role = "read" tok : array //!< [npos] token ids + @ssbo @binding = 3 @role = "write" y : array //!< [n_layers x npos x ple] layer-major side input @uniform @binding = 4 ka : PleArgs [metal_kernel(name="metal_ple_gather_q8_msl")] def metal_ple_gather_q8 { let l = gl_WorkGroupID.x let p = gl_WorkGroupID.y - let i = gl_LocalInvocationID.x // tg = ple threads (gate: ple % 32 == 0, <= 1024) + let i = gl_LocalInvocationID.x //! tg = ple threads (gate: ple % 32 == 0, <= 1024) let el = tok[p] * (ka.nlayers * ka.ple) + l * ka.ple + i let blk = el / 32u let sc = float(wsh[blk * 17u]) @@ -412,14 +385,11 @@ class MetalPleGatherQ8 { } } -// E-series PLE finish (GPU pre-step, stage 2): per (layer, position) ple-slice, mirror of -// ple_pre_finish's tail — v = proj/sqrt(dim); side = (side + pnorm·(v·rsqrt(mean(v²)+eps)))/sqrt(2), -// in place on the layer-major panel the gather wrote. proj arrives position-major off the GEMM. [metal_dispatch(name = "pf_enc_ple_finish", pso = "g_pf_pso_ple_finish", tgmem = "metal_ple_finish_msl_tgmem", tg = "ple", grid = "nlayers, npos", params = "nlayers : int64, npos : int64, ple : int64")] class MetalPleFinish { - @ssbo @binding = 0 @role = "read" proj : array // [mp x n_layers*ple] position-major model_proj·embd - @ssbo @binding = 1 @role = "weight" pnorm : array // [ple] proj-norm weight - @ssbo @binding = 2 @role = "readwrite" y : array // [n_layers x npos x ple] side input, in place + @ssbo @binding = 0 @role = "read" proj : array //!< [mp x n_layers*ple] position-major model_proj·embd + @ssbo @binding = 1 @role = "weight" pnorm : array //!< [ple] proj-norm weight + @ssbo @binding = 2 @role = "readwrite" y : array //!< [n_layers x npos x ple] side input, in place @uniform @binding = 4 ka : PleArgs @workgroup partial : float[32] @workgroup inv_sh : float @@ -428,7 +398,7 @@ class MetalPleFinish { def metal_ple_finish { let l = gl_WorkGroupID.x let p = gl_WorkGroupID.y - let i = gl_LocalInvocationID.x // tg = ple threads (gate: ple % 32 == 0, <= 1024) + let i = gl_LocalInvocationID.x //! tg = ple threads (gate: ple % 32 == 0, <= 1024) let v = proj[p * (ka.nlayers * ka.ple) + l * ka.ple + i] * ka.inv_sd let ss = simd_sum(v * v) if (gl_SubgroupInvocationID == 0u) { @@ -450,23 +420,17 @@ class MetalPleFinish { } } -// ===== K-quant mul_mm twins (format-matrix W4 / M2) — MetalQ8MulMm with the A-tile stage -// swapped to superblock dequant. The 32-elem k-block kb IS sub-block kb%8 of superblock kb/8, -// so each thread's 16-elem half decodes ONE (scale, min) pair. Same %64 shape gates, M padded 32/64. -// Metal-4 staged-tile twins of the KqMulMm K4/K5 pair, one template on the parents' exact axes -// (BLK quant-plane stride, QH overlay): flat f16 tiles per K-chunk, per-element kmask scale -// decode + nibble dequant — same math as the base's va, so staged values are identical. [ |> template_struct_instance] class template MetalKqMulMmK45TensorT { - @ssbo @binding = 0 @role = "weight" @off = "s0off" ksh : array // 16B scale blocks, half view (d, dmin at 8*blk) - @ssbo @binding = 1 @role = "weight" @off = "soff" ks4 : array // the same buffer, uint4 view - @ssbo @binding = 2 @role = "weight" @off = "qoff" kqu : array // quant plane, uint view (qs at BLK*blk; k5 qh at BLK*blk+32) - @ssbo @binding = 3 xf : array // raw activations (float, or the converted f16 panel) + @ssbo @binding = 0 @role = "weight" @off = "s0off" ksh : array //!< 16B scale blocks, half view (d, dmin at 8*blk) + @ssbo @binding = 1 @role = "weight" @off = "soff" ks4 : array //!< the same buffer, uint4 view + @ssbo @binding = 2 @role = "weight" @off = "qoff" kqu : array //!< quant plane, uint view (qs at BLK*blk; k5 qh at BLK*blk+32) + @ssbo @binding = 3 xf : array //!< raw activations (float, or the converted f16 panel) @ssbo @binding = 4 @off = "yoff" @span = "mp*rows*4" y : array @uniform @binding = 5 kdim : uint @uniform @binding = 6 ndim : uint - @workgroup twb : float16[4096] // W chunk: 64 wrows x 64 k (bk=64), flat row-major + @workgroup twb : float16[4096] //!< W chunk: 64 wrows x 64 k (bk=64), flat row-major @template_constant BLK : uint = 32u @template_constant QH : bool = false @@ -482,8 +446,6 @@ class template MetalKqMulMmK45TensorT { tmm2d_tg_begin_deva(acc, unsafe(addr(xf[0])), 32u, 64u, 4u, 64u) var kb = 0u while (kb < nkb) { - // one work item = one (wrow, 16-element half) of the 64-deep chunk — jsl names - // its 32-block; the sub-scale decode runs once per item var work = lid while (work < 256u) { let j = work >> 2u @@ -554,14 +516,12 @@ class MetalKqMulMmK5TH : MetalKqMulMmK45TensorT { override QH = true } -// Metal-4 staged-tile twin of MetalKqMulMmK6 (per-element ql|qh compose x signed sub-scale — -// same real product as the base's pre-scaled fma form, which is bit-identical by construction). [ |> template_struct_instance] class template MetalKqMulMmK6TensorT { - @ssbo @binding = 0 @role = "weight" @off = "s0off" kdh : array // d plane (scale buffer at byte nsb*16; s0off = the caller's doff) - @ssbo @binding = 1 @role = "weight" @off = "soff" ksc : array // 16B sub-scale blocks, same buffer at 0 - @ssbo @binding = 2 @role = "weight" @off = "qoff" kqu : array // ql at 48*blk, qh at 48*blk+32 - @ssbo @binding = 3 xf : array // raw activations (float, or the converted f16 panel) + @ssbo @binding = 0 @role = "weight" @off = "s0off" kdh : array //!< d plane (scale buffer at byte nsb*16; s0off = the caller's doff) + @ssbo @binding = 1 @role = "weight" @off = "soff" ksc : array //!< 16B sub-scale blocks, same buffer at 0 + @ssbo @binding = 2 @role = "weight" @off = "qoff" kqu : array //!< ql at 48*blk, qh at 48*blk+32 + @ssbo @binding = 3 xf : array //!< raw activations (float, or the converted f16 panel) @ssbo @binding = 4 @off = "yoff" @span = "mp*rows*4" y : array @uniform @binding = 5 kdim : uint @uniform @binding = 6 ndim : uint @@ -579,8 +539,6 @@ class template MetalKqMulMmK6TensorT { tmm2d_tg_begin_deva(acc, unsafe(addr(xf[0])), 32u, 64u, 4u, 64u) var kb = 0u while (kb < nkb) { - // one work item = one (wrow, 16-element half) of the 64-deep chunk — jsl names - // its 32-block; dall/sub-scale decode once per item var work = lid while (work < 256u) { let j = work >> 2u @@ -630,26 +588,17 @@ class MetalKqMulMmK6TH : MetalKqMulMmK6TensorT { typedef XT = float16 } -// ===== MoE routing (Wave C) ===== -// Router GEMV -> single-simdgroup select -> expert-indexed GEMV twins (grid.y = slot; the -// kernel reads sel[slot] GPU-side — no CPU readback, encode-ahead/spec stays compatible). -// The position-blocked prefill router (MetalMoeRouterB) lives in dasllama_metal_kernels as the -// BATCHED NR=8 stamp of the MetalMoeRouterT template — same k stride, logits bit-identical. -// The MoE gathered mul_mm family (mx4/q8 plus their tensor twins, and k4/k5/k6/q51) binds its -// uniforms as ONE kargs value at slot 5 — each form ignores the fields it does not read: a tensor -// twin serves contiguous sites only, and only the mx4 pair carries a per-expert bias. struct MoeMmArgs { kdim : uint ndim : uint - eplane : uint // per-expert plane stride, in the format's own block unit (32 or 256 elems) + eplane : uint //!< per-expert plane stride, in the format's own block unit (32 or 256 elems) nk : uint - gather : uint // 1 = bkt-indirect X rows (gate/up), 0 = contiguous bucket rows (down) + gather : uint //!< 1 = bkt-indirect X rows (gate/up), 0 = contiguous bucket rows (down) hasb : uint } -// the plane IS kdim*ndim elements, so its block stride derives from the shape — no separate input def private moe_mm_ka(fmt : KqFmt; kdim, ndim, nk : int64; gather : bool) : MoeMmArgs => ( MoeMmArgs(kdim = uint(kdim), ndim = uint(ndim), eplane = uint(kdim * ndim / (kq_sb(fmt) ? 256l : 32l)), @@ -663,15 +612,9 @@ struct MoeGxArgs { dim : uint nk : uint ne : uint - total : uint // npos*nk — a bkt word >= it (the sentinel, or stale bytes past the last - // expert's stamped tail) zeroes the row; a stale word BELOW it copies a live - // row into a tail slot no mm tile ever reads. Either way in bounds — the old - // sentinel-equality test could send a stale word's token index OOB + total : uint //!< npos*nk: a bkt word >= it marks a pad or stale row, and the gather zeroes that output row } -// gather-X materialization: the bucket's token rows copied into a CONTIGUOUS f16 panel, pad -// rows zeroed — up/gate sites then ride the contiguous tensor twin instead of the in-kernel -// gather form (validity = one bkt read against ka.total; the bucket stamps its pad tails) [metal_dispatch(name = "enc_moe_gather_x", pso = "g_pf_pso_moe_gx", tg = 256, grid = "rows", params = "rows : int64")] class MetalMoeGatherX { @ssbo @binding = 0 @role = "read" bkt : array @@ -683,7 +626,7 @@ class MetalMoeGatherX { def metal_moe_gather_x { let r = gl_WorkGroupID.x let v = bkt[r] - let isreal = v < ka.total // sentinel AND the unstamped tail past the last expert both fail this + let isreal = v < ka.total let token = isreal ? v / ka.nk : 0u var i = gl_LocalInvocationID.x while (i < ka.dim) { @@ -693,23 +636,20 @@ class MetalMoeGatherX { } } -// Metal-4 staged-tile twin of MetalMoeMulMmMx4 — CONTIGUOUS (down-site) shape: flat f16 tiles -// per K-chunk (per-element LUT dequant), bias folded as one extra rank-1 chunk (f16-staged — -// parity-tolerance vs the base's f32 seed). XT = the A stream codec. [ |> template_struct_instance] class template MetalMoeMulMmMx4TensorT { @template_constant MT : uint = 32u @template_constant REM : bool = false - @ssbo @binding = 0 @role = "weight" @off = "qoff" mxq4 : array // nibble plane, uint4 view - @ssbo @binding = 1 @role = "weight" @off = "soff" mxe : array // e8m0 scale plane + @ssbo @binding = 0 @role = "weight" @off = "qoff" mxq4 : array //!< nibble plane, uint4 view + @ssbo @binding = 1 @role = "weight" @off = "soff" mxe : array //!< e8m0 scale plane @ssbo @binding = 2 xf : array @ssbo @binding = 3 y : array @uniform @binding = 5 ka : MoeMmArgs @ssbo @binding = 6 cnt : array @ssbo @binding = 7 basep : array - @ssbo @binding = 12 @role = "weight" wb : array // [ne x ndim] per-expert bias rows - @ssbo @binding = 13 @role = "weight" vtab : array // [16] signed doubled-e2m1 values - @workgroup twb : float16[2048] // W chunk: 64 wrows x 32 k, flat row-major + @ssbo @binding = 12 @role = "weight" wb : array //!< [ne x ndim] per-expert bias rows + @ssbo @binding = 13 @role = "weight" vtab : array //!< [16] signed doubled-e2m1 values + @workgroup twb : float16[2048] //!< W chunk: 64 wrows x 32 k, flat row-major [metal_kernel(float_a_ok=true)] def metal_moe_mulmm_mx4_t { @@ -717,7 +657,7 @@ class template MetalMoeMulMmMx4TensorT { let ce = cnt[e] let mBase = gl_WorkGroupID.x * MT + (REM ? ce / 128u * 128u : 0u) let lim = MT == 128u ? ce / 128u * 128u : (ce + 31u) / 32u * 32u - if (mBase >= lim) { // threadgroup-uniform exit — cooperative-safe + if (mBase >= lim) { return } let rbase = basep[e] @@ -729,8 +669,6 @@ class template MetalMoeMulMmMx4TensorT { tmm2d_tg_begin_deva(acc, unsafe(addr(xf[0])), MT, 64u, 4u, 32u) var kb = 0u while (kb < nkb) { - // one work item = one (wrow, 16-element nibble half): scale decode + the uint4 - // quant word load once per item instead of per element var work = lid while (work < 128u) { let j = work >> 1u @@ -753,8 +691,6 @@ class template MetalMoeMulMmMx4TensorT { kb++ } if (ka.hasb != 0u) { - // per-expert bias folded into the cooperative elements at store time (the staged - // rank-1 trick died with the A tile; f32 add either way, parity story unchanged) var bp = unsafe(addr(wb[e * ka.ndim + nBase])) tmm2d_tg_store_bias(acc, cp, bp, MT, 64u, ka.ndim) } else { @@ -785,22 +721,19 @@ class MetalMoeMulMmMx4THR : MetalMoeMulMmMx4TensorT { override REM = true } -// the prefill twin over the padded bucket panel: MetalSwigluOaiT's PF stamp — same math, plus -// the PF-gated liveness exit over the bucket fields (slots 3-6). +//! The prefill stamp over the padded bucket panel, with the PF-gated liveness exit over slots 3-6. +//! Its total/256 grid covers the callers' total % 4 == 0 contract; the kernel guards gid * 4 >= total. [metal_dispatch(name = "pf_enc_swiglu_oai", pso = "g_pf_pso_swiglu_oai", tg = 64, grid = "total/256", params = "total : int64")] class MetalSwigluOaiPf : MetalSwigluOaiT { override PF = true } -// ===== MoE prefill CSR + gathered mul_mm (Wave C stage 2b) ===== -// Atomics-free CSR: count (tg/expert) -> serial prefix (1 tg) -> bucket fill (tg/expert, -// thread-0 serial walk in row order = the CPU moe_bkt order); buckets PAD to 32-row tiles. [metal_dispatch(name = "pf_enc_moe_count", pso = "g_pf_pso_moe_count", tg = 32, grid = "ne", params = "ne : int64")] class MetalMoeCount { - @ssbo @binding = 0 @role = "read" seli : array // [npos x 2k] selection rows (idx section) - @ssbo @binding = 1 @role = "write" cnt : array // [ne] out - @uniform @binding = 2 total : uint // npos * k entries + @ssbo @binding = 0 @role = "read" seli : array //!< [npos x 2k] selection rows (idx section) + @ssbo @binding = 1 @role = "write" cnt : array //!< [ne] out + @uniform @binding = 2 total : uint //!< npos * k entries @uniform @binding = 3 nk : uint [metal_kernel(name="metal_moe_count_msl")] @@ -829,9 +762,9 @@ class MetalMoeCount { [metal_dispatch(name = "pf_enc_moe_bucket", pso = "g_pf_pso_moe_bucket", tg = 32, grid = "nex", params = "nex : int64")] class MetalMoeBucket { @ssbo @binding = 0 @role = "read" seli : array - @ssbo @binding = 1 @role = "write" basep : array // [ne] exclusive prefix over the PADDED counts - @ssbo @binding = 2 @role = "write" bkt : array // [padded rows] bucket -> entry (row*k + slot) - @ssbo @binding = 3 @role = "write" inv : array // [npos*k] entry -> padded bucket row + @ssbo @binding = 1 @role = "write" basep : array //!< [ne] exclusive prefix over the PADDED counts + @ssbo @binding = 2 @role = "write" bkt : array //!< [padded rows] bucket -> entry (row*k + slot) + @ssbo @binding = 3 @role = "write" inv : array //!< [npos*k] entry -> padded bucket row @uniform @binding = 4 total : uint @uniform @binding = 5 nk : uint @ssbo @binding = 6 @role = "read" cnt : array @@ -839,12 +772,8 @@ class MetalMoeBucket { [metal_kernel(name="metal_moe_bucket_msl")] def metal_moe_bucket { - // contiguous ascending per-lane chunks + exclusive scan of chunk counts reproduce the - // serial entry order exactly (a 1-lane scan here was ~0.7ms/layer of load latency) let e = gl_WorkGroupID.x let lane = gl_SubgroupInvocationID - // in-tg fold of the old 1-tg prefix dispatch: masked padded sum below this expert - // (identical value in every tg; tg e publishes basep[e] for the mm/act consumers) var pacc = 0u var pt = lane while (pt < ne) { @@ -891,8 +820,6 @@ class MetalMoeBucket { } t++ } - // pad-tail sentinel so the gather's per-row validity is one bkt read instead of - // an O(ne) basep/cnt search (the gather-x kernel keys on it) let ce = cnt[e] var pr = ce + lane while (pr < (ce + 31u) / 32u * 32u) { @@ -902,14 +829,12 @@ class MetalMoeBucket { } } -// the ordered weighted reduce: per (position, dim slice), the k slots in slot order via inv — -// bit-stable vs the CPU park-and-accumulate; pad bucket rows are never referenced [metal_dispatch(name = "pf_enc_moe_reduce", pso = "g_pf_pso_moe_reduce", tg = 256, grid = "dim/256, npos", params = "dim : int64, npos : int64")] class MetalMoeReduce { - @ssbo @binding = 0 @role = "read" dn : array // [padded rows x dim] bucket-ordered down outputs - @ssbo @binding = 1 @role = "read" selw : array // selection rows, float view (w of row r at r*2k + k) + @ssbo @binding = 0 @role = "read" dn : array //!< [padded rows x dim] bucket-ordered down outputs + @ssbo @binding = 1 @role = "read" selw : array //!< selection rows, float view (w of row r at r*2k + k) @ssbo @binding = 2 @role = "read" inv : array - @ssbo @binding = 3 @role = "write" y : array // [npos x dim] + @ssbo @binding = 3 @role = "write" y : array //!< [npos x dim] @uniform @binding = 4 dim : uint @uniform @binding = 5 nk : uint @@ -930,21 +855,18 @@ class MetalMoeReduce { } } -// Metal-4 tensor twin of MetalMoeMulMmQ8, CONTIGUOUS rows only (bkt-indirect X cannot form a -// tensor view — gather sites ride the gather-X panel). MT/REM = the tall pair: 128 serves each -// expert's FULL 128-row tiles (floor exit), REM covers the pad-32 tail from that floor. [ |> template_struct_instance] class template MetalMoeMulMmQ8TensorT { @template_constant MT : uint = 32u @template_constant REM : bool = false - @ssbo @binding = 0 @role = "weight" @off = "wboff" wsh : array // expert STACK blob, half-scale view - @ssbo @binding = 1 @role = "weight" @off = "wboff" wqb : array // the same blob buffer, byte view + @ssbo @binding = 0 @role = "weight" @off = "wboff" wsh : array //!< expert STACK blob, half-scale view + @ssbo @binding = 1 @role = "weight" @off = "wboff" wqb : array //!< the same blob buffer, byte view @ssbo @binding = 2 xf : array @ssbo @binding = 3 y : array @uniform @binding = 5 ka : MoeMmArgs @ssbo @binding = 6 cnt : array @ssbo @binding = 7 basep : array - @workgroup twb : float16[4096] // W chunk: 64 wcols x 64 k (bk=64), dequant-staged by the helper + @workgroup twb : float16[4096] //!< W chunk: 64 wcols x 64 k (bk=64), dequant-staged by the helper [metal_kernel(float_a_ok=true)] def metal_moe_mulmm_q8_t { @@ -952,7 +874,7 @@ class template MetalMoeMulMmQ8TensorT { let ce = cnt[e] let mBase = gl_WorkGroupID.x * MT + (REM ? ce / 128u * 128u : 0u) let lim = MT == 128u ? ce / 128u * 128u : (ce + 31u) / 32u * 32u - if (mBase >= lim) { // threadgroup-uniform exit — cooperative-safe + if (mBase >= lim) { return } let rbase = basep[e] @@ -988,9 +910,6 @@ class MetalMoeMulMmQ8THR : MetalMoeMulMmQ8TensorT { override REM = true } -// Metal-4 staged-tile twins of the MoE K4/K5/K6 forms — the dense KqMulMm twins' staging -// decode with the MoeQ8 twin's expert fold (blk0 = e * eplane; every kq plane strides per -// superblock, so one fold serves scales, quants and the k6 d tail). CONTIGUOUS rows only. [ |> template_struct_instance] class template MetalMoeMulMmK45TensorT { @template_constant MT : uint = 32u @@ -1013,7 +932,7 @@ class template MetalMoeMulMmK45TensorT { let ce = cnt[e] let mBase = gl_WorkGroupID.x * MT + (REM ? ce / 128u * 128u : 0u) let lim = MT == 128u ? ce / 128u * 128u : (ce + 31u) / 32u * 32u - if (mBase >= lim) { // threadgroup-uniform exit — cooperative-safe + if (mBase >= lim) { return } let rbase = basep[e] @@ -1026,8 +945,6 @@ class template MetalMoeMulMmK45TensorT { tmm2d_tg_begin_deva(acc, unsafe(addr(xf[0])), MT, 64u, 4u, 64u) var kb = 0u while (kb < nkb) { - // one work item = one (wrow, 16-element half) of the 64-deep chunk — jsl names - // its 32-block; the sub-scale decode runs once per item var work = lid while (work < 256u) { let j = work >> 2u @@ -1126,9 +1043,6 @@ class MetalMoeMulMmK5THR : MetalMoeMulMmK45TensorT { override REM = true } -// Metal-4 staged-tile twin of the MoE Q5_1 form — the legacy kernel's 32-block d/m decode -// (d at 2*blk, m at 2*blk+1; 5 uints/block: 4 nibble words + qh) with the MoeQ8 twin's -// expert fold. CONTIGUOUS rows only. [ |> template_struct_instance] class template MetalMoeMulMmQ51TensorT { @template_constant MT : uint = 32u @@ -1148,7 +1062,7 @@ class template MetalMoeMulMmQ51TensorT { let ce = cnt[e] let mBase = gl_WorkGroupID.x * MT + (REM ? ce / 128u * 128u : 0u) let lim = MT == 128u ? ce / 128u * 128u : (ce + 31u) / 32u * 32u - if (mBase >= lim) { // threadgroup-uniform exit — cooperative-safe + if (mBase >= lim) { return } let rbase = basep[e] @@ -1160,8 +1074,6 @@ class template MetalMoeMulMmQ51TensorT { tmm2d_tg_begin_deva(acc, unsafe(addr(xf[0])), MT, 64u, 4u, 64u) var kb = 0u while (kb < nkb) { - // one work item = one (wrow, 16-element half) of the 64-deep chunk — jsl names - // its 32-block; d/m load once per item var work = lid while (work < 256u) { let j = work >> 2u @@ -1233,7 +1145,7 @@ class template MetalMoeMulMmK6TensorT { let ce = cnt[e] let mBase = gl_WorkGroupID.x * MT + (REM ? ce / 128u * 128u : 0u) let lim = MT == 128u ? ce / 128u * 128u : (ce + 31u) / 32u * 32u - if (mBase >= lim) { // threadgroup-uniform exit — cooperative-safe + if (mBase >= lim) { return } let rbase = basep[e] @@ -1246,8 +1158,6 @@ class template MetalMoeMulMmK6TensorT { tmm2d_tg_begin_deva(acc, unsafe(addr(xf[0])), MT, 64u, 4u, 64u) var kb = 0u while (kb < nkb) { - // one work item = one (wrow, 16-element half) of the 64-deep chunk — jsl names - // its 32-block; dall/sub-scale decode once per item var work = lid while (work < 256u) { let j = work >> 2u @@ -1309,9 +1219,6 @@ class MetalMoeMulMmK6THR : MetalMoeMulMmK6TensorT { override REM = true } -// The MoE mul_mm family: one 32x64 simdgroup tile loop over an expert's rows, identical for every -// weight format — a format differs in its k-block decode, the expert-plane origin it addresses -// from, and (q8) the carried-pointer state stage_init binds. Mx4 stays out: followup_general.md #8. class MetalMoeMulMmBase : MetalMmTileBase { @ssbo @binding = 3 @role = "read" xf : array @ssbo @binding = 4 @role = "write" y : array @@ -1320,13 +1227,13 @@ class MetalMoeMulMmBase : MetalMmTileBase { @ssbo @binding = 8 @role = "read" basep : array @ssbo @binding = 9 @role = "read" bkt : array - // a format owns bindings 0..2 — its weight views; its plane stride rides ka.eplane - def abstract wbase(e, nBase, lr0 : uint) : uint // expert plane origin, in the format's block unit - def abstract stage_a(wb, kb, il0, tA0 : uint) : void // decode one k-block into the A tile + //! a format owns bindings 0..2 - its weight views; its plane stride rides ka.eplane + def abstract wbase(e, nBase, lr0 : uint) : uint //! expert plane origin, in the format's block unit + def abstract stage_a(wb, kb, il0, tA0 : uint) : void //! decode one k-block into the A tile - def stage_init(wb, il0 : uint) {} // format prologue: bind carried-pointer state (q8's walk) + def stage_init(wb, il0 : uint) {} //! format prologue: bind carried-pointer state (q8's walk) - def stage_acc(var acc : simdgroup_float8x8[8]) {} // accumulator seed hook (mx4's per-expert bias) + def stage_acc(var acc : simdgroup_float8x8[8]) {} //! accumulator seed hook (mx4's per-expert bias) def run { let e = gl_WorkGroupID.z @@ -1382,15 +1289,12 @@ class MetalMoeMulMmBase : MetalMmTileBase { } } -// Gathered q8 mul_mm — the family base with the CARRIED-POINTER A stage: stage_init binds the -// scale/quant walk once, stage_a advances (+17 halves / +34 bytes per k-block; the stateless -// index form measured +3.4-3.6% in the gmm8 lab — the pointer walk IS the win). [metal_dispatch(name = "pf_enc_moe_mm_q8_c", pso = "g_pf_pso_moe_mm_q8", tgmem = "metal_moe_mulmm_q8_msl_tgmem", tg = 128, grid = "npos/32, rows/64, ne", params = "rows : int64, npos : int64, ne : int64")] class MetalMoeMulMmQ8 : MetalMoeMulMmBase { - @ssbo @binding = 0 @role = "weight" @off = "wboff" wsh : array // the expert STACK's blob slice, half-scale view - @ssbo @binding = 1 @role = "weight" @off = "wboff" wqb : array // the same blob buffer, byte view - scur : float16 const? // carried scale pointer - qp : int8 const? // carried quant pointer + @ssbo @binding = 0 @role = "weight" @off = "wboff" wsh : array //!< the expert STACK's blob slice, half-scale view + @ssbo @binding = 1 @role = "weight" @off = "wboff" wqb : array //!< the same blob buffer, byte view + scur : float16 const? //!< carried scale pointer + qp : int8 const? //!< carried quant pointer def override wbase(e, nBase, lr0 : uint) : uint => e * ka.eplane + (nBase + lr0) * (ka.kdim / 32u) @@ -1419,7 +1323,6 @@ class MetalMoeMulMmQ8 : MetalMoeMulMmBase { } } -// Gathered Q4_K mul_mm — MetalKqMulMmK4's A stage with the expert superblock shift. [metal_dispatch(name = "pf_enc_moe_mm_k4_c", pso = "g_pf_pso_moe_mm_k4", tgmem = "metal_moe_mulmm_k4_msl_tgmem", tg = 128, grid = "npos/32, rows/64, ne", params = "rows : int64, npos : int64, ne : int64")] class MetalMoeMulMmK4 : MetalMoeMulMmBase { @ssbo @binding = 0 @role = "weight" @off = "soff" ksh : array @@ -1468,7 +1371,6 @@ class MetalMoeMulMmK4 : MetalMoeMulMmBase { } } -// Gathered Q5_K mul_mm — MetalKqMulMmK5's A stage with the expert superblock shift. [metal_dispatch(name = "pf_enc_moe_mm_k5_c", pso = "g_pf_pso_moe_mm_k5", tgmem = "metal_moe_mulmm_k5_msl_tgmem", tg = 128, grid = "npos/32, rows/64, ne", params = "rows : int64, npos : int64, ne : int64")] class MetalMoeMulMmK5 : MetalMoeMulMmBase { @ssbo @binding = 0 @role = "weight" @off = "soff" ksh : array @@ -1519,12 +1421,10 @@ class MetalMoeMulMmK5 : MetalMoeMulMmBase { } } -// Gathered Q5_1 mul_mm — the k5 skeleton with the per-32 A stage: each thread's 16-elem half is -// one nibble half of the 32-block (il0), value = d*q + m folded into the f16 A tile. [metal_dispatch(name = "pf_enc_moe_mm_q51_c", pso = "g_pf_pso_moe_mm_q51", tgmem = "metal_moe_mulmm_q51_msl_tgmem", tg = 128, grid = "npos/32, rows/64, ne", params = "rows : int64, npos : int64, ne : int64")] class MetalMoeMulMmQ51 : MetalMoeMulMmBase { - @ssbo @binding = 0 @role = "weight" @off = "soff" wsh : array // scale plane (d at 2*blk, m at 2*blk+1) - @ssbo @binding = 1 @role = "weight" @off = "qoff" wqu : array // quant plane, uint view (block at 5*blk; qh at +4) + @ssbo @binding = 0 @role = "weight" @off = "soff" wsh : array //!< scale plane (d at 2*blk, m at 2*blk+1) + @ssbo @binding = 1 @role = "weight" @off = "qoff" wqu : array //!< quant plane, uint view (block at 5*blk; qh at +4) def override wbase(e, nBase, lr0 : uint) : uint => e * ka.eplane + (nBase + lr0) * (ka.kdim / 32u) @@ -1557,9 +1457,6 @@ class MetalMoeMulMmQ51 : MetalMoeMulMmBase { } } -// Gathered Q6_K mul_mm — the k6 A stage on the family base. The superblock-scalar cache the -// standalone kernel carried measured SLOWER than reload-per-kb (gmm6 lab, 3 launches: −2.4% -// ms/mm at qwen3moe pp512 shapes), so the stateless stage_a is both the join and the win. [metal_dispatch(name = "pf_enc_moe_mm_k6_c", pso = "g_pf_pso_moe_mm_k6", tgmem = "metal_moe_mulmm_k6_msl_tgmem", tg = 128, grid = "npos/32, rows/64, ne", params = "rows : int64, npos : int64, ne : int64")] class MetalMoeMulMmK6 : MetalMoeMulMmBase { @ssbo @binding = 0 @role = "weight" @off = "doff" kdh : array @@ -1582,10 +1479,9 @@ class MetalMoeMulMmK6 : MetalMoeMulMmBase { let s6 = float(((int(scw >> ((si & 3u) * 8u)) & 255) ^ 128) - 128) let dsc = dall * s6 let dmn = dsc * 32.0 - // shift folded into exact power-of-two pre-scales — see MetalKqMulMmK45T - let dsc1 = dsc * 0.00390625 - let dsc2 = dsc * 0.0000152587890625 - let dsc3 = dsc * 0.000000059604644775390625 + let dsc_sh8 = dsc * 0.00390625 + let dsc_sh16 = dsc * 0.0000152587890625 + let dsc_sh24 = dsc * 0.000000059604644775390625 let qb = blk * 48u + half6 * 16u + (gg & 1u) * 8u + il0 * 4u let hb = blk * 48u + 32u + half6 * 8u + il0 * 4u let nsh = (gg / 2u) * 4u @@ -1595,9 +1491,9 @@ class MetalMoeMulMmK6 : MetalMoeMulMmBase { let hu = kqu[hb + uint(k)] let qv = ((u >> nsh) & 0x0F0F0F0F) | (((hu >> hsh) & 0x03030303) << 4u) va[k * 4] = float16(dsc * float(qv & 255u) - dmn) - va[k * 4 + 1] = float16(dsc1 * float(qv & 65280u) - dmn) - va[k * 4 + 2] = float16(dsc2 * float(qv & 16711680u) - dmn) - va[k * 4 + 3] = float16(dsc3 * float(qv & 4278190080u) - dmn) + va[k * 4 + 1] = float16(dsc_sh8 * float(qv & 65280u) - dmn) + va[k * 4 + 2] = float16(dsc_sh16 * float(qv & 16711680u) - dmn) + va[k * 4 + 3] = float16(dsc_sh24 * float(qv & 4278190080u) - dmn) } barrier() for [unroll_full] (i in range(16)) { @@ -1611,15 +1507,12 @@ class MetalMoeMulMmK6 : MetalMoeMulMmBase { } } -// Gathered MXFP4 mul_mm — the family base with the mx4 A stage: each thread's 16-elem half IS -// one nibble half of the 32-block (il0 = 0 low, 1 high); stage_init stages the doubled-e2m1 -// value table, stage_acc seeds per-expert bias (hasb; bias precedes reduce). [metal_dispatch(name = "pf_enc_moe_mm_mx4_c", pso = "g_pf_pso_moe_mm_mx4", tgmem = "metal_moe_mulmm_mx4_msl_tgmem", tg = 128, grid = "npos/32, rows/64, ne", params = "rows : int64, npos : int64, ne : int64")] class MetalMoeMulMmMx4 : MetalMoeMulMmBase { - @ssbo @binding = 0 @role = "weight" @off = "qoff" mxq4 : array // nibble plane, uint4 view (one block = one load) + @ssbo @binding = 0 @role = "weight" @off = "qoff" mxq4 : array //!< nibble plane, uint4 view (one block = one load) @ssbo @binding = 1 @role = "weight" @off = "soff" mxe : array - @ssbo @binding = 12 @role = "weight" wbias : array // [ne x ndim] per-expert bias rows (hasb models) - @ssbo @binding = 13 @role = "weight" vtab : array // [16] signed doubled-e2m1 values (host-built) + @ssbo @binding = 12 @role = "weight" wbias : array //!< [ne x ndim] per-expert bias rows (hasb models) + @ssbo @binding = 13 @role = "weight" vtab : array //!< [16] signed doubled-e2m1 values (host-built) @workgroup vt : float[32] def override wbase(e, nBase, lr0 : uint) : uint => e * ka.eplane + (nBase + lr0) * (ka.kdim / 32u) @@ -1634,8 +1527,6 @@ class MetalMoeMulMmMx4 : MetalMoeMulMmBase { def override stage_acc(var acc : simdgroup_float8x8[8]) { if (ka.hasb != 0u) { - // bias as the accumulator seed: every row of tile i gets wbias[e][col] (stride-0 - // load); padded ghost rows are harmlessly biased — never read let e = gl_WorkGroupID.z let sg = gl_SubgroupID let wb0 = e * ka.ndim + gl_WorkGroupID.y * 64u + (sg % 2u) * 32u @@ -1649,7 +1540,7 @@ class MetalMoeMulMmMx4 : MetalMoeMulMmBase { var va : float16[16] let blk = wb + kb let sc = uint(mxe[blk]) - let d = uint_bits_to_float(sc < 2u ? (0x00200000u << sc) : ((sc - 1u) << 23u)) // exact e8m0_half, denormal e < 2 included + let d = uint_bits_to_float(sc < 2u ? (0x00200000u << sc) : ((sc - 1u) << 23u)) //! exact e8m0_half, denormal e < 2 included let u4 = mxq4[blk] for [unroll_full] (w in range(4)) { let uw = w == 0 ? u4.x : (w == 1 ? u4.y : (w == 2 ? u4.z : u4.w)) @@ -1670,31 +1561,19 @@ class MetalMoeMulMmMx4 : MetalMoeMulMmBase { } } -// ===== K-quant site GEMVs (format-matrix W4) — the gemv-lab winners, productionized ===== -// f32-X single-row weight streams over DISK-ORDER kq quant planes + GPU-form scale buffers: -// k4/k5 read 16B compact scale blocks, k6 reads 16B sub-scale + a trailing packed f16 d plane. -// ===== K-quant small-batch mv twins (the kq ext form) — batched decode sites at B = 2..8 ===== -// The gemv-lab ext winners productionized (-25..-40% vs the per-stream B x B1 wall at B=4). One -// thread per output row; y binds at the site's column byte offset, grid.y = column groups of R. -// ===== K-quant B=5..8 single-pass twins (lab extx8 form): ONE weight pass vs two B4 groups; x panel -// STAGED through tgmem per superblock (0.45 -> 0.317 ms; the SLC-resident lab can't rank this — in-graph -// A/B decides, DASLLAMA_METAL_KQ_B8=0 falls back). REQUIRES mp == 8 (nlive >= 5): stage reads all 8 rows, stores gate on nr. -// One thread per rotation pair: NORM (2j, 2j+1 within each head) or NEOX (j, j+half) per the -// mode uniform, matching rope_scaled_tab / rope_scaled_neox_tab exactly via the position's -// precomputed table row. One kernel serves q (n = qd) and k (n = kv_dim) as two dispatches. [metal_dispatch(name = "enc_rope", pso = "g_pf_pso_rope", tg = 64, grid = "npairs/64", params = "npairs : int64")] class MetalRope { - @ssbo @binding = 0 @role = "readwrite" @off = "voff" v : array // [ntok x n], roped in place - @ssbo @binding = 1 @role = "weight" tcos : array // [ntok x head_size/2] + @ssbo @binding = 0 @role = "readwrite" @off = "voff" v : array //!< [ntok x n], roped in place + @ssbo @binding = 1 @role = "weight" tcos : array //!< [ntok x head_size/2] @ssbo @binding = 2 @role = "weight" tsin : array - @uniform @binding = 3 n : uint // row width (qd or kv_dim), % head_size + @uniform @binding = 3 n : uint //!< row width (qd or kv_dim), % head_size @uniform @binding = 4 head_size : uint - @uniform @binding = 5 npairs : uint // ntok * n/2 — grid guard - @uniform @binding = 6 neox : uint // pair (j, j+half) instead of (2j, 2j+1); same table row j - @uniform @binding = 7 @default = head_size rot : uint // partial rotary width; null bind = full rope (== head_size) + @uniform @binding = 5 npairs : uint //!< ntok * n/2 — grid guard + @uniform @binding = 6 neox : uint //!< pair (j, j+half) instead of (2j, 2j+1); same table row j + @uniform @binding = 7 @default = head_size rot : uint //!< partial rotary width; null bind = full rope (== head_size) [metal_kernel(name="metal_rope_msl")] def metal_rope { @@ -1709,13 +1588,12 @@ class MetalRope { let halfr = rot / 2u let h = rem / half let j = rem % half - // threads j < rot/2 rotate the (j, j+rot/2) pair; the rest identity-cover [rot, hs) - let rotp = j < halfr + let in_rotary = j < halfr //! rotates the (j, j+rot/2) pair; the rest identity-cover [rot, hs) let hb = p * n + h * head_size - let i = neox != 0u ? (rotp ? hb + j : hb + rot + (j - halfr)) : hb + 2u * j - let i2 = neox != 0u ? (rotp ? i + halfr : i + (half - halfr)) : i + 1u - let fcr = rotp ? tcos[p * halfr + j] : 1.0 - let fci = rotp ? tsin[p * halfr + j] : 0.0 + let i = neox != 0u ? (in_rotary ? hb + j : hb + rot + (j - halfr)) : hb + 2u * j + let i2 = neox != 0u ? (in_rotary ? i + halfr : i + (half - halfr)) : i + 1u + let fcr = in_rotary ? tcos[p * halfr + j] : 1.0 + let fci = in_rotary ? tsin[p * halfr + j] : 0.0 let v0 = v[i] let v1 = v[i2] v[i] = v0 * fcr - v1 * fci @@ -1723,14 +1601,12 @@ class MetalRope { } } -// Additive per-row bias (x[r*n + i] += b[i]) — the QKV bias epilogue for the prefill panels -// (decode folds it into rope-store; prefill is GEMM-bound, so a plain elementwise pass is free). [metal_dispatch(name = "enc_add_bias_rows", pso = "g_pf_pso_addbias", tg = 64, grid = "total/64", params = "total : int64")] class MetalAddBiasRows { - @ssbo @binding = 0 @role = "readwrite" @off = "off" @span = "total*4" x : array // [nrows x n], updated in place (bound at the panel offset) - @ssbo @binding = 1 @role = "weight" @off = "boff" b : array // [n] (the tower driver binds biases inside the model blob) + @ssbo @binding = 0 @role = "readwrite" @off = "off" @span = "total*4" x : array //!< [nrows x n], updated in place (bound at the panel offset) + @ssbo @binding = 1 @role = "weight" @off = "boff" b : array //!< [n] (the tower driver binds biases inside the model blob) @uniform @binding = 2 n : uint - @uniform @binding = 3 total : uint // nrows * n — grid guard + @uniform @binding = 3 total : uint //!< nrows * n — grid guard [metal_kernel(name="metal_add_bias_rows_msl")] def metal_add_bias_rows { @@ -1742,50 +1618,38 @@ class MetalAddBiasRows { } } -// Attention: a tiled-GEMM trio over a per-head F16 score slab padded to np32 = ceil32(npos) — -// metal_attn_qk (S = scale*Q.K^T, written HALF once) -> metal_attn_rowstat (rowmax + 1/sum) -// -> metal_attn_av (O = P.V, exp at P staging); no separate softmax pass touches the slab. -// One layer's attention geometry as ONE kargs value, shared by all THREE stages and by each -// stage's mm/tensor twins — the trio walks the same slab, so the caller derives this once per -// layer. Stages ignore the fields they don't read (AV has no scale/window, QK no softcap/hass). struct AttnArgs { qd : uint kv_dim : uint head_size : uint kv_mul : uint - npos : uint // KEY rows (continuation: qoff existing + the chunk) - np32 : uint // padded key extent = the score slab's column stride + npos : uint //!< KEY rows (continuation: qoff existing + the chunk) + np32 : uint //!< padded key extent = the score slab's column stride scale : float - qoff : uint // the chunk's first GLOBAL position (0 = fresh start) - qrows : uint // padded QUERY rows — the score slab's row extent - window : uint // > 0 = sliding span (this layer); 0 = global - softcap : float // > 0 = attention-logit soft cap (gemma2) + qoff : uint //!< the chunk's first GLOBAL position (0 = fresh start) + qrows : uint //!< padded QUERY rows — the score slab's row extent + window : uint //!< > 0 = sliding span (this layer); 0 = global + softcap : float //!< > 0 = attention-logit soft cap (gemma2) hass : uint - uend : uint // > 0 = uniform span end (media rows): queries at [ulo, uend) attend [window floor, uend); 0 = causal - ulo : uint // uniform span start; read only while uend > 0 (queries outside [ulo, uend) stay causal) + uend : uint //!< > 0 = uniform span end (media rows): queries at [ulo, uend) attend [window floor, uend); 0 = causal + ulo : uint //!< uniform span start; read only while uend > 0 (queries outside [ulo, uend) stay causal) } -// One threadgroup (128 threads = 4 simdgroups) per 32x32 score block; blocks fully above the -// causal diagonal exit early. Q staging folds `scale` in; K stages transposed, rows >= npos -// zeroed (pads can carry NaN). head_size walks in 64-wide K-SLABS — hs 64 is one slab, 128 two. [metal_dispatch(name = "enc_qk", pso = "g_pf_pso_qk", tgmem = "metal_attn_qk_msl_tgmem", tg = 128, grid = "mp/32, nk64/32, heads", params = "mp : int64, nk64 : int64, heads : int64")] class MetalAttnQK { - @ssbo @binding = 0 @role = "read" q : array // [mp x qd], roped - @ssbo @binding = 1 @role = "read" k : array // [nk64 x kv_dim], roped (existing rows + the chunk) - @ssbo @binding = 2 @role = "write" att : array // [n_heads x qrows x np32] raw scores out, f16 slab + @ssbo @binding = 0 @role = "read" q : array //!< [mp x qd], roped + @ssbo @binding = 1 @role = "read" k : array //!< [nk64 x kv_dim], roped (existing rows + the chunk) + @ssbo @binding = 2 @role = "write" att : array //!< [n_heads x qrows x np32] raw scores out, f16 slab @uniform @binding = 3 ka : AttnArgs - @workgroup ta : float[2048] // Q block: 32 qi-rows x 64 (row stride 64) - @workgroup tb : float[2048] // KT block: 64 k-rows x 32 j-cols (row stride 32) + @workgroup ta : float[2048] //!< Q block: 32 qi-rows x 64 (row stride 64) + @workgroup tb : float[2048] //!< KT block: 64 k-rows x 32 j-cols (row stride 32) [metal_kernel(name="metal_attn_qk_msl")] def metal_attn_qk { let qi0 = gl_WorkGroupID.x * 32u let j0 = gl_WorkGroupID.y * 32u let h = gl_WorkGroupID.z - // skip blocks fully past both uend and the causal reach (tail rows above the span stay - // causal), or fully below every row's sliding ka.window (the first row's wstart is the - // block minimum; pf_p_weight zeroes P over the skipped region) if ((ka.uend > 0u ? j0 >= max(ka.uend, ka.qoff + qi0 + 32u) : j0 > ka.qoff + qi0 + 31u) || (ka.window > 0u && ka.qoff + qi0 + 1u > ka.window && j0 + 32u <= ka.qoff + qi0 + 1u - ka.window)) { return @@ -1845,9 +1709,7 @@ class MetalAttnQK { } } -// The P weight the AV kernels stage on the fly: raw score -> masked softcapped exp * 1/sum. -// EXACTLY mirrors metal_attn_rowstat's window/live-length/softcap math — the two must agree -// or rows renormalize against the wrong max. +[arch(at="../ARCHITECTURE_GPU_PREFILL.md#prefill-attn-slab")] def pf_p_weight(sr : float; jglob, qpos, window : uint; softcap : float; uend, ulo : uint; m, inv : float) : float { let cnt = (uend > 0u && qpos >= ulo && qpos < uend) ? uend : qpos + 1u let jlo = window > 0u && qpos + 1u > window ? qpos + 1u - window : 0u @@ -1858,14 +1720,12 @@ def pf_p_weight(sr : float; jglob, qpos, window : uint; softcap : float; uend, u return exp(tv - m) * inv } -// Per-row softmax statistics: rowmax (masked, softcapped, sink included) and 1/sum — the AV -// kernels apply exp at P staging, so the score slab is written once (QK) and read once (AV). [metal_dispatch(name = "enc_rowstat", pso = "g_pf_pso_rowstat", tgmem = "metal_attn_rowstat_msl_tgmem", tg = 128, grid = "npos, heads", params = "npos : int64, heads : int64")] class MetalAttnRowstat { - @ssbo @binding = 0 @role = "read" att : array // [n_heads x qrows x np32] RAW scores, f16 slab + @ssbo @binding = 0 @role = "read" att : array //!< [n_heads x qrows x np32] RAW scores, f16 slab @uniform @binding = 1 ka : AttnArgs - @ssbo @binding = 2 @role = "write" stat : array // [n_heads x qrows x 2]: rowmax, 1/sum - @ssbo @binding = 20 @role = "weight" @default = g_one sink : array // [nheads]; null = identity + @ssbo @binding = 2 @role = "write" stat : array //!< [n_heads x qrows x 2]: rowmax, 1/sum + @ssbo @binding = 20 @role = "weight" @default = g_one sink : array //!< [nheads]; null = identity @workgroup red : float[4] @workgroup bcast : float @@ -1937,18 +1797,15 @@ class MetalAttnRowstat { } } -// One threadgroup (128 threads = 4 simdgroups) per 32x32 output block: O = P.V walking j in -// 32-blocks up to the causal limit qi0+32 (P's zeroed tail keeps whole blocks exact). V rows -// >= npos stage as 0 (pad rows can carry NaN; 0*NaN would still poison). hs % 32 == 0 required. [metal_dispatch(name = "enc_av", pso = "g_pf_pso_av", tgmem = "metal_attn_av_msl_tgmem", tg = 128, grid = "mp/32, head_size/32, heads", params = "mp : int64, heads : int64, head_size : int64")] class MetalAttnAV { - @ssbo @binding = 0 @role = "read" att : array // [n_heads x qrows x np32] RAW scores, f16 slab - @ssbo @binding = 1 @role = "read" v : array // [nk64 x kv_dim] raw V (existing rows + the chunk) - @ssbo @binding = 2 @role = "write" xb : array // [mp x qd] attention output + @ssbo @binding = 0 @role = "read" att : array //!< [n_heads x qrows x np32] RAW scores, f16 slab + @ssbo @binding = 1 @role = "read" v : array //!< [nk64 x kv_dim] raw V (existing rows + the chunk) + @ssbo @binding = 2 @role = "write" xb : array //!< [mp x qd] attention output @uniform @binding = 3 ka : AttnArgs - @ssbo @binding = 4 @role = "read" stat : array // [n_heads x qrows x 2] rowmax, 1/sum - @workgroup ta : float[1024] // P block: 32 qi-rows x 32 j (stride 32) - @workgroup tb : float[1024] // V block: 32 j-rows x 32 d (stride 32) + @ssbo @binding = 4 @role = "read" stat : array //!< [n_heads x qrows x 2] rowmax, 1/sum + @workgroup ta : float[1024] //!< P block: 32 qi-rows x 32 j (stride 32) + @workgroup tb : float[1024] //!< V block: 32 j-rows x 32 d (stride 32) [metal_kernel(name="metal_attn_av_msl")] def metal_attn_av { @@ -1958,9 +1815,6 @@ class MetalAttnAV { let lid = gl_LocalInvocationID.x let sg = gl_SubgroupID let kvhoff = (h / ka.kv_mul) * ka.head_size - // P rows are zero past each row's live length, so the walk bound is the tile's max: - // causal reach, lifted to uend only when the tile holds span rows (causal-only tiles - // above the span keep their short walk) let creach = ka.qoff + qi0 + 32u let jlimit = min(ka.uend > 0u && ka.qoff + qi0 < ka.uend && creach > ka.ulo ? max(ka.uend, creach) : creach, ka.np32) let qm = (sg / 2u) * 16u @@ -1977,8 +1831,7 @@ class MetalAttnAV { let c = e % 32u let qpos = ka.qoff + qi0 + r let sbase = (h * ka.qrows + qi0 + r) * 2u - // jb caps at np32 - 32 (jlimit is np32-clamped, jb steps by 32), so jb + c is - // always a live score column — no bound needed + //! jlimit is np32-clamped and jb steps by 32, so jb + c is always a live score column let sr = float(att[(h * ka.qrows + qi0 + r) * ka.np32 + jb + c]) ta[e] = pf_p_weight(sr, jb + c, qpos, ka.window, ka.softcap, ka.uend, ka.ulo, stat[sbase], stat[sbase + 1u]) tb[e] = jb + r < ka.npos ? v[(jb + r) * ka.kv_dim + kvhoff + d0 + c] : 0.0 @@ -2012,20 +1865,14 @@ class MetalAttnAV { } } -// The tiled attention pair (v21 lessons applied to the trio's QK/AV GEMMs — the old -// 32x32 scalar-f32-staged kernels ran ~60x below mul_mm rate, owning 24ms of the 3B window). -// QK: S[h] = scale * Q_h . K_h^T, 32x64 C tiles; DASLLAMA_METAL_ATTN=0 pins the trio (hs % 64 != 0 too). -// Metal-4 staged-tile twin of MetalAttnQKMm: flat f16 tiles per head-dim chunk (the softmax -// scale folded on the staged K side), same causal/window block skips (threadgroup-uniform). -// XT = the Q stream codec — the f16 twin keeps matmul2d on the native half x half path. [ |> template_struct_instance] class template MetalAttnQKMmTensorT { @ssbo @binding = 0 q : array @ssbo @binding = 1 k : array @ssbo @binding = 2 att : array @uniform @binding = 3 ka : AttnArgs - @workgroup twb : float16[2048] // K chunk: 64 keys x 32 k, flat (scale folded here) + @workgroup twb : float16[2048] //!< K chunk: 64 keys x 32 k, flat (scale folded here) [metal_kernel(float_a_ok=true)] def metal_attn_qk_mm_t { @@ -2044,8 +1891,6 @@ class template MetalAttnQKMmTensorT { tmm2d_tg_begin_deva(acc, unsafe(addr(q[0])), 32u, 64u, 4u, 32u) var kb = 0u while (kb * 32u < ka.head_size) { - // Q streams from device raw; the softmax scale rides the staged K side instead - // ((q*s)·k == q·(k*s)), one work item = one (key row, 16-element half) var work = lid while (work < 128u) { let j = work >> 1u @@ -2077,19 +1922,16 @@ class MetalAttnQKMmTH : MetalAttnQKMmTensorT { [metal_dispatch(name = "enc_qk_mm_c", pso = "g_pf_pso_qkmm", tgmem = "metal_attn_qk_mm_msl_tgmem", tg = 128, grid = "mp/32, nk64/64, heads", params = "mp : int64, nk64 : int64, heads : int64")] class MetalAttnQKMm : MetalMmTileBase { - @ssbo @binding = 0 @role = "read" q : array // [mp x qd/4], roped - @ssbo @binding = 1 @role = "read" k : array // [nk64 x kv_dim/4], roped (existing rows + the chunk) - @ssbo @binding = 2 @role = "write" att : array // [n_heads x qrows x np32] raw scores out, f16 slab + @ssbo @binding = 0 @role = "read" q : array //!< [mp x qd/4], roped + @ssbo @binding = 1 @role = "read" k : array //!< [nk64 x kv_dim/4], roped (existing rows + the chunk) + @ssbo @binding = 2 @role = "write" att : array //!< [n_heads x qrows x np32] raw scores out, f16 slab @uniform @binding = 3 ka : AttnArgs - // inherited ta = K tiles (k row, key col), tb = Q tiles (query row, k col) + //! inherited ta = K tiles (k row, key col), tb = Q tiles (query row, k col) [metal_kernel(name="metal_attn_qk_mm_msl")] def metal_attn_qk_mm { - let mBase = gl_WorkGroupID.x * 32u // query rows - let nBase = gl_WorkGroupID.y * 64u // key rows - // skip blocks fully above the causal diagonal (uniform span: fully past both uend and the - // block's causal reach — tail rows above the span stay causal), or fully below every - // row's sliding ka.window + let mBase = gl_WorkGroupID.x * 32u //! query rows + let nBase = gl_WorkGroupID.y * 64u //! key rows if ((ka.uend > 0u ? nBase >= max(ka.uend, ka.qoff + mBase + 32u) : nBase > ka.qoff + mBase + 31u) || (ka.window > 0u && ka.qoff + mBase + 1u > ka.window && nBase + 64u <= ka.qoff + mBase + 1u - ka.window)) { return @@ -2101,13 +1943,13 @@ class MetalAttnQKMm : MetalMmTileBase { let qoff4 = (h * ka.head_size) / 4u let qd4 = ka.qd / 4u let kvd4 = ka.kv_dim / 4u - var mc : simdgroup_float8x8[8] // C quadrant: 2 row-tiles x 4 col-tiles - let lr0 = lid / 2u // A split: key row + 16-k half + var mc : simdgroup_float8x8[8] //!< C quadrant: 2 row-tiles x 4 col-tiles + let lr0 = lid / 2u //! A split: key row + 16-k half let il0 = lid % 2u let syA = lr0 / 8u let lxA = lr0 % 8u let tA0 = (il0 * 2u * 8u + syA) * 64u + lxA - let lr1 = lid / 4u // B split: query row + 8-k run + let lr1 = lid / 4u //! B split: query row + 8-k run let iy = (lid % 4u) * 8u let ibB = ((lid % 4u) * 4u + lr1 / 8u) * 64u + (lr1 % 8u) * 8u let aB = (sg % 2u) * 256u @@ -2142,22 +1984,18 @@ class MetalAttnQKMm : MetalMmTileBase { va[14] = float16(a3.z) va[15] = float16(a3.w) barrier() - // K stage as a rolled loop off tA0 (tA1 = tA0 + 512) — 16 hand-written strided - // stores hoist 16 tile addresses into loop-lifetime registers for [unroll_full] (i in range(16)) { ta[tA0 + uint(i / 8) * 512u + uint(i % 8) * 8u] = va[i] } tg_store_half4(tb, ibB, b0) tg_store_half4(tb, ibB + 4u, b1) barrier() - // math ROLLED over matrix arrays + das-pointer tile bumps — the hand-unrolled - // spelling costs an occupancy tier (this kernel measured max_threads 704) acc_quad(aB, bB, ma, mb, mc) kb++ } let base = h * ka.qrows * ka.np32 - let row0 = mBase + (sg / 2u) * 16u // accumulator rows = queries - let col0 = nBase + (sg % 2u) * 32u // accumulator cols = keys + let row0 = mBase + (sg / 2u) * 16u //! accumulator rows = queries + let col0 = nBase + (sg % 2u) * 32u //! accumulator cols = keys var hc : simdgroup_half8x8 for [unroll_full] (i in range(8)) { sgmat_to_half(hc, mc[i]) @@ -2166,22 +2004,16 @@ class MetalAttnQKMm : MetalMmTileBase { } } -// AV: O_h = P_h . V_h — C tile 32 tokens x 64 V-columns, k walks the causally limited position -// axis in 32-blocks. V stages contiguous float4 loads, position rows >= npos ZEROED (pf_p_weight -// zeroes P columns >= npos EXACTLY; 0 * NaN from a pad V row would poison the tile). -// Metal-4 staged-tile twin of MetalAttnAVMm: P x V over flat f16 tiles, V staged NATURAL rows. -// PADFREE = clean pipeline (npos % 64 == 0: no pad position in any chunk, staging selects fold -// out); the checked stamp zero-guards pad rows (0 * stale-NaN would poison the tile). [ |> template_struct_instance] class template MetalAttnAVMmTensorT { @ssbo @binding = 0 att : array @ssbo @binding = 1 v : array @ssbo @binding = 2 xb : array @uniform @binding = 3 ka : AttnArgs - @ssbo @binding = 4 @role = "read" stat : array // [n_heads x qrows x 2] rowmax, 1/sum - @workgroup twp : float16[2048] // P chunk: 32 rows x 64 pos, exp applied at staging - @workgroup twb : float16[4096] // V chunk: 64 positions x 64 v-cols, NATURAL rows + @ssbo @binding = 4 @role = "read" stat : array //!< [n_heads x qrows x 2] rowmax, 1/sum + @workgroup twp : float16[2048] //!< P chunk: 32 rows x 64 pos, exp applied at staging + @workgroup twb : float16[4096] //!< V chunk: 64 positions x 64 v-cols, NATURAL rows @template_constant PADFREE : bool = false [metal_kernel] @@ -2191,8 +2023,6 @@ class template MetalAttnAVMmTensorT { let h = gl_WorkGroupID.z let kvhoff = (h / ka.kv_mul) * ka.head_size let lid = gl_LocalInvocationID.x - // the tile-max walk bound: causal reach, lifted to uend only when the tile holds span - // rows (P weights are zero past each row's live length by construction) let creach = ka.qoff + mBase + 32u let klimit = min(ka.uend > 0u && ka.qoff + mBase < ka.uend && creach > ka.ulo ? max(ka.uend, creach) : creach, ka.np32) var acc : float[2048] @@ -2200,8 +2030,6 @@ class template MetalAttnAVMmTensorT { tmm2d_tg_begin_nt(acc, 32u, 64u, 4u, 64u) var kb = 0u while (kb * 64u < klimit) { - // P stages with the exp/mask applied (one work item = one row's 16-pos run, - // stats hoisted); V rows land NATURAL [pos][col] — coalesced, no transpose gather var work = lid while (work < 128u) { let r = work >> 2u @@ -2213,8 +2041,7 @@ class template MetalAttnAVMmTensorT { let rowb = (h * ka.qrows + mBase + r) * ka.np32 for [unroll_full] (t in range(16)) { let jg = kb * 64u + ph + uint(t) - // jg < klimit <= np32 on both stamps (np32 % 64 == 0) — the PADFREE axis - // carries only the V-row guard below + //! jg stays below np32 on both stamps, so only the V-row guard below varies with PADFREE let sr = float(att[rowb + jg]) twp[r * 64u + ph + uint(t)] = float16(pf_p_weight(sr, jg, qpos, ka.window, ka.softcap, ka.uend, ka.ulo, sm, sinv)) } @@ -2249,18 +2076,17 @@ class MetalAttnAVMmTP : MetalAttnAVMmTensorT { override PADFREE = true } -// PADFREE = clean pipeline (npos % 32 == 0: no pad position in any block); carries -// MetalMmTileBase's tiles + acc_quad inline — a template extending a base class from -// another module trips the reified struct's finalizer typing. +//! acc_quad is inlined here rather than inherited: a class template extending a base class +//! from another module trips the reified struct's finalizer typing. [ |> template_struct_instance] class template MetalAttnAVMmSgT { - @ssbo @binding = 0 @role = "read" att : array // [n_heads x qrows x np32] RAW scores, f16 slab - @ssbo @binding = 1 @role = "read" v : array // [nk64 x kv_dim/4] raw V (existing rows + the chunk) - @ssbo @binding = 2 @role = "write" xb : array // [mp x qd] attention output + @ssbo @binding = 0 @role = "read" att : array //!< [n_heads x qrows x np32] RAW scores, f16 slab + @ssbo @binding = 1 @role = "read" v : array //!< [nk64 x kv_dim/4] raw V (existing rows + the chunk) + @ssbo @binding = 2 @role = "write" xb : array //!< [mp x qd] attention output @uniform @binding = 3 ka : AttnArgs - @ssbo @binding = 4 @role = "read" stat : array // [n_heads x qrows x 2] rowmax, 1/sum - @workgroup ta : float16[2048] // V tiles (pos row, col col) - @workgroup tb : float16[1024] // P tiles (token row, pos col) + @ssbo @binding = 4 @role = "read" stat : array //!< [n_heads x qrows x 2] rowmax, 1/sum + @workgroup ta : float16[2048] //!< V tiles (pos row, col col) + @workgroup tb : float16[1024] //!< P tiles (token row, pos col) @template_constant PADFREE : bool = false def acc_quad(aB, bB : uint; var ma : simdgroup_half8x8[4]; var mb : simdgroup_half8x8[2]; var mc : simdgroup_float8x8[8]) { @@ -2285,17 +2111,17 @@ class template MetalAttnAVMmSgT { def metal_attn_av_mm { let lid = gl_LocalInvocationID.x let sg = gl_SubgroupID - let mBase = gl_WorkGroupID.x * 32u // token rows - let vBase = gl_WorkGroupID.y * 64u // V columns within the head + let mBase = gl_WorkGroupID.x * 32u //! token rows + let vBase = gl_WorkGroupID.y * 64u //! V columns within the head let h = gl_WorkGroupID.z let kvhoff4 = ((h / ka.kv_mul) * ka.head_size) / 4u let kvd4 = ka.kv_dim / 4u - var mc : simdgroup_float8x8[8] // C quadrant: 2 row-tiles x 4 col-tiles - // A split: thread stages one position row x 16 contiguous V columns (4 x tg_store_half4) + var mc : simdgroup_float8x8[8] //!< C quadrant: 2 row-tiles x 4 col-tiles + //! A split: thread stages one position row x 16 contiguous V columns (4 x tg_store_half4) let pr = lid / 4u let vc16 = (lid % 4u) * 16u - let sxyA = (pr / 8u) * 8u * 64u + (pr % 8u) * 8u // 64*(8*(pos/8)) + 8*(pos%8) - // B split: thread stages one token row x 8 contiguous positions of P + let sxyA = (pr / 8u) * 8u * 64u + (pr % 8u) * 8u + //! B split: thread stages one token row x 8 contiguous positions of P let lr1 = lid / 4u let iy = (lid % 4u) * 8u let ibB = ((lid % 4u) * 4u + lr1 / 8u) * 64u + (lr1 % 8u) * 8u @@ -2303,8 +2129,6 @@ class template MetalAttnAVMmSgT { let bB = (sg / 2u) * 128u var ma : simdgroup_half8x8[4] var mb : simdgroup_half8x8[2] - // the tile-max walk bound: causal reach, lifted to uend only when the tile holds span - // rows (P is softmax-zeroed past each row's live length either way) let creach = ka.qoff + mBase + 32u let klimit = min(ka.uend > 0u && ka.qoff + mBase < ka.uend && creach > ka.ulo ? max(ka.uend, creach) : creach, ka.np32) var kb = 0u @@ -2331,20 +2155,18 @@ class template MetalAttnAVMmSgT { pf_p_weight(float(att[srcB + 6u]), jg + 6u, qpos, ka.window, ka.softcap, ka.uend, ka.ulo, sm, sinv), pf_p_weight(float(att[srcB + 7u]), jg + 7u, qpos, ka.window, ka.softcap, ka.uend, ka.ulo, sm, sinv)) barrier() - let tbase = sxyA + (vc16 / 8u) * 64u // first col-tile this thread touches + let tbase = sxyA + (vc16 / 8u) * 64u //! first col-tile this thread touches tg_store_half4(ta, tbase, a0) tg_store_half4(ta, tbase + 4u, a1) - tg_store_half4(ta, tbase + 64u, a2) // next 8-column tile + tg_store_half4(ta, tbase + 64u, a2) //! next 8-column tile tg_store_half4(ta, tbase + 68u, a3) tg_store_half4(tb, ibB, b0) tg_store_half4(tb, ibB + 4u, b1) barrier() - // math ROLLED over matrix arrays + das-pointer tile bumps — the hand-unrolled - // spelling costs an occupancy tier (this kernel measured max_threads 704) acc_quad(aB, bB, ma, mb, mc) kb++ } - let row0 = mBase + (sg / 2u) * 16u // accumulator rows = tokens + let row0 = mBase + (sg / 2u) * 16u //! accumulator rows = tokens let col0 = h * ka.head_size + vBase + (sg % 2u) * 32u for [unroll_full] (i in range(8)) { simdgroup_store(mc[i], xb, (row0 + uint(i / 4) * 8u) * ka.qd + col0 + uint(i % 4) * 8u, ka.qd) @@ -2361,15 +2183,14 @@ class MetalAttnAVMmP : MetalAttnAVMmSgT { override PADFREE = true } -// Interleave two [npos x d] panels into the [npos x 2d] MTP eh_proj input — the draft-warm -// cat rows [enorm(embed) ; hnorm(hidden)]; one thread per source element. +//! Interleave two [npos x d] panels into the [npos x 2d] MTP eh_proj input: rows are [enorm(embed) ; hnorm(hidden)]. [metal_dispatch(name = "pf_enc_cat2", pso = "g_pf_pso_cat2", tg = 64, grid = "total/64", params = "total : int64")] class MetalPfCat2 { @ssbo @binding = 0 @role = "write" y : array @ssbo @binding = 1 @role = "read" a : array @ssbo @binding = 2 @role = "read" b : array @uniform @binding = 3 d : uint - @uniform @binding = 4 total : uint // grid guard: npos * d + @uniform @binding = 4 total : uint //!< grid guard: npos * d [metal_kernel(name="metal_pf_cat2_msl")] def metal_pf_cat2 { @@ -2384,21 +2205,15 @@ class MetalPfCat2 { } } -// DeltaNet (Wave D): the β/α projection GEMV (MetalDnBa) lives in dasllama_metal_kernels as -// the BATCHED stamp of the MetalQ8GemvT template — same stream walk, grid-y position axis. -// ===== the whole-prefill driver ===== -// Registered as prefill override "metal" (DASLLAMA_PIN_PREFILL). One command buffer per prefill; -// ONE commit+wait, then unified-memory readback hands x_b + per-layer roped-K/raw-V back to the CPU. -var private g_pf_failed = false // prefill PSO bring-up failed (the device latch is common's g_failed) -// per-prefill transients, reused across calls (prefill orchestration is serial) +var private g_pf_failed = false //!< prefill PSO bring-up failed (the device latch is common's g_failed) +//! per-prefill transients, reused across calls (prefill orchestration is serial) var private @scratch g_pf_bks : array var private @scratch g_pf_bvs : array var private @scratch g_pf_cbs : array var private g_pf_pool : MetalBufferPool -var private g_pf_upool : MetalBufferPool // UNTRACKED pool: uniforms + rope tables (GPU-read-only) -// what the prefill kernels implement beyond the base llama dense block — grows wave by wave +var private g_pf_upool : MetalBufferPool //!< UNTRACKED pool: uniforms + rope tables (GPU-read-only) let PF_NEEDS_OK = (MetalNeed.neox | MetalNeed.qkv_bias | MetalNeed.qk_norm | MetalNeed.qd_neq_dim | MetalNeed.softcap | MetalNeed.sliding | MetalNeed.pre_post_norm | MetalNeed.geglu | MetalNeed.v_norm | MetalNeed.attn_scale | MetalNeed.out_scale | @@ -2406,7 +2221,7 @@ let PF_NEEDS_OK = (MetalNeed.neox | MetalNeed.qkv_bias | MetalNeed.qk_norm | Met MetalNeed.ple) var private g_min_npos = 64l -var private g_max_npos = 2048l // naive-attention P footprint cap: heads x npos^2 floats +var private g_max_npos = 2048l //!< naive-attention P footprint cap: heads x npos^2 floats var private g_prefills = 0l var private g_pf_inited = false var private g_pf_pso_rope : MetalComputePipeline? @@ -2415,49 +2230,49 @@ var private g_pf_pso_qk : MetalComputePipeline? var private g_pf_pso_rowstat : MetalComputePipeline? var private g_pf_pso_av : MetalComputePipeline? var private g_pf_pso_cat2 : MetalComputePipeline? -var private g_pf_pso_mm_t : MetalComputePipeline? // the mul_mm TENSOR twin; the base is the shared g_pso_mm -var private g_pf_pso_mm_th : MetalComputePipeline? // its half-X stamp (the converted f16 activation panel) -var private g_pf_pso_mm_t128 : MetalComputePipeline? // tall 128-row M-tile stamps: W streams M/128 times +var private g_pf_pso_mm_t : MetalComputePipeline? //!< the mul_mm TENSOR twin; the base is the shared g_pso_mm +var private g_pf_pso_mm_th : MetalComputePipeline? //!< its half-X stamp (the converted f16 activation panel) +var private g_pf_pso_mm_t128 : MetalComputePipeline? var private g_pf_pso_mm_th128 : MetalComputePipeline? var private g_pf_pso_cvt_half : MetalComputePipeline? -var private g_pf_bxh : MetalBuffer? // per-forward f16 activation scratch panels (null = f32 path); -var private g_pf_bxh2 : MetalBuffer? // ... double-buffered so a site's GEMM overlaps the next site's convert +var private g_pf_bxh : MetalBuffer? //!< per-forward f16 activation scratch panel (null = the f32 path) +var private g_pf_bxh2 : MetalBuffer? var private g_pf_bxh_flip : bool -var private g_pf_bxh_bytes : uint64 // acquired panel capacity — pf_cvt_panel's fit check -var private g_pf_pso_dq_q8 : MetalComputePipeline? // q8 blob -> device f16 W panel (the dev-W pass) -var private g_pf_pso_dq_k4 : MetalComputePipeline? // the K-quant dequant passes onto the same panel +var private g_pf_bxh_bytes : uint64 //!< acquired panel capacity — pf_cvt_panel's fit check +var private g_pf_pso_dq_q8 : MetalComputePipeline? //!< q8 blob -> device f16 W panel (the dev-W pass) +var private g_pf_pso_dq_k4 : MetalComputePipeline? //!< the K-quant dequant passes onto the same panel var private g_pf_pso_dq_k5 : MetalComputePipeline? var private g_pf_pso_dq_k6 : MetalComputePipeline? -var private g_pf_pso_hmm_th : MetalComputePipeline? // all-device half x half mul_mm reading that panel -var private g_pf_pso_hmm_th128 : MetalComputePipeline? // its tall 128-row M-tile stamp -var private g_pf_bwh : MetalBuffer? // per-forward f16 W panels (dev-W form), double-buffered like bxh +var private g_pf_pso_hmm_th : MetalComputePipeline? //!< all-device half x half mul_mm reading that panel +var private g_pf_pso_hmm_th128 : MetalComputePipeline? +var private g_pf_bwh : MetalBuffer? //!< per-forward f16 W panels (dev-W form), double-buffered like bxh var private g_pf_bwh2 : MetalBuffer? var private g_pf_bwh_flip : bool var private g_pf_bwh_bytes : uint64 -var private g_pf_pso_bf16_mm : MetalComputePipeline? // native-BF16 A twin (E-series model_proj) -var private g_pf_pso_bf16_mm_th : MetalComputePipeline? // its half-X stamp (tensor-crowned only) -var private g_pf_pso_bf16_mm_t128 : MetalComputePipeline? // tall 128-row M-tile stamps +var private g_pf_pso_bf16_mm : MetalComputePipeline? //!< native-BF16 A twin (E-series model_proj) +var private g_pf_pso_bf16_mm_th : MetalComputePipeline? //!< its half-X stamp (tensor-crowned only) +var private g_pf_pso_bf16_mm_t128 : MetalComputePipeline? var private g_pf_pso_bf16_mm_th128 : MetalComputePipeline? -var private g_pf_bf16_mm_tensor : bool // crowned tensor twin selected (no tgmem bind) -var private g_pf_mm_tensor : bool // ditto for the production q8 mul_mm -var private g_pf_moe_mm_q8_tensor : bool // "moe_mulmm_q8" crowned (contiguous sites only) +var private g_pf_bf16_mm_tensor : bool //!< crowned tensor twin selected (no tgmem bind) +var private g_pf_mm_tensor : bool //!< crowned tensor twin selected for the production q8 mul_mm +var private g_pf_moe_mm_q8_tensor : bool //!< "moe_mulmm_q8" crowned (contiguous sites only) var private g_pf_pso_moe_mm_q8_t : MetalComputePipeline? var private g_pf_pso_moe_mm_q8_th : MetalComputePipeline? -var private g_pf_moe_mm_mx4_tensor : bool // "moe_mulmm_mx4" crowned (contiguous sites only) +var private g_pf_moe_mm_mx4_tensor : bool //!< "moe_mulmm_mx4" crowned (contiguous sites only) var private g_pf_pso_moe_mm_mx4_t : MetalComputePipeline? var private g_pf_pso_moe_mm_mx4_th : MetalComputePipeline? -var private g_pf_pso_moe_gx : MetalComputePipeline? // gather-X materialization (up/gate contiguous form) -var private g_pf_pso_moe_mm_q51_t : MetalComputePipeline? // moe q5_1 twins (contiguous rows; the k4 crown proxies — same staging form class) +var private g_pf_pso_moe_gx : MetalComputePipeline? //!< gather-X materialization (up/gate contiguous form) +var private g_pf_pso_moe_mm_q51_t : MetalComputePipeline? //!< moe q5_1 twins (contiguous rows; the k4 crown proxies — same staging form class) var private g_pf_pso_moe_mm_q51_th : MetalComputePipeline? var private g_pf_pso_moe_mm_q51_th128 : MetalComputePipeline? var private g_pf_pso_moe_mm_q51_thr : MetalComputePipeline? -var private g_pf_pso_moe_mm_k4_t : MetalComputePipeline? // moe kq twins (contiguous rows; dense kq crowns gate) +var private g_pf_pso_moe_mm_k4_t : MetalComputePipeline? //!< moe kq twins (contiguous rows; dense kq crowns gate) var private g_pf_pso_moe_mm_k4_th : MetalComputePipeline? var private g_pf_pso_moe_mm_k5_t : MetalComputePipeline? var private g_pf_pso_moe_mm_k5_th : MetalComputePipeline? var private g_pf_pso_moe_mm_k6_t : MetalComputePipeline? var private g_pf_pso_moe_mm_k6_th : MetalComputePipeline? -var private g_pf_pso_moe_mm_q8_th128 : MetalComputePipeline? // moe tall pair (128-floor + remainder) +var private g_pf_pso_moe_mm_q8_th128 : MetalComputePipeline? //!< moe tall pair (128-floor + remainder) var private g_pf_pso_moe_mm_q8_thr : MetalComputePipeline? var private g_pf_pso_moe_mm_mx4_th128 : MetalComputePipeline? var private g_pf_pso_moe_mm_mx4_thr : MetalComputePipeline? @@ -2467,24 +2282,24 @@ var private g_pf_pso_moe_mm_k5_th128 : MetalComputePipeline? var private g_pf_pso_moe_mm_k5_thr : MetalComputePipeline? var private g_pf_pso_moe_mm_k6_th128 : MetalComputePipeline? var private g_pf_pso_moe_mm_k6_thr : MetalComputePipeline? -var private g_pf_kq_mm4_tensor : bool // "kq_mulmm_k4" crowned +var private g_pf_kq_mm4_tensor : bool //!< "kq_mulmm_k4" crowned var private g_pf_pso_kq_mm4_t : MetalComputePipeline? var private g_pf_pso_kq_mm4_th : MetalComputePipeline? -var private g_pf_kq_mm5_tensor : bool // "kq_mulmm_k5" crowned +var private g_pf_kq_mm5_tensor : bool //!< "kq_mulmm_k5" crowned var private g_pf_pso_kq_mm5_t : MetalComputePipeline? var private g_pf_pso_kq_mm5_th : MetalComputePipeline? -var private g_pf_kq_mm6_tensor : bool // "kq_mulmm_k6" crowned +var private g_pf_kq_mm6_tensor : bool //!< "kq_mulmm_k6" crowned var private g_pf_pso_kq_mm6_t : MetalComputePipeline? var private g_pf_pso_kq_mm6_th : MetalComputePipeline? -var private g_pf_qkmm_tensor : bool // "attn_qkmm" crowned +var private g_pf_qkmm_tensor : bool //!< "attn_qkmm" crowned var private g_pf_pso_qkmm_t : MetalComputePipeline? -var private g_pf_pso_qkmm_th : MetalComputePipeline? // half-Q stamp (the last float-operand site retired) -var private g_pf_avmm_tensor : bool // "attn_avmm" crowned +var private g_pf_pso_qkmm_th : MetalComputePipeline? +var private g_pf_avmm_tensor : bool //!< "attn_avmm" crowned var private g_pf_pso_avmm_t : MetalComputePipeline? var private g_pf_pso_avmm_tp : MetalComputePipeline? var private g_pf_pso_avmm_p : MetalComputePipeline? -var private g_pf_pso_ple_gather : MetalComputePipeline? // PLE pre-step: q8 token-row gather -var private g_pf_pso_ple_finish : MetalComputePipeline? // PLE pre-step: rms + combine, in place +var private g_pf_pso_ple_gather : MetalComputePipeline? //!< PLE pre-step: q8 token-row gather +var private g_pf_pso_ple_finish : MetalComputePipeline? //!< PLE pre-step: rms + combine, in place var private g_pf_pso_qkmm : MetalComputePipeline? var private g_pf_pso_avmm : MetalComputePipeline? var private g_pf_pso_moe_count : MetalComputePipeline? @@ -2497,14 +2312,13 @@ var private g_pf_pso_moe_mm_k6 : MetalComputePipeline? var private g_pf_pso_swiglu_oai : MetalComputePipeline? var private g_pf_pso_moe_mm_mx4 : MetalComputePipeline? var private g_pf_pso_moe_mm_q51 : MetalComputePipeline? -var private g_mm_legacy = false // set_metal_prefill_mulmm_legacy — tests' exact-parity rail -var private g_pf_logits_cpu = false // set_metal_prefill_logits_cpu — the logits A/B rail -// timing-attribution knockout (DASLLAMA_METAL_PREFILL_SKIP=attn|gemm|ew|nongemm|moe|moe_mm| -// moe_act|moe_bias|moe_reduce|moe_only_router|moe_only_route|moe_no_mm_act): skips encoding that -// stage family (moe_bias = hasb=0, the mm bias fold off). Output GARBAGE, debug only. +var private g_mm_legacy = false //!< set_metal_prefill_mulmm_legacy — tests' exact-parity rail +var private g_pf_logits_cpu = false //!< set_metal_prefill_logits_cpu — the logits A/B rail +//! Timing-attribution knockout: DASLLAMA_METAL_PREFILL_SKIP / set_metal_prefill_skip names one +//! stage family to leave unencoded. Output is GARBAGE while non-empty; the family names are the +//! g_pf_skip comparisons below. var private g_pf_skip = "" -// composite skip predicates for the MoE stages (moe_only_* isolate the route chain per-kernel) def private pf_skip_moe_mm : bool { return (g_pf_skip == "moe_mm" || g_pf_skip == "moe_only_route" || g_pf_skip == "moe_only_router" || g_pf_skip == "moe_only_sel" || g_pf_skip == "moe_no_mm_act") @@ -2520,13 +2334,13 @@ def private pf_skip_moe_reduce : bool { g_pf_skip == "moe_only_sel") } -//! Prefills below this npos decline to the CPU path (submit+readback overhead outweighs the win). -//! Set 1 to force every prefill onto the GPU (tests). //! Test A/B seat: pin the span serving on/off in-process (DASLLAMA_METAL_SPAN's setter twin). def public set_metal_prefill_span(on : bool) { g_pf_env_span = on } +//! Prefills below this npos decline to the CPU path (submit+readback overhead outweighs the win). +//! Set 1 to force every prefill onto the GPU (tests). def public set_metal_prefill_min_npos(v : int64) { g_min_npos = v } @@ -2580,7 +2394,6 @@ def public set_metal_prefill_skip(v : string) { g_pf_skip = v } -// cumulative per-stage prefill wall since load/reset — the pp chase harness's numbers rail var private g_pf_stage_prefills = 0l var private g_pf_stage_setup_us = 0l var private g_pf_stage_encwait_us = 0l @@ -2625,8 +2438,8 @@ def public metal_prefill_pso_init : bool { //! refilled weight arrays, same contract as metal_gemm_shutdown). Lazily re-initializes on the //! next served prefill. def public metal_prefill_shutdown { // nolint:STYLE037,STYLE038 — flat one-release-per-PSO list - kcov_fold() // PSO pointers recycle across re-init — counts fold into names first - residency_reset() // the set references pooled buffers the drains below release + kcov_fold() //! PSO pointers recycle across re-init — counts fold into names first + residency_reset() //! the set references pooled buffers the drains below release pool_drain(g_pf_pool) pool_drain(g_pf_upool) if (g_pf_pso_moe_mm_q8_t != null) { @@ -2848,11 +2661,10 @@ def public metal_prefill_shutdown { // nolint:STYLE037,STYLE038 — flat one-r g_pf_failed = false } -[cold_path] // the moe kq twin PSOs, gated by the dense kq crowns (the same staging form -// class; own tune families are an arc-end candidate) +[cold_path] //! the moe kq twin PSOs ride the dense kq crowns - the same staging form class def private pf_compile_moe_kq_twins(var ok : bool&) { if (g_pf_kq_mm4_tensor) { - // q5_1 has no dense crown; the k4 crown proxies (same file, non-256-divisible axes) + //! q5_1 has no dense crown; the k4 crown proxies (same file, non-256-divisible axes) g_pf_pso_moe_mm_q51_t = compile_pso(MetalMoeMulMmQ51T_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51T_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51T_metal_moe_mulmm_q51_t_msl_fastmath, ok) g_pf_pso_moe_mm_q51_th = compile_pso(MetalMoeMulMmQ51TH_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51TH_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51TH_metal_moe_mulmm_q51_t_msl_fastmath, ok) g_pf_pso_moe_mm_q51_th128 = compile_pso(MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl_fastmath, ok) @@ -2876,7 +2688,7 @@ def private pf_compile_moe_kq_twins(var ok : bool&) { } } -[cold_path] // one-time device/PSO bring-up, guarded by its own inited flag +[cold_path] def private metal_prefill_init : bool { // nolint:STYLE038 — flat one-compile-per-PSO list if (g_pf_inited) { return true @@ -2884,16 +2696,15 @@ def private metal_prefill_init : bool { // nolint:STYLE038 — flat one-compil if (g_pf_failed) { return false } - if (!metal_common_init()) { // ONE device + queue for the whole family (M3) — this also arms the hazard-rail knobs on prefill-first runs + if (!metal_common_init()) { //! also arms the hazard-rail knobs on prefill-first runs to_log(LOG_WARNING, "dasLLAMA metal prefill: no Metal device - prefill stays on the CPU\n") g_pf_failed = true return false } - if (!metal_decode_init()) { // the family kernel registry — the generated enc_* builders bind ITS PSOs (idempotent) + if (!metal_decode_init()) { //! the family kernel registry — the generated enc_* builders bind ITS PSOs (idempotent) g_pf_failed = true return false } - // raced-constant knobs from the box sidecar (defaults = the M5 race winners) TALL_OCC_FLOOR = metal_tall_floor() DEVW_SMALL_PANEL = uint64(metal_devw_small_panel_mb()) * 1024ul * 1024ul CVT_MIN_ROWS = metal_cvt_min_rows() @@ -2904,7 +2715,7 @@ def private metal_prefill_init : bool { // nolint:STYLE038 — flat one-compil g_pf_pso_rowstat = compile_pso(metal_attn_rowstat_msl, metal_attn_rowstat_msl_entry, metal_attn_rowstat_msl_fastmath, ok) g_pf_pso_av = compile_pso(metal_attn_av_msl, metal_attn_av_msl_entry, metal_attn_av_msl_fastmath, ok) g_pf_pso_cat2 = compile_pso(metal_pf_cat2_msl, metal_pf_cat2_msl_entry, metal_pf_cat2_msl_fastmath, ok) - // the panel converter serves every half-X family (q8/kq/bf16), crown-independent + //! the panel converter serves every half-X family (q8/kq/bf16), crown-independent g_pf_pso_cvt_half = compile_pso(metal_cvt_half_msl, metal_cvt_half_msl_entry, metal_cvt_half_msl_fastmath, ok) g_pf_mm_tensor = metal_tensor_crowned("mulmm_q8") if (g_pf_mm_tensor) { @@ -2940,7 +2751,7 @@ def private metal_prefill_init : bool { // nolint:STYLE038 — flat one-compil g_pf_pso_kq_mm6_t = compile_pso(MetalKqMulMmK6T_metal_kq_mulmm_k6_t_msl, MetalKqMulMmK6T_metal_kq_mulmm_k6_t_msl_entry, MetalKqMulMmK6T_metal_kq_mulmm_k6_t_msl_fastmath, ok) g_pf_pso_kq_mm6_th = compile_pso(MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl, MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl_entry, MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl_fastmath, ok) } - // dev-W: ONE all-device GEMM for every crowned family; dequant passes compile per family + //! dev-W: ONE all-device GEMM for every crowned family; dequant passes compile per family if (g_pf_mm_tensor || g_pf_kq_mm4_tensor || g_pf_kq_mm5_tensor || g_pf_kq_mm6_tensor) { g_pf_pso_hmm_th = compile_pso(MetalHalfMulMmTH_metal_half_mulmm_th_msl, MetalHalfMulMmTH_metal_half_mulmm_th_msl_entry, MetalHalfMulMmTH_metal_half_mulmm_th_msl_fastmath, ok) g_pf_pso_hmm_th128 = compile_pso(MetalHalfMulMmTH128_metal_half_mulmm_th_msl, MetalHalfMulMmTH128_metal_half_mulmm_th_msl_entry, MetalHalfMulMmTH128_metal_half_mulmm_th_msl_fastmath, ok) @@ -3003,8 +2814,7 @@ def private metal_prefill_init : bool { // nolint:STYLE038 — flat one-compil return true } -// the mul_mm %64 shape gate over EVERY GEMM'd width — both attention classes' qd/kv_dim -// (hetero models GEMM each class's width; uniform models reduce to the old layer-0 check) +//! the mul_mm %64 shape gate over EVERY GEMM'd width, both attention classes included def private pf_mm_shape64(t : Model) : bool { let c = t.config let hs_sw = c.head_size_swa > 0l ? c.head_size_swa : c.head_size @@ -3016,8 +2826,6 @@ def private pf_mm_shape64(t : Model) : bool { ((c.n_heads * hs_sw) % 64l) == 0l && ((kvh_sw * hs_sw) % 64l) == 0l) } -// The window-READINESS leg: are THIS window's rope tables built yet? forward_prefill builds them -// AFTER it consults the PLE gate, so a capability question must not ask this one. def private rope_rows_ready(t : Model; s : Session; npos : int64) : bool { let c = t.config let swa_hs = c.head_size_swa > 0l ? c.head_size_swa : c.head_size @@ -3025,54 +2833,48 @@ def private rope_rows_ready(t : Model; s : Session; npos : int64) : bool { (!has_dual_rope(c) || long_length(s.rope_cos_swa) >= npos * (swa_hs / 2l))) } -// the std dense stack + PF_NEEDS_OK features are wired — anything else declines to the CPU -// loop. Returns the FIRST failing clause; .none = supported. -[unused_argument(start_pos)] // start_pos > 0 (a continuation chunk) is served (M2.5): the -// existing rows gather into the K/V panels and the causal diagonal shifts by qoff — the gate -// keeps the argument so future clauses can window it +//! Returns the FIRST failing clause; .none = the model and window serve. +[unused_argument(start_pos)] //! a continuation chunk (start_pos > 0) serves - no clause here depends on where it starts def private prefill_decline(t : Model; s : Session; npos, start_pos : int64) : MetalPrefillDecline { - // the A/B rail: DASLLAMA_METAL_SPAN=0 declines the span to the tripwire-guarded CPU arm + //! the A/B rail: DASLLAMA_METAL_SPAN=0 declines the span to the tripwire-guarded CPU arm if (s.attn_uniform_end != 0l && !g_pf_env_span) { return MetalPrefillDecline.non_causal_span } let why = prefill_decline_caps(t, npos, s.attn_uniform_end != 0l) if (why != MetalPrefillDecline.none) return why - // rope tables are the hook's input (partial rope: rows rope_dim/2 wide; dual-rope: swa class width) + //! rope tables are the hook's input (partial rope: rows rope_dim/2 wide; dual-rope: swa class width) return rope_rows_ready(t, s, npos) ? MetalPrefillDecline.none : MetalPrefillDecline.rope_rows } -// Everything a model either can or cannot do, independent of how far THIS window has been set up. -// Callers that run before the window is staged (the PLE gpu gate) ask this one; a window that then -// turns out not to be ready declines later, and metal_prefill_forward's fallback covers it. def private prefill_decline_caps(t : Model; npos : int64; span : bool = false) : MetalPrefillDecline { - // npos window is a POLICY decline (blob-only and short SPANS serve any npos: neither has a safe CPU path) + //! npos window is a POLICY decline (blob-only and short SPANS serve any npos: neither has a safe CPU path) if (!t.metal_blob && ((npos < g_min_npos && !span) || npos > g_max_npos)) { return MetalPrefillDecline.npos_window } if (t.quant != QuantMode.q8) { return MetalPrefillDecline.quant_mode } - // kquant rides the mul_mm path only — mm pinned off or a shape the %64 gate rejects has no kq-capable GEMM and declines + //! kquant rides the mul_mm path only — mm pinned off or a shape the %64 gate rejects has no kq-capable GEMM and declines if (t.kquant_native) { - // kq_load_gpu_supported rejects fmts without a GPU kernel (q4_0 QAT tier) before they dispatch a wrong-layout branch + //! kq_load_gpu_supported rejects fmts without a GPU kernel (q4_0 QAT tier) before they dispatch a wrong-layout branch if (g_mm_legacy || !g_pf_env_mulmm || !pf_mm_shape64(t) || !kq_load_gpu_supported(t)) { return MetalPrefillDecline.kquant_native } } - // wscale_f16 rides the mul_mm path only — a model the mm shape gate rejects has no s16-capable GEMM and declines + //! wscale_f16 rides the mul_mm path only — a model the mm shape gate rejects has no s16-capable GEMM and declines if (t.wscale_f16) { if (g_mm_legacy || !g_pf_env_mulmm || !pf_mm_shape64(t)) { return MetalPrefillDecline.wscale_f16 } } - // non-std graphs decline; deltanet hybrids serve via dn_metal_ok (ds == 128 makes every dn GEMM width %128) + //! non-std graphs decline; deltanet hybrids serve via dn_metal_ok (ds == 128 makes every dn GEMM width %128) if ((!t.blocks.attn_is_std && !(t.config.hybrid_deltanet && dn_metal_ok(t))) || (!t.blocks.ffn_is_dense && (!moe_metal_ok(t) || (t.config.n_ff_exp % 64l) != 0l || (t.config.dim % 64l) != 0l))) { return MetalPrefillDecline.graph } - // the GEMM kernel reads ROW-MAJOR Q8 weights — a repack backend's interleaved layout is unreadable here + //! the GEMM kernel reads ROW-MAJOR Q8 weights — a repack backend's interleaved layout is unreadable here if (kernel_backend_needs_repack(active_kernel_backend())) { return MetalPrefillDecline.backend_repack } @@ -3081,7 +2883,6 @@ def private prefill_decline_caps(t : Model; npos : int64; span : bool = false) : } let c = t.config let hidden = layer_hidden(t, 0l) - // MatFormer E-series: at most TWO per-layer FFN widths serve, dense trunks, no MTP let h1 = ffn_second_hidden(t) if (h1 != 0l && (h1 < 0l || !t.blocks.ffn_is_dense || c.n_layer_nextn > 0l)) { return MetalPrefillDecline.layers @@ -3089,17 +2890,17 @@ def private prefill_decline_caps(t : Model; npos : int64; span : bool = false) : if ((c.dim % 32l) != 0l || (hidden % 32l) != 0l || (h1 > 0l && (h1 % 32l) != 0l)) { return MetalPrefillDecline.shape } - // per-CLASS: head_size/kv_dim % 32 grid the AV kernel (QK k-slabs any size); hetero geometry and missing attn_v serve + //! per-CLASS: head_size/kv_dim % 32 grid the AV kernel (QK k-slabs any size); hetero geometry and missing attn_v serve for (l in range64(c.n_layers)) { if ((layer_head_size(c, l) % 32l) != 0l || (layer_kv_dim(c, l) % 32l) != 0l) { return MetalPrefillDecline.shape } - // E-series shared-KV layers (Q-only) serve when the source is byte-compatible — the panel aliases it + //! E-series shared-KV layers (Q-only) serve when the source is byte-compatible — the panel aliases it if (t.kv_src[l] != l && !kv_share_ok(t, l)) { return MetalPrefillDecline.layers } } - // AFTER the capability gates (the support matrix asserts those reasons): drivers are BLOB-ONLY — planar q8 has no upload path, and a blob model rides the mul_mm rail exclusively + //! AFTER the capability gates (the support matrix asserts those reasons): drivers are BLOB-ONLY — planar q8 has no upload path, and a blob model rides the mul_mm rail exclusively if (!t.metal_blob || g_mm_legacy || !g_pf_env_mulmm || !pf_mm_shape64(t)) { return MetalPrefillDecline.planar @@ -3108,8 +2909,6 @@ def private prefill_decline_caps(t : Model; npos : int64; span : bool = false) : } -// The GEMV-tail row cap: npos % 32 remainders up to this many rows peel onto the fixed-B mv -// family (two dispatches past 4). Above it the padded tile is cheaper than 3+ weight streams. let private MM_TAIL_MAX = 8l var private g_pf_tail_sites = 0l @@ -3120,9 +2919,7 @@ def public metal_prefill_tail_stats() : tuple { return (sites = g_pf_tail_sites, rows = g_pf_tail_rows) } -// the peeled rows [row0, row0+r) of one mul_mm site as fixed-B GEMVs: y rows at stride d (every -// mul_mm site's bn uniform equals its grid width d — a wider fused-row site must NOT take the -// tail); r == 1 rides the reduction-split GEMV, r >= 2 the b4 form only (b2's stripe needs % 256). +[arch(at="../ARCHITECTURE_GPU_PREFILL.md#gemv-tail-peel")] def private enc_gemm_mm_tail(enc : MetalComputeEncoder?; bwblob : MetalBuffer?; wboff : uint64; bx, by, bk, bn : MetalBuffer?; yoff : uint64; kdim, d, row0, r : int64) { g_pf_tail_sites++ @@ -3142,9 +2939,6 @@ def private enc_gemm_mm_tail(enc : MetalComputeEncoder?; bwblob : MetalBuffer?; } } -// the flip half of the half-X twin rail: hand out the next f16 scratch panel when the knob, -// the panels and the fit allow (double-buffered so a consumer's GEMM overlaps the next twin's -// producer). Producers (dual-store stamps) take it ungated by rows - their twin is free. def private pf_twin_panel(rows, kdim : int64) : MetalBuffer? { if (!g_pf_env_half_x || g_pf_bxh == null || kdim <= 0l || uint64(rows * kdim * 2l) > g_pf_bxh_bytes) { return null @@ -3154,9 +2948,7 @@ def private pf_twin_panel(rows, kdim : int64) : MetalBuffer? { return bxh } -// the CONVERT form (no dual-store producer owns the panel): encode the f32 -> f16 pass; the -// 256-row gate stays here - under it the convert dispatches outweigh the halved stream. -def private pf_cvt_panel(enc : MetalComputeEncoder?; bx : MetalBuffer?; rows, kdim : int64; ko : bool = false) : MetalBuffer? { +def private pf_cvt_panel(enc : MetalComputeEncoder?; bx : MetalBuffer?; rows, kdim : int64; skip_convert : bool = false) : MetalBuffer? { if (rows < CVT_MIN_ROWS) { return null } @@ -3164,7 +2956,7 @@ def private pf_cvt_panel(enc : MetalComputeEncoder?; bx : MetalBuffer?; rows, kd if (bxh == null) { return null } - if (ko) { // attribution: stale halves, twin path unchanged + if (skip_convert) { //! attribution KO: stale panel halves, the twin path itself unchanged return bxh } var cka = CvtArgs(total = uint(rows * kdim)) @@ -3172,9 +2964,7 @@ def private pf_cvt_panel(enc : MetalComputeEncoder?; bx : MetalBuffer?; rows, kd return bxh } -// dev-W tile count: 1 = whole panel (map rules), >1 = N-column tiles each under the 32MB -// knee, 0 = keep the tg twin; slow_fb (kq fallback ~1.28x q8uh) lowers the over-knee bar -// and the tiled rows floor — the tiled 1.06-vs-q8uh read still beats THAT fallback +[arch(at="../ARCHITECTURE_GPU_PREFILL.md#devw-panel-knees")] def private pf_devw_tiles(rows, d, kdim : int64; slow_fb : bool = false) : int64 { if (!g_pf_env_dev_w || g_pf_bwh == null || kdim <= 0l || kdim % 32l != 0l || (kdim > DEVW_LONG_K && rows < (slow_fb ? DEVW_WIDE_N_ROWS : DEVW_LONG_K_ROWS))) { @@ -3185,7 +2975,6 @@ def private pf_devw_tiles(rows, d, kdim : int64; slow_fb : bool = false) : int64 && pb <= g_pf_bwh_bytes) { return 1l } - // fast-fallback floor 1024: the 0.95 isolated tiled win at 512 rows read flat-negative e2e let tile_floor = slow_fb ? DEVW_WIDE_N_ROWS : DEVW_LONG_K_ROWS let tile_over = slow_fb ? DEVW_SMALL_PANEL : DEVW_BIG_PANEL if (pb > tile_over && rows >= tile_floor) { @@ -3196,7 +2985,6 @@ def private pf_devw_tiles(rows, d, kdim : int64; slow_fb : bool = false) : int64 } } } - // whole-panel 32-48MiB at deep M: the fallback when no tile split divides if (pb <= DEVW_BIG_PANEL && rows >= DEVW_BIG_ROWS && pb <= g_pf_bwh_bytes) { return 1l } @@ -3209,8 +2997,6 @@ def private pf_devw_flip : MetalBuffer ? { return bwh } -// the dev-W GEMM dispatch: tall 128-row M-tiles on the rows' 128-floor (panel re-read -// M/128 times), the 32-tile stamp on the remainder — same occupancy floor as the mul_mm pick def private pf_enc_hmm(enc : MetalComputeEncoder?; bwh, bxh, by : MetalBuffer?; yoff : uint64; bk, bn : MetalBuffer?; rows, td, dfull, kdim : int64) { var r0 = 0l @@ -3224,8 +3010,7 @@ def private pf_enc_hmm(enc : MetalComputeEncoder?; bwh, bxh, by : MetalBuffer?; } } -// one q8 dev-W tile: dequant the [tbase, tbase+td) W columns into the flip panel, GEMM into -// y's column slice (bn stays the FULL row stride; the y base pointer carries the column base) +//! N-column tile: bn stays the FULL row stride, the y base pointer carries the column base def private pf_enc_devw_q8_tile(enc : MetalComputeEncoder?; bwblob : MetalBuffer?; wboff : uint64; bxh, by, bk, bn : MetalBuffer?; rows, tbase, td, dfull, kdim : int64; yoff : uint64) { var bwh = pf_devw_flip() @@ -3249,9 +3034,8 @@ def private pf_devw_panel(enc : MetalComputeEncoder?; bwblob : MetalBuffer?; wbo return true } -// the kq-format dev-W site: same predicate/tiling, the format's superblock dequant per tile -// (tile plane offsets: 16B scale blocks, K4 128B / K5 160B / K6 192B quant superblocks + the -// k6 2B d tail — all per-superblock strides x tbase*nsb) +//! per-tile plane offsets stride per superblock: 16B scale blocks, K4 128B / K5 160B / K6 192B +//! quant superblocks, plus the k6 2B d tail def private pf_devw_panel_kq(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; woff : int64; bxh, by, bk, bn : MetalBuffer?; rows, d, kdim : int64; yoff : uint64) : bool { let dq = fmt == KqFmt.k6 ? g_pf_pso_dq_k6 : (fmt == KqFmt.k4 ? g_pf_pso_dq_k4 : g_pf_pso_dq_k5) @@ -3285,9 +3069,8 @@ def private pf_devw_panel_kq(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; return true } -// the tensor-path pick: dev-W panel > tall 128-row M-tiles on the rows' 128-floor (W -// streamed M/128 times) > the 32-tile stamp for the remainder at its row offset — the -// remainder's X stride needs kdim, so kdim-less callers stay whole-dispatch 32-tile +//! kdim-less callers stay whole-dispatch 32-tile: the remainder arm needs kdim for its X stride +[arch(at="../ARCHITECTURE_GPU_PREFILL.md#prefill-gemm-ladder")] def private enc_gemm_mm_tensor(enc : MetalComputeEncoder?; bwblob : MetalBuffer?; wboff : uint64; bx, by, bk, bn : MetalBuffer?; rows, d : int64; yoff : uint64; bxh : MetalBuffer?; kdim : int64 = 0l) { if (bxh != null && g_pf_pso_hmm_th != null) { if (pf_devw_panel(enc, bwblob, wboff, bxh, by, bk, bn, rows, d, kdim, yoff)) { @@ -3296,7 +3079,6 @@ def private enc_gemm_mm_tensor(enc : MetalComputeEncoder?; bwblob : MetalBuffer? } let half_form = bxh != null && g_pf_pso_mm_th != null var r0 = 0l - // occupancy floor: an under-occupied tall grid starves the GPU (small prompts regress hard unfloored — race data in the sidecar archive) if (g_pf_env_tall && rows >= 128l && (kdim > 0l || rows % 128l == 0l) && rows / 128l * (d / 64l) >= TALL_OCC_FLOOR) { let tall = half_form ? g_pf_pso_mm_th128 : g_pf_pso_mm_t128 @@ -3321,12 +3103,11 @@ def private enc_gemm_mm_tensor(enc : MetalComputeEncoder?; bwblob : MetalBuffer? } } -// the production mul_mm dispatch: W blob bound twice (half-scale + byte views), grid (mp/32 -// token tiles, d/64 output tiles); yoff places K/V outputs past a continuation's panel rows; -// kdim/npos arm the GEMV tail; bxh = the caller-minted f16 twin (one convert per panel). +//! yoff places K/V outputs past a continuation's panel rows; kdim/npos arm the GEMV tail; +//! bxh is the caller-minted f16 twin (one convert per panel). def private enc_gemm_mm(enc : MetalComputeEncoder?; bwblob : MetalBuffer?; wboff : uint64; bx, by, bk, bn : MetalBuffer?; mp, d : int64; yoff : uint64 = 0ul; kdim : int64 = 0l; npos : int64 = 0l; bxh : MetalBuffer? = null) { let r = npos % 32l - // per-form reduction alignment: the gemv walks per-block; the b4 stripe reads whole 128-quant rounds + //! per-form reduction alignment: the gemv walks per-block; the b4 stripe reads whole 128-quant rounds let align_ok = r == 1l ? kdim % 32l == 0l : kdim % 128l == 0l if (g_pf_env_mm_tail && npos > 0l && r >= 1l && r <= MM_TAIL_MAX && align_ok && d % 8l == 0l) { let nfull = npos - r @@ -3347,14 +3128,13 @@ def private enc_gemm_mm(enc : MetalComputeEncoder?; bwblob : MetalBuffer?; wboff } } -// the E-series model_proj GEMM off the kept-bf16 blob — the crown-resolved pick; kdim feeds -// the tall/remainder split's X stride (kdim-less callers stay whole-dispatch 32-tile) +//! kdim feeds the tall/remainder split's X stride; kdim-less callers stay whole-dispatch 32-tile +[arch(at="../ARCHITECTURE_GPU_PREFILL.md#prefill-gemm-ladder")] def pf_enc_bf16_mm(enc : MetalComputeEncoder?; bw : MetalBuffer?; wboff : uint64; bx, by, bk, bn : MetalBuffer?; mp, nd : int64; bxh : MetalBuffer? = null; kdim : int64 = 0l) { if (g_pf_bf16_mm_tensor) { let half_form = bxh != null && g_pf_pso_bf16_mm_th != null var r0 = 0l - // same occupancy floor as the mul_mm/dev-W picks if (g_pf_env_tall && mp >= 128l && (kdim > 0l || mp % 128l == 0l) && mp / 128l * (nd / 64l) >= TALL_OCC_FLOOR) { let tall = half_form ? g_pf_pso_bf16_mm_th128 : g_pf_pso_bf16_mm_t128 @@ -3382,12 +3162,10 @@ def pf_enc_bf16_mm(enc : MetalComputeEncoder?; bw : MetalBuffer?; wboff : uint64 } } -// one kq weight site on the prefill mul_mm path: the format's mul_mm twin over the whole-plane -// binds (kq_quants_of / kq_scales_of — k6 binds its split scale plane twice, sub-scales at soff -// + the f16 d tail at doff). Same grid/tgmem as enc_gemm_mm; bxh = the caller-minted f16 twin. +//! k6 binds its split scale plane twice: sub-scales at soff, the f16 d tail at doff def private pf_enc_kq_site_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; woff, rows : int64; bx, by, bk, bn : MetalBuffer?; mp : int64; yoff : uint64 = 0ul; bxh : MetalBuffer? = null; kdim : int64 = 0l) { - // dev-W arm: shared all-device GEMM, per-format dequant pass, only behind the fmt's crown + //! dev-W arm: shared all-device GEMM, per-format dequant pass, only behind the fmt's crown let fmt_tensor = fmt == KqFmt.k6 ? g_pf_kq_mm6_tensor : (fmt == KqFmt.k4 ? g_pf_kq_mm4_tensor : g_pf_kq_mm5_tensor) if (fmt_tensor && bxh != null && g_pf_pso_hmm_th != null && kdim > 0l) { if (pf_devw_panel_kq(enc, t, fmt, woff, bxh, by, bk, bn, mp, rows, kdim, yoff)) { @@ -3429,8 +3207,6 @@ def private pf_enc_kq_site_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt } } -// the kq classifier GEMV (one f32 row against the [vocab x dim] kq plane) — the moved decode -// kernels' PSOs, prefill-owned twins def private pf_enc_kq_gemv(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; woff, rows, n : int64; bx : MetalBuffer?; xoff : uint64; by, bn, bd : MetalBuffer?) { let bq = kq_quants_of(g_dev, t, fmt, woff) @@ -3445,33 +3221,23 @@ def private pf_enc_kq_gemv(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; w } -// pf_enc_rms is [metal_dispatch]-generated from MetalRmsNorm (kernels-side class — the 256/tg -// prefill shape rides the same lensed class as decode's enc_rms / enc_rms_b). -// pf_enc_ple_gather is [metal_dispatch]-generated from MetalPleGatherQ8 (PLE stage 1: q8 -// token-row gather into the layer-major side panel; the dual-view q8 pair binds at eoff). -// pf_enc_ple_finish is [metal_dispatch]-generated from MetalPleFinish (PLE stage 3: rms + -// combine, in place on the panel the gather wrote). -// ===== MoE prefill encoders (Wave C stage 2b) ===== -// per-position router + select + the atomics-free CSR (count -> prefix -> bucket) for layer l +[arch(at="../ARCHITECTURE_GPU_PREFILL.md#prefill-moe-buckets")] def private pf_enc_moe_route(enc : MetalComputeEncoder?; t : Model; l : int64; bx, blg, bsel, bcnt, bbase, bbkt, binv, bdim, bne, bnk, bgm, brb, bhasb, btot, bnp : MetalBuffer?; npos : int64) { let c = t.config var bw_rt = upload_region(unsafe(addr < void? >(t.fblob[t.router_off + l * c.n_expert * c.dim])), uint64(c.n_expert * c.dim * 4l)) - enc_moe_router_b(enc, bw_rt, bx, blg, bdim, bne, bdim, brb, bhasb, bnp, c.n_expert, npos) // bxs = bdim: per-position x stride = dim - return if (g_pf_skip == "moe_only_router") // attribution: router GEMV alone, no select/CSR + enc_moe_router_b(enc, bw_rt, bx, blg, bdim, bne, bdim, brb, bhasb, bnp, c.n_expert, npos) //! bxs = bdim: per-position x stride = dim + return if (g_pf_skip == "moe_only_router") //! attribution: router GEMV alone, no select/CSR enc_moe_select(enc, blg, bsel, bsel, bne, bnk, bgm, npos) - return if (g_pf_skip == "moe_only_sel") // attribution: router + select, no CSR + return if (g_pf_skip == "moe_only_sel") //! attribution: router + select, no CSR pf_enc_moe_count(enc, bsel, bcnt, btot, bnk, c.n_expert) pf_enc_moe_bucket(enc, bsel, bbase, bbkt, binv, btot, bnk, bcnt, bne, c.n_expert) } -// the MetalMoeMulMmBase family tail: xf@3 y@4 cnt@7 basep@8 bkt@9 (kargs@5 binds at the site). -// Production rides the generated builders below; the A/B race harnesses still hand-encode -// through this, so a binding renumber desyncs loudly instead of unseen. def private kn_moe_mm_family_tail(enc : MetalComputeEncoder?; bx, by, bcnt, bbase, bbkt : MetalBuffer?) { kn_buffer(enc, bx, 0ul, 3) kn_buffer(enc, by, 0ul, 4) @@ -3480,13 +3246,10 @@ def private kn_moe_mm_family_tail(enc : MetalComputeEncoder?; bx, by, bcnt, bbas kn_buffer(enc, bbkt, 0ul, 9) } -// one gathered expert mul_mm site: grid (ceil(npos/32) tiles, rows/64, ne experts); the twin -// exits tiles past the expert's padded count. Per-format generated builders; the tensor twins -// keep their own compact binding layout (contiguous-only) so the pick swaps builders. def private pf_enc_moe_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; stack_off, rows, npos : int64; // nolint:STYLE037,STYLE038 — flat per-format twin-pick ladder, one arm per weight format bx, by, bcnt, bbase, bbkt : MetalBuffer?; var ka : MoeMmArgs; contiguous : bool = false; bxh : MetalBuffer? = null) { - return if (g_pf_skip == "moe_mm_disp") // attribution: gather+cvt kept, mm dispatches out + return if (g_pf_skip == "moe_mm_disp") //! attribution: gather+cvt kept, mm dispatches out let ne = t.config.n_expert if (fmt == KqFmt.q8) { let bw = blob_of(g_dev, t, stack_off) @@ -3506,7 +3269,7 @@ def private pf_enc_moe_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; st } } elif (fmt == KqFmt.q51) { let qp = q51_planes_of(g_dev, t, stack_off) - // the twin walks 64-deep K chunks (2 blocks/step) — an odd 32-block count stays legacy + //! the twin walks 64-deep K chunks (2 blocks/step) — an odd 32-block count stays legacy if (contiguous && (ka.kdim & 63u) == 0u && g_pf_pso_moe_mm_q51_t != null) { if (bxh != null && g_pf_pso_moe_mm_q51_th != null) { if (g_pf_env_tall && npos * int64(ka.nk) >= 128l * ne && g_pf_pso_moe_mm_q51_th128 != null && g_pf_pso_moe_mm_q51_thr != null) { @@ -3575,26 +3338,25 @@ def private pf_enc_moe_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; st } } -// mint the contiguous gather-X panel once per layer (shared by the up AND gate sites); -// null = the caller keeps the in-kernel gather form +//! mint the contiguous gather-X panel once per layer - up and gate share it; +//! null = the caller keeps the in-kernel gather form. +[arch(at="../ARCHITECTURE_GPU_PREFILL.md#prefill-moe-buckets")] def private pf_moe_gather_panel(enc : MetalComputeEncoder?; bbkt, bx : MetalBuffer?; var bmxg : MetalBuffer?; th_ok : bool; dim, nk, ne, mpad, npos : int64) : MetalBuffer? { if (!th_ok || bmxg == null || g_pf_pso_moe_gx == null) { return null } var gxka = MoeGxArgs(dim = uint(dim), nk = uint(nk), ne = uint(ne), total = uint(npos * nk)) - if (g_pf_skip != "moe_gather") { // attribution: stale panel, twin path unchanged + if (g_pf_skip != "moe_gather") { //! attribution: stale panel, twin path unchanged enc_moe_gather_x(enc, bbkt, bx, bmxg, gxka, mpad) } return bmxg } -// gemma4 router-input norm rows (weightless rms * 1/sqrt(dim) * rscale, one tg per position) -// the MXFP4 gathered expert mul_mm (gpt-oss) def private pf_enc_moe_mm_mx4(enc : MetalComputeEncoder?; t : Model; stack_off, rows, npos : int64; bx, by, bcnt, bbase, bbkt, bwb : MetalBuffer?; var ka : MoeMmArgs; contiguous : bool = false; bxh : MetalBuffer? = null) { - return if (g_pf_skip == "moe_mm_disp") // attribution: gather+cvt kept, mm dispatches out + return if (g_pf_skip == "moe_mm_disp") //! attribution: gather+cvt kept, mm dispatches out let ne = t.config.n_expert let mp = mx4_of(g_dev, t, stack_off) if (g_pf_moe_mm_mx4_tensor && contiguous && g_pf_pso_moe_mm_mx4_t != null) { @@ -3613,23 +3375,14 @@ def private pf_enc_moe_mm_mx4(enc : MetalComputeEncoder?; t : Model; stack_off, } } -// pf_enc_moe_reduce is [metal_dispatch]-generated from MetalMoeReduce (bsel binds the float -// w view — row layout in-kernel). -// enc_add_bias_rows is [metal_dispatch]-generated from MetalAddBiasRows (x binds at the panel -// offset, exact total*4 staging). Per-head QK-norm uses the kernels-side enc_qk_norm builder -// directly — the prefill twin was the same grid/tg with an x offset, now a builder param. -// enc_rope is [metal_dispatch]-generated from MetalRope (rot @default = head_size — full rope on null). -// enc_qk / enc_av / enc_rowstat are [metal_dispatch]-generated from MetalAttnQK / MetalAttnAV / -// MetalAttnRowstat (sink @default = g_one — identity on null). The mm wrappers below pick the -// Metal-4 tensor twin's generated builder (_t_c) when it compiled. -def enc_qk_mm(enc : MetalComputeEncoder?; bq, bk, batt : MetalBuffer?; var ka : AttnArgs; mp, nk64, heads : int64; bqh : MetalBuffer? = null) { // public: the tower driver dispatches the crowned trio too +def enc_qk_mm(enc : MetalComputeEncoder?; bq, bk, batt : MetalBuffer?; var ka : AttnArgs; mp, nk64, heads : int64; bqh : MetalBuffer? = null) { //! public: the tower driver dispatches the crowned trio too if (g_pf_qkmm_tensor && g_pf_pso_qkmm_t != null) { if (bqh != null && g_pf_pso_qkmm_th != null) { enc_qk_mm_th_c(enc, bqh, bk, batt, ka, mp, nk64, heads) @@ -3641,10 +3394,8 @@ def enc_qk_mm(enc : MetalComputeEncoder?; bq, bk, batt : MetalBuffer?; var ka : } } -def enc_av_mm(enc : MetalComputeEncoder?; batt, bv, bxb : MetalBuffer?; var ka : AttnArgs; bstat : MetalBuffer?; mp, heads, head_size : int64) { // public: the tower driver dispatches the crowned trio too - // the PADFREE (clean-PSO) pick needs the whole WALK inside live rows, not just npos - // divisibility: a padded query chunk (qoff + qrows > npos) walks pad-query tiles past npos, - // where a real row's 0 * stale-NaN V read poisons the tile — the checked stamp's guard +[arch(at="../ARCHITECTURE_GPU_PREFILL.md#prefill-attn-slab")] +def enc_av_mm(enc : MetalComputeEncoder?; batt, bv, bxb : MetalBuffer?; var ka : AttnArgs; bstat : MetalBuffer?; mp, heads, head_size : int64) { //! public: the tower driver dispatches the crowned trio too let walk_live = ka.qoff + ka.qrows == ka.npos if (g_pf_avmm_tensor && g_pf_pso_avmm_t != null) { if (walk_live && ka.npos % 64u == 0u && g_pf_pso_avmm_tp != null) { @@ -3659,26 +3410,15 @@ def enc_av_mm(enc : MetalComputeEncoder?; batt, bv, bxb : MetalBuffer?; var ka : } } -// swiglu and add share the (a, b, total) elementwise shape -// ===== deltanet prefill encoders (Wave D) — the prefill-local twins of the decode-side set ===== -// hist/state bind the per-session DnMirror arena at the layer's byte offset; the rest is window scratch. -// pf_enc_dn_ba is [metal_dispatch]-generated from MetalDnBa (kernels-side class — the dual-view -// q8 blob pair binds at boff, y span d*np*4 exact). -// batched f32-slab GEMV riding MetalMoeRouterB's generated builder: d rows per position -// (dn_ba_f32 β/α d = dt_rank; the shexp gate d = 1); y[p*d + row] — the pf_enc_dn_ba layout. -// The thin wrapper carries the dummy binds (rb = g_one dead, hasb = g_zero) per the lens doctrine. +//! Batched f32-slab GEMV on MetalMoeRouterB's builder: d rows per position, y[p*d + row]. def private pf_enc_slab_gemv_b(enc : MetalComputeEncoder?; bw, bx, by, bn, bd, bnp : MetalBuffer?; d, npos : int64) { - enc_moe_router_b(enc, bw, bx, by, bn, bd, bn, g_one, g_zero, bnp, d, npos) // bxs = bn: per-position x stride = dim + enc_moe_router_b(enc, bw, bx, by, bn, bd, bn, g_one, g_zero, bnp, d, npos) //! bxs = bn: per-position x stride = dim } -// pf_enc_swiglu_oai is [metal_dispatch]-generated from MetalSwigluOaiPf (float4-lane swiglu_oai); -// its total/256 grid == the hand (total/4 + 63)/64 under the callers' total % 4 == 0 contract — -// off-contract the ceil form is the larger side, and the kernel guards gid * 4 >= total. -// GPU-PLE gate (register_ple_gpu_gate): true iff THIS window's metal prefill will engage AND -// the pre-step kernels cover the model — q8 emb table, kept-bf16 model_proj, slice/shape gates. +//! true iff THIS window's metal prefill will engage AND the pre-step kernels cover the model [unused_argument(s, start_pos)] def private metal_ple_pre_gpu_gate(t : Model; s : Session; npos, start_pos : int64) : bool { if (active_prefill_override() != "metal" || @@ -3686,7 +3426,6 @@ def private metal_ple_pre_gpu_gate(t : Model; s : Session; npos, start_pos : int return false } let ple = t.config.n_embd_per_layer - // CAPABILITY only — the rope-rows leg would answer "not yet" every time at this point if (ple % 32l != 0l || ple > 1024l || (t.config.n_layers * ple) % 64l != 0l || prefill_decline_caps(t, npos) != MetalPrefillDecline.none) { return false @@ -3694,14 +3433,14 @@ def private metal_ple_pre_gpu_gate(t : Model; s : Session; npos, start_pos : int return metal_prefill_init() } -[hot_path] +[hot_path, arch(at="../ARCHITECTURE_GPU_PREFILL.md#prefill-pad-rows-and-coop"), arch(at="../ARCHITECTURE_GPU_PREFILL.md#prefill-chunked-submit")] def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : bool { // nolint:STYLE037,STYLE038 — the prefill step driver; the layer stack's phases are hz-barrier coupled var why = prefill_decline(t, s, npos, start_pos) if (why == MetalPrefillDecline.none && !metal_prefill_init()) { why = MetalPrefillDecline.device } if (why != MetalPrefillDecline.none) { - if (s.ple_gpu_pending) { // the gate promised a device pre-step — build it on CPU first + if (s.ple_gpu_pending) { //! the gate promised a device pre-step — build it on CPU first ple_pre_prefill(t, s, s.ple_gpu_tokens, npos) s.ple_gpu_pending = false } @@ -3712,7 +3451,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } return false } - residency_flush() // pin/commit before the first submission (the post-CPU-window slack) + residency_flush() //! pin/commit before the first submission (the post-CPU-window slack) let ts_all = ref_time_ticks() let c = t.config let dim = c.dim @@ -3721,13 +3460,12 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : let qd = n_heads * head_size let kv_dim = c.n_kv_heads * head_size let hidden = layer_hidden(t, 0l) - let hid2 = ffn_second_hidden(t) // decline guarantees 0 (uniform) or the one other width + let hid2 = ffn_second_hidden(t) //! decline guarantees 0 (uniform) or the one other width let hid_mx = max(hidden, hid2) let kv_mul = uint(n_heads / c.n_kv_heads) let scale = c.attn_scale > 0.0 ? c.attn_scale : 1.0 / sqrt(float(head_size)) - let half = (c.rope_dim > 0l ? c.rope_dim : head_size) / 2l // partial rope: table rows are rope_dim/2 wide - // deltanet (Wave D): the recurrent-state mirror must be resident/synced BEFORE encoding — - // prepare zeroes at pos 0 or syncs a CPU prefix; a cold mid-stream window has no repair path + let half = (c.rope_dim > 0l ? c.rope_dim : head_size) / 2l //! partial rope: table rows are rope_dim/2 wide + //! the recurrent-state mirror syncs BEFORE encoding - a cold mid-stream window has no repair path let dn = c.recr_mask != 0ul var bdn_state : MetalBuffer? var dn_state_base = 0ul @@ -3742,9 +3480,6 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : dn_state_base = dm.state_off dn_conv_base = dm.conv_off } - // the two-class attention geometry (gemma4): the config fields describe the GLOBAL class, - // the _sw twins the SLIDING class (the loader guarantees at most two) — buffers size to the - // class maxima and each layer binds its class's uniform set let hs_sw = c.head_size_swa > 0l ? c.head_size_swa : head_size let kvh_sw = c.n_kv_heads_swa > 0l ? c.n_kv_heads_swa : c.n_kv_heads let qd_sw = n_heads * hs_sw @@ -3752,37 +3487,26 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : let hetero = hs_sw != head_size || kvh_sw != c.n_kv_heads let qd_mx = max(qd, qd_sw) let half_sw = hs_sw / 2l - let mp = ((npos + 31l) / 32l) * 32l // every kernel's M grid is mp/32 (weight mul_mm, kq twins, the attention trio) — a 64 pad billed a dead 32-row GEMM block on every short prefill - // a continuation chunk (M2.5) attends the session's existing rows too: the K/V panels hold - // [0, start_pos) gathered rows + the chunk at the start_pos offset, keys pad to the QK key - // grid's 64-tile, and the score slabs widen to nk64 columns (rows stay the mp queries) + let mp = ((npos + 31l) / 32l) * 32l let nk = start_pos + npos let nk64 = ((nk + 63l) / 64l) * 64l - // the K/V GEMMs write mp FULL M-tile rows at the start_pos row offset — a continuation's - // panel must hold [0, start_pos + mp) rows or the pad rows write PAST the pool buffer - // (silent neighbor corruption; whether it bites depends on pool layout) let kvrows = max(nk64, start_pos + mp) - // pooled per-prefill buffers (activations sized mp rows — the GEMM has no edge masking; rows - // past npos are never read by the norm/rope/attention/elementwise kernels, and stale bytes in - // the requant image only ever land in pad output rows: C-block rows are independent) let bytes_x = uint64(mp * dim * 4l) - let bytes_xb = uint64(mp * max(dim, qd_mx) * 4l) // dim-wide norm outs AND the qd-wide AV out + let bytes_xb = uint64(mp * max(dim, qd_mx) * 4l) //! dim-wide norm outs AND the qd-wide AV out let bytes_q = uint64(mp * qd_mx * 4l) - let nsh = !t.blocks.ffn_is_dense ? c.n_ff_shexp : 0l // shared expert (qwen35moe) rides bhb/bhb2 + let nsh = !t.blocks.ffn_is_dense ? c.n_ff_shexp : 0l //! shared expert (qwen35moe) rides bhb/bhb2 let bytes_h = uint64(mp * max(hid_mx, nsh) * 4l) - let bytes_att = uint64(n_heads * mp * nk64 * 2l) // per-head f16 score slabs: mp queries x nk64 keys - let bytes_stat = uint64(n_heads * mp * 2l * 4l) // per-row softmax stats: rowmax + 1/sum + let bytes_att = uint64(n_heads * mp * nk64 * 2l) //! per-head f16 score slabs: mp queries x nk64 keys + let bytes_stat = uint64(n_heads * mp * 2l * 4l) //! per-row softmax stats: rowmax + 1/sum let bytes_tab = uint64(npos * half * 4l) - let bytes_tab_sw = uint64(npos * half_sw * 4l) // the swa pair's row width is ITS class's hs/2 + let bytes_tab_sw = uint64(npos * half_sw * 4l) //! the swa pair's row width is ITS class's hs/2 var bx = pool_acquire_pinned(g_pf_pool, g_dev, bytes_x) var bxb = pool_acquire_pinned(g_pf_pool, g_dev, bytes_xb) var bxb2 = pool_acquire_pinned(g_pf_pool, g_dev, bytes_x) var bq = pool_acquire_pinned(g_pf_pool, g_dev, bytes_q) var bhb = pool_acquire_pinned(g_pf_pool, g_dev, bytes_h) var bhb2 = pool_acquire_pinned(g_pf_pool, g_dev, bytes_h) - // MoE (Wave C stage 2b): per-position routing + padded bucket panels (32-row tiles/expert); - // g4moe adds the router-input/acc panel (bxb2 doubles as the pre_ffn2 expert input — the - // serial encoder makes the reuse safe) + //! bxb2 doubles as g4moe's pre_ffn2 expert input - the serial encoder makes the reuse safe let moe = !t.blocks.ffn_is_dense let g4moe = moe && c.moe_dense_shexp let mtot = moe ? npos * c.n_expert_used : 0l @@ -3803,15 +3527,14 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : var bmg = moe ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_mg) : null var bmg2 = moe ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_mg) : null var bmdn = moe ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_mdn) : null - // acquire only when a contiguous twin can consume it — the gather sites' own th_ok - // predicate; without a crowned _th twin the panel would sit wired and untouched + //! acquire only when a contiguous twin can consume it - without a crowned _th twin the panel + //! would sit wired and untouched let mxg_th = (g_pf_pso_moe_mm_mx4_th != null || g_pf_pso_moe_mm_q8_th != null || g_pf_pso_moe_mm_k4_th != null || g_pf_pso_moe_mm_k5_th != null || g_pf_pso_moe_mm_k6_th != null) let want_mxg = moe && g_pf_pso_moe_gx != null && npos >= 256l && mxg_th let bytes_mxg = uint64(mpad * dim * 2l) var bmxg = want_mxg ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_mxg) : null var bmg4rt = g4moe ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_x) : null - // deltanet scratch (recurrent layers) — GEMM outputs pad to mp rows like every panel let cd_dn = dn ? dn_conv_dim(c) : 0l let di_dn = dn ? c.ssm_d_inner : 0l let nvh_dn = dn ? c.ssm_dt_rank : 0l @@ -3828,24 +3551,17 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : var bdnqg = c.q_gated ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_dn_qg) : null var bdngate = c.q_gated ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_q) : null var batt = pool_acquire_pinned(g_pf_pool, g_dev, bytes_att) - // rowstat writes [0, npos) only; rows [npos, mp) stay recycled-pool bytes, and AV pad C - // rows computed from them are read ONLY as row-confined A operands downstream — no pad AV - // row may ever become a matmul B operand (V pad rows stage as 0 for the same reason) var bstats = pool_acquire_pinned(g_pf_pool, g_dev, bytes_stat) - // deepstack (qwen3vl dense): the wide quantum's tail slices upload as PER-SLICE contiguous - // planes so the per-layer add is the existing enc_add at a slice offset — a repack, no kernel let nds = s.ds_active ? c.n_deepstack : 0l - // the wide borrow: upload the caller's quantum whole and slice it on-device (bds turns - // GPU-written, so it must ride the TRACKED pool); the CPU-split arm survives for the - // warm/MTP edge, which reads x_b host-side - let wide = nds > 0l // a ds quantum always arrives as the wide borrow (forward_prefill_embd arms it with ds_active) + //! bds is GPU-written by the on-device slice, so it rides the TRACKED pool + let wide = nds > 0l //! a ds quantum always arrives as the wide borrow (forward_prefill_embd arms it with ds_active) if (wide && s.wide_src == null) { panic("metal_prefill_forward: ds_active with no wide borrow - forward_prefill_embd's contract broke") } let wide_stride = s.wide_stride let bytes_ds = uint64(npos * nds * dim * 4l) let bytes_wide = uint64(npos * wide_stride * 4l) - var bds = wide ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_ds) : null // GPU-written by the extract - the TRACKED pool + var bds = wide ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_ds) : null var bwide = wide ? pool_acquire_untracked_pinned(g_pf_upool, g_dev, bytes_wide) : null var bcos = pool_acquire_untracked_pinned(g_pf_upool, g_dev, bytes_tab) var bsin = pool_acquire_untracked_pinned(g_pf_upool, g_dev, bytes_tab) @@ -3858,31 +3574,31 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : bvs |> clear() bks |> reserve(c.n_layers + c.n_layer_nextn) bvs |> reserve(c.n_layers + c.n_layer_nextn) - var no_panel : MetalBuffer? // recurrent layers' null K/V slot + var null_kv_panel : MetalBuffer? for (l in range64(c.n_layers + c.n_layer_nextn)) { - if (layer_kv_dim(c, l) == 0l) { // recurrent layer (deltanet): no K/V at all - bks |> push(no_panel) - bvs |> push(no_panel) + if (layer_kv_dim(c, l) == 0l) { //! recurrent layer (deltanet): no K/V at all + bks |> push(null_kv_panel) + bvs |> push(null_kv_panel) continue } - if (kv_shared_layer(t, l)) { // E-series: alias the source layer's panels (same class geometry) + if (kv_shared_layer(t, l)) { //! E-series: alias the source layer's panels (same class geometry) bks |> push(bks[t.kv_src[l]]) bvs |> push(bvs[t.kv_src[l]]) continue } - let bytes_kv_l = uint64(kvrows * layer_kv_dim(c, l) * 4l) // per-layer panels: each class's width + let bytes_kv_l = uint64(kvrows * layer_kv_dim(c, l) * 4l) //! per-layer panels: each class's width bks |> push(pool_acquire_pinned(g_pf_pool, g_dev, bytes_kv_l)) bvs |> push(pool_acquire_pinned(g_pf_pool, g_dev, bytes_kv_l)) } - // E-series PLE: side input uploaded LAYER-major ([l][p][ple] — the flat geglu ⊙ reads layer l's - // block at one offset); gate outputs pad to mp rows like every GEMM panel + //! the PLE side input uploads LAYER-major ([l][p][ple]) so the flat geglu reads layer l's + //! block at one offset let plef = has_ple(c) let ple_n = c.n_embd_per_layer let ple_all = c.n_layers * ple_n let bytes_ple_side = uint64(c.n_layers * npos * ple_n * 4l) let bytes_ple_g = uint64(mp * ple_n * 4l) let bytes_ple_proj = uint64(mp * ple_all * 4l) - let ple_gpu = plef && s.ple_gpu_pending // the gate stashed tokens — build the side input on device + let ple_gpu = plef && s.ple_gpu_pending //! the gate stashed tokens — build the side input on device var bple : MetalBuffer? var bpleg : MetalBuffer? var bple_proj : MetalBuffer? @@ -3902,7 +3618,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } else { bple = pool_acquire_untracked_pinned(g_pf_upool, g_dev, bytes_ple_side) unsafe { - // transpose s.ple_inp (position-major, p*all + l*ple) into layer-major blocks + //! transpose s.ple_inp (position-major, p*all + l*ple) into layer-major blocks var dst = reinterpret(metal_buffer_contents(bple)) let src = addr < float const? >(s.ple_inp[0]) for (l in range64(c.n_layers)) { @@ -3914,21 +3630,19 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } } - // the half-X activation panel: one f16 scratch covering the largest A panel any mul_mm - // site converts (xb/hb/the 2*dim MTP cat/deltanet/PLE inputs) + //! one f16 scratch covering the largest A panel any mul_mm site converts let bytes_xh = max(max(max(bytes_xb, bytes_h), uint64(mp * 2l * dim * 4l)), max(max(bytes_dn_di, bytes_ple_g), moe ? bytes_mg : 0ul)) / 2ul let any_th = (g_pf_pso_mm_th != null || g_pf_pso_kq_mm4_th != null || g_pf_pso_kq_mm5_th != null || g_pf_pso_kq_mm6_th != null || g_pf_pso_bf16_mm_th != null - || g_pf_pso_moe_mm_q8_th != null || g_pf_pso_moe_mm_mx4_th != null) // the MoE down-site cvt consumes the panel too + || g_pf_pso_moe_mm_q8_th != null || g_pf_pso_moe_mm_mx4_th != null) //! the MoE down-site cvt consumes the panel too let want_xh = any_th g_pf_bxh = want_xh ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_xh) : null g_pf_bxh2 = want_xh ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_xh) : null g_pf_bxh_flip = false g_pf_bxh_bytes = want_xh ? bytes_xh : 0ul - // the dev-W f16 panels: the largest layer-site N x K dequant output, capped at the big- - // panel ceiling (over-knee sites run as N-column TILES each under it; the vocab - // classifier fails the fit and keeps the tg twin) + //! the largest layer-site N x K dequant output, capped at the big-panel ceiling: over-knee + //! sites run as N-column TILES each under it, and the vocab classifier keeps the tg twin let bytes_wh = min(uint64(2l * max(dim, qd_mx) * max(hid_mx, max(nsh, max(2l * dim, di_dn)))), DEVW_BIG_PANEL) let want_wh = (g_pf_env_dev_w && g_pf_pso_hmm_th != null && (g_pf_pso_dq_q8 != null || g_pf_pso_dq_k4 != null || g_pf_pso_dq_k5 != null || g_pf_pso_dq_k6 != null)) @@ -3936,10 +3650,9 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : g_pf_bwh2 = want_wh ? pool_acquire_pinned(g_pf_pool, g_dev, bytes_wh) : null g_pf_bwh_flip = false g_pf_bwh_bytes = want_wh ? bytes_wh : 0ul - // upload the embedded rows + this prefill's rope table(s) (built for the chunk's GLOBAL - // positions — build_rope_table takes start_pos; dual-rope: the sliding class's pair too) + //! rope tables are built for the chunk's GLOBAL positions (build_rope_table takes start_pos) unsafe { - if (wide) { // ONE wide upload; bx and the bds slices extract on-device at encode time + if (wide) { //! ONE wide upload; bx and the bds slices extract on-device at encode time memcpy(metal_buffer_contents(bwide), reinterpret(s.wide_src + s.wide_soff * wide_stride), npos * wide_stride * 4l) } else { memcpy(metal_buffer_contents(bx), addr < void? >(s.x_b[0]), npos * dim * 4l) @@ -3951,16 +3664,14 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : memcpy(metal_buffer_contents(bsin_swa), addr < void? >(s.rope_sin_swa[0]), npos * half_sw * 4l) } } - // continuation: gather the session's existing rows [0, start_pos) into every layer's panel - // head as f32 (paged sessions gather through kv_runs; tq4 rows dequant ROTATED and un-rotate - // per head — GPU attention runs in the raw basis). K rows are stored ROPED, so no re-rope. + //! tq4 rows dequant ROTATED and un-rotate per head - GPU attention runs in the raw basis; + //! K rows are stored ROPED, so no re-rope. if (start_pos > 0l) { unsafe { let gather_nrun = kv_runs(s, 0l, start_pos, s.kv_runs) let runsg = addr < KVRun const? >(s.kv_runs[0]) let sgp = (s.kv_dtype_k == KVDtype.tq4 || s.kv_dtype_v == KVDtype.tq4) ? addr < float const? >(s.kv_signs[0]) : null for (l in range64(c.n_layers + c.n_layer_nextn)) { - // recurrent: no rows; shared (E-series): aliased panel — the source's gather covers it continue if (bks[l] == null || kv_shared_layer(t, l)) var kdst = reinterpret(metal_buffer_contents(bks[l])) var vdst = reinterpret(metal_buffer_contents(bvs[l])) @@ -3982,7 +3693,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } } - // layer-invariant uniforms (weight offsets ride the region cache, so nothing varies per layer) + //! layer-invariant uniforms (weight offsets ride the region cache, so nothing varies per layer) var u_dim = uniform_u32(uint(dim)) var u_qd = uniform_u32(uint(qd)) var u_kvd = uniform_u32(uint(kv_dim)) @@ -4011,12 +3722,10 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : var u_moe_ptot = moe ? uniform_u32(uint(mpad * c.n_ff_exp)) : null var u_moe_invd = g4moe ? uniform_f32(1.0 / sqrt(float(dim))) : null var u_moe_gmode = moe ? uniform_u32(c.moe_gate == MoeGate.softmax_weight ? 1u : (c.norm_topk_prob ? 0u : 2u)) : null - // shared expert (qwen35moe): nsh width + npos*nsh act span + the gate GEMV's 1-row bound var u_moe_nsh = nsh > 0l ? uniform_u32(uint(nsh)) : null var u_moe_shtot = nsh > 0l ? uniform_u32(uint(npos * nsh)) : null var u_moe_one = nsh > 0l ? uniform_u32(1u) : null var u_eps = uniform_f32(c.norm_eps) - // deltanet + gated-attention uniforms (Wave D) var u_dn_cd = dn ? uniform_u32(uint(cd_dn)) : null var u_dn_di = dn ? uniform_u32(uint(di_dn)) : null var u_dn_nvh = dn ? uniform_u32(uint(nvh_dn)) : null @@ -4024,28 +3733,23 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : var u_dn_qd2 = c.q_gated ? uniform_u32(uint(2l * qd)) : null var u_qtot = c.q_gated ? uniform_u32(uint(npos * qd)) : null var u_rot = (c.rope_dim > 0l && c.rope_dim != head_size) ? uniform_u32(uint(c.rope_dim)) : null - // E-series PLE: gate/proj widths + the per-layer geglu ⊙ span var u_ple = plef ? uniform_u32(uint(ple_n)) : null var u_ple_tot = plef ? uniform_u32(uint(npos * ple_n)) : null var u_ple_all = ple_gpu ? uniform_u32(uint(ple_all)) : null - // the SLIDING-class uniform twins (hetero models — uniform models leave these null and - // every layer binds the base set) + //! hetero-only sliding-class uniform twins; uniform models leave these null and bind the base set var u_qd_sw = hetero ? uniform_u32(uint(qd_sw)) : null var u_kvd_sw = hetero ? uniform_u32(uint(kvd_sw)) : null var u_hs_sw = hetero ? uniform_u32(uint(hs_sw)) : null var u_npairs_q_sw = hetero ? uniform_u32(uint(npos * qd_sw / 2l)) : null var u_npairs_k_sw = hetero ? uniform_u32(uint(npos * kvd_sw / 2l)) : null - // the V-from-K panel copy's grid guards (npos rows of the class's kv width) var u_vtot = vfromk ? uniform_u32(uint(npos * kv_dim)) : null var u_vtot_sw = (vfromk && hetero) ? uniform_u32(uint(npos * kvd_sw)) : null - // logits-on-GPU (default ON, DASLLAMA_METAL_LOGITS=0 pins the CPU classifier): last-position - // rmsnorm + classifier GEMV ride the last command buffer (prefill_override_logits_done skips - // the CPU final step); q8 classifiers only, softcap + suppress ride epilogue kernels + //! prefill_override_logits_done skips the CPU final step; q8 classifiers only, with softcap + //! and suppress on epilogue kernels let cls_fmt = c.shared_weights ? t.emb_fmt : t.wcls_fmt let tied_f32 = c.shared_weights && !t.cls_q8 && cls_fmt == KqFmt.q8 - // knockout mode keeps gpu logits: constant across skip configs (deltas stay clean), and a - // blob-only metal-flavor load HAS no CPU classifier to fall back to. NextN models serve - // too — the readback stashes mtp_h from bxf (forward_prefill's handoff contract) + //! GPU logits stay on under the knockout rail (deltas stay clean), and a blob-only + //! metal-flavor load has no CPU classifier to fall back to let gpu_logits = (!g_pf_logits_cpu && g_pf_env_logits && !tied_f32 && t.wcls_off >= 0l) @@ -4053,7 +3757,6 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : var blog = gpu_logits ? pool_acquire_pinned(g_pf_pool, g_dev, uint64(c.vocab_size * 4l)) : null var u_vocab = gpu_logits ? uniform_u32(uint(c.vocab_size)) : null var u_flcap = (gpu_logits && c.final_logit_softcap > 0.0) ? uniform_f32(c.final_logit_softcap) : null - // suppressed token ids pin to -1e30 AFTER the cap (gemma4) — the CPU classifier's order let nsupp = long_length(t.suppress) var bsupp : MetalBuffer? var u_nsupp : MetalBuffer? @@ -4067,16 +3770,15 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } u_nsupp = uniform_u32(uint(nsupp)) } - // MTP draft-slab warm (spec on): ONE extra loop iteration runs the draft block at FULL - // npos so every trunk uniform reuses verbatim — the last warm row is garbage by design - // (needs the unknown next token), causally unread, rewritten by the next draft/seam + //! MTP draft-slab warm: ONE extra loop iteration runs the draft block at FULL npos so every + //! trunk uniform reuses verbatim; the last warm row is garbage by design and causally unread let warm = (get_mtp_spec() && c.n_layer_nextn == 1l && gpu_logits && t.mtp_ehproj_off >= 0l && (dim % 64l) == 0l) let n_enc_layers = c.n_layers + (warm ? 1l : 0l) - var bwm_res : MetalBuffer? // warm: trunk residual save (x_b readback + the cls tail read it) - var bwm_emb : MetalBuffer? // warm: shifted embed rows - var bwm_cat : MetalBuffer? // warm: [mp x 2dim] eh_proj input - var bwm_tmp : MetalBuffer? // warm: rms_final intermediate + var bwm_res : MetalBuffer? //!< warm: trunk residual save (x_b readback + the cls tail read it) + var bwm_emb : MetalBuffer? //!< warm: shifted embed rows + var bwm_cat : MetalBuffer? //!< warm: [mp x 2dim] eh_proj input + var bwm_tmp : MetalBuffer? //!< warm: rms_final intermediate var u_dim2 : MetalBuffer? var u_wm_tot : MetalBuffer? if (warm) { @@ -4086,43 +3788,34 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : bwm_tmp = pool_acquire_pinned(g_pf_pool, g_dev, uint64(npos * dim * 4l)) u_dim2 = uniform_u32(uint(2l * dim)) u_wm_tot = uniform_u32(uint(npos * dim)) - if (wide) { // this edge reads x_b host-side - split the borrow first + if (wide) { //! this edge reads x_b host-side - split the borrow first ds_split_quantum(t, s, npos) } - // shifted embeds: row p pairs the NEXT position's embed with hidden p — s.x_b still - // holds the window's embed panel here; the garbage last row reuses row 0 + //! shifted embeds: row p pairs the NEXT position's embed with hidden p; the garbage last row reuses row 0 unsafe { var dst = reinterpret(metal_buffer_contents(bwm_emb)) memcpy(reinterpret(dst), addr < void? >(s.x_b[dim]), (npos - 1l) * dim * 4l) memcpy(reinterpret(dst + (npos - 1l) * dim * 4l), addr < void? >(s.x_b[0]), dim * 4l) } } - // the tiled QK/AV pair (default): ~10x the old trio GEMMs' rate; needs hs % 64 (the AV grid; - // BOTH classes); queries pad to mp % 32 and keys to nk64 % 64 — both true by construction. - // DASLLAMA_METAL_ATTN=0 pins the trio. + //! the tiled QK/AV pair needs hs % 64 on BOTH classes; DASLLAMA_METAL_ATTN=0 pins the trio let mmattn = (head_size % 64l) == 0l && (hs_sw % 64l) == 0l && g_pf_env_attn let ts_enc = ref_time_ticks() let setup_us = get_time_usec(ts_all) var err : string var gpu_ms : double var encode_ms : double - // command-buffer split (DASLLAMA_METAL_NCB chunks): each chunk commits as soon as encoded, so - // the scheduler analyzes chunk k while chunk k-1 executes. DASLLAMA_METAL_UNRETAINED=1 skips - // per-dispatch retain/release too. Default ~4 layers/chunk (3B: slack 57ms -> 9ms, +10% pp512). let ncb = clamp(int64(g_pf_env_ncb > 0 ? g_pf_env_ncb : int((n_enc_layers + 3l) / 4l)), 1l, n_enc_layers) let unret = g_pf_env_unretained let layers_per_cb = (n_enc_layers + ncb - 1l) / ncb - // the capture rail: kn_* record each chunk as a step graph, graph_flush_sched replays on a - // CONCURRENT encoder (auto-schedule + hz barriers at real hazards). DASLLAMA_METAL_SCHED=0 - // keeps capture order; DASLLAMA_METAL_PF_CAPTURE=0 = the direct serial-encode rollback. let cap = g_pf_env_capture var cbs & = unsafe(g_pf_cbs) - residency_flush() // commit THIS eval's own notes before its first submission + residency_flush() //! commit THIS eval's own notes before its first submission cbs |> clear() cbs |> reserve(ncb) var cb : MetalCommandBuffer? var enc : MetalComputeEncoder? - var dnli = 0l // recurrent-layer index — addresses the dn state/conv mirror slices in order + var dnli = 0l //! recurrent-layer index — addresses the dn state/conv mirror slices in order { for (l in range64(n_enc_layers)) { if (l % layers_per_cb == 0l) { @@ -4141,15 +3834,14 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : gr_arm(true) } } - if (l == 0l && wide) { // slice the wide quantum on-device: x, then the slice-major ds planes + if (l == 0l && wide) { //! slice the wide quantum on-device: x, then the slice-major ds planes enc_head_restride(enc, bwide, 0ul, bx, 0ul, u_wide_rw, u_wide_dim, u_total_dim, npos * dim) for (sl in range64(nds)) { enc_head_restride(enc, bwide, uint64((sl + 1l) * dim * 4l), bds, uint64(sl * npos * dim * 4l), u_wide_rw, u_wide_dim, u_total_dim, npos * dim) } } if (l == 0l && ple_gpu) { - // PLE pre-step on device (the serial encoder orders the three stages): q8 token-row - // gather (layer-major, sqrt(ple) folded) -> bf16 model_proj GEMM off bx -> rms+combine + //! the serial encoder orders the three PLE stages: gather -> model_proj GEMM -> rms+combine unsafe { var pka = ple_ka(npos, ple_n, c.n_layers, dim, c.norm_eps) let bemb = blob_of(g_dev, t, t.ple_emb_off) @@ -4162,9 +3854,8 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : s.ple_gpu_pending = false } if (warm && l == c.n_layers) { - // trunk done — save the residual panel (x_b readback + cls read it), then swap - // bx to the draft block's eh_proj input; the body below runs the draft layer - // verbatim (same uniforms, npos rows, K/V panel + weight arrays at index l) + //! trunk done - save the residual panel (x_b readback + cls read it), then swap bx to the + //! draft block's eh_proj input; the body below runs the draft layer verbatim at index l unsafe { enc_copy_row(enc, bx, 0ul, bwm_res, 0ul, u_wm_tot, npos * dim) var bw_en = upload_region(addr < void? >(t.fblob[t.mtp_enorm_off]), uint64(dim * 4l)) @@ -4186,8 +3877,6 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : unsafe { var bw_att = upload_region(addr < void? >(t.fblob[t.rms_att_off + l * dim]), uint64(dim * 4l)) var bw_ffn = upload_region(addr < void? >(t.fblob[t.rms_ffn_off + l * dim]), uint64(dim * 4l)) - // sliding layers on hetero models (gemma4) swap the whole class geometry — - // sizes, GEMM grids, uniform binds; uniform models bind the base set everywhere let lsl = layer_is_sliding(c, l) let het = hetero && lsl let hs_l = het ? hs_sw : head_size @@ -4201,11 +3890,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : var u_npairs_k_l = het ? u_npairs_k_sw : u_npairs_k let has_wv = t.wv_offs[l] >= 0l let recr = layer_is_recurrent(c, l) - // E-series shared-KV layer: Q-only — bks[l]/bvs[l] alias the source's panels let kvsh = kv_shared_layer(t, l) - // attention: [pending W2 residual +] norm -> [requant ->] Q/K/V -> rope -> - // scores+softmax -> P.V -> out-proj (fused path folds each residual add into the - // FOLLOWING add+rms+quant; the default path feeds normed f32 rows straight to mul_mm) var bxh_x : MetalBuffer? if (g_pf_skip != "ew" && g_pf_skip != "nongemm") { bxh_x = g_pso_rms_hx != null ? pf_twin_panel(mp, dim) : null @@ -4216,8 +3901,6 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } if (recr) { - // deltanet layer (Wave D): batched projections -> conv+SiLU -> q/k L2 -> fused - // sequential scan (state walks the whole window in-kernel) -> gated out-norm -> out-proj if (g_pf_skip != "gemm") { if (bxh_x == null) { bxh_x = pf_cvt_panel(enc, bxb, mp, dim) @@ -4227,7 +3910,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : let bwz = blob_of(g_dev, t, t.dngate_offs[l]) enc_gemm_mm(enc, bwz.buf, bwz.boff, bxb, bdnz, u_dim, u_dn_di, mp, di_dn, 0ul, dim, npos, bxh_x) if (t.dn_ba_f32) { - // F32-on-disk β/α (35B): fblob slabs ride the router-b f32 GEMV + //! F32-on-disk β/α (35B): fblob slabs ride the router-b f32 GEMV var bw_bt = upload_region(addr < void? >(t.fblob[t.dn_betaf_off + l * dim * nvh_dn]), uint64(dim * nvh_dn * 4l)) pf_enc_slab_gemv_b(enc, bw_bt, bxb, bdnb, u_dim, u_dn_nvh, u_dn_np, nvh_dn, npos) var bw_al = upload_region(addr < void? >(t.fblob[t.dn_alphaf_off + l * dim * nvh_dn]), uint64(dim * nvh_dn * 4l)) @@ -4261,8 +3944,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : dnli++ } if (!recr && g_pf_skip != "gemm") { - // K-quant tensors take their mul_mm twins per tensor (the gate pins the - // mm shape for kquant loads); q8-tagged tensors keep the blob path + //! K-quant tensors take their mul_mm twins per tensor; q8-tagged tensors keep the blob path if (bxh_x == null) { bxh_x = pf_cvt_panel(enc, bxb, mp, dim) } @@ -4271,7 +3953,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : let fv = has_wv ? fmt_at(t.wv_fmt, l) : KqFmt.q8 if (fq != KqFmt.q8 || fk != KqFmt.q8 || fv != KqFmt.q8) { if (c.q_gated) { - // 2x-wide packed [q|gate] projection, deinterleaved into the q panel + gate rows + //! 2x-wide packed [q|gate] projection, deinterleaved into the q panel + gate rows if (fq != KqFmt.q8) { pf_enc_kq_site_mm(enc, t, fq, t.wq_offs[l], 2l * qd_l, bxb, bdnqg, u_dim, u_dn_qd2, mp, 0ul, bxh_x, dim) } else { @@ -4305,14 +3987,14 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } else { let bwqb = blob_of(g_dev, t, t.wq_offs[l]) if (c.q_gated) { - // 2x-wide packed [q|gate] projection, deinterleaved into the q panel + gate rows + //! 2x-wide packed [q|gate] projection, deinterleaved into the q panel + gate rows enc_gemm_mm(enc, bwqb.buf, bwqb.boff, bxb, bdnqg, u_dim, u_dn_qd2, mp, 2l * qd_l, 0ul, dim, npos, bxh_x) enc_dn_deint(enc, bdnqg, bq, bdngate, DnDeintArgs(hs = uint(hs_l), qd = uint(qd_l), qs = uint(qd_l)), qd_l, npos) } else { enc_gemm_mm(enc, bwqb.buf, bwqb.boff, bxb, bq, u_dim, u_qd_l, mp, qd_l, 0ul, dim, npos, bxh_x) } - if (!kvsh) { // shared layers have no K/V tensors (offs -1) + if (!kvsh) { //! shared layers have no K/V tensors (offs -1) let bwkb = blob_of(g_dev, t, t.wk_offs[l]) enc_gemm_mm(enc, bwkb.buf, bwkb.boff, bxb, bks[l], u_dim, u_kvd_l, mp, kvd_l, koff, dim, npos, bxh_x) if (has_wv) { @@ -4323,15 +4005,13 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } if (!recr && !kvsh && (!has_wv || c.v_norm) && g_pf_skip != "ew" && g_pf_skip != "nongemm") { - // gemma4 V: no-wv layers copy the PRE-norm/PRE-rope K panel rows into the V - // panel; v_norm then runs the weightless per-head RMS (ones plane) in place — - // the CPU mm_qkv order exactly, BEFORE qk_norm touches k + //! no-wv layers copy the PRE-norm/PRE-rope K rows into the V panel, then v_norm runs the + //! weightless per-head RMS in place - the CPU mm_qkv order, BEFORE qk_norm touches k if (!has_wv) { enc_copy_row(enc, bks[l], koff, bvs[l], koff, het ? u_vtot_sw : u_vtot, npos * kvd_l) } if (c.v_norm) { - // MAX-width ones upload: the region cache is address-keyed and both - // classes read this one plane (the single-decode lesson) + //! MAX-width ones upload: the region cache is address-keyed and both classes read this one plane var bones = upload_region(addr < void? >(t.fblob[t.rms_ones_off]), uint64(max_head_size(c) * 4l)) var vka = QkNormArgs(nq = 0u, koffe = 0u, rstride = uint(kvd_l), hs = uint(hs_l), woffe = 0u, eps = c.norm_eps, soffe = 0u) @@ -4339,9 +4019,8 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } if (!recr && has_bias && g_pf_skip != "ew" && g_pf_skip != "nongemm") { - // QKV bias before rope — chunk rows only (existing rows stored biased+roped). - // Per-layer widths for the offsets; the count uniforms stay base-class (no - // hetero model carries QKV bias — the CPU bias-plane layout is uniform too) + //! QKV bias before rope, chunk rows only (existing rows are stored biased+roped); the count + //! uniforms stay base-class - no hetero model carries QKV bias var bbq = upload_region(addr < void? >(t.bq[l * qd_l]), uint64(qd_l * 4l)) var bbk = upload_region(addr < void? >(t.bk[l * kvd_l]), uint64(kvd_l * 4l)) var bbv = upload_region(addr < void? >(t.bv[l * kvd_l]), uint64(kvd_l * 4l)) @@ -4350,7 +4029,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : enc_add_bias_rows(enc, bvs[l], koff, bbv, 0ul, u_kvd, u_totkv, npos * kv_dim) } if (!recr && has_qkn && g_pf_skip != "ew" && g_pf_skip != "nongemm") { - // per-head QK-norm before rope — the chunk's q panel and its new K rows + //! per-head QK-norm before rope — the chunk's q panel and its new K rows var bqw = upload_region(addr < void? >(t.fblob[t.rms_q_offs[l]]), uint64(hs_l * 4l)) var qka = QkNormArgs(nq = uint(n_heads), koffe = uint(qd_l), rstride = uint(qd_l), hs = uint(hs_l), woffe = uint(hs_l), eps = c.norm_eps, soffe = uint(qd_l)) @@ -4363,8 +4042,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } if (!recr && g_pf_skip != "ew" && g_pf_skip != "nongemm") { - // sliding layers rope with the swa row pair (dual-rope configs — gemma3/4; - // hetero: the swa pair's rows are hs_sw/2 wide — the class's own width) + //! sliding layers rope with the swa row pair, whose rows are the class's own hs/2 wide var bcos_l = lsl && dual_rope ? bcos_swa : bcos var bsin_l = lsl && dual_rope ? bsin_swa : bsin enc_rope(enc, bq, 0ul, bcos_l, bsin_l, u_qd_l, u_hs_l, u_npairs_q_l, u_neox, u_rot, npos * qd_l / 2l) @@ -4373,9 +4051,6 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } if (!recr && g_pf_skip != "attn" && g_pf_skip != "nongemm") { - // sliding layers bind the span — the QK forms skip fully-below-window blocks, - // pf_p_weight masks + zeroes the below-window prefix; global layers bind 0 - // the trio walks one slab, so its whole geometry derives ONCE here var atka = AttnArgs(qd = uint(qd_l), kv_dim = uint(kvd_l), head_size = uint(hs_l), kv_mul = het ? uint(n_heads / kvh_sw) : kv_mul, npos = uint(nk), np32 = uint(nk64), @@ -4387,8 +4062,6 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : ulo = s.attn_uniform_end > 0l ? uint(s.attn_uniform_lo) : 0u) if (g_pf_skip != "attn_qk") { if (mmattn) { - // half-Q: the roped Q slab converts once per layer (the last - // float-operand tmm2d site — q8u's measured 8-11% half-A win class) enc_qk_mm(enc, bq, bks[l], batt, atka, mp, nk64, n_heads, bqh = pf_cvt_panel(enc, bq, mp, qd_l)) } else { @@ -4411,7 +4084,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } if (!recr && c.q_gated && g_pf_skip != "ew" && g_pf_skip != "nongemm") { - // gated-attention epilogue: out ⊙ σ(gate) between the attention output and wo (the CPU order) + //! gated-attention epilogue: out ⊙ σ(gate) between the attention output and wo (the CPU order) enc_sigmul(enc, bxb, 0ul, bdngate, 0ul, u_qtot, npos * qd) } if (!recr && g_pf_skip != "gemm") { @@ -4428,18 +4101,16 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : enc_add_bias_rows(enc, bxb2, 0ul, bwo_b, 0ul, u_dim, u_total_dim, npos * dim) } } - // ffn: [post-attn norm ->] [WO residual +] norm -> [requant ->] W1/W3 -> - // swiglu/geglu[+requant] -> W2 [-> post-ffn norm] var bxh_ffn : MetalBuffer? if (g_pf_skip != "ew" && g_pf_skip != "nongemm") { if (c.pre_post_norm) { - // gemma sandwich: norm the attention branch IN PLACE before the residual add + //! gemma sandwich: norm the attention branch IN PLACE before the residual add var bw_pa = upload_region(addr < void? >(t.fblob[t.rms_post_att_off + l * dim]), uint64(dim * 4l)) pf_enc_rms(enc, bxb2, 0ul, bw_pa, bxb2, u_dim, u_eps, npos) } enc_add(enc, bx, 0ul, bxb2, 0ul, u_total_dim, npos * dim) - // dual-store only where a dense FFN will read the twin — the routed-MoE arm - // rides bmxg/bmg, so its layers would pay the f16 write for nothing + //! dual-store only where a dense FFN reads the twin - the routed-MoE arm rides bmxg/bmg, + //! so its layers would pay the f16 write for nothing bxh_ffn = (!moe || g4moe) && g_pso_rms_hx != null ? pf_twin_panel(mp, dim) : null if (bxh_ffn != null) { pf_enc_rms_hx(enc, bx, 0ul, bw_ffn, bxb, u_dim, u_eps, bxh_ffn, npos) @@ -4448,9 +4119,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } if (moe && g_pf_skip != "gemm" && g_pf_skip != "moe") { - // MoE FFN (Wave C stage 2b): per-position routing + CSR, then one gathered - // mul_mm per projection over the touched experts; ordered reduce into bxb - // (g4: its own router norm + pre_ffn2 input via bxb2, reduce into bmg4rt) + //! g4moe routes its own router norm and pre_ffn2 input through bxb2 and reduces into bmg4rt let fe1 = fmt_at(t.we1_fmt, l) let fe3 = fmt_at(t.we3_fmt, l) if (g4moe) { @@ -4472,14 +4141,13 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : enc_moe_wscale(enc, bmsel, bmsel, bw_ds, u_moe_nk, npos) } if (nsh > 0l) { - // shexp raw gate dots (σ in the combine) — bmlg is free once select consumed it + //! shexp raw gate dots (σ in the combine) — bmlg is free once select consumed it var bw_shg = upload_region(unsafe(addr < void? >(t.fblob[t.shexp_gate_off + l * dim])), uint64(dim * 4l)) pf_enc_slab_gemv_b(enc, bw_shg, bxb, bmlg, u_dim, u_moe_one, u_moe_np, 1l, npos) } if (!pf_skip_moe_mm()) { if (t.experts_mx4) { - // per-expert bias folds into the mm accumulator seed (hasb); the - // moe_bias chase arm knocks the fold out for attribution + //! per-expert bias folds into the mm accumulator seed (hasb); the moe_bias arm knocks it out let hasb = g_pf_skip != "moe_bias" var bwb1 = upload_region(unsafe(addr < void? >(t.fblob[t.web1_off + l * c.n_expert * c.n_ff_exp])), uint64(c.n_expert * c.n_ff_exp * 4l)) var bwb3 = upload_region(unsafe(addr < void? >(t.fblob[t.web3_off + l * c.n_expert * c.n_ff_exp])), uint64(c.n_expert * c.n_ff_exp * 4l)) @@ -4504,7 +4172,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : contiguous = bxg1 != null, bxh = bxg1) } if (nsh > 0l) { - // shexp gate/up: dense q8 mul_mm at the wsh planes (bhb/bhb2 sized max(hidden, nsh)) + //! shexp gate/up: dense q8 mul_mm at the wsh planes (bhb/bhb2 sized max(hidden, nsh)) let bxh_sh = pf_cvt_panel(enc, bxb, mp, dim) let bwsh1 = blob_of(g_dev, t, t.wsh1_off + l * dim * nsh) enc_gemm_mm(enc, bwsh1.buf, bwsh1.boff, bxb, bhb, u_dim, u_moe_nsh, mp, nsh, 0ul, dim, npos, bxh_sh) @@ -4530,16 +4198,13 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : if (moe && g_pf_skip != "gemm" && g_pf_skip != "moe") { let fe2 = fmt_at(t.we2_fmt, l) if (!pf_skip_moe_mm()) { - // half-X converts the npos*nk-row bucket panel; pad-tile overreads stay - // pad C rows. Only the q8/mx4 twins consume — other formats skip the pass. let down_th = t.experts_mx4 ? g_pf_pso_moe_mm_mx4_th != null : ( fe2 == KqFmt.q8 ? g_pf_pso_moe_mm_q8_th != null : ( fe2 == KqFmt.k4 ? g_pf_pso_moe_mm_k4_th != null : ( fe2 == KqFmt.k5 ? g_pf_pso_moe_mm_k5_th != null : ( fe2 == KqFmt.k6 ? g_pf_pso_moe_mm_k6_th != null : ( fe2 == KqFmt.q51 && g_pf_pso_moe_mm_q51_th != null))))) - // the bucket panel is PADDED — the twin indexes rows via basep, so the - // convert must cover mpad rows, not the mtot prefix (tail experts read f16) + //! the bucket panel is PADDED - the convert must cover mpad rows, not the mtot prefix let bxh_mg = down_th ? pf_cvt_panel(enc, bmg, mpad, c.n_ff_exp, g_pf_skip == "moe_cvt") : null if (t.experts_mx4) { var bwb2 = upload_region(unsafe(addr < void? >(t.fblob[t.web2_off + l * c.n_expert * dim])), uint64(c.n_expert * dim * 4l)) @@ -4553,7 +4218,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : moe_mm_ka(fe2, c.n_ff_exp, dim, c.n_expert_used, false), contiguous = true, bxh = bxh_mg) } if (nsh > 0l) { - // shexp down into bxb2 (free post-residual) — bxb still feeds the reduce + //! shexp down into bxb2 (free post-residual) — bxb still feeds the reduce let bwsh2 = blob_of(g_dev, t, t.wsh2_off + l * dim * nsh) enc_gemm_mm(enc, bwsh2.buf, bwsh2.boff, bhb, bxb2, u_moe_nsh, u_dim, mp, dim, 0ul, nsh, npos, pf_cvt_panel(enc, bhb, mp, nsh)) } @@ -4561,7 +4226,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : if (!pf_skip_moe_reduce()) { pf_enc_moe_reduce(enc, bmdn, bmsel, bminv, g4moe ? bmg4rt : bxb, u_dim, u_moe_nk, dim, npos) if (nsh > 0l) { - // routed sum lands in bxb first — the shexp branch adds σ(gate)-scaled on top + //! routed sum lands in bxb first — the shexp branch adds σ(gate)-scaled on top enc_axpy_sig(enc, bxb, bxb2, bmlg, u_total_dim, u_dim, npos * dim) } } @@ -4570,10 +4235,10 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : pf_enc_rms(enc, bmg4rt, 0ul, bw_pf2, bmg4rt, u_dim, u_eps, npos) } } - let hid_l = layer_hidden(t, l) // per-layer (MatFormer E-series) + let hid_l = layer_hidden(t, l) //! per-layer (MatFormer E-series) let u_hid_l = (u_hidden2 == null || hid_l == hidden) ? u_hidden : u_hidden2 let u_th_l = (u_total_h2 == null || hid_l == hidden) ? u_total_h : u_total_h2 - if ((!moe || g4moe) && g_pf_skip != "gemm") { // g4: the dense parallel shared branch + if ((!moe || g4moe) && g_pf_skip != "gemm") { //! g4: the dense parallel shared branch if (bxh_ffn == null) { bxh_ffn = pf_cvt_panel(enc, bxb, mp, dim) } @@ -4630,7 +4295,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } if (g4moe && g_pf_skip != "ew" && g_pf_skip != "nongemm") { - // dense-branch post-norm, then routed + dense summed into bxb for the epilogue + //! dense-branch post-norm, then routed + dense summed into bxb for the epilogue var bw_pf1 = upload_region(unsafe(addr < void? >(t.fblob[t.rms_post_ffn1_off + l * dim])), uint64(dim * 4l)) pf_enc_rms(enc, bxb, 0ul, bw_pf1, bxb, u_dim, u_eps, npos) enc_add(enc, bxb, 0ul, bmg4rt, 0ul, u_total_dim, npos * dim) @@ -4642,8 +4307,8 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } if (plef) { - // E-series PLE between FFN residual and out_scale (the CPU order): plain x_b += - // ffn_branch, then branch = post_norm(proj · (gelu(gate · x_b) ⊙ side[l])) + //! PLE sits between the FFN residual and out_scale (the CPU order): x_b += ffn_branch, then + //! branch = post_norm(proj · (gelu(gate · x_b) ⊙ side[l])) if (g_pf_skip != "ew" && g_pf_skip != "nongemm") { enc_add(enc, bx, 0ul, bxb, 0ul, u_total_dim, npos * dim) } @@ -4664,22 +4329,21 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } if (g_pf_skip != "ew" && g_pf_skip != "nongemm") { - // gemma4 layer_out_scale multiplies the WHOLE layer output — (x + branch) * s - // folds into the residual add's ascale slot (a 4-byte view into the weights blob) + //! layer_out_scale multiplies the WHOLE layer output: (x + branch) * s folds into the + //! residual add's ascale slot (a 4-byte view into the weights blob) var bosc : MetalBuffer? if (c.layer_out_scale) { bosc = upload_region(addr < void? >(t.fblob[t.out_scale_off + l]), 4ul) } enc_add(enc, bx, 0ul, bxb, 0ul, u_total_dim, npos * dim, bosc) - if (l < nds) { // deepstack: slice l adds to the layer output (every row; text tails are zero) + if (l < nds) { //! deepstack: slice l adds to the layer output (every row; text tails are zero) enc_add(enc, bx, 0ul, bds, uint64(l * npos * dim * 4l), u_total_dim, npos * dim) } } } } if (gpu_logits) { - // final rmsnorm on the LAST position + classifier GEMV — the caller samples from - // s.logits, so this closes the whole forward inside the GPU window + //! the caller samples from s.logits, so this closes the whole forward inside the GPU window unsafe { var bwfin = upload_region(addr < void? >(t.fblob[t.rms_final_off]), uint64(dim * 4l)) pf_enc_rms(enc, warm ? bwm_res : bx, uint64((npos - 1l) * dim * 4l), bwfin, bxf, u_dim, u_eps, 1l) @@ -4690,11 +4354,11 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : enc_gemv(enc, bwc.buf, bwc.boff, bxf, blog, u_dim, u_vocab, c.vocab_size) } if (u_flcap != null) { - // final-logit soft cap (gemma2): cap*tanh over the classifier row in place + //! final-logit soft cap (gemma2): cap*tanh over the classifier row in place enc_softcap_row(enc, blog, 0ul, u_vocab, u_flcap, c.vocab_size) } if (bsupp != null) { - // gemma4 suppressed ids pin to -1e30 AFTER the cap (the CPU classifier's order) + //! gemma4 suppressed ids pin to -1e30 AFTER the cap (the CPU classifier's order) enc_suppress_row(enc, blog, 0ul, bsupp, u_nsupp, nsupp) } } @@ -4708,9 +4372,6 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : metal_commit(cb) cbs |> push(cb) } - // completion + readback INTERLEAVE: chunks complete in commit order, each completed chunk's - // roped-K/raw-V rows stream into the CPU KV codec while later chunks keep the GPU busy (safe - // the moment a chunk reports complete). The residual-stream copy needs the LAST chunk. var ran = true var gpu_t0 = 0.0lf var gpu_t1 = 0.0lf @@ -4737,11 +4398,10 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : let ts_rb = ref_time_ticks() let l1 = min(int64(i + 1) * layers_per_cb, n_enc_layers) for (l in range64(int64(i) * layers_per_cb, l1)) { - // recurrent: no rows; shared (E-series): the source layer's store covers the alias if (bks[l] == null || kv_shared_layer(t, l)) { continue } - // the chunk's rows sit past a continuation's gathered panel head + //! the chunk's rows sit past a continuation's gathered panel head var kpan = reinterpret(metal_buffer_contents(bks[l])) var vpan = reinterpret(metal_buffer_contents(bvs[l])) let kvd_l = layer_kv_dim(c, l) @@ -4749,9 +4409,8 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : let koff_l = start_pos * kvd_l * 4l memcpy(addr < void? >(s.k_b[0]), reinterpret(kpan + koff_l), npos * kvd_l * 4l) memcpy(addr < void? >(s.v_b[0]), reinterpret(vpan + koff_l), npos * kvd_l * 4l) - // tq4 sessions store in the ROTATED basis: the GPU ran attention unrotated, - // so rotate the readback rows per head before the codec store (the CPU - // prefill's exact discipline — dasllama_common's tq4 store path) + //! tq4 sessions store in the ROTATED basis: the GPU ran attention unrotated, so rotate the + //! readback rows per head before the codec store if (s.kv_dtype_k == KVDtype.tq4 || s.kv_dtype_v == KVDtype.tq4) { let sgp = addr < float const? >(s.kv_signs[0]) if (s.kv_dtype_k == KVDtype.tq4) { @@ -4769,11 +4428,11 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } } cbs |> clear() - gpu_ms = (gpu_t1 - gpu_t0) * 1000.0lf // whole-GPU window: first chunk start -> last chunk end + gpu_ms = (gpu_t1 - gpu_t0) * 1000.0lf //! whole-GPU window: first chunk start -> last chunk end let encwait_us = get_time_usec(ts_enc) let ok = ran if (ran) { - if (dn) { // the window completed — the GPU state now holds position start_pos+npos-1's update + if (dn) { //! the window completed — the GPU state now holds position start_pos+npos-1's update dn_mirror_advance(s.uid, start_pos + npos - 1l) } let ts_rb = ref_time_ticks() @@ -4782,7 +4441,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : if (gpu_logits) { memcpy(addr < void? >(s.logits[0]), metal_buffer_contents(blog), c.vocab_size * 4l) if (c.n_layer_nextn > 0l) { - // forward_prefill's mtp_h contract — bxf holds the last row's post-final-norm hidden + //! forward_prefill's mtp_h contract — bxf holds the last row's post-final-norm hidden memcpy(addr < void? >(s.mtp_h[0]), metal_buffer_contents(bxf), dim * 4l) } } @@ -4799,7 +4458,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : to_log(LOG_ERROR, "dasLLAMA metal prefill: dispatch failed ({err}) - falling back to the CPU layer loop\n") // nolint:PERF028,PERF026 — error path, and the CPU fallback dwarfs the log decline(MetalPrefillDecline.gpu_error) } - // return the pooled buffers (uniforms too); the weight regions stay resident + //! return the pooled buffers (uniforms too); the weight regions stay resident pool_release(g_pf_pool, bx, bytes_x) pool_release(g_pf_pool, bxb, bytes_xb) pool_release(g_pf_pool, bxb2, bytes_x) @@ -4890,7 +4549,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : } pool_release(g_pf_upool, bsin, bytes_tab) for (l in range64(c.n_layers + c.n_layer_nextn)) { - if (bks[l] == null || kv_shared_layer(t, l)) { // shared: aliased — the source releases it + if (bks[l] == null || kv_shared_layer(t, l)) { continue } let bytes_kv_l = uint64(kvrows * layer_kv_dim(c, l) * 4l) @@ -4910,7 +4569,7 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : pool_release(g_pf_upool, u_ple, 4ul) pool_release(g_pf_upool, u_ple_tot, 4ul) } - bks |> clear() // non-owning handles — the pool owns them now + bks |> clear() //! non-owning handles — the pool owns them now bvs |> clear() pool_release(g_pf_upool, u_dim, 4ul) pool_release(g_pf_upool, u_qd, 4ul) @@ -4990,50 +4649,37 @@ def metal_prefill_forward(t : Model; var s : Session; npos, start_pos : int64) : return ok } -// Knobs resolved once at [init]. They were read per prefill call, and get_env_variable allocates -// its result in the context heap on every call — see PERF027. +//! Knobs resolve once at [init]: get_env_variable allocates in the context heap on every call (PERF027). var private g_pf_env_mulmm = true var private g_pf_env_mm_tail = true var private g_pf_env_half_x = true var private g_pf_env_dev_w = true var private g_pf_env_tall = true -// dev-W engage rules = the probe's M5 shape map (bench_metal_nax_probe grid): PANEL SIZE -// dominates (<=32MB wins at every M, 47MB only at >=2048 rows, 112MB loses everywhere — -// the f16 panel's 2-vs-1.06 B/w W stream past cache); wide-N panels' dequant tax needs rows. - -// tall M-tile occupancy floor, in 128-row-x-64-col threadgroups: raced 32/64/128 at mid-M -// across three dense families — 64 wins, 32 adds nothing, the small-prompt guard held (at -// rows=128 the d>=4096 demand keeps small-d sites short). Race data: the sidecar archive. -var private CVT_MIN_ROWS = 256l // sidecar knob "metal_cvt_min_rows" — cached at init -var private TALL_OCC_FLOOR = 64l // sidecar knob "metal_tall_floor" — cached at init -var private DEVW_SMALL_PANEL = 32ul * 1024ul * 1024ul // sidecar knob "metal_devw_small_panel_mb" + +var private CVT_MIN_ROWS = 256l //!< sidecar knob "metal_cvt_min_rows" — cached at init +var private TALL_OCC_FLOOR = 64l //!< sidecar knob "metal_tall_floor" — cached at init +var private DEVW_SMALL_PANEL = 32ul * 1024ul * 1024ul //!< sidecar knob "metal_devw_small_panel_mb" let DEVW_BIG_PANEL = 48ul * 1024ul * 1024ul let DEVW_WIDE_N = 4096l let DEVW_WIDE_N_ROWS = 512l let DEVW_BIG_ROWS = 2048l -// e2e-only clause the isolated grid cannot see (it races one site; production overlaps): -// a long-K (down) dequant serializes on the panel pair behind the up/gate GEMM chain at -// small M — engaged there it LOSES e2e despite winning its isolated site race let DEVW_LONG_K = 4096l let DEVW_LONG_K_ROWS = 1024l -// deep-dense panels (24B+: 300MB+ up/gate/down) need tile counts far past the 8 the first -// knee map raced; narrow tiles measured fine (a 20-tg tile dispatch still beat the kq-tg -// fallback at 512 rows), so the only tile bars are divisibility, the knee, and the pool let DEVW_MAX_TILES = 32l var private g_pf_env_span = true var private g_pf_env_logits = true var private g_pf_env_attn = true var private g_pf_env_unretained = false var private g_pf_env_capture = true -var private g_pf_env_ncb = 0 // 0 = unset, fall back to the layer-derived default +var private g_pf_env_ncb = 0 //!< 0 = unset, fall back to the layer-derived default [init] def dasllama_metal_prefill_register() { - // registered but dormant: only select_prefill_override("metal") (env rail - // DASLLAMA_PIN_PREFILL) activates it, and unsupported shapes decline per call + //! registered but dormant - only select_prefill_override("metal") activates it, and + //! unsupported shapes decline per call register_prefill_override("metal", @@metal_prefill_forward) - register_prefill_override_mrope_tables("metal") // enc_rope reads the per-token table rows, so the mrope grid map serves unchanged - register_prefill_override_ds_adds("metal") // the per-layer slice adds encode via enc_add over the uploaded slice planes + register_prefill_override_mrope_tables("metal") + register_prefill_override_ds_adds("metal") register_ple_gpu_gate(@@metal_ple_pre_gpu_gate) g_pf_env_mulmm = g_env_metal.mulmm g_pf_env_mm_tail = g_env_metal.mm_tail @@ -5052,7 +4698,6 @@ def dasllama_metal_prefill_register() { } } -// ===== Metal-4 tensor twin race (the tuner's crowning section) ===== def private race_mulmm_bf16(dev : MetalDevice?; queue : MetalCommandQueue?) : MetalTensorRaceResult { var res = MetalTensorRaceResult(family = "mulmm_bf16", winner = "", base_ms = -1.0lf, twin_ms = -1.0lf, note = "") @@ -5067,7 +4712,7 @@ def private race_mulmm_bf16(dev : MetalDevice?; queue : MetalCommandQueue?) : Me } var twin_pso = pipeline_from_source(dev, MetalBf16MulMmT_metal_bf16_mulmm_t_msl, MetalBf16MulMmT_metal_bf16_mulmm_t_msl_entry, MetalBf16MulMmT_metal_bf16_mulmm_t_msl_fastmath, err) if (twin_pso == null) { - // no tensor support on this box/toolchain — the simdgroup kernel keeps the crown + //! no tensor support on this box/toolchain — the simdgroup kernel keeps the crown res.winner = "simdgroup" res.note = "twin pso: {err}" metal_release(base_pso) @@ -5228,7 +4873,7 @@ def private race_moe_mulmm_q8(dev : MetalDevice?; queue : MetalCommandQueue?) : basep[e] = uint(e * rows_per) } for (i in range(m)) { - bkt[i] = uint(i) // identity buckets: gather=0 semantics match + bkt[i] = uint(i) //! identity buckets: gather=0 semantics match } var bw = race_buf(dev, uint64(ne * eblk * 34), unsafe(addr(blob[0]))) var bxa = race_buf(dev, uint64(m * kdim * 4), unsafe(addr(xa[0]))) @@ -5237,7 +4882,6 @@ def private race_moe_mulmm_q8(dev : MetalDevice?; queue : MetalCommandQueue?) : var bcnt = race_buf(dev, uint64(ne * 4), unsafe(addr(cnt[0]))) var bbase = race_buf(dev, uint64(ne * 4), unsafe(addr(basep[0]))) var bbkt = race_buf(dev, uint64(m * 4), unsafe(addr(bkt[0]))) - // bind through the family's builder — a hand-rolled list here desyncs unseen by any suite var rka = moe_mm_ka(KqFmt.q8, int64(kdim), int64(ndim), 1l, false) let grid = uint3(uint(rows_per / 32), uint(ndim / 64), uint(ne)) let tg = uint3(128u, 1u, 1u) @@ -5305,14 +4949,14 @@ def private race_moe_mulmm_mx4(dev : MetalDevice?; queue : MetalCommandQueue?) : } var xa <- race_x_f32(m * kdim) var nplane : array - nplane |> resize(ne * eblk * 4) // 16B nibbles per block + nplane |> resize(ne * eblk * 4) //! 16B nibbles per block for (i in range(ne * eblk * 4)) { nplane[i] = uint(i) * 2654435761u } var eplane : array eplane |> resize(ne * eblk) for (i in range(ne * eblk)) { - eplane[i] = uint8(125 + i % 4) // e8m0 near 1.0 — no overflow across the fold + eplane[i] = uint8(125 + i % 4) //! e8m0 near 1.0 — no overflow across the fold } var vtabh : array vtabh |> resize(16) @@ -5344,7 +4988,6 @@ def private race_moe_mulmm_mx4(dev : MetalDevice?; queue : MetalCommandQueue?) : var bcnt = race_buf(dev, uint64(ne * 4), unsafe(addr(cnt[0]))) var bbase = race_buf(dev, uint64(ne * 4), unsafe(addr(basep[0]))) var bbkt = race_buf(dev, uint64(m * 4), unsafe(addr(bkt[0]))) - // same rule as the q8 race: bind through the family's builder, never a hand-rolled list var rka = moe_mm_mx4_ka(int64(kdim), int64(ndim), 1l, false, false) let grid = uint3(uint(rows_per / 32), uint(ndim / 64), uint(ne)) let tg = uint3(128u, 1u, 1u) @@ -5395,9 +5038,8 @@ def private race_moe_mulmm_mx4(dev : MetalDevice?; queue : MetalCommandQueue?) : return res } -// one kq mulmm race: random quant planes + constant f16 scales (any bit pattern is a valid -// plane — the twin-vs-base envelope doubles as a layout-agreement check). k6 binds the d plane -// at its tail offset; k4/k5 bind the compact scale blocks at 0. +//! random quant planes + constant f16 scales: any bit pattern is a valid plane, so the +//! twin-vs-base envelope doubles as a layout-agreement check def private race_kq_mulmm(dev : MetalDevice?; queue : MetalCommandQueue?; family : string; // nolint:STYLE038 — one-shot A/B race harness; buffers + PSOs stay live to the release tail base_src, base_entry : string; base_fm : bool; base_tgmem : uint64; twin_src, twin_entry : string; twin_fm : bool; twin_tgmem : uint64; @@ -5425,9 +5067,9 @@ def private race_kq_mulmm(dev : MetalDevice?; queue : MetalCommandQueue?; family var qplane : array qplane |> resize(nblk * qu_per_sb) for (i in range(nblk * qu_per_sb)) { - qplane[i] = uint(i) * 2654435761u // deterministic pseudo-random bit pattern + qplane[i] = uint(i) * 2654435761u //! deterministic pseudo-random bit pattern } - // scales: k4/k5 = compact 16B blocks; k6 = int8 sub-scale plane + the f16 d tail + //! scales: k4/k5 = compact 16B blocks; k6 = int8 sub-scale plane + the f16 d tail var splane : array let sbytes = k6 ? nblk * 16 + nblk * 2 : nblk * 16 splane |> resize(sbytes) @@ -5445,13 +5087,13 @@ def private race_kq_mulmm(dev : MetalDevice?; queue : MetalCommandQueue?; family unsafe { var ph = addr(splane[0]) for (b in range(nblk)) { - ph[b * 8] = float16(0.25) // d - ph[b * 8 + 1] = float16(0.25) // dmin + ph[b * 8] = float16(0.25) //! d + ph[b * 8 + 1] = float16(0.25) //! dmin } } for (b in range(nblk)) { for (kx in range(4, 12)) { - splane[b * 16 + kx] = uint8(17) // kmask bytes: small scales, both halves + splane[b * 16 + kx] = uint8(17) //! kmask bytes: small scales, both halves } } } @@ -5508,15 +5150,14 @@ def private race_kq_mulmm(dev : MetalDevice?; queue : MetalCommandQueue?; family return res } -// attention pair races: synthetic Q/K/V; BOTH att/xb outputs pre-zeroed (causal-skipped tiles -// stay unwritten in both kernels — fresh-buffer garbage would flake the envelope compare). +//! synthetic Q/K/V with BOTH att/xb outputs pre-zeroed: causal-skipped tiles stay unwritten +//! in both kernels, and fresh-buffer garbage would flake the envelope compare def private race_attn_pair(dev : MetalDevice?; queue : MetalCommandQueue?) : array { // nolint:STYLE038 — one-shot A/B race harness; buffers + PSOs stay live to the release tail var out : array let heads = 8 let hs = 128 let qd = heads * hs let kvd = qd - // real-model shape class: a 128x128 slab crowned the wrong kernel (twins win at 512) let mp = 512 let np32 = 512 var err = "" @@ -5542,7 +5183,6 @@ def private race_attn_pair(dev : MetalDevice?; queue : MetalCommandQueue?) : arr var bxb_b = race_buf(dev, uint64(mp * qd * 4), unsafe(addr(zeros[0]))) var bxb_t = race_buf(dev, uint64(mp * qd * 4), unsafe(addr(zeros[0]))) var bstat = race_buf(dev, uint64(heads * mp * 2 * 4), unsafe(addr(sv[0]))) - // the race binds the SAME kargs the encoders do — a hand-rolled list silently desyncs var rka = AttnArgs(qd = uint(qd), kv_dim = uint(kvd), head_size = uint(hs), kv_mul = 1u, npos = uint(np32), np32 = uint(np32), scale = 0.125, qoff = 0u, qrows = uint(mp), window = 0u, softcap = 0.0, hass = 0u) From adaf47379035b5f91afd5b6b92c2d9f0984ca2ea Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Thu, 27 Aug 2026 15:16:23 -0700 Subject: [PATCH 04/10] dasLLAMA: dragon rounds over the harvest's rule and architecture landings Two rounds plus an N0 cold re-read, all findings verified against the driver before applying. Architecture doc: the form ladder is peel-first then three forms; the W-panel re-read count named per stamp; the knee map now speaks in the gate's own constants including the DEVW_WIDE_N clause the first landing missed; the per-format staging paragraph moved to the MoE section; both modal sentences left for their REVIEW.md homes. REVIEW_GPU: sentinel/cooperative-op/PSO/SSBO terms defined in place, the GEMV-peel rule names its API, the pf_p_weight<->rowstat mirror duty collapsed to protecting the attn-trio cells that already automate it (moved to tests/REVIEW.md beside its siblings), and the role-file rule deleted - REVIEW.das's check_gpu_role_partition automates it. Five more REVIEW.das lint candidates and a REVIEW_PREFILL.md split proposal ledgered in the arc plan. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014fKJGuUL8tP58Y6NvoVeSn --- modules/dasLLAMA/ARCHITECTURE.md | 6 +- modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md | 105 +++++++++++-------- modules/dasLLAMA/REVIEW.md | 1 + modules/dasLLAMA/REVIEW_GPU.md | 82 +++++++-------- modules/dasLLAMA/tests/REVIEW.md | 5 + 5 files changed, 108 insertions(+), 91 deletions(-) diff --git a/modules/dasLLAMA/ARCHITECTURE.md b/modules/dasLLAMA/ARCHITECTURE.md index bf898004ea..1a11070b08 100644 --- a/modules/dasLLAMA/ARCHITECTURE.md +++ b/modules/dasLLAMA/ARCHITECTURE.md @@ -13,7 +13,7 @@ Shipped-arc plan docs live in `history/dasLLAMA/` (the archive log is `history/R a `*_plan.md` in this folder is an ACTIVE arc's working plan. Passages retired from this document are archived in `history/dasLLAMA/architecture_retired_notes.md`. -Seven companions carry this document's sections, each keeping its sections' numbers. The +The companions carry this document's sections, each keeping its sections' numbers. The routing block under each numbered heading below is the index: it names every companion that section runs to, and the sections that companion holds. @@ -40,8 +40,8 @@ re-transcoding `$LCPP/src/unicode-data.cpp`). - `ARCHITECTURE_GPU.md` - sec.2.2b: the tensor-GEMM and fused-attention shapes that measured out. - `ARCHITECTURE_GPU_PREFILL.md` - sec.2.2c-2.2i: the Metal prefill driver's GEMM form ladder, dev-W knee map, attention slab, MoE bucket rail, and chunked submission. -- `ARCHITECTURE_RUNTIME.md` - sec.2.2-2.4, 2.6-2.9, 2.11, 2.12: kernel shape, caches, lint - policy, knobs, coverage, the GPU ramp. +- `ARCHITECTURE_RUNTIME.md` - sec.2.2, 2.3, 2.3a, 2.4, 2.6-2.9, 2.11, 2.12: kernel shape, + caches, lint policy, knobs, coverage, the GPU ramp. - `ARCHITECTURE_MEASUREMENT.md` - sec.2.5, 2.10: the benchmark rig, the tune gate, and the sanctioned instrumentation rails. diff --git a/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md b/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md index c9415220d5..01cac8b38b 100644 --- a/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md +++ b/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md @@ -4,35 +4,32 @@ Companion to `ARCHITECTURE.md`; section numbers are that document's. ### 2.2c The prefill GEMM form ladder {#prefill-gemm-ladder} -Every weight GEMM in `dasllama_metal_prefill.das` picks one of four forms, in this order, per site -per forward: +Every weight GEMM in `dasllama/dasllama_metal_prefill.das` splits its rows across two decisions. +First the GEMV tail peel (sec.2.2e) takes up to `MM_TAIL_MAX` remainder rows off the padded tile. +The rows that remain pick one of three forms, in this order, per site per forward: 1. **dev-W all-device** - the weight plane is dequantized into a device f16 panel and multiplied half x half. No threadgroup staging and no barriers, so the staged-operand tax is gone; the - dequant pass is paid once per site per forward against a GEMM that re-reads the operand `d/64` - times. sec.2.2d carries the panel size rules. + dequant pass is paid once per site per forward against a GEMM that re-reads the f16 W panel + once per M row tile (`mp/128` on the tall stamp, `mp/32` on the 32-row stamp). sec.2.2d + carries the panel size rules. 2. **tall 128-row M-tile** - the stamp streams W `M/128` times over a 128-row tile, taken on the row count's 128-floor with the 32-row stamp on the remainder. The remainder arm strides X by - `kdim`, so a caller that passes no `kdim` stays whole-dispatch 32-tile. + `kdim`, so a caller that passes no `kdim` takes the tall stamp only when its row count is + already a multiple of 128, and otherwise stays whole-dispatch 32-tile. 3. **32-row tile** - the default stamp. -4. **GEMV tail peel** - sec.2.2e. **Half operands ride an f16 activation panel.** One pass converts the f32 panel; the GEMM then re-reads it at half the bytes `d/64` times, so the convert amortizes above a row floor -(`CVT_MIN_ROWS`, default 256) and loses under it. The panel is double-buffered so a consumer's -GEMM overlaps the next twin's producer, and a producer that dual-stores the f16 form takes a panel -ungated by rows because its twin is free. +(`CVT_MIN_ROWS`, default 256) and loses under it. Two panels alternate, so one site's GEMM reads +panel A while the next site's convert writes panel B. A site whose producer kernel writes the +f16 copy alongside its f32 output takes its panel from `pf_twin_panel` directly instead of +`pf_cvt_panel`, skipping the row floor entirely, because there is no convert pass to amortize. **The bf16-A stamp widens without dequantizing** - a bf16 row widens by an exact bit shift and rounds to the f16 tile - so the E-series `per_layer_model_proj` GEMM serves straight off the kept-bf16 blob with no resident f32 copy. -**The staging form that wins is per format, not universal.** The gathered q8 mul_mm carries its -scale and quant pointers across k-blocks; the stateless index form measured 3.4-3.6% slower in the -gmm8 lab. The gathered Q6_K goes the other way: the superblock-scalar cache the standalone kernel -carried measured 2.4% slower per mm than reloading per k-block in the gmm6 lab, so its stage is -stateless. - **The occupancy floor guards the tall stamp.** A tall grid is taken only when `rows/128 * (d/64) >= TALL_OCC_FLOOR` (default 64, a sidecar knob). An under-occupied tall grid starves the GPU and small prompts regress hard without the floor; 32 adds nothing over 64, raced @@ -40,24 +37,31 @@ at mid-M across three dense families. ### 2.2d The dev-W panel knee map {#devw-panel-knees} -Panel SIZE dominates the dev-W decision, not shape: a panel at or under 32 MiB wins at every row -count, 47 MiB wins only from 2048 rows, and 112 MiB loses everywhere - the f16 panel's W stream is -2 bytes an element against the q8 blob's 1.06 once it leaves cache. Wide-N panels pay a dequant -tax that only deep M repays. The grid these rules come from is -`benchmarks/matmul/bench_metal_nax_probe.das`. +Panel SIZE dominates the dev-W decision, not shape - each threshold is a knee, the panel size at +which the dev-W win flips sign. A panel at or under `DEVW_SMALL_PANEL` (32 MiB) engages at every +row count while its output width is at or under `DEVW_WIDE_N` (4096), and from +`DEVW_WIDE_N_ROWS` (512 rows) when wider; a panel up to `DEVW_BIG_PANEL` (48 MiB) engages from +`DEVW_BIG_ROWS` (2048 rows); above that the panel either splits into N-column tiles or the site +declines. The mechanism: the f16 panel's W stream is 2 bytes an element against the q8 blob's +1.06 once it leaves cache, and a wide-N panel costs more dequant work, which only a large row +count repays. The raced evidence +(32 MiB wins everywhere, 47 MiB only from 2048 rows, 112 MiB loses everywhere) is +`benchmarks/matmul/bench_metal_nax_probe.das`'s grid. Three clauses the isolated grid cannot see, because it races one site while production overlaps sites: - **A long-K (down-projection) dequant serializes** on the panel pair behind the up/gate GEMM chain at small M, so it loses end to end there despite winning its isolated site race. The - long-K floor is 1024 rows; the isolated tiled win at 512 rows read flat-negative end to end. + long-K floor is 1024 rows on q8; the same tiling that wins its isolated site race at 512 + rows measures zero to negative end to end. - **An over-knee panel runs as N-column TILES**, each under the small-panel knee, with the tile - count bounded only by divisibility, the knee and the pool. Deep-dense models (300 MB+ - up/gate/down planes) need far more tiles than the first knee map raced, and narrow tiles measure - fine - a 20-threadgroup tile dispatch still beat the tg-staged fallback at 512 rows. -- **A k-quant tg fallback is about 1.28x the q8 half-panel form**, so a k-quant site lowers both - the over-knee bar and the tiled-rows floor: a tiled read still beats THAT fallback. + count bounded by `DEVW_MAX_TILES` (32), divisibility, the small-panel knee and the pool. + Deep-dense models (300 MB+ up/gate/down planes) need up to that many tiles, and narrow tiles + measure fine - a 20-threadgroup tile dispatch still beat the tg-staged fallback at 512 rows. +- **A k-quant tg fallback is about 1.28x the q8 half-panel form**, so a k-quant site lowers the + over-knee bar, the tiled-rows floor, and the long-K floor (1024 rows to 512): a tiled read + still beats THAT fallback. The knee constants are box-raced and cached at init from the sidecar (`metal_cvt_min_rows`, `metal_tall_floor`, `metal_devw_small_panel_mb`). @@ -68,7 +72,8 @@ A prefill panel pads to `mp = ceil32(npos)`, so `npos % 32` rows of every GEMM a `MM_TAIL_MAX` (8) remainder rows peel off the padded tile onto the fixed-B mv family instead; above that the padded tile is cheaper than three or more weight streams. One peeled row rides the reduction-split GEMV, two or more ride the b4 form only - the reduction-split GEMV walks per -block and needs `kdim % 32`, while the b4 stripe reads whole 128-quant rounds. +block and needs `kdim % 32`, while the b4 form - the batched fixed-B mv stamp, up to four rows a +dispatch (`enc_mv_b4_c`) - reads whole 128-quant rounds and needs `kdim % 128`. ### 2.2f The prefill attention slab {#prefill-attn-slab} @@ -81,12 +86,11 @@ serve it: the tiled QK/AV GEMM pair (the default, needing `head_size % 64` on BO classes) and the scalar 32x32 trio, which serves when that gate fails or `DASLLAMA_METAL_ATTN=0` pins it. -- **A pad row of K or V stages as 0.** Pad rows carry recycled pool bytes and may hold NaN, and - `0 * NaN` poisons a whole cooperative tile. `pf_p_weight` zeroes P columns past each row's live +- **A pad row of K or V stages as 0.** `pf_p_weight` zeroes P columns past each row's live length exactly, so the P side needs no guard; the K and V sides do. -- **The PADFREE stamps drop that guard**, and an encoder may pick one only when the whole WALK - stays inside live rows - `qoff + qrows == npos` as well as the divisibility. A padded query - chunk walks pad-query tiles past `npos`, where a real row's read poisons the tile. +- **The PADFREE stamps drop that guard**; an encoder picks one only where the whole WALK stays + inside live rows - `qoff + qrows == npos` as well as the divisibility. A padded query chunk + walks pad-query tiles past `npos`, where a real row's read poisons the tile. - **A block skip lifts to `uend` only where the tile holds span rows.** A causal-only tile above the uniform span keeps its short causal walk, and a tile below every row's sliding window is skipped whole because `pf_p_weight` zeroes P over the skipped region. @@ -100,24 +104,34 @@ base set everywhere. ### 2.2g The prefill MoE bucket rail {#prefill-moe-buckets} -Routing is atomics-free: count (one threadgroup per expert) -> in-threadgroup prefix -> bucket -fill. Each expert's bucket PADS to a whole 32-row tile, every threadgroup computes the same padded -prefix, and threadgroup `e` publishes `basep[e]` for the mm and activation consumers. The bucket -fill splits the entry range into contiguous ascending per-lane chunks and scans the chunk counts, -which reproduces the serial entry order exactly, so the ordered weighted reduce is bit-stable -against the CPU park-and-accumulate. The selection is read GPU-side by the kernels; nothing reads -back to the CPU, so encode-ahead and speculation stay compatible. +Routing is atomics-free: a router GEMV and a select pass, then a per-expert count kernel, then +one bucket kernel that computes the padded prefix and fills the buckets. Each expert's bucket +PADS to a whole 32-row tile, every threadgroup computes the same padded prefix, and threadgroup +`e` publishes `basep[e]` for the mm and activation consumers. The bucket fill splits the entry +range into contiguous ascending per-lane chunks and scans the chunk counts, which reproduces the +serial entry order exactly, so the ordered weighted reduce is bit-stable against the CPU path +that parks each routed expert's rows and reduces them in entry order. The selection is read +GPU-side by the kernels; nothing reads back to the CPU, so encode-ahead and speculation stay +compatible. Pad bucket rows carry a stamped sentinel and the reduce never references them. The gather-X pass copies the bucket's token rows into a CONTIGUOUS f16 panel with pad rows zeroed, which lets the up and gate sites ride the contiguous tensor twins instead of the in-kernel gather form; the panel is -minted once per layer and shared by both sites. A bkt-indirect X can never form a tensor view, -which is why every tensor twin of the MoE family serves contiguous rows only. +minted once per layer and shared by both sites. An X read through the bucket index can never +form a tensor view, which is why every tensor twin of the MoE family serves contiguous rows +only. + +**The staging form that wins inside the gathered mul_mm kernels is per format, not universal.** +The gathered q8 form carries its scale and quant pointers across k-blocks; the stateless index +form measures 3.4-3.6% slower (`benchmarks/matmul/bench_metal_moe_lab.das`, gmm8 section). The +gathered Q6_K is the opposite: a superblock-scalar cache measures 2.4% slower per mm than +reloading per k-block (same lab, gmm6 section), so its stage is stateless. ### 2.2h Pad rows and cooperative-op constraints {#prefill-pad-rows-and-coop} -Activation panels size to `mp = ceil32(npos)` rows because every kernel's M grid is `mp/32`; a -64-row pad would bill a dead 32-row GEMM block on every short prefill. The GEMM has no edge +Activation panels size to `mp = ceil32(npos)` rows because every kernel's M grid divides `mp` by +its tile height - 32 for the default stamp, 128 for the tall stamps; a 64-row pad would bill a +dead 32-row GEMM block on every short prefill. The GEMM has no edge masking, so pad rows are written with whatever the tile computes. That is safe because C-block rows are independent and no pad row is read back: the norm, rope, attention and elementwise kernels all bound at `npos`, and rowstat writes `[0, npos)` only. @@ -126,10 +140,9 @@ A continuation chunk (`start_pos > 0`) attends the session's existing rows: the `[0, start_pos)` gathered rows plus the chunk at the `start_pos` offset, keys pad to the QK key grid's 64-tile, and the score slabs widen to `nk64` columns while the rows stay the `mp` queries. -Cooperative matmul ops constrain the kernel bodies two ways. The accumulate loop is spelled ROLLED -over matrix arrays with pointer tile bumps: the hand-unrolled spelling hoists sixteen tile +Cooperative matmul ops shape the kernel bodies: the accumulate loop is spelled ROLLED over +matrix arrays with pointer tile bumps, because the hand-unrolled spelling hoists sixteen tile addresses into loop-lifetime registers and costs an occupancy tier (measured `max_threads` 704). -And an early exit inside such a body must be threadgroup-uniform. ### 2.2i Chunked submission and interleaved readback {#prefill-chunked-submit} diff --git a/modules/dasLLAMA/REVIEW.md b/modules/dasLLAMA/REVIEW.md index 74df4af13d..a2434af009 100644 --- a/modules/dasLLAMA/REVIEW.md +++ b/modules/dasLLAMA/REVIEW.md @@ -63,6 +63,7 @@ that can change between dispatches goes in a uniform, a kargs field, or an `@off **Never reorder or merge the float multiplies in a function that builds a RoPE angle table (`dasllama/dasllama_rope.das`) - keep the multiply order the code already has.** A regrouping moves the angles in the last bits and flips token-exact fixtures. + **A diff that changes a kernel-selection predicate in `dasllama/` is based on timing that ran both variants interleaved in one process, under one instrument.** The same holds for a constant in `dasllama/` whose value was chosen by timing two candidates against each other. A diff --git a/modules/dasLLAMA/REVIEW_GPU.md b/modules/dasLLAMA/REVIEW_GPU.md index 7c514e0935..525be52835 100644 --- a/modules/dasLLAMA/REVIEW_GPU.md +++ b/modules/dasLLAMA/REVIEW_GPU.md @@ -1,7 +1,7 @@ # dasLLAMA GPU Code Review Checklist **Read `REVIEW_COMMON.md` (repo root) first - its contract binds this checklist.** Architecture -doc: `ARCHITECTURE_GPU.md`. +docs: `ARCHITECTURE_GPU.md`, `ARCHITECTURE_GPU_PREFILL.md`. **Routed from `REVIEW.md`: a diff touching a GPU kernel, driver, dispatch class, or the K/V mirrors applies this list together with `REVIEW.md`.** @@ -10,15 +10,15 @@ mirrors applies this list together with `REVIEW.md`.** the choice at compile time instead.** A `class template` / `def abstract` / `def override` splice is compile-time and conforms - check the emission, not the das spelling. -**Never give a `*_decline_caps` predicate a parameter beyond the model and the call shape - its -row count and its span shape - however that parameter is derived; window-setup state is asked -by `prefill_decline` / `decode_decline` instead.** +**Never give a `*_decline_caps` predicate a parameter beyond the model, the row count, and +whether the call carries a uniform attention span - however that parameter is derived; +window-setup state is asked by `prefill_decline` / `decode_decline` instead.** **A bounds or tail guard that branches per iteration in a kernel's main loop, where the host already knows its answer as it picks the pipeline, is a defect - stamp the guard instead.** Stamped means the guard is carried by a `@template_constant` - a `static_if` block, or a value -select on the constant. The guard-free instance is the one stamped without the guard, and the -guard is absent from that instance's generated `*_msl` global. +select on the constant. The instance stamped without the guard shows no guard in its generated +`*_msl` global. **Never let a `matmul2d` left or right operand reach the op as `float` outside a kernel class stamped `[metal_kernel(float_a_ok=true)]` - convert it in the pass that writes the operand's @@ -42,13 +42,15 @@ arrays - read the one per-row entry instead.** The bucket-building kernel writes entry. The scan repeats on every thread of every row's threadgroup, and it grows with the bucket count. -**Never test a bucket row's validity by comparing it with the pad sentinel - compare it with -the live entry count instead.** Stale bytes past the last expert's stamped tail are not the -sentinel, and an equality test sends their token index out of bounds. +**Never test a bucket row's validity against the pad sentinel `0xFFFFFFFF` - compare the row's +bucket word with the live entry count (`npos * nk`) instead.** Rows past the last expert's +stamped tail hold stale pool bytes, not the sentinel, and an equality test sends their token +index out of bounds. -**An early `return` in a kernel body that runs a cooperative op is threadgroup-uniform - never -gate it on a per-thread value.** A per-thread exit leaves the threadgroup unable to complete -the cooperative op. +**Never gate an early `return` in a kernel body that runs a cooperative op - a `barrier()`, a +simdgroup matrix op, or a cross-lane reduction - on a per-thread value; gate it on a +threadgroup-uniform value instead.** A per-thread exit leaves the threadgroup unable to +complete the op. **An encoder that picks a kernel's guard-free instance shows that every address the instance touches stays inside rows holding real data.** The guard-free instance is the one stamped @@ -56,24 +58,20 @@ without the loop's bounds or tail guard. One extent dividing evenly is not that padded chunk's walk can run past the live extent, and one poisoned read in a shared tile corrupts real rows. -**Never let a prefill pad output row reach a matmul as a B operand - stage it as zero, or -bound the walk at the live row count.** Pad rows hold recycled pool bytes, so a pad row used -as B multiplies stale values (NaN included) into every real row of the tile. Pad rows read as -row-confined A operands are safe. +**Never let a prefill pad output row reach a `matmul2d` or a staged cooperative tile as its B +operand - stage it as zero, or bound the walk at the live row count.** Pad rows hold recycled +pool bytes, so a pad row used as B multiplies stale values (NaN included) into every real row +of the tile. **A prefill K/V panel is sized from the padded write extent, never from the live key count.** The K/V GEMMs write full M-tile rows at the chunk's row offset, so a panel sized to the live count is overrun silently into whatever the pool put next to it. -**Never route a GEMM site through the GEMV tail peel when its output row stride differs from -the dispatch width it passes - dispatch the padded tile instead.** The peel writes y rows at -that width, so a fused-row site whose rows are wider lands its tail rows on top of the row -beside them. - -**A diff that changes the mask, window, live-length or softcap math of `pf_p_weight` -(`dasllama/dasllama_metal_prefill.das`) changes `metal_attn_rowstat`'s copy in the same -change, and the reverse.** Rowstat mints each row's max and reciprocal sum; the AV kernels -apply the weight. Rows renormalize against the wrong max when the two disagree. +**Never pass `npos` to `enc_gemm_mm` (`dasllama/dasllama_metal_prefill.das`) from a GEMM site +whose output rows are wider than the `d` it passes - leave `npos` at zero and dispatch the +padded tile instead.** The tail peel - the up-to-8 remainder rows `enc_gemm_mm` sends to the +mv family - writes its y rows at that `d`, so a wider-row site lands its tail rows on top of +the row beside them. **Never leave a pipeline of dispatches with fewer scratch buffers than it has dispatches in flight - give each dispatch site its own instead.** One shared scratch serializes the whole @@ -97,8 +95,8 @@ axis - one compile-time choice, such as single/batch, format, or single-pass/chu **A copy-pasted kernel twin, or a kernel split into hand instances where a `static_if` on a `@template_constant` serves, is a defect - kernel twins stamp one `class template`, whatever -the stamp axis is (single/batch, format, single-pass/chunked).** Body divergence is carried by -a `@template_constant`, or by an overridden method spliced flat at emission. +the stamp axis is.** Body divergence is carried by a `@template_constant`, or by an +overridden method spliced flat at emission. **A dummy-bound field where a gate serves is a defect - a stamp-varying binding is carried by `@template_gate` instead.** @@ -116,8 +114,9 @@ defect; a per-encode field either omits `@role` or names the access its body per `weight` drops the hazard staging. **A new kernel class carries `[metal_dispatch]` / `[vk_dispatch]` with every annotation the -generated builder reads - per-field `@binding` / `@role` / `@off` / `@span` / `@default`, -`@workgroup` state with its `tgmem=` dispatch key.** +generated builder reads - per-field `@binding` / `@role` / `@off` / `@default`, `@span` on a +field whose callers bind whole output rows, `@workgroup` state with its `tgmem=` dispatch +key.** **Never give a `@span` to a kernel field whose callers bind a COLUMN TILE of a wider output row - omit the span instead.** A column-tile caller passes the tile width as the kernel's n @@ -144,22 +143,21 @@ layout the upload produces, in the key too.** A hit must cover the request. capability with no matching role gets its own role file.** `ARCHITECTURE_GPU.md` sec.1.5 carries the role table. -**Never add a role's file to a backend that does not have the capability.** - **A module that creates its own GPU device or queue is a defect - a GPU family shares the one device and queue from `dasllama/dasllama__common.das`'s init.** -**Never compile or release a Metal PSO from an engine file (`dasllama/`) other than the one -that owns its kernel class** - it goes through that file's own init/release pair. +**Never compile or release a Metal PSO (pipeline state object) from an engine file +(`dasllama/`) other than the one that owns its kernel class** - it goes through that file's +own init/release pair. **Never put race code outside the file that owns the kernel family - the shared scaffolding (`race_buf`, `race_envelope_ok`, `race_pair_ms`) belongs to `dasllama/dasllama__common.das`.** Race code is the in-engine base-vs-twin check that times both kernels on one queue and compares their outputs. -**A kernel A/B race sizes its operands at a real model shape - never at a small square slab.** -A slab small enough to sit in cache ranks the kernels by an effect production never sees, and -crowns the loser. +**Race code sizes its operands at a real model shape - never at a small square slab.** A slab +small enough to sit in cache ranks the kernels by an effect production never sees, and the +race then picks the slower kernel. **A string-typed Metal decline reason is a defect - a Metal decline reason is an enum value in `dasllama/dasllama_metal_shapes.das`, one enum per driver.** @@ -178,9 +176,9 @@ carry does not exist. is created only by a `[vk_dispatch]`-generated `ensure_*` and torn down by `vk_drop_model_state`.** -**Never size a buffer bound as one SSBO range above `vk_max_storage_range()` - check the size -where it is NEGOTIATED, not where it binds.** The bind site cannot shrink a buffer that was -sized wrong. +**Never size a buffer bound as one SSBO (shader storage buffer) range above +`vk_max_storage_range()` - check the size where it is NEGOTIATED, not where it binds.** The +bind site cannot shrink a buffer that was sized wrong. **A change to code that a served GPU decode or prefill path executes ships GPU-vs-CPU parity on one q8 and one kq (K-quant) model with the armed mirror codec.** That code is a driver @@ -229,9 +227,9 @@ serves both codecs, so a codec no kernel covers silently drops that codec's GPU **An f16 store into any GPU-resident K/V that does not clamp to the f16 finite range (+/-65504) is a defect.** -**A per-layer K/V panel that aliases another layer's is gathered, stored and released only -through its source layer.** An aliasing layer that gathers, stores or releases a second time -double-frees the panel or overwrites the source's rows. +**A per-layer K/V panel or mirror slab that aliases another layer's is gathered, stored and +released only through its source layer.** An aliasing layer that gathers, stores or releases +a second time double-frees the panel or overwrites the source's rows. **A resident override that touches the mirror before gating the session on the armed mirror codec and on the flat (non-paged) cache is a defect** - a resident override is a diff --git a/modules/dasLLAMA/tests/REVIEW.md b/modules/dasLLAMA/tests/REVIEW.md index 95c4e00ec1..84f95553f0 100644 --- a/modules/dasLLAMA/tests/REVIEW.md +++ b/modules/dasLLAMA/tests/REVIEW.md @@ -54,6 +54,11 @@ defect.** **Weakening `test_model_specs.das` is a defect.** It is the gate on the model-set table (`../performance/model_specs.das`). +**Weakening the attention-trio softcap, sink and span cells of +`test_metal_prefill_kernels.das` is a defect** - they are the only cells that fail when +`pf_p_weight` and `metal_attn_rowstat` drift apart; rows renormalize against the wrong max +when the two disagree. + **Weakening `test_exchange_schema.das` or `test_bench_records_schema.das` - loosening an assert, dropping one, or narrowing the corpus either one sweeps - is a defect** - they gate the real `write_bench_records` output. From ed61fc18d4164aab01c3b5d37446c9cbf4fdbd7a Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Thu, 27 Aug 2026 15:47:59 -0700 Subject: [PATCH 05/10] dasLLAMA metal: tall in-kernel-dequant kq stamps for the DRAM-class deep sites The Mistral-24B residue attribution (a new devw_cvt knockout that skips only the dequant dispatches) showed the whole remaining gap was dev-W's materialization traffic: mm-only would already be 1.04x upstream, but 40 layers x three 335MB f16 panels write+re-stream ~10.6 B/element where upstream's in-kernel dequant reads ~2.2. The tall-kq wave was cancelled on cache-adjacent 4B panels; at DRAM-class panels the calculus inverts, and the 1.28x tg-staging tax it was cancelled against predates the zero-init fix. New KqMulMmK4/K5/K6 TH128 stamps (dense templates gain MT + an X offset for the row remainder); the pick takes them on K-quant sites whose dev-W tiling would exceed 8 tiles, ahead of dev-W. Mistral-24B pp512: 889 -> 1107 tok/s (+24.5%, 0.897x -> 1.117x upstream - the board's worst red now leads the yardstick). Census: all 120 deep FFN sites on the tall stamps, dequant dispatches 1700 -> 220. Controls exactly flat: 4B-Q4KM 5227, 12B 1688, 26B-A4B 3643, 27Bs 726/715 (a first cold r3 sweep mis-read the 27Bs as -7%; the warm reruns match the board to the tok/s - the cold-first-process law). Gates: kq gate tall legs bit-tolerant green with a tall-only poison negative control; kq parity arm token-exact; Mistral argmax logit-exact. ARCHITECTURE_GPU_PREFILL.md 2.2c/2.2d updated in the same change. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014fKJGuUL8tP58Y6NvoVeSn --- modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md | 21 ++-- .../dasllama/dasllama_metal_prefill.das | 118 ++++++++++++++---- .../tests/test_metal_gemm_kernels.das | 24 ++-- 3 files changed, 125 insertions(+), 38 deletions(-) diff --git a/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md b/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md index 01cac8b38b..fde1008235 100644 --- a/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md +++ b/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md @@ -6,18 +6,23 @@ Companion to `ARCHITECTURE.md`; section numbers are that document's. Every weight GEMM in `dasllama/dasllama_metal_prefill.das` splits its rows across two decisions. First the GEMV tail peel (sec.2.2e) takes up to `MM_TAIL_MAX` remainder rows off the padded tile. -The rows that remain pick one of three forms, in this order, per site per forward: - -1. **dev-W all-device** - the weight plane is dequantized into a device f16 panel and multiplied +The rows that remain pick one of four forms, in this order, per site per forward: + +1. **tall in-kernel-dequant (K-quant deep class)** - a K-quant site whose panel dev-W would + split past 8 tiles is DRAM-resident, and there the `KqMulMm*TH128` stamp wins: it dequants + its own W tile in threadgroup memory and reads the quant plane (~0.56 B/element) once per + 128-row tile, where a materialized f16 panel writes 2 B/element and re-streams them per + tile. The 32-row TH stamp covers the row remainder at its X/y offsets. +2. **dev-W all-device** - the weight plane is dequantized into a device f16 panel and multiplied half x half. No threadgroup staging and no barriers, so the staged-operand tax is gone; the dequant pass is paid once per site per forward against a GEMM that re-reads the f16 W panel once per M row tile (`mp/128` on the tall stamp, `mp/32` on the 32-row stamp). sec.2.2d carries the panel size rules. -2. **tall 128-row M-tile** - the stamp streams W `M/128` times over a 128-row tile, taken on the +3. **tall 128-row M-tile** - the stamp streams W `M/128` times over a 128-row tile, taken on the row count's 128-floor with the 32-row stamp on the remainder. The remainder arm strides X by `kdim`, so a caller that passes no `kdim` takes the tall stamp only when its row count is already a multiple of 128, and otherwise stays whole-dispatch 32-tile. -3. **32-row tile** - the default stamp. +4. **32-row tile** - the default stamp. **Half operands ride an f16 activation panel.** One pass converts the f32 panel; the GEMM then re-reads it at half the bytes `d/64` times, so the convert amortizes above a row floor @@ -57,8 +62,10 @@ sites: rows measures zero to negative end to end. - **An over-knee panel runs as N-column TILES**, each under the small-panel knee, with the tile count bounded by `DEVW_MAX_TILES` (32), divisibility, the small-panel knee and the pool. - Deep-dense models (300 MB+ up/gate/down planes) need up to that many tiles, and narrow tiles - measure fine - a 20-threadgroup tile dispatch still beat the tg-staged fallback at 512 rows. + Narrow tiles measure fine - a 20-threadgroup tile dispatch still beat the tg-staged fallback + at 512 rows. A K-quant site needing more than 8 tiles leaves dev-W entirely for the tall + in-kernel-dequant stamp (sec.2.2c form 1): at that size the panel is DRAM-resident and the + f16 materialization plus re-stream loses to reading the quant plane in-kernel. - **A k-quant tg fallback is about 1.28x the q8 half-panel form**, so a k-quant site lowers the over-knee bar, the tiled-rows floor, and the long-K floor (1024 rows to 512): a tiled read still beats THAT fallback. diff --git a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das index 8fd5894db2..413dd90995 100644 --- a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das +++ b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das @@ -423,10 +423,11 @@ class MetalPleFinish { [ |> template_struct_instance] class template MetalKqMulMmK45TensorT { + @template_constant MT : uint = 32u @ssbo @binding = 0 @role = "weight" @off = "s0off" ksh : array //!< 16B scale blocks, half view (d, dmin at 8*blk) @ssbo @binding = 1 @role = "weight" @off = "soff" ks4 : array //!< the same buffer, uint4 view @ssbo @binding = 2 @role = "weight" @off = "qoff" kqu : array //!< quant plane, uint view (qs at BLK*blk; k5 qh at BLK*blk+32) - @ssbo @binding = 3 xf : array //!< raw activations (float, or the converted f16 panel) + @ssbo @binding = 3 @off = "xoff" xf : array //!< raw activations (float, or the converted f16 panel) @ssbo @binding = 4 @off = "yoff" @span = "mp*rows*4" y : array @uniform @binding = 5 kdim : uint @uniform @binding = 6 ndim : uint @@ -436,14 +437,14 @@ class template MetalKqMulMmK45TensorT { [metal_kernel(float_a_ok=true)] def metal_kq_mulmm_t { - let mBase = gl_WorkGroupID.x * 32u + let mBase = gl_WorkGroupID.x * MT let nBase = gl_WorkGroupID.y * 64u let nkb = kdim / 32u let nsb = kdim / 256u let lid = gl_LocalInvocationID.x - var acc : float[2048] + var acc : float[8192] var cp = unsafe(addr(y[mBase * ndim + nBase])) - tmm2d_tg_begin_deva(acc, unsafe(addr(xf[0])), 32u, 64u, 4u, 64u) + tmm2d_tg_begin_deva(acc, unsafe(addr(xf[0])), MT, 64u, 4u, 64u) var kb = 0u while (kb < nkb) { var work = lid @@ -484,11 +485,11 @@ class template MetalKqMulMmK45TensorT { work += gl_WorkGroupSize.x } barrier() - tmm2d_tg_step_deva(acc, unsafe(addr(xf[mBase * kdim + kb * 32u])), kdim, twb, 32u, 64u, 64u) + tmm2d_tg_step_deva(acc, unsafe(addr(xf[mBase * kdim + kb * 32u])), kdim, twb, MT, 64u, 64u) barrier() kb += 2u } - tmm2d_tg_store(acc, cp, 32u, 64u, ndim) + tmm2d_tg_store(acc, cp, MT, 64u, ndim) } } @@ -516,12 +517,29 @@ class MetalKqMulMmK5TH : MetalKqMulMmK45TensorT { override QH = true } +// tall 128-row stamps: in-kernel dequant with W read once per 128-row tile - the DRAM-class +// panel form (dev-W's materialized panel re-streams 2B/element; these read the quant plane) +[metal_dispatch(name = "enc_kq_mm_k4_th128_c", pso = "g_pf_pso_kq_mm4_th128", tgmem = "MetalKqMulMmK4TH128_metal_kq_mulmm_t_msl_tgmem", tg = 128, grid = "mp/128, rows/64", params = "mp : int64, rows : int64")] +class MetalKqMulMmK4TH128 : MetalKqMulMmK45TensorT { + typedef XT = float16 + override MT = 128u +} + +[metal_dispatch(name = "enc_kq_mm_k5_th128_c", pso = "g_pf_pso_kq_mm5_th128", tgmem = "MetalKqMulMmK5TH128_metal_kq_mulmm_t_msl_tgmem", tg = 128, grid = "mp/128, rows/64", params = "mp : int64, rows : int64")] +class MetalKqMulMmK5TH128 : MetalKqMulMmK45TensorT { + typedef XT = float16 + override BLK = 40u + override QH = true + override MT = 128u +} + [ |> template_struct_instance] class template MetalKqMulMmK6TensorT { + @template_constant MT : uint = 32u @ssbo @binding = 0 @role = "weight" @off = "s0off" kdh : array //!< d plane (scale buffer at byte nsb*16; s0off = the caller's doff) @ssbo @binding = 1 @role = "weight" @off = "soff" ksc : array //!< 16B sub-scale blocks, same buffer at 0 @ssbo @binding = 2 @role = "weight" @off = "qoff" kqu : array //!< ql at 48*blk, qh at 48*blk+32 - @ssbo @binding = 3 xf : array //!< raw activations (float, or the converted f16 panel) + @ssbo @binding = 3 @off = "xoff" xf : array //!< raw activations (float, or the converted f16 panel) @ssbo @binding = 4 @off = "yoff" @span = "mp*rows*4" y : array @uniform @binding = 5 kdim : uint @uniform @binding = 6 ndim : uint @@ -529,14 +547,14 @@ class template MetalKqMulMmK6TensorT { [metal_kernel(float_a_ok=true)] def metal_kq_mulmm_k6_t { - let mBase = gl_WorkGroupID.x * 32u + let mBase = gl_WorkGroupID.x * MT let nBase = gl_WorkGroupID.y * 64u let nkb = kdim / 32u let nsb = kdim / 256u let lid = gl_LocalInvocationID.x - var acc : float[2048] + var acc : float[8192] var cp = unsafe(addr(y[mBase * ndim + nBase])) - tmm2d_tg_begin_deva(acc, unsafe(addr(xf[0])), 32u, 64u, 4u, 64u) + tmm2d_tg_begin_deva(acc, unsafe(addr(xf[0])), MT, 64u, 4u, 64u) var kb = 0u while (kb < nkb) { var work = lid @@ -570,11 +588,11 @@ class template MetalKqMulMmK6TensorT { work += gl_WorkGroupSize.x } barrier() - tmm2d_tg_step_deva(acc, unsafe(addr(xf[mBase * kdim + kb * 32u])), kdim, twb, 32u, 64u, 64u) + tmm2d_tg_step_deva(acc, unsafe(addr(xf[mBase * kdim + kb * 32u])), kdim, twb, MT, 64u, 64u) barrier() kb += 2u } - tmm2d_tg_store(acc, cp, 32u, 64u, ndim) + tmm2d_tg_store(acc, cp, MT, 64u, ndim) } } @@ -588,6 +606,12 @@ class MetalKqMulMmK6TH : MetalKqMulMmK6TensorT { typedef XT = float16 } +[metal_dispatch(name = "enc_kq_mm_k6_th128_c", pso = "g_pf_pso_kq_mm6_th128", tgmem = "MetalKqMulMmK6TH128_metal_kq_mulmm_k6_t_msl_tgmem", tg = 128, grid = "mp/128, rows/64", params = "mp : int64, rows : int64")] +class MetalKqMulMmK6TH128 : MetalKqMulMmK6TensorT { + typedef XT = float16 + override MT = 128u +} + struct MoeMmArgs { @@ -2285,12 +2309,15 @@ var private g_pf_pso_moe_mm_k6_thr : MetalComputePipeline? var private g_pf_kq_mm4_tensor : bool //!< "kq_mulmm_k4" crowned var private g_pf_pso_kq_mm4_t : MetalComputePipeline? var private g_pf_pso_kq_mm4_th : MetalComputePipeline? +var private g_pf_pso_kq_mm4_th128 : MetalComputePipeline? //!< tall stamp - the DRAM-class panel form var private g_pf_kq_mm5_tensor : bool //!< "kq_mulmm_k5" crowned var private g_pf_pso_kq_mm5_t : MetalComputePipeline? var private g_pf_pso_kq_mm5_th : MetalComputePipeline? +var private g_pf_pso_kq_mm5_th128 : MetalComputePipeline? var private g_pf_kq_mm6_tensor : bool //!< "kq_mulmm_k6" crowned var private g_pf_pso_kq_mm6_t : MetalComputePipeline? var private g_pf_pso_kq_mm6_th : MetalComputePipeline? +var private g_pf_pso_kq_mm6_th128 : MetalComputePipeline? var private g_pf_qkmm_tensor : bool //!< "attn_qkmm" crowned var private g_pf_pso_qkmm_t : MetalComputePipeline? var private g_pf_pso_qkmm_th : MetalComputePipeline? @@ -2503,6 +2530,10 @@ def public metal_prefill_shutdown { // nolint:STYLE037,STYLE038 — flat one-r metal_release(g_pf_pso_kq_mm4_th) g_pf_pso_kq_mm4_th = null } + if (g_pf_pso_kq_mm4_th128 != null) { + metal_release(g_pf_pso_kq_mm4_th128) + g_pf_pso_kq_mm4_th128 = null + } if (g_pf_pso_kq_mm5_t != null) { metal_release(g_pf_pso_kq_mm5_t) g_pf_pso_kq_mm5_t = null @@ -2511,6 +2542,10 @@ def public metal_prefill_shutdown { // nolint:STYLE037,STYLE038 — flat one-r metal_release(g_pf_pso_kq_mm5_th) g_pf_pso_kq_mm5_th = null } + if (g_pf_pso_kq_mm5_th128 != null) { + metal_release(g_pf_pso_kq_mm5_th128) + g_pf_pso_kq_mm5_th128 = null + } if (g_pf_pso_kq_mm6_t != null) { metal_release(g_pf_pso_kq_mm6_t) g_pf_pso_kq_mm6_t = null @@ -2519,6 +2554,10 @@ def public metal_prefill_shutdown { // nolint:STYLE037,STYLE038 — flat one-r metal_release(g_pf_pso_kq_mm6_th) g_pf_pso_kq_mm6_th = null } + if (g_pf_pso_kq_mm6_th128 != null) { + metal_release(g_pf_pso_kq_mm6_th128) + g_pf_pso_kq_mm6_th128 = null + } g_pf_inited = false if (g_pf_pso_rope != null) { metal_release(g_pf_pso_rope) @@ -2740,16 +2779,19 @@ def private metal_prefill_init : bool { // nolint:STYLE038 — flat one-compil if (g_pf_kq_mm4_tensor) { g_pf_pso_kq_mm4_t = compile_pso(MetalKqMulMmK4T_metal_kq_mulmm_t_msl, MetalKqMulMmK4T_metal_kq_mulmm_t_msl_entry, MetalKqMulMmK4T_metal_kq_mulmm_t_msl_fastmath, ok) g_pf_pso_kq_mm4_th = compile_pso(MetalKqMulMmK4TH_metal_kq_mulmm_t_msl, MetalKqMulMmK4TH_metal_kq_mulmm_t_msl_entry, MetalKqMulMmK4TH_metal_kq_mulmm_t_msl_fastmath, ok) + g_pf_pso_kq_mm4_th128 = compile_pso(MetalKqMulMmK4TH128_metal_kq_mulmm_t_msl, MetalKqMulMmK4TH128_metal_kq_mulmm_t_msl_entry, MetalKqMulMmK4TH128_metal_kq_mulmm_t_msl_fastmath, ok) } g_pf_kq_mm5_tensor = metal_tensor_crowned("kq_mulmm_k5") if (g_pf_kq_mm5_tensor) { g_pf_pso_kq_mm5_t = compile_pso(MetalKqMulMmK5T_metal_kq_mulmm_t_msl, MetalKqMulMmK5T_metal_kq_mulmm_t_msl_entry, MetalKqMulMmK5T_metal_kq_mulmm_t_msl_fastmath, ok) g_pf_pso_kq_mm5_th = compile_pso(MetalKqMulMmK5TH_metal_kq_mulmm_t_msl, MetalKqMulMmK5TH_metal_kq_mulmm_t_msl_entry, MetalKqMulMmK5TH_metal_kq_mulmm_t_msl_fastmath, ok) + g_pf_pso_kq_mm5_th128 = compile_pso(MetalKqMulMmK5TH128_metal_kq_mulmm_t_msl, MetalKqMulMmK5TH128_metal_kq_mulmm_t_msl_entry, MetalKqMulMmK5TH128_metal_kq_mulmm_t_msl_fastmath, ok) } g_pf_kq_mm6_tensor = metal_tensor_crowned("kq_mulmm_k6") if (g_pf_kq_mm6_tensor) { g_pf_pso_kq_mm6_t = compile_pso(MetalKqMulMmK6T_metal_kq_mulmm_k6_t_msl, MetalKqMulMmK6T_metal_kq_mulmm_k6_t_msl_entry, MetalKqMulMmK6T_metal_kq_mulmm_k6_t_msl_fastmath, ok) g_pf_pso_kq_mm6_th = compile_pso(MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl, MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl_entry, MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl_fastmath, ok) + g_pf_pso_kq_mm6_th128 = compile_pso(MetalKqMulMmK6TH128_metal_kq_mulmm_k6_t_msl, MetalKqMulMmK6TH128_metal_kq_mulmm_k6_t_msl_entry, MetalKqMulMmK6TH128_metal_kq_mulmm_k6_t_msl_fastmath, ok) } //! dev-W: ONE all-device GEMM for every crowned family; dequant passes compile per family if (g_pf_mm_tensor || g_pf_kq_mm4_tensor || g_pf_kq_mm5_tensor || g_pf_kq_mm6_tensor) { @@ -3017,7 +3059,9 @@ def private pf_enc_devw_q8_tile(enc : MetalComputeEncoder?; bwblob : MetalBuffer let nb = kdim / 32l let nblk = td * nb var dka = CvtArgs(total = uint(nblk)) - enc_dequant_q8h(enc, bwblob, wboff + uint64(tbase * nb * 34l), bwblob, bwh, dka, (nblk + 255l) / 256l * 256l) + if (g_pf_skip != "devw_cvt") { // attribution: stale W panel, the mm's traffic unchanged + enc_dequant_q8h(enc, bwblob, wboff + uint64(tbase * nb * 34l), bwblob, bwh, dka, (nblk + 255l) / 256l * 256l) + } pf_enc_hmm(enc, bwh, bxh, by, yoff + uint64(tbase * 4l), bk, bn, rows, td, dfull, kdim) } @@ -3057,7 +3101,8 @@ def private pf_devw_panel_kq(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; var dka = CvtArgs(total = uint(nblk)) let gt = (nblk + 255l) / 256l * 256l let so = uint64(tbase * nsb * 16l) - if (fmt == KqFmt.k6) { + if (g_pf_skip == "devw_cvt") { // attribution: stale W panel, the mm's traffic unchanged + } elif (fmt == KqFmt.k6) { enc_dequant_k6h(enc, bs.buf, bs.doff + uint64(tbase * nsb * 2l), bs.buf, bs.soff + so, bq.buf, bq.qoff + uint64(tbase * nsb * 192l), bwh, dka, gt) } elif (fmt == KqFmt.k4) { enc_dequant_k4h(enc, bs.buf, bs.soff + so, bs.buf, bs.soff + so, bq.buf, bq.qoff + uint64(tbase * nsb * 128l), bwh, dka, gt) @@ -3163,23 +3208,48 @@ def pf_enc_bf16_mm(enc : MetalComputeEncoder?; bw : MetalBuffer?; wboff : uint64 } //! k6 binds its split scale plane twice: sub-scales at soff, the f16 d tail at doff -def private pf_enc_kq_site_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; woff, rows : int64; +def private pf_enc_kq_site_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; woff, rows : int64; // nolint:STYLE037 — flat per-format form-pick ladder bx, by, bk, bn : MetalBuffer?; mp : int64; yoff : uint64 = 0ul; bxh : MetalBuffer? = null; kdim : int64 = 0l) { - //! dev-W arm: shared all-device GEMM, per-format dequant pass, only behind the fmt's crown let fmt_tensor = fmt == KqFmt.k6 ? g_pf_kq_mm6_tensor : (fmt == KqFmt.k4 ? g_pf_kq_mm4_tensor : g_pf_kq_mm5_tensor) + let bq = kq_quants_of(g_dev, t, fmt, woff) + let bs = kq_scales_of(g_dev, t, fmt, woff) + //! deep-class arm: a panel dev-W would split past 8 tiles is DRAM-resident - the tall + //! in-kernel-dequant stamp reads the quant plane once per 128-row tile instead of + //! materializing and re-streaming a 2B/element f16 panel + let tall128 = fmt == KqFmt.k6 ? g_pf_pso_kq_mm6_th128 : (fmt == KqFmt.k4 ? g_pf_pso_kq_mm4_th128 : g_pf_pso_kq_mm5_th128) + if (fmt_tensor && bxh != null && tall128 != null && kdim > 0l && mp >= 128l + && pf_devw_tiles(mp, rows, kdim, slow_fb = true) > 8l) { + let r0 = mp / 128l * 128l + if (fmt == KqFmt.k6) { + enc_kq_mm_k6_th128_c(enc, bs.buf, bs.doff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, 0ul, by, yoff, bk, bn, r0, rows) + if (mp - r0 > 0l) { + enc_kq_mm_k6_th_c(enc, bs.buf, bs.doff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, uint64(r0 * kdim * 2l), by, yoff + uint64(r0 * rows * 4l), bk, bn, mp - r0, rows) + } + } elif (fmt == KqFmt.k4) { + enc_kq_mm_k4_th128_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, 0ul, by, yoff, bk, bn, r0, rows) + if (mp - r0 > 0l) { + enc_kq_mm_k4_th_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, uint64(r0 * kdim * 2l), by, yoff + uint64(r0 * rows * 4l), bk, bn, mp - r0, rows) + } + } else { + enc_kq_mm_k5_th128_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, 0ul, by, yoff, bk, bn, r0, rows) + if (mp - r0 > 0l) { + enc_kq_mm_k5_th_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, uint64(r0 * kdim * 2l), by, yoff + uint64(r0 * rows * 4l), bk, bn, mp - r0, rows) + } + } + return + } + //! dev-W arm: shared all-device GEMM, per-format dequant pass, only behind the fmt's crown if (fmt_tensor && bxh != null && g_pf_pso_hmm_th != null && kdim > 0l) { if (pf_devw_panel_kq(enc, t, fmt, woff, bxh, by, bk, bn, mp, rows, kdim, yoff)) { return } } - let bq = kq_quants_of(g_dev, t, fmt, woff) - let bs = kq_scales_of(g_dev, t, fmt, woff) if (fmt == KqFmt.k6) { if (g_pf_kq_mm6_tensor && g_pf_pso_kq_mm6_t != null) { if (bxh != null && g_pf_pso_kq_mm6_th != null) { - enc_kq_mm_k6_th_c(enc, bs.buf, bs.doff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, by, yoff, bk, bn, mp, rows) + enc_kq_mm_k6_th_c(enc, bs.buf, bs.doff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, 0ul, by, yoff, bk, bn, mp, rows) } else { - enc_kq_mm_k6_t_c(enc, bs.buf, bs.doff, bs.buf, bs.soff, bq.buf, bq.qoff, bx, by, yoff, bk, bn, mp, rows) + enc_kq_mm_k6_t_c(enc, bs.buf, bs.doff, bs.buf, bs.soff, bq.buf, bq.qoff, bx, 0ul, by, yoff, bk, bn, mp, rows) } } else { enc_kq_mm_k6_c(enc, bs.buf, bs.doff, bs.buf, bs.soff, bq.buf, bq.qoff, bx, by, yoff, bk, bn, mp, rows) @@ -3187,9 +3257,9 @@ def private pf_enc_kq_site_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt } elif (fmt == KqFmt.k4) { if (g_pf_kq_mm4_tensor && g_pf_pso_kq_mm4_t != null) { if (bxh != null && g_pf_pso_kq_mm4_th != null) { - enc_kq_mm_k4_th_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, by, yoff, bk, bn, mp, rows) + enc_kq_mm_k4_th_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, 0ul, by, yoff, bk, bn, mp, rows) } else { - enc_kq_mm_k4_t_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bx, by, yoff, bk, bn, mp, rows) + enc_kq_mm_k4_t_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bx, 0ul, by, yoff, bk, bn, mp, rows) } } else { enc_kq_mm_k4_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bx, by, yoff, bk, bn, mp, rows) @@ -3197,9 +3267,9 @@ def private pf_enc_kq_site_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt } else { if (g_pf_kq_mm5_tensor && g_pf_pso_kq_mm5_t != null) { if (bxh != null && g_pf_pso_kq_mm5_th != null) { - enc_kq_mm_k5_th_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, by, yoff, bk, bn, mp, rows) + enc_kq_mm_k5_th_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, 0ul, by, yoff, bk, bn, mp, rows) } else { - enc_kq_mm_k5_t_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bx, by, yoff, bk, bn, mp, rows) + enc_kq_mm_k5_t_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bx, 0ul, by, yoff, bk, bn, mp, rows) } } else { enc_kq_mm_k5_c(enc, bs.buf, bs.soff, bs.buf, bs.soff, bq.buf, bq.qoff, bx, by, yoff, bk, bn, mp, rows) diff --git a/modules/dasLLAMA/tests/test_metal_gemm_kernels.das b/modules/dasLLAMA/tests/test_metal_gemm_kernels.das index 9308f97224..0047dd99fc 100644 --- a/modules/dasLLAMA/tests/test_metal_gemm_kernels.das +++ b/modules/dasLLAMA/tests/test_metal_gemm_kernels.das @@ -26,26 +26,34 @@ require math // fails to compile is a RED, and the simdgroup bases always assert. Off-Apple (or with no // Metal device) every check feints. -def private kq_mulmm_gate(t : T?; dev, queue; fmt : int; tensor : bool; m, kdim, ndim : int; halfx : bool = false) { - let tag = "kq_mulmm_k{fmt}{tensor ? "t" : ""}{halfx ? " halfx" : ""} m={m} k={kdim} n={ndim}" +def private kq_mulmm_gate(t : T?; dev, queue; fmt : int; tensor : bool; m, kdim, ndim : int; halfx : bool = false; tall : bool = false) { + let tag = "kq_mulmm_k{fmt}{tensor ? "t" : ""}{tall ? " tall" : ""}{halfx ? " halfx" : ""} m={m} k={kdim} n={ndim}" var err : string let src = (tensor - ? (halfx + ? (tall + ? (fmt == 4 ? MetalKqMulMmK4TH128_metal_kq_mulmm_t_msl : (fmt == 5 ? MetalKqMulMmK5TH128_metal_kq_mulmm_t_msl : MetalKqMulMmK6TH128_metal_kq_mulmm_k6_t_msl)) + : halfx ? (fmt == 4 ? MetalKqMulMmK4TH_metal_kq_mulmm_t_msl : (fmt == 5 ? MetalKqMulMmK5TH_metal_kq_mulmm_t_msl : MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl)) : (fmt == 4 ? MetalKqMulMmK4T_metal_kq_mulmm_t_msl : (fmt == 5 ? MetalKqMulMmK5T_metal_kq_mulmm_t_msl : MetalKqMulMmK6T_metal_kq_mulmm_k6_t_msl))) : (fmt == 4 ? MetalKqMulMmK4_metal_kq_mulmm_msl : (fmt == 5 ? MetalKqMulMmK5_metal_kq_mulmm_msl : MetalKqMulMmK6_metal_kq_mulmm_msl))) let entry = (tensor - ? (halfx + ? (tall + ? (fmt == 4 ? MetalKqMulMmK4TH128_metal_kq_mulmm_t_msl_entry : (fmt == 5 ? MetalKqMulMmK5TH128_metal_kq_mulmm_t_msl_entry : MetalKqMulMmK6TH128_metal_kq_mulmm_k6_t_msl_entry)) + : halfx ? (fmt == 4 ? MetalKqMulMmK4TH_metal_kq_mulmm_t_msl_entry : (fmt == 5 ? MetalKqMulMmK5TH_metal_kq_mulmm_t_msl_entry : MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl_entry)) : (fmt == 4 ? MetalKqMulMmK4T_metal_kq_mulmm_t_msl_entry : (fmt == 5 ? MetalKqMulMmK5T_metal_kq_mulmm_t_msl_entry : MetalKqMulMmK6T_metal_kq_mulmm_k6_t_msl_entry))) : (fmt == 4 ? MetalKqMulMmK4_metal_kq_mulmm_msl_entry : (fmt == 5 ? MetalKqMulMmK5_metal_kq_mulmm_msl_entry : MetalKqMulMmK6_metal_kq_mulmm_msl_entry))) let fm = (tensor - ? (halfx + ? (tall + ? (fmt == 4 ? MetalKqMulMmK4TH128_metal_kq_mulmm_t_msl_fastmath : (fmt == 5 ? MetalKqMulMmK5TH128_metal_kq_mulmm_t_msl_fastmath : MetalKqMulMmK6TH128_metal_kq_mulmm_k6_t_msl_fastmath)) + : halfx ? (fmt == 4 ? MetalKqMulMmK4TH_metal_kq_mulmm_t_msl_fastmath : (fmt == 5 ? MetalKqMulMmK5TH_metal_kq_mulmm_t_msl_fastmath : MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl_fastmath)) : (fmt == 4 ? MetalKqMulMmK4T_metal_kq_mulmm_t_msl_fastmath : (fmt == 5 ? MetalKqMulMmK5T_metal_kq_mulmm_t_msl_fastmath : MetalKqMulMmK6T_metal_kq_mulmm_k6_t_msl_fastmath))) : (fmt == 4 ? MetalKqMulMmK4_metal_kq_mulmm_msl_fastmath : (fmt == 5 ? MetalKqMulMmK5_metal_kq_mulmm_msl_fastmath : MetalKqMulMmK6_metal_kq_mulmm_msl_fastmath))) let tgm = (tensor - ? (halfx + ? (tall + ? (fmt == 4 ? MetalKqMulMmK4TH128_metal_kq_mulmm_t_msl_tgmem : (fmt == 5 ? MetalKqMulMmK5TH128_metal_kq_mulmm_t_msl_tgmem : MetalKqMulMmK6TH128_metal_kq_mulmm_k6_t_msl_tgmem)) + : halfx ? (fmt == 4 ? MetalKqMulMmK4TH_metal_kq_mulmm_t_msl_tgmem : (fmt == 5 ? MetalKqMulMmK5TH_metal_kq_mulmm_t_msl_tgmem : MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl_tgmem)) : (fmt == 4 ? MetalKqMulMmK4T_metal_kq_mulmm_t_msl_tgmem : (fmt == 5 ? MetalKqMulMmK5T_metal_kq_mulmm_t_msl_tgmem : MetalKqMulMmK6T_metal_kq_mulmm_k6_t_msl_tgmem))) : (fmt == 4 ? MetalKqMulMmK4_metal_kq_mulmm_msl_tgmem : (fmt == 5 ? MetalKqMulMmK5_metal_kq_mulmm_msl_tgmem : MetalKqMulMmK6_metal_kq_mulmm_msl_tgmem))) @@ -110,7 +118,7 @@ def private kq_mulmm_gate(t : T?; dev, queue; fmt : int; tensor : bool; m, kdim, metal_set_buffer(enc, by, 0ul, 4) metal_set_buffer(enc, bk, 0ul, 5) metal_set_buffer(enc, bn, 0ul, 6) - metal_dispatch_threadgroups(enc, uint3(uint(m / 32), uint(ndim / 64), 1u), uint3(128u, 1u, 1u)) + metal_dispatch_threadgroups(enc, uint3(uint(m / (tall ? 128 : 32)), uint(ndim / 64), 1u), uint3(128u, 1u, 1u)) } t |> success(ran, "{tag}: encode: {err}") if (ran) { @@ -1680,6 +1688,8 @@ def test_metal_gemm_kernels(t : T?) { kq_mulmm_gate(t, dev, queue, fmt, false, 64, 512, 64) kq_mulmm_gate(t, dev, queue, fmt, true, 64, 512, 64) kq_mulmm_gate(t, dev, queue, fmt, true, 64, 512, 64, halfx = true) + // tall 128-row stamp: the deep-class in-kernel-dequant form (m = two tall tiles) + kq_mulmm_gate(t, dev, queue, fmt, true, 256, 512, 64, halfx = true, tall = true) } kq_mulmm_gate(t, dev, queue, 4, false, 32, 256, 128) // second shape: 2 col tiles q8_mulmm_t_gate(t, dev, queue, 64, 256, 64) From 3a41d806e1fa6da9d031219705c4c1fdd06c835f Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Thu, 27 Aug 2026 16:02:53 -0700 Subject: [PATCH 06/10] dasLLAMA metal: tall-kq gate widened and re-keyed to panel bytes The tile-count proxy raced two ways at once: the 12B's 118MiB FFN panels (tc=4) win +14.8% on the tall stamp while the 27B's 84MiB qkv (also tc=4) measures a small loss - the real knee is panel SIZE, not tile count. The gate is now TALLKQ_MIN_PANEL = 96MiB on the site's would-be f16 panel. pp512, warm r5: Qwen3.8-27B 726 -> 893 (+22.8%, 1.186x upstream); Qwen3.6-27B 715 -> 886 (+23.9%, 1.199x); gemma-4-12B 1688 -> 1940 (+14.8%, 1.139x). Mistral flat at 1107 (1.117x), 4B-Q4KM and 26B-A4B exactly flat. Every board-v7 red cell now leads the yardstick. Gates: kq parity arm token-exact; fam-gemma4 family matrix pass under PARITY_FULL. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014fKJGuUL8tP58Y6NvoVeSn --- modules/dasLLAMA/dasllama/dasllama_metal_prefill.das | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das index 413dd90995..cc6434169f 100644 --- a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das +++ b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das @@ -3218,7 +3218,7 @@ def private pf_enc_kq_site_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt //! materializing and re-streaming a 2B/element f16 panel let tall128 = fmt == KqFmt.k6 ? g_pf_pso_kq_mm6_th128 : (fmt == KqFmt.k4 ? g_pf_pso_kq_mm4_th128 : g_pf_pso_kq_mm5_th128) if (fmt_tensor && bxh != null && tall128 != null && kdim > 0l && mp >= 128l - && pf_devw_tiles(mp, rows, kdim, slow_fb = true) > 8l) { + && uint64(rows * kdim * 2l) >= TALLKQ_MIN_PANEL) { let r0 = mp / 128l * 128l if (fmt == KqFmt.k6) { enc_kq_mm_k6_th128_c(enc, bs.buf, bs.doff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, 0ul, by, yoff, bk, bn, r0, rows) @@ -4736,6 +4736,10 @@ let DEVW_BIG_ROWS = 2048l let DEVW_LONG_K = 4096l let DEVW_LONG_K_ROWS = 1024l let DEVW_MAX_TILES = 32l +// a kq site whose f16 panel would exceed this is DRAM-resident - the tall in-kernel-dequant +// stamp beats both dev-W tiling and the short tg twin there (raced: 118MiB+ wins 15-25%, +// 84MiB washes negative - the knee sits between) +var private TALLKQ_MIN_PANEL = 96ul * 1024ul * 1024ul var private g_pf_env_span = true var private g_pf_env_logits = true var private g_pf_env_attn = true From 667d4c1d5986d9609539c39a249cf6eb030fe884 Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Thu, 27 Aug 2026 16:03:25 -0700 Subject: [PATCH 07/10] dasLLAMA: ARCHITECTURE_GPU_PREFILL.md follows the tall-kq gate re-key Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014fKJGuUL8tP58Y6NvoVeSn --- modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md b/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md index fde1008235..75269fe89d 100644 --- a/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md +++ b/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md @@ -8,11 +8,13 @@ Every weight GEMM in `dasllama/dasllama_metal_prefill.das` splits its rows acros First the GEMV tail peel (sec.2.2e) takes up to `MM_TAIL_MAX` remainder rows off the padded tile. The rows that remain pick one of four forms, in this order, per site per forward: -1. **tall in-kernel-dequant (K-quant deep class)** - a K-quant site whose panel dev-W would - split past 8 tiles is DRAM-resident, and there the `KqMulMm*TH128` stamp wins: it dequants - its own W tile in threadgroup memory and reads the quant plane (~0.56 B/element) once per - 128-row tile, where a materialized f16 panel writes 2 B/element and re-streams them per - tile. The 32-row TH stamp covers the row remainder at its X/y offsets. +1. **tall in-kernel-dequant (K-quant deep class)** - a K-quant site whose f16 panel would + reach `TALLKQ_MIN_PANEL` (96 MiB) is DRAM-resident, and there the `KqMulMm*TH128` stamp + wins: it dequants its own W tile in threadgroup memory and reads the quant plane + (~0.56 B/element) once per 128-row tile, where a materialized f16 panel writes + 2 B/element and re-streams them per tile. The knee is panel SIZE, not tile count - a + 118 MiB panel wins 15-25% on the tall stamp while an 84 MiB one measures a small loss. + The 32-row TH stamp covers the row remainder at its X/y offsets. 2. **dev-W all-device** - the weight plane is dequantized into a device f16 panel and multiplied half x half. No threadgroup staging and no barriers, so the staged-operand tax is gone; the dequant pass is paid once per site per forward against a GEMM that re-reads the f16 W panel @@ -63,9 +65,10 @@ sites: - **An over-knee panel runs as N-column TILES**, each under the small-panel knee, with the tile count bounded by `DEVW_MAX_TILES` (32), divisibility, the small-panel knee and the pool. Narrow tiles measure fine - a 20-threadgroup tile dispatch still beat the tg-staged fallback - at 512 rows. A K-quant site needing more than 8 tiles leaves dev-W entirely for the tall - in-kernel-dequant stamp (sec.2.2c form 1): at that size the panel is DRAM-resident and the - f16 materialization plus re-stream loses to reading the quant plane in-kernel. + at 512 rows. A K-quant site whose panel reaches `TALLKQ_MIN_PANEL` (96 MiB) leaves dev-W + entirely for the tall in-kernel-dequant stamp (sec.2.2c form 1): at that size the panel is + DRAM-resident and the f16 materialization plus re-stream loses to reading the quant plane + in-kernel. - **A k-quant tg fallback is about 1.28x the q8 half-panel form**, so a k-quant site lowers the over-knee bar, the tiled-rows floor, and the long-K floor (1024 rows to 512): a tiled read still beats THAT fallback. From f33c678233ba0c015446fe34261ef63a4c03bba9 Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Thu, 27 Aug 2026 18:53:00 -0700 Subject: [PATCH 08/10] dasLLAMA: board v8 - the M5 metal board re-minted at ref pin b10659 Release-exe grade, full metal-leg LLM catalog, das + stock refs both fresh at the new pin. Every pp512 and tg128 cell is at or ahead of upstream for the first time: the arc's five former reds land at Mistral-24B 1.117, gemma-12B 1.138, gemma-26B-A4B 1.051, Qwen3.6-27B 1.202, Qwen3.8-27B 1.185; the E-series/gptoss/qwen-MoE cells hold 1.006-1.183 pp and 1.003-1.332 tg. Site records regenerated; records/site/exchange schema gates green (37+2+21). Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014fKJGuUL8tP58Y6NvoVeSn --- modules/dasLLAMA/performance/records/m5.json | 342 +-- .../records/m5.tune.461b01bf9c73.json | 2649 +++++++++++++++++ site/files/dasllama/bench_records.json | 342 +-- 3 files changed, 2991 insertions(+), 342 deletions(-) create mode 100644 modules/dasLLAMA/performance/records/m5.tune.461b01bf9c73.json diff --git a/modules/dasLLAMA/performance/records/m5.json b/modules/dasLLAMA/performance/records/m5.json index c6457fea3d..c4af6bdfec 100644 --- a/modules/dasLLAMA/performance/records/m5.json +++ b/modules/dasLLAMA/performance/records/m5.json @@ -8,7 +8,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E2B-it-Q8_0.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -23,20 +23,20 @@ }, "tests":{ "pp512":{ - "tok_s":8642.0529972527293, - "stddev":47.174034118652344 + "tok_s":8692.8377108443274, + "stddev":42.567550659179688 }, "tg128":{ - "tok_s":160.97335724299222, - "stddev":0.89381587505340576 + "tok_s":161.72247100178595, + "stddev":0.25893470644950867 } }, "source":"official", - "sha":"3e28d443c", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights q8 native; q8 activations; f16 scales; metal blob", @@ -55,8 +55,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E2B-it-Q8_0.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E2B-it-Q8_0.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -70,16 +70,16 @@ }, "tests":{ "pp512":{ - "tok_s":7531.6944620000004, - "stddev":43.024726999999999 + "tok_s":7527.4361060000001, + "stddev":28.764002000000001 }, "tg128":{ - "tok_s":137.73860400000001, - "stddev":0.74135899999999999 + "tok_s":136.59289799999999, + "stddev":0.146476 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -272,7 +272,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E2B-it-Q8_0.gguf --image-mmproj /Users/borisbatkin/Work/llama.cpp/models/mmproj-gemma-4-E2B-it-bf16.gguf --image /Users/borisbatkin/Work/llama.cpp/models/coco-val2017-000000039769.jpg -r 3 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -287,23 +287,23 @@ }, "tests":{ "img:enc":{ - "ms":37.465000000000003 + "ms":37.079999999999998 }, "img:pp":{ - "tok_s":3560.2619987676017 + "tok_s":3542.7974473690188 }, "img:tg":{ - "tok_s":154.73169524045306, + "tok_s":155.15743307542721, "text":": This is an image of two tabby cats lying on a pink surface." } }, "workload":"image-chat", "source":"official", - "sha":"b63198111", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4v f32; weights q8 native; q8 activations; f16 scales; metal blob", @@ -523,7 +523,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-12B-it-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -538,20 +538,20 @@ }, "tests":{ "pp512":{ - "tok_s":1686.5738524264857, - "stddev":1.4621291160583496 + "tok_s":1938.9908117881037, + "stddev":3.0214979648590088 }, "tg128":{ - "tok_s":63.71401394823058, - "stddev":2.7017333507537842 + "tok_s":63.761391280043405, + "stddev":2.6959183216094971 } }, "source":"official", - "sha":"b63198111", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -570,8 +570,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-12B-it-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-12B-it-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -585,16 +585,16 @@ }, "tests":{ "pp512":{ - "tok_s":1701.870887, - "stddev":0.77144800000000002 + "tok_s":1703.5040280000001, + "stddev":1.5609329999999999 }, "tg128":{ - "tok_s":60.556725, - "stddev":0.094574000000000005 + "tok_s":60.580466000000001, + "stddev":0.22184499999999999 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -611,7 +611,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-12B-it-Q4_K_M.gguf --image-mmproj /Users/borisbatkin/Work/llama.cpp/models/mmproj-gemma-4-12B-it-BF16.gguf --image /Users/borisbatkin/Work/llama.cpp/models/coco-val2017-000000039769.jpg -r 3 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -626,23 +626,23 @@ }, "tests":{ "img:enc":{ - "ms":7.1550000000000002 + "ms":7.1980000000000004 }, "img:pp":{ - "tok_s":1089.7659797415299 + "tok_s":1284.7225081736351 }, "img:tg":{ - "tok_s":65.601451218190434, + "tok_s":65.699831751300422, "text":"Two tabby cats are lying on a pink surface, with one cat on the left and the other on the right." } }, "workload":"image-chat", "source":"official", - "sha":"4c135f4bd", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4uv f32; weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -683,7 +683,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E4B-it-Q8_0.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -698,20 +698,20 @@ }, "tests":{ "pp512":{ - "tok_s":5115.2998693325899, - "stddev":10.156952857971191 + "tok_s":5123.0211944582243, + "stddev":21.226161956787109 }, "tg128":{ - "tok_s":90.05206929423548, - "stddev":0.048173848539590836 + "tok_s":90.197186400189821, + "stddev":0.03762681782245636 } }, "source":"official", - "sha":"4c135f4bd", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights q8 native; q8 activations; f16 scales; metal blob", @@ -730,8 +730,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E4B-it-Q8_0.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E4B-it-Q8_0.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -745,16 +745,16 @@ }, "tests":{ "pp512":{ - "tok_s":4348.8734290000002, - "stddev":14.695126999999999 + "tok_s":4331.2716979999996, + "stddev":7.9024109999999999 }, "tg128":{ - "tok_s":81.298264000000003, - "stddev":0.43596400000000002 + "tok_s":81.157066999999998, + "stddev":0.26690799999999998 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -771,7 +771,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E4B-it-Q8_0.gguf --image-mmproj /Users/borisbatkin/Work/llama.cpp/models/mmproj-gemma-4-E4B-it-BF16.gguf --image /Users/borisbatkin/Work/llama.cpp/models/coco-val2017-000000039769.jpg -r 3 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -786,23 +786,23 @@ }, "tests":{ "img:enc":{ - "ms":38.392000000000003 + "ms":38.402000000000001 }, "img:pp":{ - "tok_s":1767.785508691612 + "tok_s":1764.6859198425357 }, "img:tg":{ - "tok_s":88.229860844966353, + "tok_s":88.326299431675466, "text":"The user wants a one-sentence description of the provided image.\nThe image contains two cats lying on a pink surface.\n\nPlan: Describe the main subjects" } }, "workload":"image-chat", "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4v f32; weights q8 native; q8 activations; f16 scales; metal blob", @@ -843,7 +843,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gpt-oss-20b-mxfp4.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -858,20 +858,20 @@ }, "tests":{ "pp512":{ - "tok_s":3988.4431260025494, - "stddev":17.16136360168457 + "tok_s":3989.4203630795723, + "stddev":18.226713180541992 }, "tg128":{ - "tok_s":163.34938114401598, - "stddev":0.14880651235580444 + "tok_s":163.21584485670596, + "stddev":0.13277889788150787 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights mxfp4/q8 native; q8 activations; f16 scales; metal blob", @@ -890,8 +890,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gpt-oss-20b-mxfp4.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gpt-oss-20b-mxfp4.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -905,16 +905,16 @@ }, "tests":{ "pp512":{ - "tok_s":3483.8785250000001, - "stddev":8.3781250000000007 + "tok_s":3475.262072, + "stddev":8.8958180000000002 }, "tg128":{ - "tok_s":147.45539099999999, - "stddev":0.24805099999999999 + "tok_s":147.511551, + "stddev":0.410717 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -941,7 +941,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/Mistral-Small-3.1-24B-Instruct-2503-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -956,20 +956,20 @@ }, "tests":{ "pp512":{ - "tok_s":678.27299728451783, - "stddev":10.671237945556641 + "tok_s":1107.5193206908937, + "stddev":1.1255176067352295 }, "tg128":{ - "tok_s":38.179134606688692, - "stddev":0.13497893512248993 + "tok_s":38.298495651945146, + "stddev":0.053260661661624908 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6 native; q8 activations; f32 scales; metal blob", @@ -988,8 +988,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Mistral-Small-3.1-24B-Instruct-2503-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Mistral-Small-3.1-24B-Instruct-2503-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -1003,16 +1003,16 @@ }, "tests":{ "pp512":{ - "tok_s":991.262429, - "stddev":0.68436399999999997 + "tok_s":991.28601000000003, + "stddev":0.77159100000000003 }, "tg128":{ - "tok_s":36.665574999999997, - "stddev":1.0958939999999999 + "tok_s":36.653257000000004, + "stddev":1.1031610000000001 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -1039,7 +1039,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-26B-A4B-it-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -1054,20 +1054,20 @@ }, "tests":{ "pp512":{ - "tok_s":3045.4359807557762, - "stddev":11.667203903198242 + "tok_s":3648.4381650295713, + "stddev":15.327509880065918 }, "tg128":{ - "tok_s":118.15454129201358, - "stddev":5.1164727210998535 + "tok_s":118.26094767794341, + "stddev":5.0962691307067871 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/q51/q8 native; q8 activations; f16 scales; metal blob", @@ -1086,8 +1086,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-26B-A4B-it-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-26B-A4B-it-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -1101,16 +1101,16 @@ }, "tests":{ "pp512":{ - "tok_s":3461.0379939999998, - "stddev":11.285895999999999 + "tok_s":3469.808806, + "stddev":11.919931 }, "tg128":{ - "tok_s":99.731941000000006, - "stddev":0.35907899999999998 + "tok_s":99.490211000000002, + "stddev":0.274507 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -1137,7 +1137,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-27B-MTP-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -1152,20 +1152,20 @@ }, "tests":{ "pp512":{ - "tok_s":715.40921968834391, - "stddev":0.28290107846260071 + "tok_s":888.29681098337915, + "stddev":4.535797119140625 }, "tg128":{ - "tok_s":27.391927471755071, - "stddev":0.2634216845035553 + "tok_s":27.423391866797225, + "stddev":0.11130748689174652 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f16 scales; metal blob", @@ -1184,8 +1184,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-27B-MTP-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-27B-MTP-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -1199,16 +1199,16 @@ }, "tests":{ "pp512":{ - "tok_s":738.58820300000002, - "stddev":0.42859700000000001 + "tok_s":739.10453299999995, + "stddev":0.48830800000000002 }, "tg128":{ - "tok_s":27.243791000000002, - "stddev":0.97493399999999997 + "tok_s":27.332798, + "stddev":0.96453999999999995 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -1235,7 +1235,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3-30B-A3B-Instruct-2507-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -1250,20 +1250,20 @@ }, "tests":{ "pp512":{ - "tok_s":3503.0512105282019, - "stddev":20.681808471679688 + "tok_s":3506.8078045084162, + "stddev":19.61585807800293 }, "tg128":{ - "tok_s":165.11343776111951, - "stddev":0.42980408668518066 + "tok_s":165.24557967328658, + "stddev":0.11801531910896301 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -1282,8 +1282,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3-30B-A3B-Instruct-2507-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3-30B-A3B-Instruct-2507-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -1297,16 +1297,16 @@ }, "tests":{ "pp512":{ - "tok_s":3435.2990580000001, - "stddev":14.437657 + "tok_s":3425.5220340000001, + "stddev":13.952795 }, "tg128":{ - "tok_s":138.64061000000001, - "stddev":0.70350400000000002 + "tok_s":136.43157400000001, + "stddev":0.83255500000000005 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -1333,7 +1333,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.8-27B-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -1348,20 +1348,20 @@ }, "tests":{ "pp512":{ - "tok_s":726.61977095890393, - "stddev":0.84915745258331299 + "tok_s":891.6510131320847, + "stddev":3.1367990970611572 }, "tg128":{ - "tok_s":27.829948364707995, - "stddev":0.31860759854316711 + "tok_s":27.886035408758552, + "stddev":0.073721945285797119 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f16 scales; metal blob", @@ -1380,8 +1380,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.8-27B-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.8-27B-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -1395,16 +1395,16 @@ }, "tests":{ "pp512":{ - "tok_s":752.521342, - "stddev":0.74508200000000002 + "tok_s":752.63394100000005, + "stddev":0.68924799999999997 }, "tg128":{ - "tok_s":25.334861, - "stddev":0.59087599999999996 + "tok_s":25.433668999999998, + "stddev":0.53600499999999995 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -1431,7 +1431,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-35B-A3B-MTP-UD-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -1446,20 +1446,20 @@ }, "tests":{ "pp512":{ - "tok_s":3203.3164089532825, - "stddev":10.003824234008789 + "tok_s":3201.3003848974017, + "stddev":5.6111979484558105 }, "tg128":{ - "tok_s":126.71243283801149, - "stddev":0.31083890795707703 + "tok_s":127.311408165347, + "stddev":0.40768790245056152 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k5/k6/q8 native; q8 activations; f16 scales; metal blob", @@ -1478,8 +1478,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-35B-A3B-MTP-UD-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-35B-A3B-MTP-UD-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -1493,16 +1493,16 @@ }, "tests":{ "pp512":{ - "tok_s":3181.7403960000001, - "stddev":16.853456000000001 + "tok_s":3183.6708789999998, + "stddev":19.433194 }, "tg128":{ - "tok_s":95.617856000000003, - "stddev":0.433614 + "tok_s":95.600543000000002, + "stddev":0.52021399999999995 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { diff --git a/modules/dasLLAMA/performance/records/m5.tune.461b01bf9c73.json b/modules/dasLLAMA/performance/records/m5.tune.461b01bf9c73.json new file mode 100644 index 0000000000..70e5752de9 --- /dev/null +++ b/modules/dasLLAMA/performance/records/m5.tune.461b01bf9c73.json @@ -0,0 +1,2649 @@ +{ + "kernels" : { + "add_inplace" : "vec8_u2", + "cvt_f32_to_f16" : "vec16", + "rope_scaled_neox_tab" : "vec8_u2", + "q51q8_tile_gen" : "mr8", + "softmax" : "vec8_u2", + "mul_inplace" : "u4", + "quantize_q8_0_bs_into_ptr" : "plain", + "dot_q8kv" : "vec4_u2", + "dot_q8q8" : "vec16", + "quantize_q8kv_row" : "plain", + "axpy_f16" : "vec8_u2", + "q40q8_tile_gen" : "mr8", + "axpy_tq4kv" : "vec8_u2", + "cvt_tq4kv_to_f32" : "vec8_u2", + "axpy" : "vec8_u2", + "dot_q8q8kv" : "plain", + "dot_mx4q8" : "u2", + "softmax_sink" : "vec8_u2", + "dot_q8q8_laneq4x4" : "u2", + "dot_bf16" : "vec8_u2", + "add_scale_inplace" : "vec8_u2", + "cvt_q8kv_to_f32" : "vec8_u2", + "axpy_q8kv" : "vec8_u2", + "dot_q8q8_f16s" : "vec16", + "q8q8_tile_gen" : "mr8_budget", + "quantize_q8_0_into_ptr" : "plain", + "k4q8_tile_gen" : "mr8", + "k5q8_tile_gen" : "mr8", + "k6q8_tile_gen" : "mr4", + "gemm_f32_uk_4x16" : "u2", + "dot_q51e" : "vec16", + "dot_f16" : "vec8_u2", + "cvt_f16_to_f32" : "vec8_u2", + "dot" : "vec8_u2", + "dot_q8tq4kv" : "vec16", + "scale_inplace" : "vec8_u2", + "dot_q4" : "vec4_u4", + "quantize_tq4kv_row" : "plain", + "copy_floats" : "vec8_u2", + "rmsnorm" : "vec8" + }, + "provenance" : { + "validation" : "ok", + "noise_probes" : "start cv 0.13%; mid1 cv 0.09%; mid2 cv 0.18%; end cv 0.22%", + "platform" : "darwin", + "noise_floor_cv_pct" : "0.22", + "engine_sha" : "dc0992306", + "box" : "darwin|arm64|Mac17,6|25G72|Apple M5 Max", + "written" : "2026-08-28T00:21:30.590Z", + "validation_demoted" : "1", + "mode" : "normal", + "dasllama_version" : "10", + "noise" : "ok", + "binary" : "/Users/borisbatkin/Work/daScript/bin/daslang", + "arch" : "arm64", + "validation_max_drift_pct" : "0.69" + }, + "race" : { + "cvt_q8kv_to_f32" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 375.84375, + "best_us" : 375.34375 + }, + "vec32" : { + "med_us" : 374.625, + "best_us" : 374.125 + }, + "vec32_u4" : { + "med_us" : 375.84375, + "best_us" : 375.375 + }, + "vec32_u8" : { + "med_us" : 375.78125, + "best_us" : 375.3125 + }, + "vec16_u2" : { + "med_us" : 376.15625, + "best_us" : 375.5625 + }, + "vec16_u4" : { + "med_us" : 375.6875, + "best_us" : 375.125 + }, + "vec16_u8" : { + "med_us" : 376.0625, + "best_us" : 375.46875 + }, + "vec4" : { + "med_us" : 376.5, + "best_us" : 375.8125 + }, + "vec8" : { + "med_us" : 374.78125, + "best_us" : 374.25 + }, + "vec4_u4" : { + "med_us" : 375.78125, + "best_us" : 375.34375 + }, + "vec8_u4" : { + "med_us" : 375.21875, + "best_us" : 374.90625 + }, + "plain" : { + "med_us" : 374.75, + "best_us" : 374.25 + }, + "u2" : { + "med_us" : 375.8125, + "best_us" : 375.375 + }, + "u4" : { + "med_us" : 375.96875, + "best_us" : 375.46875 + }, + "u8" : { + "med_us" : 375.8125, + "best_us" : 375.4375 + }, + "vec4_u2" : { + "med_us" : 375.8125, + "best_us" : 375.5625 + }, + "vec4_u8" : { + "med_us" : 376.15625, + "best_us" : 375.875 + }, + "vec8_u2" : { + "med_us" : 375.21875, + "best_us" : 374.5 + }, + "vec8_u8" : { + "med_us" : 375.125, + "best_us" : 374.84375 + }, + "vec16" : { + "med_us" : 374.875, + "best_us" : 374.53125 + } + } + }, + "add_inplace" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 334.75, + "best_us" : 333.5625 + }, + "vec32" : { + "med_us" : 357.40625, + "best_us" : 356.40625 + }, + "vec32_u4" : { + "med_us" : 335.6875, + "best_us" : 333.84375 + }, + "vec32_u8" : { + "med_us" : 333.875, + "best_us" : 332.4375 + }, + "vec16_u2" : { + "med_us" : 338, + "best_us" : 336.5625 + }, + "vec16_u4" : { + "med_us" : 336.59375, + "best_us" : 335.96875 + }, + "vec16_u8" : { + "med_us" : 1261.03125, + "best_us" : 410.9375 + }, + "vec4" : { + "med_us" : 360.15625, + "best_us" : 358.125 + }, + "vec8" : { + "med_us" : 359.1875, + "best_us" : 356.6875 + }, + "vec4_u4" : { + "med_us" : 340.65625, + "best_us" : 335.875 + }, + "vec8_u4" : { + "med_us" : 337.09375, + "best_us" : 334.25 + }, + "plain" : { + "med_us" : 359.625, + "best_us" : 358.34375 + }, + "u2" : { + "med_us" : 360.375, + "best_us" : 359.40625 + }, + "u4" : { + "med_us" : 350.21875, + "best_us" : 335.71875 + }, + "u8" : { + "med_us" : 337.03125, + "best_us" : 335.21875 + }, + "vec4_u2" : { + "med_us" : 358.90625, + "best_us" : 356.5625 + }, + "vec4_u8" : { + "med_us" : 337.6875, + "best_us" : 334.09375 + }, + "vec8_u2" : { + "med_us" : 342.625, + "best_us" : 339.84375 + }, + "vec8_u8" : { + "med_us" : 334.125, + "best_us" : 333.5625 + }, + "vec16" : { + "med_us" : 339.875, + "best_us" : 336.25 + } + } + }, + "axpy_q8kv" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 395.125, + "best_us" : 395.03125 + }, + "vec32" : { + "med_us" : 396.15625, + "best_us" : 395.90625 + }, + "vec32_u4" : { + "med_us" : 395.1875, + "best_us" : 395.15625 + }, + "vec32_u8" : { + "med_us" : 395.71875, + "best_us" : 395.625 + }, + "vec16_u2" : { + "med_us" : 394.6875, + "best_us" : 394.5625 + }, + "vec16_u4" : { + "med_us" : 394.71875, + "best_us" : 394.6875 + }, + "vec16_u8" : { + "med_us" : 395.03125, + "best_us" : 394.59375 + }, + "vec4" : { + "med_us" : 393.75, + "best_us" : 393.15625 + }, + "vec8" : { + "med_us" : 393.6875, + "best_us" : 393.625 + }, + "vec4_u4" : { + "med_us" : 393.28125, + "best_us" : 393.21875 + }, + "vec8_u4" : { + "med_us" : 395.34375, + "best_us" : 395.15625 + }, + "plain" : { + "med_us" : 393.15625, + "best_us" : 393.0625 + }, + "u2" : { + "med_us" : 394.75, + "best_us" : 394.6875 + }, + "u4" : { + "med_us" : 394.6875, + "best_us" : 394.59375 + }, + "u8" : { + "med_us" : 394.75, + "best_us" : 394.625 + }, + "vec4_u2" : { + "med_us" : 393.21875, + "best_us" : 393.125 + }, + "vec4_u8" : { + "med_us" : 393.28125, + "best_us" : 393.25 + }, + "vec8_u2" : { + "med_us" : 399.03125, + "best_us" : 399 + }, + "vec8_u8" : { + "med_us" : 395.28125, + "best_us" : 395.1875 + }, + "vec16" : { + "med_us" : 393.6875, + "best_us" : 393.15625 + } + } + }, + "cvt_f32_to_f16" : { + "winner" : "vec16", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 7.954991495486066, + "rows" : { + "vec32_u2" : { + "med_us" : 347.0625, + "best_us" : 346.75 + }, + "vec32" : { + "med_us" : 347.0625, + "best_us" : 347 + }, + "vec32_u4" : { + "med_us" : 347.0625, + "best_us" : 346.84375 + }, + "vec32_u8" : { + "med_us" : 347.0625, + "best_us" : 346.84375 + }, + "vec16_u2" : { + "med_us" : 335.84375, + "best_us" : 335.46875 + }, + "vec16_u4" : { + "med_us" : 335.875, + "best_us" : 335.40625 + }, + "vec16_u8" : { + "med_us" : 335.828125, + "best_us" : 335.6875 + }, + "vec4" : { + "med_us" : 365.625, + "best_us" : 365.21875 + }, + "vec8" : { + "med_us" : 358.4375, + "best_us" : 358.3125 + }, + "vec4_u4" : { + "med_us" : 363.46875, + "best_us" : 362.5 + }, + "vec8_u4" : { + "med_us" : 358.34375, + "best_us" : 358.28125 + }, + "plain" : { + "med_us" : 358.5, + "best_us" : 358.0625 + }, + "u2" : { + "med_us" : 358.4375, + "best_us" : 358.0625 + }, + "u4" : { + "med_us" : 358.53125, + "best_us" : 358.125 + }, + "u8" : { + "med_us" : 358.28125, + "best_us" : 358.09375 + }, + "vec4_u2" : { + "med_us" : 360.65625, + "best_us" : 360.40625 + }, + "vec4_u8" : { + "med_us" : 362.21875, + "best_us" : 362.09375 + }, + "vec8_u2" : { + "med_us" : 358.359375, + "best_us" : 358.09375 + }, + "vec8_u8" : { + "med_us" : 358.28125, + "best_us" : 358.15625 + }, + "vec16" : { + "med_us" : 329.640625, + "best_us" : 329.46875 + } + } + }, + "rope_scaled_neox_tab" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.17611273380775314, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 683.3103448275862, + "best_us" : 682.0344827586207 + }, + "vec32" : { + "med_us" : 641.1935483870968, + "best_us" : 638.3548387096774 + }, + "vec32_u4" : { + "med_us" : 641.5806451612904, + "best_us" : 640.6774193548387 + }, + "vec32_u8" : { + "med_us" : 638.516129032258, + "best_us" : 637.6129032258065 + }, + "vec16_u2" : { + "med_us" : 379.71875, + "best_us" : 374.03125 + }, + "vec16_u4" : { + "med_us" : 374.28125, + "best_us" : 373.46875 + }, + "vec16_u8" : { + "med_us" : 374.125, + "best_us" : 373.09375 + }, + "vec4" : { + "med_us" : 396.96875, + "best_us" : 396.03125 + }, + "vec8" : { + "med_us" : 372.40625, + "best_us" : 367.8125 + }, + "vec4_u4" : { + "med_us" : 372.5625, + "best_us" : 369.5625 + }, + "vec8_u4" : { + "med_us" : 369.40625, + "best_us" : 367.96875 + }, + "plain" : { + "med_us" : 397.09375, + "best_us" : 394.71875 + }, + "u2" : { + "med_us" : 380.9375, + "best_us" : 379.90625 + }, + "u4" : { + "med_us" : 371.59375, + "best_us" : 371.15625 + }, + "u8" : { + "med_us" : 417.53125, + "best_us" : 415.53125 + }, + "vec4_u2" : { + "med_us" : 380.09375, + "best_us" : 379.46875 + }, + "vec4_u8" : { + "med_us" : 415.65625, + "best_us" : 415.25 + }, + "vec8_u2" : { + "med_us" : 375.78125, + "best_us" : 373.0625 + }, + "vec8_u8" : { + "med_us" : 403.21875, + "best_us" : 402.0625 + }, + "vec16" : { + "med_us" : 369.6875, + "best_us" : 366.59375 + } + } + }, + "q51q8_tile_gen" : { + "winner" : "mr8", + "rows" : { + "mr8" : { + "streamed_us" : 582 + }, + "dot_maddubs_width256_mr8" : { + "streamed_us" : 4014 + }, + "dot_vpdpbusd_width256_mr8_nrsplit2" : { + "streamed_us" : 3989 + }, + "dot_maddubs_width256_mr8_nrsplit2" : { + "streamed_us" : 3962 + }, + "mr4" : { + "streamed_us" : 605 + }, + "reference" : { + "streamed_us" : 3795 + }, + "mr4_nrsplit2" : { + "streamed_us" : 595 + }, + "dot_vpdpbusd_width256_mr8" : { + "streamed_us" : 3976 + }, + "dot_vpdpbusd_width512_mr16" : { + "streamed_us" : 3930 + }, + "mr8_nrsplit2" : { + "streamed_us" : 605 + }, + "dot_vpdpbusd_width512_mr16_nrsplit2" : { + "streamed_us" : 3961 + } + } + }, + "softmax" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 3164.8333333333335, + "best_us" : 3160.5 + }, + "vec32" : { + "med_us" : 3173.1666666666665, + "best_us" : 3171.5 + }, + "vec32_u4" : { + "med_us" : 3161.5, + "best_us" : 3155 + }, + "vec32_u8" : { + "med_us" : 3157.8333333333335, + "best_us" : 3152.5 + }, + "vec16_u2" : { + "med_us" : 3173.3333333333335, + "best_us" : 3171.8333333333335 + }, + "vec16_u4" : { + "med_us" : 3170, + "best_us" : 3168 + }, + "vec16_u8" : { + "med_us" : 3996.25, + "best_us" : 3965.5 + }, + "vec4" : { + "med_us" : 3161.6666666666665, + "best_us" : 3157 + }, + "vec8" : { + "med_us" : 3164.1666666666665, + "best_us" : 3159.8333333333335 + }, + "vec4_u4" : { + "med_us" : 3152.8333333333335, + "best_us" : 3151.3333333333335 + }, + "vec8_u4" : { + "med_us" : 3160.8333333333335, + "best_us" : 3156.1666666666665 + }, + "plain" : { + "med_us" : 3162.1666666666665, + "best_us" : 3160.1666666666665 + }, + "u2" : { + "med_us" : 3163.8333333333335, + "best_us" : 3155.3333333333335 + }, + "u4" : { + "med_us" : 3160.8333333333335, + "best_us" : 3151.5 + }, + "u8" : { + "med_us" : 3156.6666666666665, + "best_us" : 3150.3333333333335 + }, + "vec4_u2" : { + "med_us" : 3165.8333333333335, + "best_us" : 3164.6666666666665 + }, + "vec4_u8" : { + "med_us" : 3157.5, + "best_us" : 3153 + }, + "vec8_u2" : { + "med_us" : 3155.8333333333335, + "best_us" : 3155.5 + }, + "vec8_u8" : { + "med_us" : 3158.6666666666665, + "best_us" : 3155.8333333333335 + }, + "vec16" : { + "med_us" : 3178.5, + "best_us" : 3174.3333333333335 + } + } + }, + "q8q8_tile_gen" : { + "winner" : "mr8_budget", + "rows" : { + "kstep1" : { + "tile_us" : 22853, + "gemv_us" : 200, + "hot_us" : 10.375 + }, + "kstep2_nrsplit2" : { + "tile_us" : 24109, + "gemv_us" : 198, + "hot_us" : 10.375 + }, + "kstep1_nrsplit2" : { + "tile_us" : 24364, + "gemv_us" : 200, + "hot_us" : 10.3125 + }, + "reference" : { + "tile_us" : 33428, + "gemv_us" : 197, + "hot_us" : 10.4375 + }, + "kstep4_nrsplit2" : { + "tile_us" : 24358, + "gemv_us" : 197, + "hot_us" : 9.9375 + }, + "kstep4_nrsplit2_mr8_gkstep2" : { + "tile_us" : 24093, + "gemv_us" : 195, + "hot_us" : 9.8125 + }, + "kstep1_nrsplit2_mr8" : { + "tile_us" : 23238, + "gemv_us" : 195, + "hot_us" : 9.625 + }, + "kstep2_nrsplit2_mr8" : { + "tile_us" : 22821, + "gemv_us" : 195, + "hot_us" : 9.9375 + }, + "kstep4_nrsplit2_mr8" : { + "tile_us" : 24086, + "gemv_us" : 196, + "hot_us" : 9.625 + }, + "kstep2_gkstep2" : { + "tile_us" : 23300, + "gemv_us" : 201, + "hot_us" : 10.0625 + }, + "kstep2_gkstep4" : { + "tile_us" : 23325, + "gemv_us" : 199, + "hot_us" : 10.125 + }, + "kstep4_nrsplit2_mr8_gkstep4" : { + "tile_us" : 24068, + "gemv_us" : 197, + "hot_us" : 9.6875 + }, + "mr8_budget" : { + "tile_us" : 22177, + "gemv_us" : 197, + "hot_us" : 9.9375 + }, + "kstep2" : { + "tile_us" : 23311, + "gemv_us" : 199, + "hot_us" : 10.1875 + }, + "kstep4" : { + "tile_us" : 24784, + "gemv_us" : 199, + "hot_us" : 10.4375 + } + } + }, + "mul_inplace" : { + "winner" : "u4", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 3.1380847327900594, + "rows" : { + "vec32_u2" : { + "med_us" : 335.265625, + "best_us" : 333.46875 + }, + "vec32" : { + "med_us" : 359.09375, + "best_us" : 357.1875 + }, + "vec32_u4" : { + "med_us" : 336.96875, + "best_us" : 335.90625 + }, + "vec32_u8" : { + "med_us" : 333.59375, + "best_us" : 331.875 + }, + "vec16_u2" : { + "med_us" : 361.53125, + "best_us" : 360.0625 + }, + "vec16_u4" : { + "med_us" : 336.28125, + "best_us" : 334.71875 + }, + "vec16_u8" : { + "med_us" : 336.15625, + "best_us" : 334.5625 + }, + "vec4" : { + "med_us" : 362.59375, + "best_us" : 359.75 + }, + "vec8" : { + "med_us" : 358.125, + "best_us" : 357.1875 + }, + "vec4_u4" : { + "med_us" : 336.671875, + "best_us" : 335.53125 + }, + "vec8_u4" : { + "med_us" : 334.78125, + "best_us" : 333.15625 + }, + "plain" : { + "med_us" : 360.1875, + "best_us" : 359.40625 + }, + "u2" : { + "med_us" : 362.125, + "best_us" : 361.5 + }, + "u4" : { + "med_us" : 336.15625, + "best_us" : 334.15625 + }, + "u8" : { + "med_us" : 339.34375, + "best_us" : 333.90625 + }, + "vec4_u2" : { + "med_us" : 359.15625, + "best_us" : 358.34375 + }, + "vec4_u8" : { + "med_us" : 336.96875, + "best_us" : 336.40625 + }, + "vec8_u2" : { + "med_us" : 347.046875, + "best_us" : 334.28125 + }, + "vec8_u8" : { + "med_us" : 334.609375, + "best_us" : 332.1875 + }, + "vec16" : { + "med_us" : 359.75, + "best_us" : 358.8125 + } + } + }, + "k4q8_tile_gen" : { + "winner" : "mr8", + "rows" : { + "mr8" : { + "tile_us" : 27966, + "gemv_us" : 168, + "hot_us" : 10.5 + }, + "dot_maddubs_width256_mr8" : { + "tile_us" : 468175, + "gemv_us" : 1835, + "hot_us" : 110.6875 + }, + "dot_vpdpbusd_width256_mr8_nrsplit2" : { + "tile_us" : 468345, + "gemv_us" : 1855, + "hot_us" : 114.6875 + }, + "dot_maddubs_width256_mr8_nrsplit2" : { + "tile_us" : 468984, + "gemv_us" : 1797, + "hot_us" : 109.4375 + }, + "mr4" : { + "tile_us" : 30554, + "gemv_us" : 189, + "hot_us" : 11.5625 + }, + "reference" : { + "tile_us" : 469930, + "gemv_us" : 1856, + "hot_us" : 114.5625 + }, + "mr4_nrsplit2" : { + "tile_us" : 36942, + "gemv_us" : 191, + "hot_us" : 11.8125 + }, + "dot_vpdpbusd_width256_mr8" : { + "tile_us" : 470220, + "gemv_us" : 1812, + "hot_us" : 114.875 + }, + "dot_vpdpbusd_width512_mr16" : { + "tile_us" : 469323, + "gemv_us" : 1800, + "hot_us" : 109.75 + }, + "mr8_nrsplit2" : { + "tile_us" : 33459, + "gemv_us" : 168, + "hot_us" : 10.9375 + }, + "dot_vpdpbusd_width512_mr16_nrsplit2" : { + "tile_us" : 469153, + "gemv_us" : 1823, + "hot_us" : 114.8125 + } + } + }, + "k5q8_tile_gen" : { + "winner" : "mr8", + "rows" : { + "mr8" : { + "tile_us" : 27275, + "gemv_us" : 424, + "hot_us" : 27 + }, + "dot_maddubs_width256_mr8" : { + "tile_us" : 223401, + "gemv_us" : 2201, + "hot_us" : 132.8125 + }, + "dot_vpdpbusd_width256_mr8_nrsplit2" : { + "tile_us" : 223909, + "gemv_us" : 2214, + "hot_us" : 137.4375 + }, + "dot_maddubs_width256_mr8_nrsplit2" : { + "tile_us" : 223260, + "gemv_us" : 2228, + "hot_us" : 136 + }, + "mr4" : { + "tile_us" : 28252, + "gemv_us" : 415, + "hot_us" : 26.25 + }, + "reference" : { + "tile_us" : 224443, + "gemv_us" : 2168, + "hot_us" : 129.9375 + }, + "mr4_nrsplit2" : { + "tile_us" : 32825, + "gemv_us" : 433, + "hot_us" : 27.0625 + }, + "dot_vpdpbusd_width256_mr8" : { + "tile_us" : 223614, + "gemv_us" : 2169, + "hot_us" : 137.4375 + }, + "dot_vpdpbusd_width512_mr16" : { + "tile_us" : 223483, + "gemv_us" : 2154, + "hot_us" : 137.375 + }, + "mr8_nrsplit2" : { + "tile_us" : 29689, + "gemv_us" : 428, + "hot_us" : 27.375 + }, + "dot_vpdpbusd_width512_mr16_nrsplit2" : { + "tile_us" : 223820, + "gemv_us" : 2130, + "hot_us" : 135.375 + } + } + }, + "k6q8_tile_gen" : { + "winner" : "mr4", + "rows" : { + "mr8" : { + "tile_us" : 43106, + "gemv_us" : 346, + "hot_us" : 20.875 + }, + "dot_maddubs_width256_mr8" : { + "tile_us" : 199543, + "gemv_us" : 5629, + "hot_us" : 339.25 + }, + "dot_vpdpbusd_width256_mr8_nrsplit2" : { + "tile_us" : 199894, + "gemv_us" : 5822, + "hot_us" : 355 + }, + "dot_maddubs_width256_mr8_nrsplit2" : { + "tile_us" : 199706, + "gemv_us" : 5940, + "hot_us" : 359.1875 + }, + "mr4" : { + "tile_us" : 37130, + "gemv_us" : 347, + "hot_us" : 21.125 + }, + "reference" : { + "tile_us" : 199983, + "gemv_us" : 5522, + "hot_us" : 351.0625 + }, + "mr4_nrsplit2" : { + "tile_us" : 38556, + "gemv_us" : 346, + "hot_us" : 21.5625 + }, + "dot_vpdpbusd_width256_mr8" : { + "tile_us" : 199646, + "gemv_us" : 5846, + "hot_us" : 359.1875 + }, + "dot_vpdpbusd_width512_mr16" : { + "tile_us" : 199772, + "gemv_us" : 5926, + "hot_us" : 357.6875 + }, + "mr8_nrsplit2" : { + "tile_us" : 42686, + "gemv_us" : 335, + "hot_us" : 21.125 + }, + "dot_vpdpbusd_width512_mr16_nrsplit2" : { + "tile_us" : 199636, + "gemv_us" : 5872, + "hot_us" : 359.5 + } + } + }, + "quantize_q8_0_into_ptr" : { + "winner" : "plain", + "fallback" : "plain", + "floor_pct" : 0.17611273380775314, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 2443, + "best_us" : 2440.5 + }, + "vec32" : { + "med_us" : 2404.75, + "best_us" : 2404.125 + }, + "vec32_u4" : { + "med_us" : 2439.625, + "best_us" : 2439.25 + }, + "vec32_u8" : { + "med_us" : 2440.375, + "best_us" : 2439.125 + }, + "vec16_u2" : { + "med_us" : 2409.125, + "best_us" : 2408.5 + }, + "vec16_u4" : { + "med_us" : 2413.375, + "best_us" : 2408.25 + }, + "vec16_u8" : { + "med_us" : 2408.25, + "best_us" : 2407.625 + }, + "vec4" : { + "med_us" : 2406.375, + "best_us" : 2405.125 + }, + "vec8" : { + "med_us" : 2408.375, + "best_us" : 2406.5 + }, + "vec4_u4" : { + "med_us" : 3062, + "best_us" : 3061.3333333333335 + }, + "vec8_u4" : { + "med_us" : 2538.285714285714, + "best_us" : 2537.285714285714 + }, + "plain" : { + "med_us" : 2411.375, + "best_us" : 2408.5 + }, + "u2" : { + "med_us" : 2409.125, + "best_us" : 2406.125 + }, + "u4" : { + "med_us" : 2410.125, + "best_us" : 2408.75 + }, + "u8" : { + "med_us" : 2410.75, + "best_us" : 2410 + }, + "vec4_u2" : { + "med_us" : 3057.5, + "best_us" : 3051.8333333333335 + }, + "vec4_u8" : { + "med_us" : 3055.6666666666665, + "best_us" : 3052.6666666666665 + }, + "vec8_u2" : { + "med_us" : 2531.714285714286, + "best_us" : 2531.285714285714 + }, + "vec8_u8" : { + "med_us" : 2538.285714285714, + "best_us" : 2535.1428571428573 + }, + "vec16" : { + "med_us" : 2403.875, + "best_us" : 2402.625 + } + } + }, + "dot_q8kv" : { + "winner" : "vec4_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 24.369294735525816, + "rows" : { + "vec32_u2" : { + "med_us" : 1290.6, + "best_us" : 1289.7333333333333 + }, + "vec32" : { + "med_us" : 1923.9, + "best_us" : 1922.6 + }, + "vec32_u4" : { + "med_us" : 1291.2, + "best_us" : 1289.8 + }, + "vec32_u8" : { + "med_us" : 1292.2, + "best_us" : 1291.4666666666667 + }, + "vec16_u2" : { + "med_us" : 875.3181818181819, + "best_us" : 874.7272727272727 + }, + "vec16_u4" : { + "med_us" : 874.2727272727273, + "best_us" : 873.4545454545455 + }, + "vec16_u8" : { + "med_us" : 874.4545454545455, + "best_us" : 873.8181818181819 + }, + "vec4" : { + "med_us" : 1922.4, + "best_us" : 1919.6 + }, + "vec8" : { + "med_us" : 1921.9, + "best_us" : 1921 + }, + "vec4_u4" : { + "med_us" : 504.125, + "best_us" : 503.78125 + }, + "vec8_u4" : { + "med_us" : 667.0333333333333, + "best_us" : 666.8666666666667 + }, + "plain" : { + "med_us" : 1921.7, + "best_us" : 1921.3 + }, + "u2" : { + "med_us" : 1226.875, + "best_us" : 1225.125 + }, + "u4" : { + "med_us" : 1226.5, + "best_us" : 1225.25 + }, + "u8" : { + "med_us" : 1226.8125, + "best_us" : 1224.5 + }, + "vec4_u2" : { + "med_us" : 503.859375, + "best_us" : 503.28125 + }, + "vec4_u8" : { + "med_us" : 503.9375, + "best_us" : 503.53125 + }, + "vec8_u2" : { + "med_us" : 666.55, + "best_us" : 666.1666666666666 + }, + "vec8_u8" : { + "med_us" : 666.4333333333333, + "best_us" : 666.3666666666667 + }, + "vec16" : { + "med_us" : 1921.1, + "best_us" : 1920.8 + } + } + }, + "quantize_q8_0_bs_into_ptr" : { + "winner" : "plain", + "fallback" : "plain", + "floor_pct" : 0.17611273380775314, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 2373.125, + "best_us" : 2352.375 + }, + "vec32" : { + "med_us" : 2050.6666666666665, + "best_us" : 2038 + }, + "vec32_u4" : { + "med_us" : 2375.625, + "best_us" : 2362.75 + }, + "vec32_u8" : { + "med_us" : 2372.375, + "best_us" : 2365.875 + }, + "vec16_u2" : { + "med_us" : 2338.125, + "best_us" : 2335.125 + }, + "vec16_u4" : { + "med_us" : 2335, + "best_us" : 2325.875 + }, + "vec16_u8" : { + "med_us" : 2364.5, + "best_us" : 2341.125 + }, + "vec4" : { + "med_us" : 2041.7777777777778, + "best_us" : 2037.4444444444443 + }, + "vec8" : { + "med_us" : 2044.7777777777778, + "best_us" : 2041.111111111111 + }, + "vec4_u4" : { + "med_us" : 2518.5714285714284, + "best_us" : 2504 + }, + "vec8_u4" : { + "med_us" : 2154.1111111111113, + "best_us" : 2144 + }, + "plain" : { + "med_us" : 2040.4444444444443, + "best_us" : 2037.111111111111 + }, + "u2" : { + "med_us" : 2344.125, + "best_us" : 2332.875 + }, + "u4" : { + "med_us" : 2340.875, + "best_us" : 2328.75 + }, + "u8" : { + "med_us" : 2336.25, + "best_us" : 2334.5 + }, + "vec4_u2" : { + "med_us" : 2526.5714285714284, + "best_us" : 2506 + }, + "vec4_u8" : { + "med_us" : 2511.5714285714284, + "best_us" : 2501.4285714285716 + }, + "vec8_u2" : { + "med_us" : 2156.6666666666665, + "best_us" : 2152.4444444444443 + }, + "vec8_u8" : { + "med_us" : 2154.5555555555557, + "best_us" : 2151.4444444444443 + }, + "vec16" : { + "med_us" : 2043.5555555555557, + "best_us" : 2039.7777777777778 + } + } + }, + "dot_q8q8" : { + "winner" : "vec16", + "fallback" : "vec16", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 595, + "best_us" : 594.53125 + }, + "vec32" : { + "med_us" : 575.625, + "best_us" : 575.5625 + }, + "vec32_u4" : { + "med_us" : 595.03125, + "best_us" : 594 + }, + "vec32_u8" : { + "med_us" : 594.84375, + "best_us" : 594.46875 + }, + "vec16_u2" : { + "med_us" : 582.09375, + "best_us" : 580.84375 + }, + "vec16_u4" : { + "med_us" : 580.9375, + "best_us" : 579.34375 + }, + "vec16_u8" : { + "med_us" : 581.6875, + "best_us" : 580.09375 + }, + "vec4" : { + "med_us" : 575.84375, + "best_us" : 575.34375 + }, + "vec8" : { + "med_us" : 575.1875, + "best_us" : 574.8125 + }, + "vec4_u4" : { + "med_us" : 1942.9, + "best_us" : 1942 + }, + "vec8_u4" : { + "med_us" : 747.8461538461538, + "best_us" : 747.6923076923077 + }, + "plain" : { + "med_us" : 575.75, + "best_us" : 575.05 + }, + "u2" : { + "med_us" : 581.6521739130435, + "best_us" : 579.304347826087 + }, + "u4" : { + "med_us" : 581.7666666666667, + "best_us" : 580.3 + }, + "u8" : { + "med_us" : 580.75, + "best_us" : 579.75 + }, + "vec4_u2" : { + "med_us" : 1942.6, + "best_us" : 1941.9 + }, + "vec4_u8" : { + "med_us" : 1942.1, + "best_us" : 1941.4 + }, + "vec8_u2" : { + "med_us" : 747.6923076923077, + "best_us" : 746.9615384615385 + }, + "vec8_u8" : { + "med_us" : 747.76, + "best_us" : 747.04 + }, + "vec16" : { + "med_us" : 576.15625, + "best_us" : 575.09375 + } + } + }, + "gemm_f32_uk_4x16" : { + "winner" : "u2", + "fallback" : "u2", + "floor_pct" : 0.17611273380775314, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 540.4375, + "best_us" : 540.09375 + }, + "vec32" : { + "med_us" : 595.625, + "best_us" : 595.40625 + }, + "vec32_u4" : { + "med_us" : 549.375, + "best_us" : 548.34375 + }, + "vec32_u8" : { + "med_us" : 546.1875, + "best_us" : 545.96875 + }, + "vec16_u2" : { + "med_us" : 540, + "best_us" : 539.78125 + }, + "vec16_u4" : { + "med_us" : 549.34375, + "best_us" : 548.96875 + }, + "vec16_u8" : { + "med_us" : 545.78125, + "best_us" : 545.625 + }, + "vec4" : { + "med_us" : 595.03125, + "best_us" : 594.1875 + }, + "vec8" : { + "med_us" : 595.03125, + "best_us" : 594.4375 + }, + "vec4_u4" : { + "med_us" : 549.34375, + "best_us" : 549.1875 + }, + "vec8_u4" : { + "med_us" : 549.78125, + "best_us" : 548.78125 + }, + "plain" : { + "med_us" : 594.84375, + "best_us" : 594.71875 + }, + "u2" : { + "med_us" : 540.125, + "best_us" : 540 + }, + "u4" : { + "med_us" : 549.25, + "best_us" : 548.65625 + }, + "u8" : { + "med_us" : 546.28125, + "best_us" : 545.84375 + }, + "vec4_u2" : { + "med_us" : 539.96875, + "best_us" : 539.84375 + }, + "vec4_u8" : { + "med_us" : 546.8125, + "best_us" : 546.46875 + }, + "vec8_u2" : { + "med_us" : 540.375, + "best_us" : 539.53125 + }, + "vec8_u8" : { + "med_us" : 546.25, + "best_us" : 545.84375 + }, + "vec16" : { + "med_us" : 594.90625, + "best_us" : 594.40625 + } + } + }, + "quantize_q8kv_row" : { + "winner" : "plain", + "fallback" : "plain", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 1192.5625, + "best_us" : 1190.5 + }, + "vec32" : { + "med_us" : 1173.25, + "best_us" : 1173.125 + }, + "vec32_u4" : { + "med_us" : 1191.125, + "best_us" : 1188.875 + }, + "vec32_u8" : { + "med_us" : 1191.5, + "best_us" : 1191 + }, + "vec16_u2" : { + "med_us" : 1200.6875, + "best_us" : 1199.4375 + }, + "vec16_u4" : { + "med_us" : 1174.0625, + "best_us" : 1172.5625 + }, + "vec16_u8" : { + "med_us" : 1173.625, + "best_us" : 1173.4375 + }, + "vec4" : { + "med_us" : 1200.5625, + "best_us" : 1198.1875 + }, + "vec8" : { + "med_us" : 1197.8125, + "best_us" : 1197.625 + }, + "vec4_u4" : { + "med_us" : 1494.7692307692307, + "best_us" : 1493.076923076923 + }, + "vec8_u4" : { + "med_us" : 1229, + "best_us" : 1228.625 + }, + "plain" : { + "med_us" : 1199.1875, + "best_us" : 1197.1875 + }, + "u2" : { + "med_us" : 1173.3529411764705, + "best_us" : 1172.4705882352941 + }, + "u4" : { + "med_us" : 1172.9411764705883, + "best_us" : 1172.1176470588234 + }, + "u8" : { + "med_us" : 1173.1764705882354, + "best_us" : 1172.9411764705883 + }, + "vec4_u2" : { + "med_us" : 1493.3076923076924, + "best_us" : 1493.1538461538462 + }, + "vec4_u8" : { + "med_us" : 1495.1538461538462, + "best_us" : 1493.4615384615386 + }, + "vec8_u2" : { + "med_us" : 1228.5625, + "best_us" : 1226.625 + }, + "vec8_u8" : { + "med_us" : 1228.625, + "best_us" : 1227.4375 + }, + "vec16" : { + "med_us" : 1173.3125, + "best_us" : 1172.1875 + } + } + }, + "dot_f16" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 283.75, + "best_us" : 283.3125 + }, + "vec32" : { + "med_us" : 284.40625, + "best_us" : 284.0625 + }, + "vec32_u4" : { + "med_us" : 283.71875, + "best_us" : 283.0625 + }, + "vec32_u8" : { + "med_us" : 285.15625, + "best_us" : 284.53125 + }, + "vec16_u2" : { + "med_us" : 269.28125, + "best_us" : 269.0625 + }, + "vec16_u4" : { + "med_us" : 268.71875, + "best_us" : 268.21875 + }, + "vec16_u8" : { + "med_us" : 270.65625, + "best_us" : 269.90625 + }, + "vec4" : { + "med_us" : 420.40625, + "best_us" : 419.6875 + }, + "vec8" : { + "med_us" : 258.03125, + "best_us" : 257.65625 + }, + "vec4_u4" : { + "med_us" : 415.03125, + "best_us" : 414.53125 + }, + "vec8_u4" : { + "med_us" : 259.875, + "best_us" : 259.4375 + }, + "plain" : { + "med_us" : 3924.6, + "best_us" : 3854 + }, + "u2" : { + "med_us" : 3894.8, + "best_us" : 3839 + }, + "u4" : { + "med_us" : 3900, + "best_us" : 3871.6 + }, + "u8" : { + "med_us" : 3874.6, + "best_us" : 3852.4 + }, + "vec4_u2" : { + "med_us" : 419.625, + "best_us" : 419.03125 + }, + "vec4_u8" : { + "med_us" : 416.71875, + "best_us" : 416.53125 + }, + "vec8_u2" : { + "med_us" : 258.96875, + "best_us" : 258.625 + }, + "vec8_u8" : { + "med_us" : 260.8125, + "best_us" : 260.40625 + }, + "vec16" : { + "med_us" : 267.84375, + "best_us" : 267.59375 + } + } + }, + "axpy_f16" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 284.40625, + "best_us" : 283.78125 + }, + "vec32" : { + "med_us" : 301.1875, + "best_us" : 298.125 + }, + "vec32_u4" : { + "med_us" : 285.21875, + "best_us" : 285.0625 + }, + "vec32_u8" : { + "med_us" : 285.21875, + "best_us" : 284.78125 + }, + "vec16_u2" : { + "med_us" : 298.65625, + "best_us" : 298.1875 + }, + "vec16_u4" : { + "med_us" : 287.71875, + "best_us" : 287.375 + }, + "vec16_u8" : { + "med_us" : 288.15625, + "best_us" : 287.03125 + }, + "vec4" : { + "med_us" : 301.8125, + "best_us" : 301.53125 + }, + "vec8" : { + "med_us" : 299.8125, + "best_us" : 297.1875 + }, + "vec4_u4" : { + "med_us" : 298.09375, + "best_us" : 288.1875 + }, + "vec8_u4" : { + "med_us" : 284.46875, + "best_us" : 284.40625 + }, + "plain" : { + "med_us" : 301.4375, + "best_us" : 301.28125 + }, + "u2" : { + "med_us" : 284.59375, + "best_us" : 284.5 + }, + "u4" : { + "med_us" : 284.65625, + "best_us" : 284.625 + }, + "u8" : { + "med_us" : 284.25, + "best_us" : 284.0625 + }, + "vec4_u2" : { + "med_us" : 301.0625, + "best_us" : 300.21875 + }, + "vec4_u8" : { + "med_us" : 287.875, + "best_us" : 287.5625 + }, + "vec8_u2" : { + "med_us" : 285.21875, + "best_us" : 284.46875 + }, + "vec8_u8" : { + "med_us" : 283.875, + "best_us" : 283.53125 + }, + "vec16" : { + "med_us" : 297.75, + "best_us" : 296.78125 + } + } + }, + "cvt_f16_to_f32" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 250.78125, + "best_us" : 247.875 + }, + "vec32" : { + "med_us" : 251.71875, + "best_us" : 251.34375 + }, + "vec32_u4" : { + "med_us" : 248.25, + "best_us" : 245.125 + }, + "vec32_u8" : { + "med_us" : 247.28125, + "best_us" : 246.28125 + }, + "vec16_u2" : { + "med_us" : 249, + "best_us" : 246.8125 + }, + "vec16_u4" : { + "med_us" : 247.1875, + "best_us" : 244.90625 + }, + "vec16_u8" : { + "med_us" : 247.40625, + "best_us" : 246.9375 + }, + "vec4" : { + "med_us" : 249.21875, + "best_us" : 245 + }, + "vec8" : { + "med_us" : 250.25, + "best_us" : 241.75 + }, + "vec4_u4" : { + "med_us" : 251.75, + "best_us" : 249.4375 + }, + "vec8_u4" : { + "med_us" : 247.4375, + "best_us" : 244.625 + }, + "plain" : { + "med_us" : 246.875, + "best_us" : 239.53125 + }, + "u2" : { + "med_us" : 250.0625, + "best_us" : 248.9375 + }, + "u4" : { + "med_us" : 248.75, + "best_us" : 246.78125 + }, + "u8" : { + "med_us" : 245.84375, + "best_us" : 243.59375 + }, + "vec4_u2" : { + "med_us" : 245.40625, + "best_us" : 241.59375 + }, + "vec4_u8" : { + "med_us" : 249.75, + "best_us" : 247 + }, + "vec8_u2" : { + "med_us" : 249.15625, + "best_us" : 246.9375 + }, + "vec8_u8" : { + "med_us" : 247.03125, + "best_us" : 245.4375 + }, + "vec16" : { + "med_us" : 250.8125, + "best_us" : 247.90625 + } + } + }, + "dot" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 1633.1818181818182, + "best_us" : 1624.909090909091 + }, + "vec32" : { + "med_us" : 1647.6363636363637, + "best_us" : 1634.7272727272727 + }, + "vec32_u4" : { + "med_us" : 1628, + "best_us" : 1626.4166666666667 + }, + "vec32_u8" : { + "med_us" : 1646.3636363636363, + "best_us" : 1643.090909090909 + }, + "vec16_u2" : { + "med_us" : 1628.5833333333333, + "best_us" : 1621.9166666666667 + }, + "vec16_u4" : { + "med_us" : 1624, + "best_us" : 1622.5 + }, + "vec16_u8" : { + "med_us" : 1627.4166666666667, + "best_us" : 1623 + }, + "vec4" : { + "med_us" : 1787.4545454545455, + "best_us" : 1782.6363636363637 + }, + "vec8" : { + "med_us" : 1647, + "best_us" : 1637.6666666666667 + }, + "vec4_u4" : { + "med_us" : 1784.4545454545455, + "best_us" : 1782.2727272727273 + }, + "vec8_u4" : { + "med_us" : 1627.5, + "best_us" : 1622.9166666666667 + }, + "plain" : { + "med_us" : 15745, + "best_us" : 15554 + }, + "u2" : { + "med_us" : 15667, + "best_us" : 15332 + }, + "u4" : { + "med_us" : 15629, + "best_us" : 15571 + }, + "u8" : { + "med_us" : 15679, + "best_us" : 15429 + }, + "vec4_u2" : { + "med_us" : 1790, + "best_us" : 1788.6363636363637 + }, + "vec4_u8" : { + "med_us" : 1788, + "best_us" : 1779.5454545454545 + }, + "vec8_u2" : { + "med_us" : 1631.75, + "best_us" : 1627.9166666666667 + }, + "vec8_u8" : { + "med_us" : 1625.1666666666667, + "best_us" : 1624.75 + }, + "vec16" : { + "med_us" : 1639.75, + "best_us" : 1627.1666666666667 + } + } + }, + "q40q8_tile_gen" : { + "winner" : "mr8", + "rows" : { + "mr8" : { + "tile_us" : 29230, + "gemv_us" : 156, + "hot_us" : 9.5625 + }, + "dot_maddubs_width256_mr8" : { + "tile_us" : 308190, + "gemv_us" : 1194, + "hot_us" : 72.625 + }, + "dot_vpdpbusd_width256_mr8_nrsplit2" : { + "tile_us" : 308699, + "gemv_us" : 1221, + "hot_us" : 75.8125 + }, + "dot_maddubs_width256_mr8_nrsplit2" : { + "tile_us" : 308316, + "gemv_us" : 1154, + "hot_us" : 74.625 + }, + "mr4" : { + "tile_us" : 32916, + "gemv_us" : 171, + "hot_us" : 10.75 + }, + "reference" : { + "tile_us" : 308066, + "gemv_us" : 1220, + "hot_us" : 75.8125 + }, + "mr4_nrsplit2" : { + "tile_us" : 36740, + "gemv_us" : 177, + "hot_us" : 11 + }, + "dot_vpdpbusd_width256_mr8" : { + "tile_us" : 308246, + "gemv_us" : 1168, + "hot_us" : 74.4375 + }, + "dot_vpdpbusd_width512_mr16" : { + "tile_us" : 308362, + "gemv_us" : 1225, + "hot_us" : 75.8125 + }, + "mr8_nrsplit2" : { + "tile_us" : 33142, + "gemv_us" : 164, + "hot_us" : 10.1875 + }, + "dot_vpdpbusd_width512_mr16_nrsplit2" : { + "tile_us" : 308306, + "gemv_us" : 1222, + "hot_us" : 75.875 + } + } + }, + "axpy" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 336, + "best_us" : 335.21875 + }, + "vec32" : { + "med_us" : 358.6875, + "best_us" : 358.40625 + }, + "vec32_u4" : { + "med_us" : 337.5, + "best_us" : 336.71875 + }, + "vec32_u8" : { + "med_us" : 337.90625, + "best_us" : 336.75 + }, + "vec16_u2" : { + "med_us" : 362.3125, + "best_us" : 361.1875 + }, + "vec16_u4" : { + "med_us" : 356.84375, + "best_us" : 335.09375 + }, + "vec16_u8" : { + "med_us" : 336.6875, + "best_us" : 334.34375 + }, + "vec4" : { + "med_us" : 360.5625, + "best_us" : 359.96875 + }, + "vec8" : { + "med_us" : 360.03125, + "best_us" : 359.1875 + }, + "vec4_u4" : { + "med_us" : 336.25, + "best_us" : 335.6875 + }, + "vec8_u4" : { + "med_us" : 337.28125, + "best_us" : 336.25 + }, + "plain" : { + "med_us" : 360.84375, + "best_us" : 360.5 + }, + "u2" : { + "med_us" : 361.875, + "best_us" : 361 + }, + "u4" : { + "med_us" : 336.46875, + "best_us" : 335.0625 + }, + "u8" : { + "med_us" : 336.28125, + "best_us" : 334.5 + }, + "vec4_u2" : { + "med_us" : 361.6875, + "best_us" : 359.96875 + }, + "vec4_u8" : { + "med_us" : 336.84375, + "best_us" : 336.0625 + }, + "vec8_u2" : { + "med_us" : 337.875, + "best_us" : 336.1875 + }, + "vec8_u8" : { + "med_us" : 335.75, + "best_us" : 335.53125 + }, + "vec16" : { + "med_us" : 361.34375, + "best_us" : 360.4375 + } + } + }, + "dot_q8q8kv" : { + "winner" : "plain", + "fallback" : "vec16", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 5.287910071117229, + "rows" : { + "vec32_u2" : { + "med_us" : 140, + "best_us" : 139.75 + }, + "vec32" : { + "med_us" : 136.15625, + "best_us" : 135.90625 + }, + "vec32_u4" : { + "med_us" : 140.03125, + "best_us" : 140 + }, + "vec32_u8" : { + "med_us" : 140.40625, + "best_us" : 139.96875 + }, + "vec16_u2" : { + "med_us" : 139.53125, + "best_us" : 139.25 + }, + "vec16_u4" : { + "med_us" : 139.6875, + "best_us" : 139.53125 + }, + "vec16_u8" : { + "med_us" : 139.625, + "best_us" : 139.53125 + }, + "vec4" : { + "med_us" : 128.671875, + "best_us" : 128.25 + }, + "vec8" : { + "med_us" : 128.84375, + "best_us" : 128.8125 + }, + "vec4_u4" : { + "med_us" : 487.84375, + "best_us" : 487.5625 + }, + "vec8_u4" : { + "med_us" : 194.21875, + "best_us" : 194 + }, + "plain" : { + "med_us" : 129.015625, + "best_us" : 128.65625 + }, + "u2" : { + "med_us" : 139.71875, + "best_us" : 139.53125 + }, + "u4" : { + "med_us" : 139.5, + "best_us" : 139.25 + }, + "u8" : { + "med_us" : 139.53125, + "best_us" : 139.28125 + }, + "vec4_u2" : { + "med_us" : 487.84375, + "best_us" : 487.6875 + }, + "vec4_u8" : { + "med_us" : 487.65625, + "best_us" : 487.53125 + }, + "vec8_u2" : { + "med_us" : 194.3125, + "best_us" : 194.03125 + }, + "vec8_u8" : { + "med_us" : 194.40625, + "best_us" : 193.9375 + }, + "vec16" : { + "med_us" : 136.21875, + "best_us" : 135.8125 + } + } + }, + "dot_mx4q8" : { + "winner" : "u2", + "fallback" : "u2", + "floor_pct" : 0.17611273380775314, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 163.59375, + "best_us" : 163.53125 + }, + "vec32" : { + "med_us" : 164.1875, + "best_us" : 164.15625 + }, + "vec32_u4" : { + "med_us" : 164, + "best_us" : 163.96875 + }, + "vec32_u8" : { + "med_us" : 163.96875, + "best_us" : 163.71875 + }, + "vec16_u2" : { + "med_us" : 163.5625, + "best_us" : 163.5 + }, + "vec16_u4" : { + "med_us" : 163.9375, + "best_us" : 163.6875 + }, + "vec16_u8" : { + "med_us" : 164.03125, + "best_us" : 163.75 + }, + "vec4" : { + "med_us" : 164.21875, + "best_us" : 164.03125 + }, + "vec8" : { + "med_us" : 164.15625, + "best_us" : 163.84375 + }, + "vec4_u4" : { + "med_us" : 164, + "best_us" : 163.65625 + }, + "vec8_u4" : { + "med_us" : 164.0625, + "best_us" : 164 + }, + "plain" : { + "med_us" : 164, + "best_us" : 163.625 + }, + "u2" : { + "med_us" : 163.78125, + "best_us" : 163.53125 + }, + "u4" : { + "med_us" : 164, + "best_us" : 163.6875 + }, + "u8" : { + "med_us" : 164.25, + "best_us" : 163.8125 + }, + "vec4_u2" : { + "med_us" : 163.53125, + "best_us" : 163.40625 + }, + "vec4_u8" : { + "med_us" : 163.78125, + "best_us" : 163.6875 + }, + "vec8_u2" : { + "med_us" : 163.71875, + "best_us" : 163.53125 + }, + "vec8_u8" : { + "med_us" : 163.71875, + "best_us" : 163.65625 + }, + "vec16" : { + "med_us" : 164.125, + "best_us" : 164.03125 + } + } + }, + "dot_q8q8_laneq4x4" : { + "winner" : "u2", + "fallback" : "u2", + "floor_pct" : 0.17611273380775314, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 750.5384615384615, + "best_us" : 748.8846153846154 + }, + "vec32" : { + "med_us" : 756.2307692307693, + "best_us" : 755.3461538461538 + }, + "vec32_u4" : { + "med_us" : 752.2307692307693, + "best_us" : 752.0769230769231 + }, + "vec32_u8" : { + "med_us" : 846.7083333333334, + "best_us" : 844.6666666666666 + }, + "vec16_u2" : { + "med_us" : 750.4230769230769, + "best_us" : 749.7692307692307 + }, + "vec16_u4" : { + "med_us" : 752.5, + "best_us" : 751.5 + }, + "vec16_u8" : { + "med_us" : 845.695652173913, + "best_us" : 843.695652173913 + }, + "vec4" : { + "med_us" : 755.6153846153846, + "best_us" : 755.0769230769231 + }, + "vec8" : { + "med_us" : 755.5, + "best_us" : 754.8846153846154 + }, + "vec4_u4" : { + "med_us" : 752.9615384615385, + "best_us" : 752 + }, + "vec8_u4" : { + "med_us" : 752.6153846153846, + "best_us" : 751.6538461538462 + }, + "plain" : { + "med_us" : 755.5769230769231, + "best_us" : 754.6923076923077 + }, + "u2" : { + "med_us" : 750.8846153846154, + "best_us" : 749.8076923076923 + }, + "u4" : { + "med_us" : 752.8076923076923, + "best_us" : 752.1153846153846 + }, + "u8" : { + "med_us" : 846.6521739130435, + "best_us" : 845.2608695652174 + }, + "vec4_u2" : { + "med_us" : 750.8846153846154, + "best_us" : 749.0769230769231 + }, + "vec4_u8" : { + "med_us" : 845.1739130434783, + "best_us" : 842.304347826087 + }, + "vec8_u2" : { + "med_us" : 751.7307692307693, + "best_us" : 750.2692307692307 + }, + "vec8_u8" : { + "med_us" : 846.8260869565217, + "best_us" : 844.1304347826087 + }, + "vec16" : { + "med_us" : 755.3076923076923, + "best_us" : 754.8461538461538 + } + } + }, + "scale_inplace" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 251.71875, + "best_us" : 250.3125 + }, + "vec32" : { + "med_us" : 248.5625, + "best_us" : 245.5 + }, + "vec32_u4" : { + "med_us" : 249.71875, + "best_us" : 249.65625 + }, + "vec32_u8" : { + "med_us" : 250.5625, + "best_us" : 248.3125 + }, + "vec16_u2" : { + "med_us" : 265.46875, + "best_us" : 264.40625 + }, + "vec16_u4" : { + "med_us" : 264.84375, + "best_us" : 264.5 + }, + "vec16_u8" : { + "med_us" : 1112.611111111111, + "best_us" : 1111.5555555555557 + }, + "vec4" : { + "med_us" : 246.46875, + "best_us" : 244.90625 + }, + "vec8" : { + "med_us" : 250.25, + "best_us" : 248.6875 + }, + "vec4_u4" : { + "med_us" : 247.8125, + "best_us" : 247.1875 + }, + "vec8_u4" : { + "med_us" : 251.9375, + "best_us" : 251.3125 + }, + "plain" : { + "med_us" : 245.671875, + "best_us" : 244.75 + }, + "u2" : { + "med_us" : 246.1875, + "best_us" : 244.84375 + }, + "u4" : { + "med_us" : 247.5, + "best_us" : 244.46875 + }, + "u8" : { + "med_us" : 248.0625, + "best_us" : 247.09375 + }, + "vec4_u2" : { + "med_us" : 246.109375, + "best_us" : 244.59375 + }, + "vec4_u8" : { + "med_us" : 248, + "best_us" : 246.40625 + }, + "vec8_u2" : { + "med_us" : 254.078125, + "best_us" : 251.0625 + }, + "vec8_u8" : { + "med_us" : 251.25, + "best_us" : 250.6875 + }, + "vec16" : { + "med_us" : 268.6875, + "best_us" : 267.15625 + } + }, + "demoted" : "plain" + }, + "dot_q4" : { + "winner" : "vec4_u4", + "fallback" : "vec4_u4", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 1640.5, + "best_us" : 1627.9166666666667 + }, + "vec32" : { + "med_us" : 1967, + "best_us" : 1965.2 + }, + "vec32_u4" : { + "med_us" : 1555.5, + "best_us" : 1552.0833333333333 + }, + "vec32_u8" : { + "med_us" : 1523.3333333333333, + "best_us" : 1517.8333333333333 + }, + "vec16_u2" : { + "med_us" : 1014.1578947368421, + "best_us" : 1013.4736842105264 + }, + "vec16_u4" : { + "med_us" : 1014.2105263157895, + "best_us" : 1013.2105263157895 + }, + "vec16_u8" : { + "med_us" : 1013.8421052631579, + "best_us" : 1012.8947368421053 + }, + "vec4" : { + "med_us" : 1967.9, + "best_us" : 1966.6 + }, + "vec8" : { + "med_us" : 1969.9, + "best_us" : 1968.7 + }, + "vec4_u4" : { + "med_us" : 815.5833333333334, + "best_us" : 815.1666666666666 + }, + "vec8_u4" : { + "med_us" : 847.695652173913, + "best_us" : 847 + }, + "plain" : { + "med_us" : 1968.6, + "best_us" : 1968.2 + }, + "u2" : { + "med_us" : 1023.8421052631579, + "best_us" : 1023.2631578947369 + }, + "u4" : { + "med_us" : 1023.7368421052631, + "best_us" : 1023.3157894736842 + }, + "u8" : { + "med_us" : 1024.5263157894738, + "best_us" : 1023.578947368421 + }, + "vec4_u2" : { + "med_us" : 815.6666666666666, + "best_us" : 814.9166666666666 + }, + "vec4_u8" : { + "med_us" : 816, + "best_us" : 815.375 + }, + "vec8_u2" : { + "med_us" : 847.3913043478261, + "best_us" : 847.0869565217391 + }, + "vec8_u8" : { + "med_us" : 847.7391304347826, + "best_us" : 847.2608695652174 + }, + "vec16" : { + "med_us" : 1968.4, + "best_us" : 1967.4 + } + } + }, + "copy_floats" : { + "winner" : "vec8_u2", + "fallback" : "vec8_u2", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 0, + "rows" : { + "vec32_u2" : { + "med_us" : 464.59375, + "best_us" : 271.46875 + }, + "vec32" : { + "med_us" : 504.671875, + "best_us" : 265.3125 + }, + "vec32_u4" : { + "med_us" : 566.0625, + "best_us" : 271.4375 + }, + "vec32_u8" : { + "med_us" : 565.4375, + "best_us" : 267.28125 + }, + "vec16_u2" : { + "med_us" : 276.21875, + "best_us" : 267.59375 + }, + "vec16_u4" : { + "med_us" : 281.875, + "best_us" : 266.3125 + }, + "vec16_u8" : { + "med_us" : 546.9375, + "best_us" : 263.8125 + }, + "vec4" : { + "med_us" : 275.3125, + "best_us" : 266.28125 + }, + "vec8" : { + "med_us" : 423.984375, + "best_us" : 266.125 + }, + "vec4_u4" : { + "med_us" : 275.40625, + "best_us" : 269.65625 + }, + "vec8_u4" : { + "med_us" : 565.578125, + "best_us" : 266.375 + }, + "plain" : { + "med_us" : 566.46875, + "best_us" : 267.5 + }, + "u2" : { + "med_us" : 565.84375, + "best_us" : 266.46875 + }, + "u4" : { + "med_us" : 342.375, + "best_us" : 266.78125 + }, + "u8" : { + "med_us" : 433.609375, + "best_us" : 263.84375 + }, + "vec4_u2" : { + "med_us" : 419.5625, + "best_us" : 266.40625 + }, + "vec4_u8" : { + "med_us" : 277.5, + "best_us" : 264.625 + }, + "vec8_u2" : { + "med_us" : 430.8125, + "best_us" : 265.03125 + }, + "vec8_u8" : { + "med_us" : 565.890625, + "best_us" : 266.125 + }, + "vec16" : { + "med_us" : 566.28125, + "best_us" : 265.65625 + } + } + }, + "rmsnorm" : { + "winner" : "vec8", + "fallback" : "plain", + "floor_pct" : 0.12710752840515288, + "margin_pct" : 86.05360389419975, + "rows" : { + "vec32_u2" : { + "med_us" : 626.6774193548387, + "best_us" : 625.7741935483871 + }, + "vec32" : { + "med_us" : 614.09375, + "best_us" : 613.9375 + }, + "vec32_u4" : { + "med_us" : 620.8125, + "best_us" : 619.1875 + }, + "vec32_u8" : { + "med_us" : 621.28125, + "best_us" : 621.09375 + }, + "vec16_u2" : { + "med_us" : 602.328125, + "best_us" : 601.5 + }, + "vec16_u4" : { + "med_us" : 606.171875, + "best_us" : 605.34375 + }, + "vec16_u8" : { + "med_us" : 611.046875, + "best_us" : 610.09375 + }, + "vec4" : { + "med_us" : 686.0344827586207, + "best_us" : 684.6206896551724 + }, + "vec8" : { + "med_us" : 593.484375, + "best_us" : 592.15625 + }, + "vec4_u4" : { + "med_us" : 693.2857142857143, + "best_us" : 692.7857142857143 + }, + "vec8_u4" : { + "med_us" : 599.296875, + "best_us" : 598.4375 + }, + "plain" : { + "med_us" : 4304, + "best_us" : 4209.25 + }, + "u2" : { + "med_us" : 4237, + "best_us" : 4189.25 + }, + "u4" : { + "med_us" : 4209, + "best_us" : 4201 + }, + "u8" : { + "med_us" : 4302.25, + "best_us" : 4229.25 + }, + "vec4_u2" : { + "med_us" : 686.2413793103449, + "best_us" : 685.9310344827586 + }, + "vec4_u8" : { + "med_us" : 693.3571428571429, + "best_us" : 692.7857142857143 + }, + "vec8_u2" : { + "med_us" : 598.671875, + "best_us" : 597.375 + }, + "vec8_u8" : { + "med_us" : 599.234375, + "best_us" : 598.375 + }, + "vec16" : { + "med_us" : 600.09375, + "best_us" : 599.59375 + } + } + } + }, + "runtime" : { + "jobque_spin_us" : 30000, + "target_chunk_work" : 1, + "norm_par_threshold" : 256000, + "gemv_lane_cap" : 0, + "matmul_min_chunk_rows" : 16, + "batch_grid_2d" : 0, + "metal_devw_small_panel_mb" : 32, + "team_rank_gate" : -1, + "kv_store_par_threshold" : 256000, + "q8_l2_budget" : 4194304, + "rope_par_threshold" : 100000, + "jobque_join_poll" : 50, + "q8_token_block" : 128, + "requant_par_threshold" : 256000, + "metal_tensor" : "mulmm_bf16,mulmm_q8,moe_mulmm_q8,moe_mulmm_mx4,attn_qkmm,kq_mulmm_k4,kq_mulmm_k5,kq_mulmm_k6,gemmb_q8,gemmb_sk_q8,gemm64b_q8", + "matmul_min_chunk_rows_gemv" : 64, + "attn_par_threshold" : 100000, + "batch_lane_cap" : 0, + "metal_cvt_min_rows" : 256, + "metal_tall_floor" : 64, + "act_par_threshold" : 100000, + "threads" : 6, + "dispatch_worker_limit" : 0, + "q8_batch_chunks_per_job" : 4, + "q8_chunks_per_job" : 2, + "q4_chunks_per_job" : 4 + } +} \ No newline at end of file diff --git a/site/files/dasllama/bench_records.json b/site/files/dasllama/bench_records.json index c3128a51e6..9b4891d9d1 100644 --- a/site/files/dasllama/bench_records.json +++ b/site/files/dasllama/bench_records.json @@ -503,7 +503,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-35B-A3B-MTP-UD-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -518,20 +518,20 @@ }, "tests":{ "pp512":{ - "tok_s":3203.3164089532825, - "stddev":10.003824234008789 + "tok_s":3201.3003848974017, + "stddev":5.6111979484558105 }, "tg128":{ - "tok_s":126.71243283801149, - "stddev":0.31083890795707703 + "tok_s":127.311408165347, + "stddev":0.40768790245056152 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k5/k6/q8 native; q8 activations; f16 scales; metal blob", @@ -550,8 +550,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-35B-A3B-MTP-UD-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-35B-A3B-MTP-UD-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -565,16 +565,16 @@ }, "tests":{ "pp512":{ - "tok_s":3181.7403960000001, - "stddev":16.853456000000001 + "tok_s":3183.6708789999998, + "stddev":19.433194 }, "tg128":{ - "tok_s":95.617856000000003, - "stddev":0.433614 + "tok_s":95.600543000000002, + "stddev":0.52021399999999995 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -1266,7 +1266,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-27B-MTP-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -1281,20 +1281,20 @@ }, "tests":{ "pp512":{ - "tok_s":715.40921968834391, - "stddev":0.28290107846260071 + "tok_s":888.29681098337915, + "stddev":4.535797119140625 }, "tg128":{ - "tok_s":27.391927471755071, - "stddev":0.2634216845035553 + "tok_s":27.423391866797225, + "stddev":0.11130748689174652 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f16 scales; metal blob", @@ -1313,8 +1313,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-27B-MTP-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.6-27B-MTP-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -1328,16 +1328,16 @@ }, "tests":{ "pp512":{ - "tok_s":738.58820300000002, - "stddev":0.42859700000000001 + "tok_s":739.10453299999995, + "stddev":0.48830800000000002 }, "tg128":{ - "tok_s":27.243791000000002, - "stddev":0.97493399999999997 + "tok_s":27.332798, + "stddev":0.96453999999999995 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -2584,7 +2584,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-12B-it-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -2599,20 +2599,20 @@ }, "tests":{ "pp512":{ - "tok_s":1686.5738524264857, - "stddev":1.4621291160583496 + "tok_s":1938.9908117881037, + "stddev":3.0214979648590088 }, "tg128":{ - "tok_s":63.71401394823058, - "stddev":2.7017333507537842 + "tok_s":63.761391280043405, + "stddev":2.6959183216094971 } }, "source":"official", - "sha":"b63198111", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -2631,8 +2631,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-12B-it-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-12B-it-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -2646,16 +2646,16 @@ }, "tests":{ "pp512":{ - "tok_s":1701.870887, - "stddev":0.77144800000000002 + "tok_s":1703.5040280000001, + "stddev":1.5609329999999999 }, "tg128":{ - "tok_s":60.556725, - "stddev":0.094574000000000005 + "tok_s":60.580466000000001, + "stddev":0.22184499999999999 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -2672,7 +2672,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-12B-it-Q4_K_M.gguf --image-mmproj /Users/borisbatkin/Work/llama.cpp/models/mmproj-gemma-4-12B-it-BF16.gguf --image /Users/borisbatkin/Work/llama.cpp/models/coco-val2017-000000039769.jpg -r 3 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -2687,23 +2687,23 @@ }, "tests":{ "img:enc":{ - "ms":7.1550000000000002 + "ms":7.1980000000000004 }, "img:pp":{ - "tok_s":1089.7659797415299 + "tok_s":1284.7225081736351 }, "img:tg":{ - "tok_s":65.601451218190434, + "tok_s":65.699831751300422, "text":"Two tabby cats are lying on a pink surface, with one cat on the left and the other on the right." } }, "workload":"image-chat", "source":"official", - "sha":"4c135f4bd", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4uv f32; weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -3967,7 +3967,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E4B-it-Q8_0.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -3982,20 +3982,20 @@ }, "tests":{ "pp512":{ - "tok_s":5115.2998693325899, - "stddev":10.156952857971191 + "tok_s":5123.0211944582243, + "stddev":21.226161956787109 }, "tg128":{ - "tok_s":90.05206929423548, - "stddev":0.048173848539590836 + "tok_s":90.197186400189821, + "stddev":0.03762681782245636 } }, "source":"official", - "sha":"4c135f4bd", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights q8 native; q8 activations; f16 scales; metal blob", @@ -4014,8 +4014,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E4B-it-Q8_0.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E4B-it-Q8_0.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -4029,16 +4029,16 @@ }, "tests":{ "pp512":{ - "tok_s":4348.8734290000002, - "stddev":14.695126999999999 + "tok_s":4331.2716979999996, + "stddev":7.9024109999999999 }, "tg128":{ - "tok_s":81.298264000000003, - "stddev":0.43596400000000002 + "tok_s":81.157066999999998, + "stddev":0.26690799999999998 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -4055,7 +4055,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E4B-it-Q8_0.gguf --image-mmproj /Users/borisbatkin/Work/llama.cpp/models/mmproj-gemma-4-E4B-it-BF16.gguf --image /Users/borisbatkin/Work/llama.cpp/models/coco-val2017-000000039769.jpg -r 3 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -4070,23 +4070,23 @@ }, "tests":{ "img:enc":{ - "ms":38.392000000000003 + "ms":38.402000000000001 }, "img:pp":{ - "tok_s":1767.785508691612 + "tok_s":1764.6859198425357 }, "img:tg":{ - "tok_s":88.229860844966353, + "tok_s":88.326299431675466, "text":"The user wants a one-sentence description of the provided image.\nThe image contains two cats lying on a pink surface.\n\nPlan: Describe the main subjects" } }, "workload":"image-chat", "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4v f32; weights q8 native; q8 activations; f16 scales; metal blob", @@ -4918,7 +4918,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gpt-oss-20b-mxfp4.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -4933,20 +4933,20 @@ }, "tests":{ "pp512":{ - "tok_s":3988.4431260025494, - "stddev":17.16136360168457 + "tok_s":3989.4203630795723, + "stddev":18.226713180541992 }, "tg128":{ - "tok_s":163.34938114401598, - "stddev":0.14880651235580444 + "tok_s":163.21584485670596, + "stddev":0.13277889788150787 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights mxfp4/q8 native; q8 activations; f16 scales; metal blob", @@ -4965,8 +4965,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gpt-oss-20b-mxfp4.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gpt-oss-20b-mxfp4.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -4980,16 +4980,16 @@ }, "tests":{ "pp512":{ - "tok_s":3483.8785250000001, - "stddev":8.3781250000000007 + "tok_s":3475.262072, + "stddev":8.8958180000000002 }, "tg128":{ - "tok_s":147.45539099999999, - "stddev":0.24805099999999999 + "tok_s":147.511551, + "stddev":0.410717 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -5681,7 +5681,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3-30B-A3B-Instruct-2507-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -5696,20 +5696,20 @@ }, "tests":{ "pp512":{ - "tok_s":3503.0512105282019, - "stddev":20.681808471679688 + "tok_s":3506.8078045084162, + "stddev":19.61585807800293 }, "tg128":{ - "tok_s":165.11343776111951, - "stddev":0.42980408668518066 + "tok_s":165.24557967328658, + "stddev":0.11801531910896301 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -5728,8 +5728,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3-30B-A3B-Instruct-2507-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3-30B-A3B-Instruct-2507-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -5743,16 +5743,16 @@ }, "tests":{ "pp512":{ - "tok_s":3435.2990580000001, - "stddev":14.437657 + "tok_s":3425.5220340000001, + "stddev":13.952795 }, "tg128":{ - "tok_s":138.64061000000001, - "stddev":0.70350400000000002 + "tok_s":136.43157400000001, + "stddev":0.83255500000000005 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -6450,7 +6450,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/Mistral-Small-3.1-24B-Instruct-2503-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -6465,20 +6465,20 @@ }, "tests":{ "pp512":{ - "tok_s":678.27299728451783, - "stddev":10.671237945556641 + "tok_s":1107.5193206908937, + "stddev":1.1255176067352295 }, "tg128":{ - "tok_s":38.179134606688692, - "stddev":0.13497893512248993 + "tok_s":38.298495651945146, + "stddev":0.053260661661624908 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6 native; q8 activations; f32 scales; metal blob", @@ -6497,8 +6497,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Mistral-Small-3.1-24B-Instruct-2503-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Mistral-Small-3.1-24B-Instruct-2503-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -6512,16 +6512,16 @@ }, "tests":{ "pp512":{ - "tok_s":991.262429, - "stddev":0.68436399999999997 + "tok_s":991.28601000000003, + "stddev":0.77159100000000003 }, "tg128":{ - "tok_s":36.665574999999997, - "stddev":1.0958939999999999 + "tok_s":36.653257000000004, + "stddev":1.1031610000000001 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -7219,7 +7219,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-26B-A4B-it-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -7234,20 +7234,20 @@ }, "tests":{ "pp512":{ - "tok_s":3045.4359807557762, - "stddev":11.667203903198242 + "tok_s":3648.4381650295713, + "stddev":15.327509880065918 }, "tg128":{ - "tok_s":118.15454129201358, - "stddev":5.1164727210998535 + "tok_s":118.26094767794341, + "stddev":5.0962691307067871 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/q51/q8 native; q8 activations; f16 scales; metal blob", @@ -7266,8 +7266,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-26B-A4B-it-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-26B-A4B-it-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -7281,16 +7281,16 @@ }, "tests":{ "pp512":{ - "tok_s":3461.0379939999998, - "stddev":11.285895999999999 + "tok_s":3469.808806, + "stddev":11.919931 }, "tg128":{ - "tok_s":99.731941000000006, - "stddev":0.35907899999999998 + "tok_s":99.490211000000002, + "stddev":0.274507 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -15410,7 +15410,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E2B-it-Q8_0.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -15425,20 +15425,20 @@ }, "tests":{ "pp512":{ - "tok_s":8642.0529972527293, - "stddev":47.174034118652344 + "tok_s":8692.8377108443274, + "stddev":42.567550659179688 }, "tg128":{ - "tok_s":160.97335724299222, - "stddev":0.89381587505340576 + "tok_s":161.72247100178595, + "stddev":0.25893470644950867 } }, "source":"official", - "sha":"3e28d443c", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights q8 native; q8 activations; f16 scales; metal blob", @@ -15457,8 +15457,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E2B-it-Q8_0.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E2B-it-Q8_0.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -15472,16 +15472,16 @@ }, "tests":{ "pp512":{ - "tok_s":7531.6944620000004, - "stddev":43.024726999999999 + "tok_s":7527.4361060000001, + "stddev":28.764002000000001 }, "tg128":{ - "tok_s":137.73860400000001, - "stddev":0.74135899999999999 + "tok_s":136.59289799999999, + "stddev":0.146476 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { @@ -15674,7 +15674,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/gemma-4-E2B-it-Q8_0.gguf --image-mmproj /Users/borisbatkin/Work/llama.cpp/models/mmproj-gemma-4-E2B-it-bf16.gguf --image /Users/borisbatkin/Work/llama.cpp/models/coco-val2017-000000039769.jpg -r 3 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -15689,23 +15689,23 @@ }, "tests":{ "img:enc":{ - "ms":37.465000000000003 + "ms":37.079999999999998 }, "img:pp":{ - "tok_s":3560.2619987676017 + "tok_s":3542.7974473690188 }, "img:tg":{ - "tok_s":154.73169524045306, + "tok_s":155.15743307542721, "text":": This is an image of two tabby cats lying on a pink surface." } }, "workload":"image-chat", "source":"official", - "sha":"b63198111", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4v f32; weights q8 native; q8 activations; f16 scales; metal blob", @@ -17856,7 +17856,7 @@ "flavor":"tuned", "box":"m5", "threads":6, - "date":"2026-08-26", + "date":"2026-08-27", "cmd":"modules/dasLLAMA/performance/_rig/dasllama-bench.app/Contents/MacOS/dasllama-bench -- -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.8-27B-Q4_K_M.gguf -p 512 -n 128 -r 5 -t 6 -o json --json-path modules/dasLLAMA/performance/records/_cell_m5.json --ngl 99", "hardware":{ "cpu":"Apple M5 Max", @@ -17871,20 +17871,20 @@ }, "tests":{ "pp512":{ - "tok_s":726.61977095890393, - "stddev":0.84915745258331299 + "tok_s":891.6510131320847, + "stddev":3.1367990970611572 }, "tg128":{ - "tok_s":27.829948364707995, - "stddev":0.31860759854316711 + "tok_s":27.886035408758552, + "stddev":0.073721945285797119 } }, "source":"official", - "sha":"5e59c0bf1", + "sha":"dc0992306", "version":"0.6.4", "dasllama_version":10, - "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr4 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr4_nrsplit2 (manifest)", - "tune_sha":"e9717e93f2558aaddd75c972dddb3d4b29ba0793f3ab4bfcd7aa51cc184c9d4c", + "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", + "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f16 scales; metal blob", @@ -17903,8 +17903,8 @@ "flavor":"stock", "box":"m5", "threads":6, - "date":"2026-08-26", - "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-3737e41/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.8-27B-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", + "date":"2026-08-27", + "cmd":"/Users/borisbatkin/Work/llama.cpp-ref-6fdd0ac/build-stock/bin/llama-bench -m /Users/borisbatkin/Work/llama.cpp/models/Qwen3.8-27B-Q4_K_M.gguf -ngl 99 -t 6 -p 512 -n 128 -r 5 -o json", "hardware":{ "cpu":"Apple M5 Max", "arch":"arm64", @@ -17918,16 +17918,16 @@ }, "tests":{ "pp512":{ - "tok_s":752.521342, - "stddev":0.74508200000000002 + "tok_s":752.63394100000005, + "stddev":0.68924799999999997 }, "tg128":{ - "tok_s":25.334861, - "stddev":0.59087599999999996 + "tok_s":25.433668999999998, + "stddev":0.53600499999999995 } }, "source":"official", - "sha":"3737e4137", + "sha":"6fdd0ac89", "exec_fmt":"native gguf formats", "files":[ { From ec900aa0c1c1be2b14c0e096c791e40099221b4d Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Thu, 27 Aug 2026 23:18:03 -0700 Subject: [PATCH 09/10] dasLLAMA: pre-PR audit round - version bump, triangle rules, board re-stamp The review-md/tdd/dragon rounds' findings applied. DASLLAMA_VERSION 10 -> 11 (seven new PSOs = a new kernel roster). The devw_cvt knockout announces itself at both spellings. The seven new kernel classes enter the census blind-list with reasons. New bindings: the dev-W knee arithmetic split pure (devw_tile_pick) with a device-free test, the q51 twin-fits guard shared engine/test, a float-X T-stamp leg, and the tall remainder pair at nonzero x/y offsets. The tensor-probe replica probes two sources. The board re-stamps to 667d4c1d5 - the rebase orphaned the measured commit; the stamped tree is byte-identical under modules/dasLLAMA (sidecar renamed by content hash, site records regenerated and verified). REVIEW.md sheds its measurement family into REVIEW_MEASUREMENT.md (LINT027). REVIEW_COMMON.md gains the [arch] triangle audit rules (repo-wide). Dragon-refined wording across the rule docs; followup 53 ledgers the MoE tensor-twin template consolidation. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014fKJGuUL8tP58Y6NvoVeSn --- LAWS.md | 1 + REVIEW_COMMON.md | 13 +++++ modules/dasLLAMA/ARCHITECTURE_GPU.md | 9 ++- modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md | 42 +++++++------- modules/dasLLAMA/REVIEW.md | 47 +-------------- modules/dasLLAMA/REVIEW_GPU.md | 42 +++++++------- modules/dasLLAMA/REVIEW_MEASUREMENT.md | 47 +++++++++++++++ .../dasllama/dasllama_metal_prefill.das | 38 +++++++++---- .../dasLLAMA/dasllama/dasllama_version.das | 2 +- modules/dasLLAMA/followup_general.md | 10 ++++ modules/dasLLAMA/performance/REVIEW.md | 35 +++++++----- modules/dasLLAMA/performance/records/m5.json | 52 ++++++++--------- ...1bf9c73.json => m5.tune.d30db41e2278.json} | 2 +- modules/dasLLAMA/tests/REVIEW.md | 23 ++++---- .../dasLLAMA/tests/test_kernel_coverage.das | 12 +++- .../tests/test_metal_gemm_kernels.das | 27 +++++++++ .../tests/test_metal_prefill_kernels.das | 57 +++++++++++++++++-- site/REVIEW.md | 16 ++---- site/files/dasllama/bench_records.json | 52 ++++++++--------- 19 files changed, 333 insertions(+), 194 deletions(-) create mode 100644 modules/dasLLAMA/REVIEW_MEASUREMENT.md rename modules/dasLLAMA/performance/records/{m5.tune.461b01bf9c73.json => m5.tune.d30db41e2278.json} (99%) diff --git a/LAWS.md b/LAWS.md index 1af31188ef..688c6040b5 100644 --- a/LAWS.md +++ b/LAWS.md @@ -26,3 +26,4 @@ compacted, or cited as rules. | 2026-08-27 | .claude/agents/archivist.md (new), utils/lint (LINT027 line gate) | ARCHITECTURE.md cleanup: "1. size - needs split by sections past 300 lines (u pick the limit...) 2. some are bunch of unrelated prose. that stuff must just go. so its an extra agent for cleanup" + "we do both this PR. i'd like to not drop anchors" - archivist agent (belonging test deletes unrelated prose, census-driven splits, anchors never dropped); 300-line lint gate on rule docs in tagged folders; both arch docs groomed in this PR | | 2026-08-27 | skills/internal/make_pr.md | "should we update make_pr skill?" - the comment-drain row becomes the diff-scoped harvest row (the ruled harvest regime, trial passed on dasllama_image.das); rescue-bot references retired from the flow; the format row states no folder strips comments; the tree-frozen-during-preflight rule lands from this session's lib/-hiding incident | | 2026-08-27 | .claude/agents/ (rescue-bot, rescue-sweep-bot -> history/agents/), strip-advisory strings, .claude/hooks/README.md | "yes, lets retire both. they go to /history/agents i guess. this is evolution" - both rescue bots archived; the dormant strip advisory names the harvester as successor | +| 2026-08-27 | REVIEW_COMMON.md (the [arch] audit triangle) | "1. if function with [arch(section)] is modified, other functions which link that section are audited. 2. if [arch(foo#section)] is modified, section gets audited to not go stale. 3. if foo#section is modified, all linked functions are audited." + on scope: "repo-wide from day one." - three constitutional rules after the ships-with-tests clause; one pass per anchor discharges all duties, no cascade | diff --git a/REVIEW_COMMON.md b/REVIEW_COMMON.md index dff8d30096..a69e80326d 100644 --- a/REVIEW_COMMON.md +++ b/REVIEW_COMMON.md @@ -27,6 +27,19 @@ reachable branch ships a test that fails without it; a diff that adds a branch n distinguishes is a defect. The audit procedure - including how to settle "would this test fail without the change?" - is `skills/tdd_audit.md`. +**A diff that changes a function carrying `[arch(at="#")]` - beyond comments - +audits the anchor's other citing functions: read the section, check each citer still conforms, +verdict per function.** The citers of one anchor share one mechanism; MCP `arch_sites` lists +them. + +**A diff that adds, removes, or retargets an `[arch(at=...)]` citation audits the cited +section against the code - both sections on a retarget.** The citation claims the section +describes this function; verify it does, and that no anchor is left citer-less. + +**A diff that changes an anchored section audits every function citing that anchor.** One +audit pass over an anchor's section text and citer set discharges every audit duty the diff +triggers on that anchor - the duties never cascade. + **A rule that a test, a lint, or the folder's `REVIEW.das` enforces is deleted.** Automation replaces the rule; the checklist keeps at most "weakening that check is a defect." A rule that COULD be automated is a lint or `REVIEW.das` candidate - say so in the review round. diff --git a/modules/dasLLAMA/ARCHITECTURE_GPU.md b/modules/dasLLAMA/ARCHITECTURE_GPU.md index 90661b10af..7201eb514a 100644 --- a/modules/dasLLAMA/ARCHITECTURE_GPU.md +++ b/modules/dasLLAMA/ARCHITECTURE_GPU.md @@ -175,12 +175,11 @@ sync duty is `REVIEW_GPU.md`'s. 3.5x slower - the mixed-int combinations exist in MPP's type lists but lower off the NAX fast path. W8A8 claims from other stacks do not transfer through MPP. -**Sanctioned float-A stamps** (the licensed set of the rule that a `matmul2d` operand reaches -the op as `float` only in a class stamped `[metal_kernel(float_a_ok=true)]`, each carrying -that stamp): every tensor template's `XT = float` stamp - the live fallback wherever the half -panel is absent (below the convert row floor, panel does not fit, half-X pinned off) - and the +**Sanctioned float-A stamps** - the kernel classes stamped `[metal_kernel(float_a_ok=true)]`: +every tensor template's `XT = float` stamp - the live fallback wherever the half panel is absent +(below the convert row floor, panel does not fit, half-X pinned off) - and the batch-decode/classifier `MetalQ8GemmTensorT` family, whose half-X extension is an open ledger -item. A float A operand anywhere else is the defect the rule names. +item. - **Fused single-kernel attention (scores in threadgroup, online softmax):** loses 10-80% to the pipelined three-pass at real shapes (`benchmarks/attn/bench_metal_pf_fused_attn.das`) - Metal's cross-kernel pipelining plus full-width softmax beat tg-scope fusion. diff --git a/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md b/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md index 75269fe89d..ec0af6b8b0 100644 --- a/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md +++ b/modules/dasLLAMA/ARCHITECTURE_GPU_PREFILL.md @@ -13,13 +13,15 @@ The rows that remain pick one of four forms, in this order, per site per forward wins: it dequants its own W tile in threadgroup memory and reads the quant plane (~0.56 B/element) once per 128-row tile, where a materialized f16 panel writes 2 B/element and re-streams them per tile. The knee is panel SIZE, not tile count - a - 118 MiB panel wins 15-25% on the tall stamp while an 84 MiB one measures a small loss. + 118 MiB panel wins 15-25% on the tall stamp while an 84 MiB one measures a small loss + (`benchmarks/lcpp_bench.das -p 512 -n 0 -r 5 --ngl 99` A/B with the gate forced per run, + gemma-4-12B ffn and Qwen3.8-27B qkv carriers, m5). The 32-row TH stamp covers the row remainder at its X/y offsets. 2. **dev-W all-device** - the weight plane is dequantized into a device f16 panel and multiplied half x half. No threadgroup staging and no barriers, so the staged-operand tax is gone; the dequant pass is paid once per site per forward against a GEMM that re-reads the f16 W panel - once per M row tile (`mp/128` on the tall stamp, `mp/32` on the 32-row stamp). sec.2.2d - carries the panel size rules. + once per M row tile (`mp/128` on the tall stamp, `mp/32` on the 32-row stamp, where `mp = + ceil32(npos)` is the padded row count). sec.2.2d carries the panel size rules. 3. **tall 128-row M-tile** - the stamp streams W `M/128` times over a 128-row tile, taken on the row count's 128-floor with the 32-row stamp on the remainder. The remainder arm strides X by `kdim`, so a caller that passes no `kdim` takes the tall stamp only when its row count is @@ -39,8 +41,7 @@ kept-bf16 blob with no resident f32 copy. **The occupancy floor guards the tall stamp.** A tall grid is taken only when `rows/128 * (d/64) >= TALL_OCC_FLOOR` (default 64, a sidecar knob). An under-occupied tall grid -starves the GPU and small prompts regress hard without the floor; 32 adds nothing over 64, raced -at mid-M across three dense families. +starves the GPU and small prompts regress hard without the floor. ### 2.2d The dev-W panel knee map {#devw-panel-knees} @@ -55,30 +56,30 @@ count repays. The raced evidence (32 MiB wins everywhere, 47 MiB only from 2048 rows, 112 MiB loses everywhere) is `benchmarks/matmul/bench_metal_nax_probe.das`'s grid. -Three clauses the isolated grid cannot see, because it races one site while production overlaps +Clauses the isolated grid cannot see, because it races one site while production overlaps sites: - **A long-K (down-projection) dequant serializes** on the panel pair behind the up/gate GEMM chain at small M, so it loses end to end there despite winning its isolated site race. The long-K floor is 1024 rows on q8; the same tiling that wins its isolated site race at 512 - rows measures zero to negative end to end. + rows measures zero to negative end to end (`../benchmarks/lcpp_bench.das -p 512 -n 0` A/B + with the form forced per run). - **An over-knee panel runs as N-column TILES**, each under the small-panel knee, with the tile count bounded by `DEVW_MAX_TILES` (32), divisibility, the small-panel knee and the pool. - Narrow tiles measure fine - a 20-threadgroup tile dispatch still beat the tg-staged fallback - at 512 rows. A K-quant site whose panel reaches `TALLKQ_MIN_PANEL` (96 MiB) leaves dev-W - entirely for the tall in-kernel-dequant stamp (sec.2.2c form 1): at that size the panel is - DRAM-resident and the f16 materialization plus re-stream loses to reading the quant plane - in-kernel. -- **A k-quant tg fallback is about 1.28x the q8 half-panel form**, so a k-quant site lowers the + Narrow tiles measure fine in the same A/B. A K-quant site whose panel reaches + `TALLKQ_MIN_PANEL` leaves dev-W entirely for the tall in-kernel-dequant stamp (sec.2.2c + form 1). +- **A k-quant tg fallback is slower than the q8 half-panel form**, so a k-quant site lowers the over-knee bar, the tiled-rows floor, and the long-K floor (1024 rows to 512): a tiled read still beats THAT fallback. -The knee constants are box-raced and cached at init from the sidecar (`metal_cvt_min_rows`, -`metal_tall_floor`, `metal_devw_small_panel_mb`). +`CVT_MIN_ROWS`, `TALL_OCC_FLOOR` and `DEVW_SMALL_PANEL` are box-raced and cached at init from +the sidecar (`metal_cvt_min_rows`, `metal_tall_floor`, `metal_devw_small_panel_mb`); the other +knees are fixed. ### 2.2e The GEMV tail peel {#gemv-tail-peel} -A prefill panel pads to `mp = ceil32(npos)`, so `npos % 32` rows of every GEMM are padding. Up to +A prefill panel pads to `mp` rows, so `npos % 32` rows of every GEMM are padding. Up to `MM_TAIL_MAX` (8) remainder rows peel off the padded tile onto the fixed-B mv family instead; above that the padded tile is cheaper than three or more weight streams. One peeled row rides the reduction-split GEMV, two or more ride the b4 form only - the reduction-split GEMV walks per @@ -124,7 +125,9 @@ that parks each routed expert's rows and reduces them in entry order. The select GPU-side by the kernels; nothing reads back to the CPU, so encode-ahead and speculation stay compatible. -Pad bucket rows carry a stamped sentinel and the reduce never references them. The gather-X pass +Pad rows inside each expert's padded bucket carry a stamped sentinel and the reduce never +references them; rows past the last expert's stamped tail are unstamped stale pool bytes, which +is why validity tests compare the per-row entry against the live count, never the sentinel. The gather-X pass copies the bucket's token rows into a CONTIGUOUS f16 panel with pad rows zeroed, which lets the up and gate sites ride the contiguous tensor twins instead of the in-kernel gather form; the panel is minted once per layer and shared by both sites. An X read through the bucket index can never @@ -139,7 +142,7 @@ reloading per k-block (same lab, gmm6 section), so its stage is stateless. ### 2.2h Pad rows and cooperative-op constraints {#prefill-pad-rows-and-coop} -Activation panels size to `mp = ceil32(npos)` rows because every kernel's M grid divides `mp` by +Activation panels size to `mp` rows because every kernel's M grid divides `mp` by its tile height - 32 for the default stamp, 128 for the tall stamps; a 64-row pad would bill a dead 32-row GEMM block on every short prefill. The GEMM has no edge masking, so pad rows are written with whatever the tile computes. That is safe because C-block @@ -148,7 +151,8 @@ kernels all bound at `npos`, and rowstat writes `[0, npos)` only. A continuation chunk (`start_pos > 0`) attends the session's existing rows: the K/V panels hold `[0, start_pos)` gathered rows plus the chunk at the `start_pos` offset, keys pad to the QK key -grid's 64-tile, and the score slabs widen to `nk64` columns while the rows stay the `mp` queries. +grid's 64-tile, and the score slabs widen to `nk64` columns - the key rows padded to that +64-tile - while the rows stay the `mp` queries. Cooperative matmul ops shape the kernel bodies: the accumulate loop is spelled ROLLED over matrix arrays with pointer tile bumps, because the hand-unrolled spelling hoists sixteen tile diff --git a/modules/dasLLAMA/REVIEW.md b/modules/dasLLAMA/REVIEW.md index a2434af009..ad8b7cd1c1 100644 --- a/modules/dasLLAMA/REVIEW.md +++ b/modules/dasLLAMA/REVIEW.md @@ -11,6 +11,9 @@ two followup ledgers. **A timing rig - a script whose output is a measured wall or rate - wherever the diff puts it, answers to `benchmarks/REVIEW.md`.** +**A diff that writes a measured number down - into `PERF_LEDGER.md`, a checked-in doc, a +code comment, or a PR body - or adds a servable capability applies `REVIEW_MEASUREMENT.md`.** + **A change to what enters `performance/records/`, or to a provenance manifest, answers to `performance/REVIEW.md`.** A change to WHICH model file a recorded row or a manifest pins answers to it too. A model file here is a `.gguf`, a `.dlim`, an mmproj, or an image or audio @@ -130,50 +133,6 @@ where the override changes the outcome, naming it by the spelling a user would s environment variable name, the sidecar key, or the setter's function name. Per-site repeats are fine. A set-but-inert override stays silent. -**A self-measured served-turn time entering `PERF_LEDGER.md` comes from the released -`lcpp_bench` exe, never from the `-jit` script.** A served-turn time is a tok/s figure or a -turn wall. The released exe is `benchmarks/lcpp_bench.das` built by `daspkg release`. It is -spawned by `performance/gen_bench_records.das`, or run by hand where the cell's `PROFILE.md` -section says so. A `--for-debug-purposes` row is a debug instrument. A tutorial's printed -wall-clock is teaching output, feeding no board. - -**A subtraction of two measured walls written into `PERF_LEDGER.md` carries both raw walls -in the entry.** - -**A diff that adds an entry to `PERF_LEDGER.md` names the instrument that produced the entry's -reading.** The rule fires only for a reading no board cell produced. The entry also tags that -reading `direction-grade` when the reading compares across two processes or two commits. The -entry tags the reading `out-of-process` when the wall was measured from outside the benchmark -process. A reading that is neither carries no tag. - -**A diff that adds an entry to `PERF_LEDGER.md` never records a lab's A/B selection timing.** -That timing settles its adoption decision in the lab's own report and in the PR that lands the -kernel. The ledger learns the winner only through a re-measured cell. - -**A new servable capability gets its cell in the same change**: a board row spawned by -`performance/gen_bench_records.das`, or a manual `benchmarks/lcpp_bench.das` cell with its own -`PROFILE.md` section. A servable capability is a modality, a family, or a serving path - a -lane a user's turn can be served through, a q8 or f32 serving lane and a GPU tower included; -a new family or serving path landing inside an existing cell re-mints that cell's row on at -least one box instead. - -**A timing figure describing a served turn as a whole - tok/s, latency, a whole-turn model -or engine comparison - is a defect wherever it is written down with no cell behind it: a -checked-in doc, a ledger, a code comment, or a PR description.** The cell states its quant -mode and stamps box and engine provenance, so a number can never silently describe a format -nobody serves or a kernel set nobody ships. A rig-internal measurement margin - a crown -delta, a noise floor, tuner timing - is settled by the sidecar or manifest that carries the -value. A margin written into a source comment or a doc is a timing figure like any other. - -**A figure measuring one engine stage inside a served turn names the harness and flags that -produced it.** A stage figure is a stage wall, a stage share, a stage speedup, or a -cross-engine comparison of one stage. The rule holds wherever the figure is written down: a -checked-in doc, a ledger, a code comment, or a PR description. A board cell's `pp`/`tg` rate -and the whole wall of a `benchmarks/lcpp_bench.das` `-p`/`-n` cell measure the turn, not a -stage, and are not stage figures. The naming sits in the figure's own sentence, in a table -heading that covers the table's rows, or in a section-level provenance line that covers the -paragraphs under it. - **A change to user-facing API updates every place it is shown: a tutorial source, `.rst` page, docstring, help string, `README.md`, or checked-in document still showing the old call, flag, or default is a defect of the change, not of the docs.** User-facing means anything a consumer diff --git a/modules/dasLLAMA/REVIEW_GPU.md b/modules/dasLLAMA/REVIEW_GPU.md index 525be52835..aa87b49a66 100644 --- a/modules/dasLLAMA/REVIEW_GPU.md +++ b/modules/dasLLAMA/REVIEW_GPU.md @@ -25,8 +25,9 @@ stamped `[metal_kernel(float_a_ok=true)]` - convert it in the pass that writes t buffer, or in the staging loop that reads it.** A float operand keeps the op off its native fast path. -**A diff that stamps a kernel class `[metal_kernel(float_a_ok=true)]` lands its -`ARCHITECTURE_GPU.md` sec.2.2b ledger line in the same change.** +**A diff that stamps a kernel class `[metal_kernel(float_a_ok=true)]` outside the set +`ARCHITECTURE_GPU.md` sec.2.2b sanctions extends that section in the same change.** A class +the section already covers as a property needs no new line. **Never threadgroup-stage a `matmul2d` operand whose staged form matches its stored form - stream it from device instead.** A dequant, a transpose, or a layout or element-type change @@ -43,9 +44,10 @@ entry. The scan repeats on every thread of every row's threadgroup, and it grows bucket count. **Never test a bucket row's validity against the pad sentinel `0xFFFFFFFF` - compare the row's -bucket word with the live entry count (`npos * nk`) instead.** Rows past the last expert's -stamped tail hold stale pool bytes, not the sentinel, and an equality test sends their token -index out of bounds. +per-row bucket entry, the one the bucket-building kernel writes, with the live entry count +(positions x experts per token, `npos * nk`) instead.** Rows past the last expert's stamped +tail hold stale pool bytes, not the sentinel, and an equality test sends their token index +out of bounds. **Never gate an early `return` in a kernel body that runs a cooperative op - a `barrier()`, a simdgroup matrix op, or a cross-lane reduction - on a per-thread value; gate it on a @@ -69,9 +71,8 @@ count is overrun silently into whatever the pool put next to it. **Never pass `npos` to `enc_gemm_mm` (`dasllama/dasllama_metal_prefill.das`) from a GEMM site whose output rows are wider than the `d` it passes - leave `npos` at zero and dispatch the -padded tile instead.** The tail peel - the up-to-8 remainder rows `enc_gemm_mm` sends to the -mv family - writes its y rows at that `d`, so a wider-row site lands its tail rows on top of -the row beside them. +padded tile instead.** The tail rows `enc_gemm_mm` peels off write their y rows at that `d`, +so a wider-row site lands its tail rows on top of the row beside them. **Never leave a pipeline of dispatches with fewer scratch buffers than it has dispatches in flight - give each dispatch site its own instead.** One shared scratch serializes the whole @@ -114,14 +115,13 @@ defect; a per-encode field either omits `@role` or names the access its body per `weight` drops the hazard staging. **A new kernel class carries `[metal_dispatch]` / `[vk_dispatch]` with every annotation the -generated builder reads - per-field `@binding` / `@role` / `@off` / `@default`, `@span` on a -field whose callers bind whole output rows, `@workgroup` state with its `tgmem=` dispatch -key.** +generated builder reads - per-field `@binding` / `@role` / `@off` / `@default`, `@workgroup` +state with its `tgmem=` dispatch key.** -**Never give a `@span` to a kernel field whose callers bind a COLUMN TILE of a wider output -row - omit the span instead.** A column-tile caller passes the tile width as the kernel's n -while its rows stride the full output width, so a span computed from the tile width leaves -the rest of every row outside the tracked hazard range. +**A kernel field carries `@span` only when every caller binds whole output rows.** A caller +binding a column tile of a wider row passes the tile width as the kernel's n while its rows +stride the full output width, so a span computed from the tile width leaves the rest of +every row outside the tracked hazard range. **A NEW hand-written `enc_*` body is a defect unless it is a wrapper - a format or twin pick, a default-filling wrapper, or a composite over generated builders.** @@ -195,12 +195,12 @@ is `harness/parity.das`, or the in-suite instruments `tests/test_metal_decode_pa Vulkan arm ran with `DASLLAMA_GPU=1` - never `--ngl` - and its log shows `resident driver armed`.** The Vulkan driver declines codec-mismatched sessions silently. -**A change to `dasllama/dasllama_metal_tower.das`, to the `AttnArgs` kargs struct, to any -kernel class the tower dispatches or builder the tower borrows, or to state the whole -driver shares (a module-level `g_tw_*` variable, `metal_tower_init`, -`dasllama_metal_tower_register` - reachable from every hook) runs the gate of every -registered tower hook the changed code is reachable from.** The gates are the family gates -`tests/test_gemma4uv.das`, `tests/test_gemma4v.das`, `tests/test_gemma3v.das`, and +**A change other than a comment-only one to `dasllama/dasllama_metal_tower.das`, to the +`AttnArgs` kargs struct, to any kernel class the tower dispatches or builder the tower +borrows, or to state the whole driver shares (a module-level `g_tw_*` variable, +`metal_tower_init`, `dasllama_metal_tower_register` - reachable from every hook) runs the +gate of every registered tower hook the changed code is reachable from.** The gates are the +family gates `tests/test_gemma4uv.das`, `tests/test_gemma4v.das`, `tests/test_gemma3v.das`, and `test_qwen3v_tier1_metal` in `tests/test_qwen3v.das`; the encoder-blocks leg's `tests/test_whisper.das`; the conv legs' `tests/test_audio.das` and `tests/test_audio_embedder.das`; plus a `tests/test_model_image.das` run with the `mtower` diff --git a/modules/dasLLAMA/REVIEW_MEASUREMENT.md b/modules/dasLLAMA/REVIEW_MEASUREMENT.md new file mode 100644 index 0000000000..ff3a596860 --- /dev/null +++ b/modules/dasLLAMA/REVIEW_MEASUREMENT.md @@ -0,0 +1,47 @@ +# dasLLAMA Measurement Code Review Checklist + +**Read `REVIEW_COMMON.md` (repo root) first - its contract binds this checklist.** Architecture +doc: `ARCHITECTURE_MEASUREMENT.md`. Routed from `REVIEW.md`. + +**A self-measured served-turn time entering `PERF_LEDGER.md` comes from the released +`lcpp_bench` exe, never from the `-jit` script.** A served-turn time is a tok/s figure or a +turn wall. The released exe is `benchmarks/lcpp_bench.das` built by `daspkg release`. It is +spawned by `performance/gen_bench_records.das`, or run by hand where the cell's `PROFILE.md` +section says so. A `--for-debug-purposes` row is a debug instrument. A tutorial's printed +wall-clock is teaching output, feeding no board. + +**A subtraction of two measured walls written into `PERF_LEDGER.md` carries both raw walls +in the entry.** + +**A diff that adds an entry to `PERF_LEDGER.md` names the instrument that produced the entry's +reading.** The rule fires only for a reading no board cell produced. The entry also tags that +reading `direction-grade` when the reading compares across two processes or two commits. The +entry tags the reading `out-of-process` when the wall was measured from outside the benchmark +process. A reading that is neither carries no tag. + +**A diff that adds an entry to `PERF_LEDGER.md` never records a lab's A/B selection timing.** +That timing settles its adoption decision in the lab's own report and in the PR that lands the +kernel. The ledger learns the winner only through a re-measured cell. + +**A new servable capability gets its cell in the same change**: a board row spawned by +`performance/gen_bench_records.das`, or a manual `benchmarks/lcpp_bench.das` cell with its own +`PROFILE.md` section. A servable capability is a path that serves a weight format, modality, +family, or backend no existing cell exercises - a q8 or f32 serving lane and a GPU tower +included. A kernel or form that only makes a path an existing cell already serves faster is +not a new capability - it re-mints that cell's row on at least one box instead. + +**A timing figure describing a served turn as a whole - tok/s, latency, a whole-turn model +or engine comparison - is a defect wherever it is written down with no cell behind it: a +checked-in doc, a ledger, a code comment, or a PR description.** The cell states its quant +mode and stamps box and engine provenance, so a number can never silently describe a format +nobody serves or a kernel set nobody ships. + +**A figure measuring one engine stage inside a served turn, or any other measured margin - +a lab margin, a kernel-form delta, a gate knee - names the harness and flags that +produced it.** A stage figure is a stage wall, a stage share, a stage speedup, or a +cross-engine comparison of one stage. The rule holds wherever the figure is written down: a +checked-in doc, a ledger, a code comment, or a PR description. A board cell's `pp`/`tg` rate +and the whole wall of a `benchmarks/lcpp_bench.das` `-p`/`-n` cell measure the turn, not a +stage, and are not stage figures. The naming sits in the figure's own sentence, in a table +heading that covers the table's rows, or in a section-level provenance line that covers the +paragraphs under it. diff --git a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das index cc6434169f..e04fb30fdb 100644 --- a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das +++ b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das @@ -2419,6 +2419,9 @@ def public set_metal_prefill_tall(v : bool) { //! full math. Switchable between measurement windows, same contract as `set_metal_decode_skip`. def public set_metal_prefill_skip(v : string) { g_pf_skip = v + if (!empty(v)) { + to_log(LOG_WARNING, "dasLLAMA: set_metal_prefill_skip(\"{v}\") - prefill knockout, served output is GARBAGE\n") + } } var private g_pf_stage_prefills = 0l @@ -3006,15 +3009,17 @@ def private pf_cvt_panel(enc : MetalComputeEncoder?; bx : MetalBuffer?; rows, kd return bxh } +//! the pure knee arithmetic behind pf_devw_tiles - cap_bytes is the staging panel capacity +//! (g_pf_bwh_bytes in production; the kernel-unit test pins its own) [arch(at="../ARCHITECTURE_GPU_PREFILL.md#devw-panel-knees")] -def private pf_devw_tiles(rows, d, kdim : int64; slow_fb : bool = false) : int64 { - if (!g_pf_env_dev_w || g_pf_bwh == null || kdim <= 0l || kdim % 32l != 0l +def devw_tile_pick(rows, d, kdim : int64; slow_fb : bool; cap_bytes : uint64) : int64 { + if (kdim <= 0l || kdim % 32l != 0l || (kdim > DEVW_LONG_K && rows < (slow_fb ? DEVW_WIDE_N_ROWS : DEVW_LONG_K_ROWS))) { return 0l } let pb = uint64(d * kdim * 2l) if (pb <= DEVW_SMALL_PANEL && (d <= DEVW_WIDE_N || rows >= DEVW_WIDE_N_ROWS) - && pb <= g_pf_bwh_bytes) { + && pb <= cap_bytes) { return 1l } let tile_floor = slow_fb ? DEVW_WIDE_N_ROWS : DEVW_LONG_K_ROWS @@ -3022,17 +3027,24 @@ def private pf_devw_tiles(rows, d, kdim : int64; slow_fb : bool = false) : int64 if (pb > tile_over && rows >= tile_floor) { for (tc in range64(2l, DEVW_MAX_TILES + 1l)) { if (d % (tc * 64l) == 0l && pb / uint64(tc) <= DEVW_SMALL_PANEL - && uint64(d / tc * kdim * 2l) <= g_pf_bwh_bytes) { + && uint64(d / tc * kdim * 2l) <= cap_bytes) { return tc } } } - if (pb <= DEVW_BIG_PANEL && rows >= DEVW_BIG_ROWS && pb <= g_pf_bwh_bytes) { + if (pb <= DEVW_BIG_PANEL && rows >= DEVW_BIG_ROWS && pb <= cap_bytes) { return 1l } return 0l } +def private pf_devw_tiles(rows, d, kdim : int64; slow_fb : bool = false) : int64 { + if (!g_pf_env_dev_w || g_pf_bwh == null) { + return 0l + } + return devw_tile_pick(rows, d, kdim, slow_fb, g_pf_bwh_bytes) +} + def private pf_devw_flip : MetalBuffer ? { var bwh = g_pf_bwh_flip ? g_pf_bwh2 : g_pf_bwh g_pf_bwh_flip = !g_pf_bwh_flip @@ -3316,6 +3328,12 @@ def private kn_moe_mm_family_tail(enc : MetalComputeEncoder?; bx, by, bcnt, bbas kn_buffer(enc, bbkt, 0ul, 9) } +//! the q5_1 twin walks 64-deep K chunks (2 blocks/step) - an odd 32-block count stays legacy; +//! the kernel-unit gate keys its twin legs on this same predicate +def moe_q51_twin_fits(kdim : uint) : bool { + return (kdim & 63u) == 0u +} + def private pf_enc_moe_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; stack_off, rows, npos : int64; // nolint:STYLE037,STYLE038 — flat per-format twin-pick ladder, one arm per weight format bx, by, bcnt, bbase, bbkt : MetalBuffer?; var ka : MoeMmArgs; contiguous : bool = false; bxh : MetalBuffer? = null) { @@ -3339,8 +3357,7 @@ def private pf_enc_moe_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; st } } elif (fmt == KqFmt.q51) { let qp = q51_planes_of(g_dev, t, stack_off) - //! the twin walks 64-deep K chunks (2 blocks/step) — an odd 32-block count stays legacy - if (contiguous && (ka.kdim & 63u) == 0u && g_pf_pso_moe_mm_q51_t != null) { + if (contiguous && moe_q51_twin_fits(ka.kdim) && g_pf_pso_moe_mm_q51_t != null) { if (bxh != null && g_pf_pso_moe_mm_q51_th != null) { if (g_pf_env_tall && npos * int64(ka.nk) >= 128l * ne && g_pf_pso_moe_mm_q51_th128 != null && g_pf_pso_moe_mm_q51_thr != null) { pf_enc_moe_mm_q51_th128_c(enc, qp.sbuf, qp.soff, qp.qbuf, qp.qoff, bxh, by, ka, bcnt, bbase, rows, npos, ne) @@ -4736,10 +4753,7 @@ let DEVW_BIG_ROWS = 2048l let DEVW_LONG_K = 4096l let DEVW_LONG_K_ROWS = 1024l let DEVW_MAX_TILES = 32l -// a kq site whose f16 panel would exceed this is DRAM-resident - the tall in-kernel-dequant -// stamp beats both dev-W tiling and the short tg twin there (raced: 118MiB+ wins 15-25%, -// 84MiB washes negative - the knee sits between) -var private TALLKQ_MIN_PANEL = 96ul * 1024ul * 1024ul +var private TALLKQ_MIN_PANEL = 96ul * 1024ul * 1024ul //! DRAM-residency knee, raced on panel BYTES (ARCHITECTURE_GPU_PREFILL.md sec.2.2c/2.2d) var private g_pf_env_span = true var private g_pf_env_logits = true var private g_pf_env_attn = true @@ -4768,7 +4782,7 @@ def dasllama_metal_prefill_register() { g_pf_env_ncb = g_env_metal.ncb if (!empty(g_env_metal.prefill_skip)) { g_pf_skip = g_env_metal.prefill_skip - to_log(LOG_WARNING, "dasLLAMA metal prefill: SKIP={g_pf_skip} - timing-attribution mode, output is GARBAGE\n") + to_log(LOG_WARNING, "dasLLAMA metal prefill: DASLLAMA_METAL_PREFILL_SKIP={g_pf_skip} - timing-attribution mode, output is GARBAGE\n") } } diff --git a/modules/dasLLAMA/dasllama/dasllama_version.das b/modules/dasLLAMA/dasllama/dasllama_version.das index f2d0c69edd..08a7bc459e 100644 --- a/modules/dasLLAMA/dasllama/dasllama_version.das +++ b/modules/dasLLAMA/dasllama/dasllama_version.das @@ -9,4 +9,4 @@ require dasllama/dasllama_lint public //! dasLLAMA's release counter — decoupled from the daslang version and LLVM_JIT_CODEGEN_VERSION. //! ANY kernel work bumps it (REVIEW.md): equal versions mean an equal kernel roster, and the //! sidecar exchange keys validity on (version, box). Bench records and sidecar provenance carry it. -let DASLLAMA_VERSION = 10 // v10: the M5 NAX shapes arc - tall M-tile + half-X + dev-W stamps, MoE tensor twins + gather panel, f16 attention slab, bk=64 staged chunks +let DASLLAMA_VERSION = 11 // v11: the M5 pp deep-dense arc - tall in-kernel-dequant kq stamps (TH128), MoE q5_1 tensor twins, dev-W tiles to 32 diff --git a/modules/dasLLAMA/followup_general.md b/modules/dasLLAMA/followup_general.md index 73ac38a890..f047d3d16d 100644 --- a/modules/dasLLAMA/followup_general.md +++ b/modules/dasLLAMA/followup_general.md @@ -620,3 +620,13 @@ which are always fresh-built and never parse targets, so no borrowed view can reach the arm. Done = the arm carries the same `lock_count` guard as its siblings, added when that arm is next touched for real work. + +53. **The MoE tensor-twin templates are five hand-split copies of one scaffold** - + `MetalMoeMulMmQ8/K45/K6/Mx4/Q51TensorT` share the expert prologue, the `while (work < 256u)` + staging shell, the barrier pair, and the `tmm2d_tg_begin/step/store` epilogue verbatim, + diverging only on the weight-format decode block and its buffer views (`REVIEW_GPU.md`: + "kernel twins stamp one `class template`, whatever the stamp axis is"; the q5_1 twin made + the count five). Done = one base class template + carrying the scaffold with the decode behind an abstract method spliced flat at emission - + the `MetalMoeMulMmBase` pattern - with every format's bit-exact gate green and the MSL of + the pre-existing four stamps unchanged. diff --git a/modules/dasLLAMA/performance/REVIEW.md b/modules/dasLLAMA/performance/REVIEW.md index ffb6312466..1f905fac80 100644 --- a/modules/dasLLAMA/performance/REVIEW.md +++ b/modules/dasLLAMA/performance/REVIEW.md @@ -8,29 +8,36 @@ validate through `../dasllama/dasllama_exchange_schema.das` instead.** The engin `dasllama/` require beyond the lint macro module) is `REVIEW.das`'s to enforce; weakening that gate is a defect. -**A diff that adds a row to `records/` whose `hardware.remote_desktop` is anything but `off`, -or a sidecar whose `provenance.noise` is not `ok`, is a defect - re-mint on a box with no +**A diff that writes a row to `records/` (adds one or re-mints one in place) whose +`hardware.remote_desktop` is anything but `off` is a defect - re-mint on a box with no remote-desktop session.** -**A diff that adds a commit stamp to `records/` naming a commit the branch under review cannot -reach is a defect - re-mint.** The commit stamps are a `das` row's `sha` and a sidecar's +**A diff that writes a sidecar to `records/` whose `provenance.noise` is not `ok` is a +defect - re-mint on a quiet box.** + +**A diff that writes a commit stamp to `records/` naming a commit the branch under review +cannot reach is a defect - re-mint, or re-stamp to a reachable commit whose +`modules/dasLLAMA/` tree is byte-identical to the tree that was measured, with the PR body +naming the re-stamp.** The commit stamps are a `das` row's `sha` and a sidecar's `provenance.engine_sha`. A stamp that resolves to no commit at all counts as unreachable. -**A diff that adds a reference-engine row to `records/` whose `sha` is not the standing ref pin +**A diff that writes a reference-engine row to `records/` whose `sha` is not the standing ref pin (`DEFAULT_REF_SHA`, `../benchmarks/setup_lcpp_ref.das`) is a defect - re-mint.** -**A diff that adds a sidecar to `records/` whose `provenance.dasllama_version` differs from +**A diff that writes a sidecar to `records/` whose `provenance.dasllama_version` differs from `DASLLAMA_VERSION` (`../dasllama/dasllama_version.das`) is a defect - re-mint.** Read `DASLLAMA_VERSION` at the commit the sidecar's `provenance.engine_sha` names. -**A diff that adds a row to `records/.json` mints that row from a board cell.** A board +**A diff that writes a row to `records/.json` mints that row from a board cell.** A board cell is one `gen_bench_records.das` spawns, or a manual `../benchmarks/lcpp_bench.das` cell -its `../PROFILE.md` section documents. A timing taken any other way settles its own decision -in its own report. Those other ways include a lab's A/B arm, a reading compared across two -processes or two commits, and a wall measured from outside the benchmark process. +its `../PROFILE.md` section documents. A timing taken any other way stays out of `records/` +and settles its own decision in the report where it was taken. + +**A diff that writes a `das` row to `records/.json` times that row with the released +`lcpp_bench` exe.** That exe is `../benchmarks/lcpp_bench.das` built by `daspkg release`. -**A diff that adds a row to `records/.json` times that row with the released `lcpp_bench` -exe.** That exe is `../benchmarks/lcpp_bench.das` built by `daspkg release`. +**A diff that writes a reference-engine row to `records/.json` times that row with the +reference exe the ref pin builds.** **A field added to what `write_bench_records` (`profile_common.das`) writes is added to `../dasllama/dasllama_exchange_schema.das`'s run validation in the same change** - the @@ -49,7 +56,9 @@ strip, and the rails. **A diff that adds a submission path around `exchange_strip_private` is a defect, even where the strip itself is intact.** -**A boot path that fails when the exchange lookup fails is a defect.** +**A tune-boot path (`exchange_scope_resolver` / `exchange_boot_submit_check`, +`../dasllama/dasllama_exchange.das`) that fails when `exchange_lookup` fails is a defect - +it falls through to the local sidecar and the baked winners.** **Outside `model_specs()` (text, in `model_specs.das`) and `asr_catalog()` (audio, in `profile_common.das`), a `.das` function under this folder that lists model files, quants, diff --git a/modules/dasLLAMA/performance/records/m5.json b/modules/dasLLAMA/performance/records/m5.json index c4af6bdfec..9e395c450c 100644 --- a/modules/dasLLAMA/performance/records/m5.json +++ b/modules/dasLLAMA/performance/records/m5.json @@ -32,11 +32,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights q8 native; q8 activations; f16 scales; metal blob", @@ -299,11 +299,11 @@ }, "workload":"image-chat", "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4v f32; weights q8 native; q8 activations; f16 scales; metal blob", @@ -547,11 +547,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -638,11 +638,11 @@ }, "workload":"image-chat", "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4uv f32; weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -707,11 +707,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights q8 native; q8 activations; f16 scales; metal blob", @@ -798,11 +798,11 @@ }, "workload":"image-chat", "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4v f32; weights q8 native; q8 activations; f16 scales; metal blob", @@ -867,11 +867,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights mxfp4/q8 native; q8 activations; f16 scales; metal blob", @@ -965,11 +965,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6 native; q8 activations; f32 scales; metal blob", @@ -1063,11 +1063,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/q51/q8 native; q8 activations; f16 scales; metal blob", @@ -1161,11 +1161,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f16 scales; metal blob", @@ -1259,11 +1259,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -1357,11 +1357,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f16 scales; metal blob", @@ -1455,11 +1455,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k5/k6/q8 native; q8 activations; f16 scales; metal blob", diff --git a/modules/dasLLAMA/performance/records/m5.tune.461b01bf9c73.json b/modules/dasLLAMA/performance/records/m5.tune.d30db41e2278.json similarity index 99% rename from modules/dasLLAMA/performance/records/m5.tune.461b01bf9c73.json rename to modules/dasLLAMA/performance/records/m5.tune.d30db41e2278.json index 70e5752de9..ce8fe74409 100644 --- a/modules/dasLLAMA/performance/records/m5.tune.461b01bf9c73.json +++ b/modules/dasLLAMA/performance/records/m5.tune.d30db41e2278.json @@ -46,7 +46,7 @@ "noise_probes" : "start cv 0.13%; mid1 cv 0.09%; mid2 cv 0.18%; end cv 0.22%", "platform" : "darwin", "noise_floor_cv_pct" : "0.22", - "engine_sha" : "dc0992306", + "engine_sha" : "667d4c1d5", "box" : "darwin|arm64|Mac17,6|25G72|Apple M5 Max", "written" : "2026-08-28T00:21:30.590Z", "validation_demoted" : "1", diff --git a/modules/dasLLAMA/tests/REVIEW.md b/modules/dasLLAMA/tests/REVIEW.md index 84f95553f0..cfbb57b061 100644 --- a/modules/dasLLAMA/tests/REVIEW.md +++ b/modules/dasLLAMA/tests/REVIEW.md @@ -54,10 +54,13 @@ defect.** **Weakening `test_model_specs.das` is a defect.** It is the gate on the model-set table (`../performance/model_specs.das`). -**Weakening the attention-trio softcap, sink and span cells of -`test_metal_prefill_kernels.das` is a defect** - they are the only cells that fail when -`pf_p_weight` and `metal_attn_rowstat` drift apart; rows renormalize against the wrong max -when the two disagree. +**Weakening the softcap, sink and span cells of `test_metal_prefill_kernels.das` - dropping +or loosening a softcap, sink (`hass`) or span arm, or dropping a span shape - is a defect** - +they are what fails when `pf_p_weight` and `metal_attn_rowstat` drift apart. + +**Weakening `test_site_records.das` - the gate that byte-compares +`site/files/dasllama/bench_records.json` (repo root) against a fresh `merge_site_records` +run - is a defect.** **Weakening `test_exchange_schema.das` or `test_bench_records_schema.das` - loosening an assert, dropping one, or narrowing the corpus either one sweeps - is a defect** - they gate @@ -127,11 +130,12 @@ a defect.** A resize cap is not evidence. **A freeform token-parity cell is a defect.** Freeform coverage uses the forced-feed logits-tolerance form. Counting cells stay token-exact. -**A diff that adds a `[metal_kernel]` under `../dasllama/` covers that kernel in -`test_kernel_coverage.das`, one of two ways.** Either a census row there dispatches the -kernel, or the diff names its kernel class in that file's `CENSUS_NEVER_DISPATCHED`, with the -reason no row can reach it. A dispatching row runs on a small model - one the suite runs -without `DASLLAMA_PARITY_FULL=1`. Naming a kernel a census row could dispatch is a defect. +**A diff that adds a metal kernel class under `../dasllama/` - a `[metal_kernel]` def or a +new instance of a template carrying one - covers that class in `test_kernel_coverage.das`, +one of two ways.** Either a census row there dispatches the class, or the diff names it in +that file's `CENSUS_NEVER_DISPATCHED`, with the reason no row can reach it. A dispatching +row runs on a small model - one the suite runs without `DASLLAMA_PARITY_FULL=1`. Naming a +class a census row could dispatch is a defect. **A kernel-unit cell missing a compare against a CPU oracle that can witness the cell's property is a defect.** @@ -223,4 +227,3 @@ change** - the wire-shape pins, the render pins, and a live server leg gated on smallest GGUF that runs on the small tier (the file homes are `CLAUDE.md`'s "Model-free / no-arm tests" and "Out-of-folder test files" notes). A family whose vocab lacks the markers has no format to test. - diff --git a/modules/dasLLAMA/tests/test_kernel_coverage.das b/modules/dasLLAMA/tests/test_kernel_coverage.das index 953d024c9c..0fdedcde5b 100644 --- a/modules/dasLLAMA/tests/test_kernel_coverage.das +++ b/modules/dasLLAMA/tests/test_kernel_coverage.das @@ -54,7 +54,17 @@ let private CENSUS_NEVER_DISPATCHED <- [ "MetalMoeMulMmK5TH128", "MetalMoeMulMmK5THR", "MetalMoeMulMmK6TH128", "MetalMoeMulMmK6THR", "MetalMoeMulMmQ8TH128", "MetalMoeMulMmQ8THR", - "MetalMoeMulMmMx4TH128", "MetalMoeMulMmMx4THR" + "MetalMoeMulMmMx4TH128", "MetalMoeMulMmMx4THR", + // the q5_1 MoE tensor twins, ALL stamps: no stocked carrier holds a Q5_1 expert plane + // (the zoo's MoE carriers are Q8_0 / Q5_K_M / Q4_K_M / mxfp4; Q5_1 appears only when + // expert_ffn % 256 != 0 forces the converter off K-quants). Their coverage is the + // bit-exact twin + tall-pair gate in test_metal_prefill_kernels.das (moe_mulmm_q51_gate) + "MetalMoeMulMmQ51T", "MetalMoeMulMmQ51TH", + "MetalMoeMulMmQ51TH128", "MetalMoeMulMmQ51THR", + // the dense tall in-kernel-dequant kq stamps: they engage only when a site's f16 panel + // would reach TALLKQ_MIN_PANEL (96 MiB) - the zoo's small carriers top out far below it. + // Their coverage is the tall kernel-unit leg in test_metal_gemm_kernels.das (kq_mulmm_gate) + "MetalKqMulMmK4TH128", "MetalKqMulMmK5TH128", "MetalKqMulMmK6TH128" ] def private counting_prompt(start, last : int) : string { diff --git a/modules/dasLLAMA/tests/test_metal_gemm_kernels.das b/modules/dasLLAMA/tests/test_metal_gemm_kernels.das index 0047dd99fc..87a76cbb3c 100644 --- a/modules/dasLLAMA/tests/test_metal_gemm_kernels.das +++ b/modules/dasLLAMA/tests/test_metal_gemm_kernels.das @@ -108,6 +108,17 @@ def private kq_mulmm_gate(t : T?; dev, queue; fmt : int; tensor : bool; m, kdim, var by = buf_fill(dev, m * ndim, -1000.0) var bk = buf_u32(dev, uint(kdim)) var bn = buf_u32(dev, uint(ndim)) + // a tall m off the 128 floor mirrors the encoder's pair: the 128 stamp covers r0 rows and + // the 32-row TH covers the rest at its x/y byte offsets - the nonzero-offset arm's binding + let r0 = tall ? m / 128 * 128 : m + var rem_pso = (tall && r0 != m) ? pipeline_from_source(dev, + fmt == 4 ? MetalKqMulMmK4TH_metal_kq_mulmm_t_msl : (fmt == 5 ? MetalKqMulMmK5TH_metal_kq_mulmm_t_msl : MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl), + fmt == 4 ? MetalKqMulMmK4TH_metal_kq_mulmm_t_msl_entry : (fmt == 5 ? MetalKqMulMmK5TH_metal_kq_mulmm_t_msl_entry : MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl_entry), + fmt == 4 ? MetalKqMulMmK4TH_metal_kq_mulmm_t_msl_fastmath : (fmt == 5 ? MetalKqMulMmK5TH_metal_kq_mulmm_t_msl_fastmath : MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl_fastmath), + err) : null + if (tall && r0 != m) { + t |> success(rem_pso != null, "{tag}: remainder pipeline: {err}") + } let ran = with_compute_encoder(queue, err) $(enc : MetalComputeEncoder?) { metal_set_pipeline(enc, pso) metal_set_threadgroup_memory_length(enc, tgm, 0) @@ -119,6 +130,18 @@ def private kq_mulmm_gate(t : T?; dev, queue; fmt : int; tensor : bool; m, kdim, metal_set_buffer(enc, bk, 0ul, 5) metal_set_buffer(enc, bn, 0ul, 6) metal_dispatch_threadgroups(enc, uint3(uint(m / (tall ? 128 : 32)), uint(ndim / 64), 1u), uint3(128u, 1u, 1u)) + if (rem_pso != null) { + metal_set_pipeline(enc, rem_pso) + metal_set_threadgroup_memory_length(enc, fmt == 4 ? MetalKqMulMmK4TH_metal_kq_mulmm_t_msl_tgmem : (fmt == 5 ? MetalKqMulMmK5TH_metal_kq_mulmm_t_msl_tgmem : MetalKqMulMmK6TH_metal_kq_mulmm_k6_t_msl_tgmem), 0) + metal_set_buffer(enc, bks, fmt == 6 ? uint64(nsb * 16) : 0ul, 0) + metal_set_buffer(enc, bks, 0ul, 1) + metal_set_buffer(enc, bkq, 0ul, 2) + metal_set_buffer(enc, bx, uint64(r0 * kdim * 2), 3) + metal_set_buffer(enc, by, uint64(r0 * ndim * 4), 4) + metal_set_buffer(enc, bk, 0ul, 5) + metal_set_buffer(enc, bn, 0ul, 6) + metal_dispatch_threadgroups(enc, uint3(uint((m - r0) / 32), uint(ndim / 64), 1u), uint3(128u, 1u, 1u)) + } } t |> success(ran, "{tag}: encode: {err}") if (ran) { @@ -131,6 +154,9 @@ def private kq_mulmm_gate(t : T?; dev, queue; fmt : int; tensor : bool; m, kdim, metal_release(bk) metal_release(bn) metal_release(pso) + if (rem_pso != null) { + metal_release(rem_pso) + } delete kq delete ks delete xf @@ -1690,6 +1716,7 @@ def test_metal_gemm_kernels(t : T?) { kq_mulmm_gate(t, dev, queue, fmt, true, 64, 512, 64, halfx = true) // tall 128-row stamp: the deep-class in-kernel-dequant form (m = two tall tiles) kq_mulmm_gate(t, dev, queue, fmt, true, 256, 512, 64, halfx = true, tall = true) + kq_mulmm_gate(t, dev, queue, fmt, true, 320, 512, 64, halfx = true, tall = true) // off the 128 floor: the remainder pair at nonzero x/y offsets } kq_mulmm_gate(t, dev, queue, 4, false, 32, 256, 128) // second shape: 2 col tiles q8_mulmm_t_gate(t, dev, queue, 64, 256, 64) diff --git a/modules/dasLLAMA/tests/test_metal_prefill_kernels.das b/modules/dasLLAMA/tests/test_metal_prefill_kernels.das index 4956d7c8df..98bc84a3ff 100644 --- a/modules/dasLLAMA/tests/test_metal_prefill_kernels.das +++ b/modules/dasLLAMA/tests/test_metal_prefill_kernels.das @@ -2225,12 +2225,36 @@ def private metal4_tensor_available(dev) : bool { g_m4_probed = true var err : string var p1 = pipeline_from_source(dev, MetalQ8MulMmT_metal_q8_mulmm_t_msl, MetalQ8MulMmT_metal_q8_mulmm_t_msl_entry, MetalQ8MulMmT_metal_q8_mulmm_t_msl_fastmath, err) - g_m4_ok = p1 != null + var p2 = pipeline_from_source(dev, MetalBf16MulMmT_metal_bf16_mulmm_t_msl, MetalBf16MulMmT_metal_bf16_mulmm_t_msl_entry, MetalBf16MulMmT_metal_bf16_mulmm_t_msl_fastmath, err) + g_m4_ok = p1 != null || p2 != null metal_release(p1) + metal_release(p2) } return g_m4_ok } +//! device-free: the dev-W knee arithmetic (the pick the board's deep-dense cells ride). +//! Expectations hold at the DEVW_SMALL_PANEL default (32 MiB) - no sidecar loads here +[test] +def test_devw_tile_pick(t : T?) { + let cap = 16ul * 1024ul * 1024ul * 1024ul + // small panel (16 MiB, narrow N) serves whole + t |> equal(devw_tile_pick(256l, 4096l, 2048l, false, cap), 1l) + // deep-dense up/gate (320 MiB, d/64 = 512): first divisor tile under the small knee is 16 - + // unreachable under a 2..8 cap + t |> equal(devw_tile_pick(2048l, 32768l, 5120l, false, cap), 16l) + // deep-dense down (long-K, d/64 = 80): tc = 10, and rows below the long-K floor decline + t |> equal(devw_tile_pick(2048l, 5120l, 32768l, false, cap), 10l) + t |> equal(devw_tile_pick(512l, 5120l, 32768l, false, cap), 0l) + // over-knee under the tiled-rows floor: no form serves - unless the slow-fallback class + // lowers the floor to 512 + t |> equal(devw_tile_pick(512l, 32768l, 5120l, false, cap), 0l) + t |> equal(devw_tile_pick(512l, 32768l, 5120l, true, cap), 16l) + // mid panel (40 MiB) needs the big-rows floor + t |> equal(devw_tile_pick(2048l, 4096l, 5120l, false, cap), 1l) + t |> equal(devw_tile_pick(1024l, 4096l, 5120l, false, cap), 0l) +} + def private moe_mulmm_q51_gate(t : T?; dev, queue; kdim, ndim : int; counts : array) { var err : string var pso = pipeline_from_source(dev, metal_moe_mulmm_q51_msl, metal_moe_mulmm_q51_msl_entry, metal_moe_mulmm_q51_msl_fastmath, err) @@ -2304,9 +2328,9 @@ def private moe_mulmm_q51_gate(t : T?; dev, queue; kdim, ndim : int; counts : ar t |> equal(buf_mismatch_exact(by, want), 0) // the contiguous tensor twin (TH stamp over an f16 X): same exact-arithmetic oracle — // pow2 d / quarter m / int x all stage to f16 losslessly, so the twin is BIT-exact too. - // The twin walks 64-deep K chunks, so kdim % 64 != 0 fixtures cover the legacy form only - // (the pick guards the same bound). - if (kdim % 64 != 0) { + // The leg keys on the ENGINE's own pick predicate: weakening moe_q51_twin_fits dispatches + // the twin on the kdim=96 fixture, whose 64-deep K walk reads off the plane and mismatches. + if (!moe_q51_twin_fits(uint(kdim))) { metal_release(bw) metal_release(bs) metal_release(bx) @@ -2351,6 +2375,31 @@ def private moe_mulmm_q51_gate(t : T?; dev, queue; kdim, ndim : int; counts : ar if (rant) { t |> equal(buf_mismatch_exact(by_t, want), 0) } + // the float-X T stamp (the bxh == null pick arm): stages raw f32 rows to the same + // f16 tiles, so the int-valued fixtures stay bit-exact through it too + var tf_pso = pipeline_from_source(dev, MetalMoeMulMmQ51T_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51T_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51T_metal_moe_mulmm_q51_t_msl_fastmath, terr) + t |> success(tf_pso != null, "moe q51 mulmm T stamp: pipeline: {terr}") + if (tf_pso != null) { + var by_f = buf_fill(dev, pad * ndim, -600.0) + let ranf = with_compute_encoder(queue, terr) $(enc : MetalComputeEncoder?) { + metal_set_pipeline(enc, tf_pso) + metal_set_threadgroup_memory_length(enc, MetalMoeMulMmQ51T_metal_moe_mulmm_q51_t_msl_tgmem, 0) + metal_set_buffer(enc, bs, 0ul, 0) + metal_set_buffer(enc, bw, 0ul, 1) + metal_set_buffer(enc, bx, 0ul, 3) + metal_set_buffer(enc, by_f, 0ul, 4) + metal_set_bytes(enc, unsafe(addr(ka)), uint64(typeinfo sizeof(ka)), 5) + metal_set_buffer(enc, bcnt, 0ul, 6) + metal_set_buffer(enc, bbase, 0ul, 7) + metal_dispatch_threadgroups(enc, uint3(uint(tiles), uint(ndim / 64), uint(ne)), uint3(128u, 1u, 1u)) + } + t |> success(ranf, "moe q51 mulmm T stamp: encode: {terr}") + if (ranf) { + t |> equal(buf_mismatch_exact(by_f, want), 0) + } + metal_release(by_f) + metal_release(tf_pso) + } // the tall pair: 128-floor stamp + remainder stamp over the same fixtures — the // toolchain is proven (tw_pso compiled), so a pair PSO that fails to compile is a RED var tl_pso = pipeline_from_source(dev, MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl, MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl_entry, MetalMoeMulMmQ51TH128_metal_moe_mulmm_q51_t_msl_fastmath, terr) diff --git a/site/REVIEW.md b/site/REVIEW.md index b73264438d..791037bc5a 100644 --- a/site/REVIEW.md +++ b/site/REVIEW.md @@ -5,7 +5,7 @@ `tests/playground/` checklist.** **Never show on a page a hand-written shell command, flag, or output line invented for -illustration - show only a command that runs verbatim and produces the result the page +illustration - show only a command a run actually executed, producing the result the page shows.** **A diff that writes a `cmd` field in `files/dasllama/bench_records.json` that is not the @@ -16,17 +16,11 @@ spawns) ran is a defect.** that line on every row the run produced.** One run's `cmd` + `date` covers several rendered rows. -**A `cmd` + `date` pair on a rendered row in `files/dasllama/bench_records.json` is a defect - -put the pair on the run object that produced the rows.** +**A `cmd` or `date` inside a run's `tests` entry in `files/dasllama/bench_records.json` is a +defect - the pair belongs on the run object that produced the rows.** -**A diff that leaves `files/dasllama/bench_records.json` differing from what re-running -`modules/dasLLAMA/performance/gen_site_records.das` writes is a hand edit and a defect - -change the generator inputs and re-run it instead.** The generator merges every -`modules/dasLLAMA/performance/records/.json` and applies -`modules/dasLLAMA/performance/records/annotations.json`. - -**A diff that changes `files/performance_bench.json` also changes `benchmarks/sql/results.md`, -in the same change.** `benchmarks/sql/_update_results.das --site-json` writes the record from +**A diff that changes `files/performance_bench.json` also changes `benchmarks/sql/results.md` +(repo root), in the same change.** `benchmarks/sql/_update_results.das --site-json` writes the record from the same sweep output that regenerates those tables. **A cell in `files/performance_bench.json` differing from the same family-and-lane cell in the diff --git a/site/files/dasllama/bench_records.json b/site/files/dasllama/bench_records.json index 9b4891d9d1..d6881dd221 100644 --- a/site/files/dasllama/bench_records.json +++ b/site/files/dasllama/bench_records.json @@ -527,11 +527,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k5/k6/q8 native; q8 activations; f16 scales; metal blob", @@ -1290,11 +1290,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f16 scales; metal blob", @@ -2608,11 +2608,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -2699,11 +2699,11 @@ }, "workload":"image-chat", "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4uv f32; weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -3991,11 +3991,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights q8 native; q8 activations; f16 scales; metal blob", @@ -4082,11 +4082,11 @@ }, "workload":"image-chat", "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4v f32; weights q8 native; q8 activations; f16 scales; metal blob", @@ -4942,11 +4942,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights mxfp4/q8 native; q8 activations; f16 scales; metal blob", @@ -5705,11 +5705,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f32 scales; metal blob", @@ -6474,11 +6474,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6 native; q8 activations; f32 scales; metal blob", @@ -7243,11 +7243,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/q51/q8 native; q8 activations; f16 scales; metal blob", @@ -15434,11 +15434,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights q8 native; q8 activations; f16 scales; metal blob", @@ -15701,11 +15701,11 @@ }, "workload":"image-chat", "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"tower gemma4v f32; weights q8 native; q8 activations; f16 scales; metal blob", @@ -17880,11 +17880,11 @@ } }, "source":"official", - "sha":"dc0992306", + "sha":"667d4c1d5", "version":"0.6.4", "dasllama_version":10, "tune":"k4q8_tile_gen=mr8 (manifest); k5q8_tile_gen=mr8 (manifest); k6q8_tile_gen=mr4 (manifest); q40q8_tile_gen=mr8 (manifest); q8q8_tile_gen=mr8_budget (manifest); q51q8_tile_gen=mr8 (manifest)", - "tune_sha":"461b01bf9c73255980e2e386b40174b68b2d47fca27f931564986667b1ff7d25", + "tune_sha":"d30db41e2278b4210ebeebb9e1c789a629936fcdc3839241967083755c2cfd60", "noise":"ok", "parity":"ok", "exec_fmt":"weights k4/k6/q8 native; q8 activations; f16 scales; metal blob", From 74201edcd1f5d5f37cb7e6b5153b27b9739e2a01 Mon Sep 17 00:00:00 2001 From: Boris Batkin Date: Thu, 27 Aug 2026 23:53:13 -0700 Subject: [PATCH 10/10] dasLLAMA: ruled batch - the tall A/B seat honored, stamp-reach and corpus gates, triangle closed The woodpecker's finding fixed red-first: the dense tall-kq gate ignored set_metal_prefill_tall; the pick is now the pure tallkq_pick with a device-free test binding the override clause. The ruled checklist batch lands: the census dispatching arm admits FULL-gated rows, review_md.md sanctions plural arch-doc pointers, the row-split and scratch-flip rules re-key on their properties, REVIEW_COMMON's triangle rule 1 also audits the section and sheds the citer-less clause (LINT026 owns it). New machinery: make-pr's stamp-reach gate (engine stamps in changed record stores must be reachable from HEAD), a records-corpus sweep in performance/REVIEW.das, and site/REVIEW.das with the dl-* selector-parity check (negative-controlled). The historical parsec stamps read a dormant daemon, not a session - hand-corrected to off per the ruling; the probe refinement is followup 54. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_014fKJGuUL8tP58Y6NvoVeSn --- REVIEW_COMMON.md | 8 +- modules/dasLLAMA/REVIEW_GPU.md | 17 ++-- .../dasllama/dasllama_metal_prefill.das | 9 +- modules/dasLLAMA/followup_general.md | 7 ++ modules/dasLLAMA/performance/REVIEW.das | 51 ++++++++++ modules/dasLLAMA/performance/records/m1.json | 86 ++++++++--------- .../dasLLAMA/performance/records/zen2.json | 8 +- modules/dasLLAMA/tests/REVIEW.md | 4 +- .../tests/test_metal_prefill_kernels.das | 52 ++++++---- site/REVIEW.das | 89 ++++++++++++++++++ site/REVIEW.md | 6 +- site/files/dasllama/bench_records.json | 94 +++++++++---------- skills/internal/make_pr.md | 5 +- skills/review_md.md | 3 +- utils/internal/make-pr/gates.das | 2 +- utils/internal/make-pr/main.das | 70 +++++++++++++- 16 files changed, 376 insertions(+), 135 deletions(-) create mode 100644 site/REVIEW.das diff --git a/REVIEW_COMMON.md b/REVIEW_COMMON.md index a69e80326d..12b49d08bd 100644 --- a/REVIEW_COMMON.md +++ b/REVIEW_COMMON.md @@ -28,13 +28,13 @@ distinguishes is a defect. The audit procedure - including how to settle "would without the change?" - is `skills/tdd_audit.md`. **A diff that changes a function carrying `[arch(at="#")]` - beyond comments - -audits the anchor's other citing functions: read the section, check each citer still conforms, -verdict per function.** The citers of one anchor share one mechanism; MCP `arch_sites` lists -them. +audits the anchor's other citing functions and the cited section: read the section, check it +still describes the code and each citer still conforms, verdict per function.** The citers of +one anchor share one mechanism; MCP `arch_sites` lists them. **A diff that adds, removes, or retargets an `[arch(at=...)]` citation audits the cited section against the code - both sections on a retarget.** The citation claims the section -describes this function; verify it does, and that no anchor is left citer-less. +describes this function; verify it does. **A diff that changes an anchored section audits every function citing that anchor.** One audit pass over an anchor's section text and citer set discharges every audit duty the diff diff --git a/modules/dasLLAMA/REVIEW_GPU.md b/modules/dasLLAMA/REVIEW_GPU.md index aa87b49a66..75b5c4eed4 100644 --- a/modules/dasLLAMA/REVIEW_GPU.md +++ b/modules/dasLLAMA/REVIEW_GPU.md @@ -69,14 +69,15 @@ of the tile. The K/V GEMMs write full M-tile rows at the chunk's row offset, so a panel sized to the live count is overrun silently into whatever the pool put next to it. -**Never pass `npos` to `enc_gemm_mm` (`dasllama/dasllama_metal_prefill.das`) from a GEMM site -whose output rows are wider than the `d` it passes - leave `npos` at zero and dispatch the -padded tile instead.** The tail rows `enc_gemm_mm` peels off write their y rows at that `d`, -so a wider-row site lands its tail rows on top of the row beside them. - -**Never leave a pipeline of dispatches with fewer scratch buffers than it has dispatches in -flight - give each dispatch site its own instead.** One shared scratch serializes the whole -chain through its write-after-read hazards. +**A row-splitting GEMM encoder - one that dispatches a subset of a site's output rows at an +offset - is called only from a site whose output row stride equals the width it dispatches; a +wider-row site passes the full stride or dispatches the padded tile.** A split row writes at +`row x dispatched-width`, so a wider-row caller lands its split rows on top of the row beside +them. + +**A scratch buffer a dispatch writes is never rebound for a new write before the reader of +its previous write is encoded; a flip set smaller than the chain's encode-overlap depth is a +defect.** One shared scratch serializes the whole chain through its write-after-read hazards. **A diff that adds dispatches to an encoder path to save bandwidth also gates that path on work size, in the same change.** The gate's threshold is measured at both ends of the size diff --git a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das index e04fb30fdb..5e54895e75 100644 --- a/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das +++ b/modules/dasLLAMA/dasllama/dasllama_metal_prefill.das @@ -3219,6 +3219,12 @@ def pf_enc_bf16_mm(enc : MetalComputeEncoder?; bw : MetalBuffer?; wboff : uint64 } } +//! the dense tall-kq gate's pure half: env_tall is the set_metal_prefill_tall A/B seat - +//! the tall form must honor it like every other form override +def tallkq_pick(mp, rows, kdim : int64; env_tall : bool) : bool { + return env_tall && kdim > 0l && mp >= 128l && uint64(rows * kdim * 2l) >= TALLKQ_MIN_PANEL +} + //! k6 binds its split scale plane twice: sub-scales at soff, the f16 d tail at doff def private pf_enc_kq_site_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt; woff, rows : int64; // nolint:STYLE037 — flat per-format form-pick ladder bx, by, bk, bn : MetalBuffer?; mp : int64; yoff : uint64 = 0ul; bxh : MetalBuffer? = null; kdim : int64 = 0l) { @@ -3229,8 +3235,7 @@ def private pf_enc_kq_site_mm(enc : MetalComputeEncoder?; t : Model; fmt : KqFmt //! in-kernel-dequant stamp reads the quant plane once per 128-row tile instead of //! materializing and re-streaming a 2B/element f16 panel let tall128 = fmt == KqFmt.k6 ? g_pf_pso_kq_mm6_th128 : (fmt == KqFmt.k4 ? g_pf_pso_kq_mm4_th128 : g_pf_pso_kq_mm5_th128) - if (fmt_tensor && bxh != null && tall128 != null && kdim > 0l && mp >= 128l - && uint64(rows * kdim * 2l) >= TALLKQ_MIN_PANEL) { + if (fmt_tensor && bxh != null && tall128 != null && tallkq_pick(mp, rows, kdim, g_pf_env_tall)) { let r0 = mp / 128l * 128l if (fmt == KqFmt.k6) { enc_kq_mm_k6_th128_c(enc, bs.buf, bs.doff, bs.buf, bs.soff, bq.buf, bq.qoff, bxh, 0ul, by, yoff, bk, bn, r0, rows) diff --git a/modules/dasLLAMA/followup_general.md b/modules/dasLLAMA/followup_general.md index f047d3d16d..83b995bfe2 100644 --- a/modules/dasLLAMA/followup_general.md +++ b/modules/dasLLAMA/followup_general.md @@ -630,3 +630,10 @@ carrying the scaffold with the decode behind an abstract method spliced flat at emission - the `MetalMoeMulMmBase` pattern - with every format's bit-exact gate green and the MSL of the pre-existing four stamps unchanged. + +54. **The hardware probe stamps `remote_desktop` on daemon presence, not session activity.** + The stored-run ban means an ACTIVE remote-desktop session (its encoder load taints the + measurement); a dormant autostart daemon is harmless, yet the probe stamps its name, + which is why 47 historical m1/zen2 rows read `parsec` and were hand-corrected to `off` + (dormant by the box discipline). Done = the probe stamps `off` unless a session is live + (a connected-client check per product), with the value naming the product only then. diff --git a/modules/dasLLAMA/performance/REVIEW.das b/modules/dasLLAMA/performance/REVIEW.das index 5647e65772..2ecfa66fbc 100644 --- a/modules/dasLLAMA/performance/REVIEW.das +++ b/modules/dasLLAMA/performance/REVIEW.das @@ -99,6 +99,56 @@ def private check_last_known_good { } } +// the corpus half of REVIEW.md's write-time provenance rules that are decidable from tree +// state alone: every stored run measured with no remote-desktop session, every archived +// sidecar minted on a quiet box. (Ref-pin equality and stamp reachability bind the DIFF - +// historical rows legitimately carry older pins and shas - so they stay out of this sweep; +// reachability runs in make-pr's chain, where the orphan hazard appears.) +let private RECORDS_DIR = "modules/dasLLAMA/performance/records" + +def private check_records_corpus { + dir(RECORDS_DIR) $(name) { + return if (!(name |> ends_with(".json")) || name == "annotations.json") + let full = "{RECORDS_DIR}/{name}" + let text = fread(full) + if (empty(text)) { + gate_finding(full, "missing or unreadable") + return + } + var jerr = "" + var doc = read_json(text, jerr) + defer() { + unsafe { + delete doc + } + } + if (doc == null) { + gate_finding(full, "does not parse as JSON: {jerr}") + return + } + if (name |> find(".tune.") >= 0) { + let noise = "{doc?["provenance"]?["noise"] ?? ""}" + if (!empty(noise) && noise != "ok") { // empty = archived before the field existed + gate_finding(full, "provenance.noise is '{noise}' - an archived sidecar generation carries a quiet mint (noise ok)") + } + return + } + return if (!(doc.value is _array)) + for (model in doc.value as _array) { + let runs = model?["runs"] + continue if (runs == null || !(runs.value is _array)) + for (r in runs.value as _array) { + let rd = "{r?["hardware"]?["remote_desktop"] ?? ""}" + continue if (empty(rd)) // rows minted before the field existed + if (rd != "off") { + let gguf = "{model?["gguf"] ?? "?"}" + gate_finding(full, "{gguf}: hardware.remote_desktop is '{rd}' - a stored run is measured with no remote-desktop session; re-mint") + } + } + } + } +} + [export] def main() : int { if (!fexist(SNAPSHOT)) { @@ -108,5 +158,6 @@ def main() : int { check_last_known_good() check_schema_engine_free() check_single_exchange_client() + check_records_corpus() return gate_verdict("dasllama-performance") } diff --git a/modules/dasLLAMA/performance/records/m1.json b/modules/dasLLAMA/performance/records/m1.json index b7ce0a0bce..f7522e9add 100644 --- a/modules/dasLLAMA/performance/records/m1.json +++ b/modules/dasLLAMA/performance/records/m1.json @@ -1150,7 +1150,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -1197,7 +1197,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -1238,7 +1238,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -1279,7 +1279,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -1320,7 +1320,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -1367,7 +1367,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -2555,7 +2555,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -2643,7 +2643,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -2684,7 +2684,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -2765,7 +2765,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -3767,7 +3767,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -3866,7 +3866,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -3945,7 +3945,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -3983,7 +3983,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -4082,7 +4082,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -4181,7 +4181,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -4267,7 +4267,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -4366,7 +4366,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -4445,7 +4445,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -4483,7 +4483,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -4582,7 +4582,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -4681,7 +4681,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -4933,7 +4933,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -5026,7 +5026,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -5099,7 +5099,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -5146,7 +5146,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -5193,7 +5193,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -5240,7 +5240,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -5333,7 +5333,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -5374,7 +5374,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -5415,7 +5415,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -5820,7 +5820,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -5918,7 +5918,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -5995,7 +5995,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -6100,7 +6100,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -6205,7 +6205,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -6285,7 +6285,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -6331,7 +6331,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -6372,7 +6372,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -6418,7 +6418,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -6459,7 +6459,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -6505,7 +6505,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "pp512":{ @@ -6556,7 +6556,7 @@ "ram_gb":64, "gpu":"Apple M1 Max (32-core)", "model_id":"MacBookPro18,2", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "img:enc":{ diff --git a/modules/dasLLAMA/performance/records/zen2.json b/modules/dasLLAMA/performance/records/zen2.json index 26960e6d26..2aa8b17916 100644 --- a/modules/dasLLAMA/performance/records/zen2.json +++ b/modules/dasLLAMA/performance/records/zen2.json @@ -1962,7 +1962,7 @@ "ram_config":"8×32 GB @ 2666 MT/s", "power_plan":"High performance", "smt":"on", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -2051,7 +2051,7 @@ "ram_config":"8×32 GB @ 2666 MT/s", "power_plan":"High performance", "smt":"on", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -2129,7 +2129,7 @@ "ram_config":"8×32 GB @ 2666 MT/s", "power_plan":"High performance", "smt":"on", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ @@ -2229,7 +2229,7 @@ "ram_config":"8×32 GB @ 2666 MT/s", "power_plan":"High performance", "smt":"on", - "remote_desktop":"parsec" + "remote_desktop":"off" }, "tests":{ "asr:jfk.wav":{ diff --git a/modules/dasLLAMA/tests/REVIEW.md b/modules/dasLLAMA/tests/REVIEW.md index cfbb57b061..6b1cd8b565 100644 --- a/modules/dasLLAMA/tests/REVIEW.md +++ b/modules/dasLLAMA/tests/REVIEW.md @@ -133,8 +133,8 @@ logits-tolerance form. Counting cells stay token-exact. **A diff that adds a metal kernel class under `../dasllama/` - a `[metal_kernel]` def or a new instance of a template carrying one - covers that class in `test_kernel_coverage.das`, one of two ways.** Either a census row there dispatches the class, or the diff names it in -that file's `CENSUS_NEVER_DISPATCHED`, with the reason no row can reach it. A dispatching -row runs on a small model - one the suite runs without `DASLLAMA_PARITY_FULL=1`. Naming a +that file's `CENSUS_NEVER_DISPATCHED`, with the reason no row can reach it. A +`DASLLAMA_PARITY_FULL`-gated census row counts as the dispatching arm. Naming a class a census row could dispatch is a defect. **A kernel-unit cell missing a compare against a CPU oracle that can witness the cell's diff --git a/modules/dasLLAMA/tests/test_metal_prefill_kernels.das b/modules/dasLLAMA/tests/test_metal_prefill_kernels.das index 98bc84a3ff..a55efddebf 100644 --- a/modules/dasLLAMA/tests/test_metal_prefill_kernels.das +++ b/modules/dasLLAMA/tests/test_metal_prefill_kernels.das @@ -2235,24 +2235,42 @@ def private metal4_tensor_available(dev) : bool { //! device-free: the dev-W knee arithmetic (the pick the board's deep-dense cells ride). //! Expectations hold at the DEVW_SMALL_PANEL default (32 MiB) - no sidecar loads here -[test] +[test, unused_argument(t)] // off-Apple the body feints without touching t def test_devw_tile_pick(t : T?) { - let cap = 16ul * 1024ul * 1024ul * 1024ul - // small panel (16 MiB, narrow N) serves whole - t |> equal(devw_tile_pick(256l, 4096l, 2048l, false, cap), 1l) - // deep-dense up/gate (320 MiB, d/64 = 512): first divisor tile under the small knee is 16 - - // unreachable under a 2..8 cap - t |> equal(devw_tile_pick(2048l, 32768l, 5120l, false, cap), 16l) - // deep-dense down (long-K, d/64 = 80): tc = 10, and rows below the long-K floor decline - t |> equal(devw_tile_pick(2048l, 5120l, 32768l, false, cap), 10l) - t |> equal(devw_tile_pick(512l, 5120l, 32768l, false, cap), 0l) - // over-knee under the tiled-rows floor: no form serves - unless the slow-fallback class - // lowers the floor to 512 - t |> equal(devw_tile_pick(512l, 32768l, 5120l, false, cap), 0l) - t |> equal(devw_tile_pick(512l, 32768l, 5120l, true, cap), 16l) - // mid panel (40 MiB) needs the big-rows floor - t |> equal(devw_tile_pick(2048l, 4096l, 5120l, false, cap), 1l) - t |> equal(devw_tile_pick(1024l, 4096l, 5120l, false, cap), 0l) + static_if (typeinfo builtin_module_exists(das_metal)) { + let cap = 16ul * 1024ul * 1024ul * 1024ul + // small panel (16 MiB, narrow N) serves whole + t |> equal(devw_tile_pick(256l, 4096l, 2048l, false, cap), 1l) + // deep-dense up/gate (320 MiB, d/64 = 512): first divisor tile under the small knee is + // 16 - unreachable under a 2..8 cap + t |> equal(devw_tile_pick(2048l, 32768l, 5120l, false, cap), 16l) + // deep-dense down (long-K, d/64 = 80): tc = 10, and rows below the long-K floor decline + t |> equal(devw_tile_pick(2048l, 5120l, 32768l, false, cap), 10l) + t |> equal(devw_tile_pick(512l, 5120l, 32768l, false, cap), 0l) + // over-knee under the tiled-rows floor: no form serves - unless the slow-fallback class + // lowers the floor to 512 + t |> equal(devw_tile_pick(512l, 32768l, 5120l, false, cap), 0l) + t |> equal(devw_tile_pick(512l, 32768l, 5120l, true, cap), 16l) + // mid panel (40 MiB) needs the big-rows floor + t |> equal(devw_tile_pick(2048l, 4096l, 5120l, false, cap), 1l) + t |> equal(devw_tile_pick(1024l, 4096l, 5120l, false, cap), 0l) + } else { + feint("das_metal is not built on this platform; the knee predicate is not compiled\n") + } +} + +//! device-free: the dense tall-kq pick - the byte knee, the 128-row floor, and the +//! set_metal_prefill_tall A/B seat (the seat clause is what the override contract pins) +[test, unused_argument(t)] // off-Apple the body feints without touching t +def test_tallkq_pick(t : T?) { + static_if (typeinfo builtin_module_exists(das_metal)) { + t |> success(tallkq_pick(512l, 16384l, 4096l, true), "over-knee tall panel takes") + t |> success(!tallkq_pick(512l, 16384l, 4096l, false), "set_metal_prefill_tall(false) pins the tall form off") + t |> success(!tallkq_pick(96l, 16384l, 4096l, true), "under the 128-row floor declines") + t |> success(!tallkq_pick(512l, 4096l, 4096l, true), "under the byte knee declines") + } else { + feint("das_metal is not built on this platform; the knee predicate is not compiled\n") + } } def private moe_mulmm_q51_gate(t : T?; dev, queue; kdim, ndim : int; counts : array) { diff --git a/site/REVIEW.das b/site/REVIEW.das new file mode 100644 index 0000000000..f077e552ab --- /dev/null +++ b/site/REVIEW.das @@ -0,0 +1,89 @@ +options gen2 + +require strings +require daslib/fio +require daslib/strings_boost +require dastest/review_gate + +// The mechanical half of site/REVIEW.md (contract: REVIEW_COMMON.md at the repo root). +// Run from the repo root: bin/daslang site/REVIEW.das - exit 0 clean, 1 with findings. + +let private TABLE_CSS = "site/files/dasllama-table.css" +let private PAGE_HTML = "site/dasllama.html" + +//! one top-level selector -> its normalized body. An at-rule (`@media ...`) block is skipped +//! whole: its nested rules are responsive OVERRIDES of the same selectors by design +def private css_blocks(text : string; var out : table) { + peek_data(text) $(d) { + var i = 0 + let n = length(d) + while (i < n) { + let ob = d |> find("\{", i) + break if (ob < 0) + let sel = strip(slice(d, i, ob)) + if (sel |> starts_with("@")) { + var depth = 1 + var j = ob + 1 + while (j < n && depth > 0) { + let c = int(d[j]) + if (c == '{') { + depth++ + } elif (c == '}') { + depth-- + } + j++ + } + i = j + continue + } + let cb = d |> find("\}", ob) + break if (cb < 0) + let body = slice(d, ob + 1, cb) + // normalize: collapse whitespace runs so formatting differences do not read as drift + let parts <- [for (p in split_by_chars(body, " \t\r\n")); p; where !empty(p)] + if (!empty(sel) && (sel |> find(".dl-") >= 0)) { + out[sel] = join(parts, " ") + } + i = cb + 1 + } + } +} + +// dasllama.html carries an inline copy of some dl-* selectors beside the loaded css file; +// a body that drifts between the two copies styles the page and the injected table +// differently depending on load order +def private check_dl_selector_parity { + let css = fread(TABLE_CSS) + if (empty(css)) { + gate_finding(TABLE_CSS, "missing or unreadable") + return + } + let html = fread(PAGE_HTML) + if (empty(html)) { + gate_finding(PAGE_HTML, "missing or unreadable") + return + } + let s0 = html |> find("") + return if (s0 < 0 || s1 < 0) + var css_map : table + var html_map : table + css_blocks(css, css_map) + css_blocks(slice(html, s0 + length("