round 26 track b: qsa prompt mm #
contract (before measurement) #
owner: metal/kernels/qsa_prompt.metal; only attention's cooperative operand address preparation, softmax loop hints/output copy, and score loop hints change. no dispatch/layout/interface changes; fallback cooperative layout must remain valid. byte offsets are uint32, matching the existing cache addressing bound.
baseline: working-tree snapshot of the owned kernel at vendor commit 296b59d2f73c8f04a805df29c2fa97655adace78, saved at /tmp/sol_r26_qsa/baseline_qsa_prompt.metal (the working tree already contains prior-round changes).
question: do 32-bit operand offsets, fixed-loop unroll hints and vector threadgroup output loads reduce m5 qsa mm latency without changing any output byte?
evaluator: existing qsa_prompt_parity --mm-compare, deterministic rng seed 5, alternating paired dispatch order, full output buffer memcmp (including poisoned unwritten regions). primary matrix: t=96,1984 and pos0=0,2048,8192,30000. screen using 5 pairs, confirm using 9 pairs; reject bitwise changes or repeatable regressions. require roughly >=2% repeatable long-prompt improvement to ship a kernel change; otherwise preserve a negative/inconclusive result. ablate vector load and score hints if combined result loses. no full-model runs; no server requests; each test timeout 20s for cold compile, target <10s elapsed.
artifacts and immutable variant snapshots live in /tmp/sol_r26_qsa/; gpu tests run sequentially to avoid self-contention. budget: at most 60 short invocations plus 2 compile repairs.
decision #
ship attention offsets + fixed-loop hints + vector threadgroup loads. do not ship score unroll hints: bitwise pass, but repeated paired results did not establish a reliable gain. qsa_score_mm is unchanged in the patch. qsa_flash and all other kernels are unchanged.
- patch:
/tmp/sol_r26_qsa/sol_r26_qsa.patch(two owned files only). git -C vendor/strata apply --check /tmp/sol_r26_qsa/sol_r26_qsa.patch: exit 0.- no tracked vendor files edited; no requests to :8080; no full-model runs.
- existing
--mm-comparereused; harness now checks post-timing partials and merged/prepared activation buffers bitwise, in addition to the pre-timing whole partial-buffer memcmp.
measured confirmation #
apple m5; macos 27.0 build 26a428; cooperative layout probe true; safe math (no reassociation). timings below are medians of 9 paired alternating-order single dispatches, milliseconds. full partials, post-timing partials, and all merged/prepared output bytes passed memcmp == 0 for every row. tg memory unchanged at 7424 bytes.
| t | pos0 | baseline ms | candidate ms | reduction |
|---|---|---|---|---|
| 96 | 0 | 0.362500 | 0.291625 | 19.55% |
| 96 | 2048 | 6.023500 | 4.092000 | 32.07% |
| 96 | 8192 | 5.318875 | 3.293667 | 38.08% |
| 96 | 30000 | 1.918875 | 1.493208 | 22.18% |
| 1984 | 0 | 14.569125 | 11.676958 | 19.85% |
| 1984 | 2048 | 30.884125 | 23.683833 | 23.31% |
| 1984 | 8192 | 31.790833 | 22.275375 | 29.93% |
| 1984 | 30000 | 37.322500 | 28.089667 | 24.74% |
final_attn_*.log contains all samples. a final review rerun at t1984,pos8192 gave 31.815083 → 22.381875 ms (-29.65%), all three byte checks passed (final_review_attn_1984_8192.log). at 12 qsa layers this isolated-kernel delta is roughly 113 ms/chunk; this is not an end-to-end server claim.
short-case absolute clocks varied considerably across processes (the live server was left alone). long-case paired gains were stable across screening, ablation and confirmation. neither clocks nor competing external activity were controlled; use the paired within-process deltas rather than comparing unrelated absolute samples.
ablations / negatives #
- offsets + all attention loop hints but scalar copy: long t1984,pos2048/8192/30000 medians 30.879→24.543 / 33.366→25.781 / 36.744→28.541 ms. (
ablate_offsets_softmax_*.log) - vector load incremental against that variant, measured directly paired: 24.394500→23.880250 ms at pos2048 (-2.11%), 23.688458→22.506375 at pos8192 (-4.99%), 28.195500→27.637125 at pos30000 (-1.98%). t96,pos8192 2.514417→2.353750 (-6.39%). all bitwise checks passed. (
vector_increment_*.log) - score hints: screen t1984,pos30000 initially looked faster (10.396→9.670 ms), but 15-pair confirmation gave 5.177625→5.169417 (-0.16%). pos2048 0.481500→0.478792 (-0.56%), pos8192 1.450417→1.449083 (-0.09%). t96 pos8192 regressed 0.077625→0.081000 (+4.35%). no robust benefit: rejected. (
confirm_score_*.log; candidate sourcecombined.metal/score.metalretained) - the literal proposed
#pragma clang loop unroll(4)failed compilation: metal clang acceptsunroll_count(4), used here. one compile repair; failed attempt preserved inscreen_combined_attn_1984_8192.log.
parity coverage / limits #
- primary 2×4 t/pos matrix above: exact pre/post partials and merged/prepared equality, including causal tail chunks, crossing the 2051-cell budget at pos2048, invalid implicit ids poisoned to -1, and untouched buffer regions poisoned 0xa5.
- force generic cooperative decode (
COOP_K4=0) at t96,pos0/8192/30000: all partial and merge/prepared byte checks pass on m5. this is not physical m4 validation. - final score+topk pipeline checks at t96,pos2048 and t1984,pos8192/30000: scores, ids and post-timing equality pass. stage code is unchanged in final candidate.
- all successful benchmark invocations completed under 5s, within requested <10s limit; timeout 20s reserved for cold compilation. gpu runs were sequential; no helper agents spawned.
- rng seed 5; no exhaustive adversarial float corpus or physical non-m5 testing. safe-math compilation and unaltered arithmetic sequencing preserved the tested bit patterns.
reproduce / preserved sources #
scratch tree: /tmp/sol_r26_qsa/strata; immutable source snapshots: baseline_qsa_prompt.metal, baseline_qsa.metal, offsets_softmax.metal, vector.metal, score.metal, combined.metal in the experiment directory. final kernel in scratch differs from vector.metal only by the alignment comment. baseline kernel sha256: c768c25c3186e0715a77ad2d9a58277871b4aab50d51fca0d4dd3fa42962ac6a.
build command (existing runtime library is unmodified):
clang++ -std=c++20 -O2 -I/tmp/sol_r26_qsa/strata/metal/src -I<workspace>/vendor/strata/third_party/ggml /tmp/sol_r26_qsa/strata/metal/tests/qsa_prompt_parity.cpp <workspace>/vendor/strata/build-metal/libmtl_rt.a -framework Metal -framework Foundation -o /tmp/sol_r26_qsa/qsa_prompt_parity
run each matrix row sequentially:
STRATA_METAL_KERNELS=/tmp/sol_r26_qsa/strata/metal/kernels /tmp/sol_r26_qsa/qsa_prompt_parity --mm-compare attn 1984 8192 /tmp/sol_r26_qsa/baseline_qsa_prompt.metal 9
replace attn with score to isolate score; --score-compare t pos baseline_prompt baseline_qsa pairs checks score/topk pipeline. final source sha256 values:
/tmp/sol_r26_qsa/strata/metal/kernels/qsa_prompt.metal:4602c462fa5096f3ee9e65b03460c5b441db3f4666c573fe0b30a5ffbf0f2971/tmp/sol_r26_qsa/strata/metal/tests/qsa_prompt_parity.cpp:5bc787fecab37b0d7f8bb6695cf4957a89694650084ed509ceb81678f6f37d23/tmp/sol_r26_qsa/sol_r26_qsa.patch:c7e42096f883395eb76aa8022711f1a48514d077d17a34c78f9c38b212ea726a