Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions modules/REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
**Read `REVIEW_COMMON.md` (repo root) first - its contract binds this checklist.**

**A diff to a function carrying `[metal_kernel]`, `[spirv_kernel]`, or an annotation whose name
ends `_shader` and comes from `dasSpirv`, `dasVulkan` or `dasMetal`, to any `def` such a
function reaches directly or through another, or to a fixture the `dasMetal` or `dasSpirv`
emitter compiles, applies `REVIEW_SHADER_EMITTERS.md` (beside this file) together with its own
folder's checklist.**
ends `_shader` and comes from `dasSpirv`, `dasVulkan` or `dasMetal`; to any `def` such a
function reaches directly or through another; to a class the `dasMetal` or `dasSpirv` emitter
generates a kernel from, its member declarations included; or to a fixture that emitter
compiles, applies `REVIEW_SHADER_EMITTERS.md` (beside this file) together with its own folder's
checklist.**

**A C++ module whose CMake target links another in-tree module's target calls
`Module::require("<name>")` for it, and the returned module's `initDependencies()`, in its own
Expand All @@ -15,11 +16,10 @@ records a module nothing required as deferred and resolves an importer's imports
its code runs, so an unrequired sibling fails the importer's next load.

**A module whose `dasClangBind`-generated binding depends on another in-tree module declares
that dependency in its `bind_*.das` -
`require_modules` when the binding uses the other module's types, `require_load_modules` when
only the library import needs it - and the binder emits `initDependencies` from the lists; a hand
edit of the generated file alone is a defect.** `require_modules` adds the other module to this
module's type library, so a module that binds the same C++ types twice resolves the fields to
the other's copies; a `require_load_modules` entry the build lacks - a static exe linking only
what its program requires - is skipped, since without a library import there is no load order
to keep.
that dependency in its `bind_*.das` - `require_modules` when the binding uses the other module's
types, `require_load_modules` when only the library import needs it - and the binder emits
`initDependencies` from the lists; a hand edit of the generated file alone is a defect.**
`require_modules` adds the other module to this module's type library, so a module that binds
the same C++ types twice resolves the fields to the other's copies; a `require_load_modules`
entry the build lacks - a static exe linking only what its program requires - is skipped, since
without a library import there is no load order to keep.
3 changes: 2 additions & 1 deletion modules/REVIEW_SHADER_EMITTERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ shape constant.

**A Metal kernel that loads its operands with the `tmm2d_*` family receives a run-time-only
matmul reduction width through a `matmul2d_descriptor` whose K extent is `dynamic_extent`, and
no other way.**
no other way.** The reduction width is the K loop's bound - the length of the loop the kernel
accumulates over; the per-step chunk a `tmm2d_*` call takes is a shape constant.

**A diff that makes a kernel need a shape constant known only at run time ships a
specialization path, or records in an `ARCHITECTURE*.md` at the root of the module the kernel
Expand Down
4 changes: 2 additions & 2 deletions modules/dasLLAMA/ARCHITECTURE_GPU.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,8 @@ the production dialect against them - the bisect seat when the flash regresses.
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) - the
batch-decode/classifier `MetalQ8GemmTensorT` family, whose half-X extension is an open ledger
item, and the double-buffered `*Db` staging templates (`MetalQ8MulMmDbT`, `MetalKqMulMmK45DbT`,
`MetalKqMulMmK6DbT`), which pin `XT = float16` today - there the flag is scaffolding a future
item, and the double-buffered `*Db` staging stamps (`MetalQ8MulMmTensorT`'s `BK = 128` stamps,
`MetalKqMulMmK45DbT`, `MetalKqMulMmK6DbT`), which pin `XT = float16` today - there the flag is scaffolding a future
float stamp would need, not a live float operand - and the verify-width lab template
`MetalKqLabK4Tmv8T` in the GEMV lab, whose A operand is the decode driver's f32 x panel.
- **Fused single-kernel attention (scores in threadgroup, online softmax):** loses 10-80% to
Expand Down
12 changes: 6 additions & 6 deletions modules/dasLLAMA/REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@ docs: `ARCHITECTURE.md`, `ARCHITECTURE_ENGINE.md`, `ARCHITECTURE_RUNTIME.md`,
the Vulkan tier), `followup_metal.md` (engine work on the Metal tier, or CPU engine work
measured on macOS), `PERF_LEDGER.md` (performance; the rest goes to the followup ledgers).

**A dasLLAMA `[test]` file, wherever the diff puts it, answers to this module's
`tests/REVIEW.md`.**
**A dasLLAMA `[test]` file, wherever the diff puts it, answers to `tests/REVIEW.md` here.**

**A timing rig (a file that times a run itself and reports a wall-clock time or rate as its
result, printed or returned to a caller that prints it - a driver reading a child's clock is
Expand Down Expand Up @@ -94,8 +93,8 @@ sidecars stay valid across code changes, and per-change invalidation lives in th
mechanisms - `IMAGE_VERSION` and `layout_fingerprint()` (`dasllama/dasllama_image.das`).

**A value that cannot change between dispatches of one compiled kernel never reaches that
kernel as a uniform, a kargs field, an `@off` bind offset, or a helper parameter - stamp it
into the class as a `@template_constant` instead.**
kernel as a uniform, a kargs field, or an `@off` bind offset - stamp it into the class as a
`@template_constant` instead.**

**A function-typed global a serialized exe must re-establish lands in a `dasllama/` file with
the `[init]` that establishes it at boot; landing one where `REVIEW.das`'s restore-check walk
Expand Down Expand Up @@ -268,8 +267,9 @@ keeps the charters true - in an `ARCHITECTURE_*.md` companion, never `ARCHITECTU
same change.** A file added beside files with their own sec.1 charter lines gets one too; a
module-root ledger has none.

**A follow-up ledger row whose work landed in this change is deleted, and the rows below it
keep their numbers** - checked-in text cites rows by number, and no lint follows the citations.
**A follow-up ledger row whose work landed in this change is deleted, and the rows below keep
their numbers; when a row lists several items and one item's work landed, that item is deleted
and the row stays** - checked-in text cites rows by number.

**A diff that adds, removes, or moves a section of an `ARCHITECTURE_*.md` companion, or adds
or removes a companion, lands `ARCHITECTURE.md`'s index line and section range, the
Expand Down
13 changes: 7 additions & 6 deletions modules/dasLLAMA/REVIEW_GPU.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

**Read `REVIEW_COMMON.md` (repo root) first - its contract binds this checklist.** Architecture
docs: `ARCHITECTURE_GPU.md`, `ARCHITECTURE_GPU_MTP.md`, `ARCHITECTURE_GPU_VULKAN.md`. Planned
work: `followup_metal.md` for Metal, `followup_vulkan.md` for Vulkan.
work: `followup_metal.md` for Metal, `followup_vulkan.md` for Vulkan - never `followup_general.md`.

**Routed from `REVIEW.md`: a diff that checklist routes here applies this list together with
it.**
**Routed from `REVIEW.md`: a diff it routes here applies this list together with it.**

**A diff touching a GPU kernel timing arm - code that dispatches a kernel to measure it rather
than to serve a call - wherever the diff puts it, applies `REVIEW_GPU_RACE.md` too.**
Expand Down Expand Up @@ -109,8 +108,7 @@ count is overrun silently into whatever the pool put next to it.
**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.
`row x dispatched-width`, so a wider-row caller lands its split rows on 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 - rotate through as many buffers as the chain has dispatches in
Expand Down Expand Up @@ -234,7 +232,10 @@ anything a served GPU decode or prefill call executes or that selects what it ex
driver, a kernel class it dispatches, that class's builder, a servability gate, a race that
picks which kernel serves, a forwarder default, a weight-region or residency path, the tier
forwarders and the Vulkan tier-dispatch seams (`dasllama/dasllama_vulkan_seams.das`) the call
routes through; a rename, a comment or a bake path cannot.
routes through; a rename, a comment, a bake path, or a change confined to kernel bodies whose
emitted kernels - the `*_msl` globals or the AIR (Metal's compiled shader IR) they build into,
the SPIR-V words `DASLLAMA_VK_SPV_DUMP` writes - are byte-identical before and after, the PR
body naming that compare, cannot.

**Parity evidence counts only when it comes from `harness/parity.das`,
`benchmarks/lcpp_bench.das --parity` (`performance/model_specs.das`'s fixed model list), or an
Expand Down
19 changes: 11 additions & 8 deletions modules/dasLLAMA/benchmarks/REVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,17 @@ and corpus - or withdraws the affected rows and names the withdrawal and its rea
body.** What a cell times changes when a change inside its timed body, to its input corpus, or
to the pinned reference build (`DEFAULT_REF_SHA` in `setup_lcpp_ref.das`, or anything else
deciding which reference binary or environment the run measures) moves the measured quantity; a
change outside the timed body - a flag, a require, the submit path - does not. The new rows or
the withdrawal land in `../performance/records/<box>.json`, the file the affected rows live in.

**A diff that adds an instrument, or changes how one reports or exits, makes every mode whose
purpose is to report result rows exit non-zero on a run that reports none - wrong flags, failed
load, a device that declines.** A result row is a row carrying a time or a rate. A run that
matched nothing and reported success leaves a sidecar or a record untouched, and its caller
cannot tell.
change outside the timed body - a flag, a require, the submit path - does not, nor does a
change to a GPU kernel emitter whose emitted kernel code - the `*_msl` source globals, the AIR
they build into, the SPIR-V words the Vulkan dump writes - is byte-identical before and after,
with the PR body naming that compare. The new rows or the withdrawal land in
`../performance/records/<box>.json`, the file the affected rows live in.

**A diff that adds a file under this folder whose modes report result rows, or changes how such
a mode reports or exits, makes every result-row mode of that file exit non-zero on a run that
reports none - wrong flags, failed load, a device that declines.** A result row is a row
carrying a time, a rate, or a per-kernel occupancy count. A run that matched nothing and
reported success leaves a sidecar or a record untouched, and its caller cannot tell.

**A diff that adds an A/B arm, or changes how an arm reports or exits, makes that instrument
exit non-zero when the lever does not change what the run executes - or, when the instrument
Expand Down
2 changes: 1 addition & 1 deletion modules/dasLLAMA/benchmarks/matmul/occupancy_report.das
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def main {
check(dev, "q8_mulmm (prod GEMM)", metal_q8_mulmm_msl, metal_q8_mulmm_msl_entry, metal_q8_mulmm_msl_fastmath)
check(dev, "q8_mulmm_th 32x64", MetalQ8MulMmTH_metal_q8_mulmm_t_msl, MetalQ8MulMmTH_metal_q8_mulmm_t_msl_entry, MetalQ8MulMmTH_metal_q8_mulmm_t_msl_fastmath)
check(dev, "q8_mulmm_th128 128x64", MetalQ8MulMmTH128_metal_q8_mulmm_t_msl, MetalQ8MulMmTH128_metal_q8_mulmm_t_msl_entry, MetalQ8MulMmTH128_metal_q8_mulmm_t_msl_fastmath)
check(dev, "q8_mulmm_thdb128 128x64 dbuf", MetalQ8MulMmTHDb128_metal_q8_mulmm_db_msl, MetalQ8MulMmTHDb128_metal_q8_mulmm_db_msl_entry, MetalQ8MulMmTHDb128_metal_q8_mulmm_db_msl_fastmath)
check(dev, "q8_mulmm_thdb128 128x64 dbuf", MetalQ8MulMmTHDb128_metal_q8_mulmm_t_msl, MetalQ8MulMmTHDb128_metal_q8_mulmm_t_msl_entry, MetalQ8MulMmTHDb128_metal_q8_mulmm_t_msl_fastmath)
check(dev, "hmm_th 32x64", MetalHalfMulMmTH_metal_half_mulmm_th_msl, MetalHalfMulMmTH_metal_half_mulmm_th_msl_entry, MetalHalfMulMmTH_metal_half_mulmm_th_msl_fastmath)
check(dev, "hmm_th128 128x64", MetalHalfMulMmTH128_metal_half_mulmm_th_msl, MetalHalfMulMmTH128_metal_half_mulmm_th_msl_entry, MetalHalfMulMmTH128_metal_half_mulmm_th_msl_fastmath)
check(dev, "q8_gemm 32x32", metal_q8_gemm_msl, metal_q8_gemm_msl_entry, metal_q8_gemm_msl_fastmath)
Expand Down
48 changes: 15 additions & 33 deletions modules/dasLLAMA/dasllama/dasllama_metal_prefill.das
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,15 @@ class MetalBf16MulMm : MetalMmTileBase {
[ |> template_struct_instance]
class template MetalQ8MulMmTensorT {
@template_constant MT : uint = 32u //!< M-tile rows: W re-streams M/MT times
@template_constant BK : uint = 64u //!< K chunk the stage streams per step; 128 double-buffers two tiles
@template_constant TWB : int = 6144 //!< W stage halves: one 64 wcols x 72-half padded tile (12288B lands mid-plateau); 9216 = two tiles
@ssbo @binding = 0 @role = "weight" @off = "wboff" wsh : array<float16> //!< 34B-block W blob, half-scale view
@ssbo @binding = 1 @role = "weight" @off = "wboff" wqb : array<int8> //!< the SAME blob buffer, byte view
@ssbo @binding = 2 @off = "xoff" xf : array<XT> //!< raw activations (float, or the converted f16 panel)
@ssbo @binding = 3 @off = "yoff" @span = "mp*d*4" y : array<float>
@uniform @binding = 4 kdim : uint
@uniform @binding = 5 ndim : uint
@workgroup twb : float16[6144] //!< W chunk: 64 wcols x 72-half padded rows (bk=64; 12288B lands mid-plateau)
@workgroup twb : float16[TWB]

[metal_kernel(float_a_ok=true)]
def metal_q8_mulmm_t {
Expand All @@ -118,7 +120,7 @@ class template MetalQ8MulMmTensorT {
var wp = unsafe(addr(wqb[blk0 * 34u + 2u]))
var ap = unsafe(addr(xf[mBase * kdim]))
var cp = unsafe(addr(y[mBase * ndim + nBase]))
tmm2d_q8u_f32(MT, 64u, 4u, twb, sp, wp, ap, kdim, cp, ndim, kdim, kdim / 32u, gl_LocalInvocationIndex, 64u)
tmm2d_q8u_f32(MT, 64u, 4u, twb, sp, wp, ap, kdim, cp, ndim, kdim, kdim / 32u, gl_LocalInvocationIndex, BK)
}
}

Expand All @@ -144,39 +146,19 @@ class MetalQ8MulMmTH128 : MetalQ8MulMmTensorT {
override MT = 128u
}

[ |> template_struct_instance]
class template MetalQ8MulMmDbT {
@template_constant MT : uint = 128u
@ssbo @binding = 0 @role = "weight" @off = "wboff" wsh : array<float16>
@ssbo @binding = 1 @role = "weight" @off = "wboff" wqb : array<int8>
@ssbo @binding = 2 @off = "xoff" xf : array<XT>
@ssbo @binding = 3 @off = "yoff" @span = "mp*d*4" y : array<float>
@uniform @binding = 4 kdim : uint
@uniform @binding = 5 ndim : uint
@workgroup twb : float16[9216] //!< two 64x72-half tiles = 18432B (probed: 0-2% off the alloc plateau)

[metal_kernel(float_a_ok=true)]
def metal_q8_mulmm_db {
let mBase = gl_WorkGroupID.x * MT
let nBase = gl_WorkGroupID.y * 64u
let blk0 = nBase * (kdim / 32u)
var sp = unsafe(addr(wsh[blk0 * 17u]))
var wp = unsafe(addr(wqb[blk0 * 34u + 2u]))
var ap = unsafe(addr(xf[mBase * kdim]))
var cp = unsafe(addr(y[mBase * ndim + nBase]))
tmm2d_q8u_f32(MT, 64u, 4u, twb, sp, wp, ap, kdim, cp, ndim, kdim, kdim / 32u, gl_LocalInvocationIndex, 128u)
}
}

[metal_dispatch(name = "enc_gemm_mm_thdb128_c", pso = "g_pf_pso_mm_thdb128", tgmem = "MetalQ8MulMmTHDb128_metal_q8_mulmm_db_msl_tgmem", tg = 128, grid = "mp/128, d/64", params = "mp : int64, d : int64")]
class MetalQ8MulMmTHDb128 : MetalQ8MulMmDbT {
[metal_dispatch(name = "enc_gemm_mm_thdb128_c", pso = "g_pf_pso_mm_thdb128", tgmem = "MetalQ8MulMmTHDb128_metal_q8_mulmm_t_msl_tgmem", tg = 128, grid = "mp/128, d/64", params = "mp : int64, d : int64")]
class MetalQ8MulMmTHDb128 : MetalQ8MulMmTensorT {
typedef XT = float16
override MT = 128u
override BK = 128u
override TWB = 9216
}

[metal_dispatch(name = "enc_gemm_mm_thdb_c", pso = "g_pf_pso_mm_thdb", tgmem = "MetalQ8MulMmTHDb_metal_q8_mulmm_db_msl_tgmem", tg = 128, grid = "mp/32, d/64", params = "mp : int64, d : int64")]
class MetalQ8MulMmTHDb : MetalQ8MulMmDbT {
[metal_dispatch(name = "enc_gemm_mm_thdb_c", pso = "g_pf_pso_mm_thdb", tgmem = "MetalQ8MulMmTHDb_metal_q8_mulmm_t_msl_tgmem", tg = 128, grid = "mp/32, d/64", params = "mp : int64, d : int64")]
class MetalQ8MulMmTHDb : MetalQ8MulMmTensorT {
typedef XT = float16
override MT = 32u
override BK = 128u
override TWB = 9216
}

struct CvtArgs {
Expand Down Expand Up @@ -4147,8 +4129,8 @@ def private metal_prefill_init : bool { // nolint:STYLE038 — flat one-compil
g_pf_pso_mm_th = compile_pso(MetalQ8MulMmTH_metal_q8_mulmm_t_msl, MetalQ8MulMmTH_metal_q8_mulmm_t_msl_entry, MetalQ8MulMmTH_metal_q8_mulmm_t_msl_fastmath, ok)
g_pf_pso_mm_t128 = compile_pso(MetalQ8MulMmT128_metal_q8_mulmm_t_msl, MetalQ8MulMmT128_metal_q8_mulmm_t_msl_entry, MetalQ8MulMmT128_metal_q8_mulmm_t_msl_fastmath, ok)
g_pf_pso_mm_th128 = compile_pso(MetalQ8MulMmTH128_metal_q8_mulmm_t_msl, MetalQ8MulMmTH128_metal_q8_mulmm_t_msl_entry, MetalQ8MulMmTH128_metal_q8_mulmm_t_msl_fastmath, ok)
g_pf_pso_mm_thdb128 = compile_pso(MetalQ8MulMmTHDb128_metal_q8_mulmm_db_msl, MetalQ8MulMmTHDb128_metal_q8_mulmm_db_msl_entry, MetalQ8MulMmTHDb128_metal_q8_mulmm_db_msl_fastmath, ok)
g_pf_pso_mm_thdb = compile_pso(MetalQ8MulMmTHDb_metal_q8_mulmm_db_msl, MetalQ8MulMmTHDb_metal_q8_mulmm_db_msl_entry, MetalQ8MulMmTHDb_metal_q8_mulmm_db_msl_fastmath, ok)
g_pf_pso_mm_thdb128 = compile_pso(MetalQ8MulMmTHDb128_metal_q8_mulmm_t_msl, MetalQ8MulMmTHDb128_metal_q8_mulmm_t_msl_entry, MetalQ8MulMmTHDb128_metal_q8_mulmm_t_msl_fastmath, ok)
g_pf_pso_mm_thdb = compile_pso(MetalQ8MulMmTHDb_metal_q8_mulmm_t_msl, MetalQ8MulMmTHDb_metal_q8_mulmm_t_msl_entry, MetalQ8MulMmTHDb_metal_q8_mulmm_t_msl_fastmath, ok)
g_pf_pso_dq_q8 = compile_pso(metal_dequant_q8h_msl, metal_dequant_q8h_msl_entry, metal_dequant_q8h_msl_fastmath, ok)
}
g_pf_bf16_mm_tensor = metal_tensor_crowned("mulmm_bf16")
Expand Down
6 changes: 0 additions & 6 deletions modules/dasLLAMA/followup_general.md
Original file line number Diff line number Diff line change
Expand Up @@ -1610,9 +1610,3 @@
Nothing reaches it below `g_attn_single_max` rows of context. Unquirked: one chunk-count
formula over the deepest row, used both to size `bpart` and to dispatch, with a cell that
verifies at a context depth crossing a 64-row boundary.
143. **The q8 mul_mm tensor and double-buffer kernels are one body one stage width apart.**
`MetalQ8MulMmTensorT` and `MetalQ8MulMmDbT` (`dasllama_metal_prefill.das`) carry the same
eight-line kernel; they differ in the chunk width `tmm2d_q8u_f32` takes (64 / 128), the
staging tile (`twb` 6144 / 9216 halves) and the default M tile (32 / 128). Unquirked: one
class template with the stage width as its constant, the stamps keeping their dispatch
names, gated by the emitted-kernel identity compare and the prefill kq arms.
2 changes: 1 addition & 1 deletion modules/dasLLAMA/followup_metal.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ zoo. Facts that decide the order:
must set `IQ4XS` and `IQ4NL`; the Db forms sit on the sanctioned float-A list); the four dense
mul_mm shells onto a `MetalMoeMulMmBase` twin (~145); the MoE GEMV `GATHERED` axis (~230, the
`float4` x view stays its own axis - a measured 2.25x); the zero-risk singles (CrossVx f16/f32,
Q8MvB2/B4 onto `MetalGemvB24T`, argmax rows, rope-store batched, Q8MulMmDb, DequantK6H,
Q8MvB2/B4 onto `MetalGemvB24T`, argmax rows, rope-store batched, DequantK6H,
G4aMag/Q3aPow, the bias pair; ~325).
- Rules for every conversion: a stamp's `tgmem=` string is `<LeafClass>_<method>_msl_tgmem`, so a
hand class becoming a stamp changes it and drops its `[metal_kernel(name=..)]`; a
Expand Down
Loading
Loading