round 32 qsa flash experiment #

contract #

  • owner: qsa_flash in metal/kernels/qsa_prompt.metal; no production files edited.
  • hypothesis: four S partial buffers remove two chunk barriers without changing the explicit ((s0+s1)+(s2+s3)) reduction; separately test constant-offset K loads and fixed-loop unrolling.
  • preserve: exact fp16 output, softmax sum order, padded cells, cooperative and fallback paths, P alias lifetime. extra static shared memory must remain below 16 kib.
  • evaluator: existing qsa_prompt_parity, paired alternating A/B, T=1984, positions 0/2048/8192/30000, layers=3, pairs=7. default parity plus edge checks. baseline is immutable /tmp/sol_r32_qsa/base_qsa_prompt.metal.
  • decision: retain only bitwise-identical changes with repeatable net M5 gain (target >=3% in long-context median, no material regression at other positions). exploratory variants followed by full-position confirmation.
  • budget: serial short standalone tests only, each timeout <=20s; no server or model benchmarks.

source and execution #

  • strata HEAD: 296b59d2f73c8f04a805df29c2fa97655adace78; baseline includes the pre-existing dirty workspace changes (status saved in /tmp/sol_r32_qsa/strata_status.txt). no tracked production source was edited.
  • host: apple m5, macos 27.0 (26a428), existing vendor/strata/build-metal/qsa_prompt_parity binary. kernel source selected with STRATA_METAL_KERNELS=/tmp/sol_r32_qsa/strata/metal/kernels; safe math default; seed 5 from the existing evaluator.
  • commands: qsa_prompt_parity --flash-compare 1984 <pos0> /tmp/sol_r32_qsa/base_qsa_prompt.metal 3 7, plus default qsa_prompt_parity. all invocations exited within 3 seconds, below the 10-second budget.
  • comparison timing is three dispatches per sample, not 12 layers and not a full-model result. baseline-to-baseline check: 66.190 -> 66.122 ms at pos0=8192.

exploratory ablation (pos0=8192) #

variant before median ms after median ms change
four partial buffers only 66.299 65.770 -0.80%
+ pre-added k offsets and two-step k loop unroll 66.200 63.984 -3.35%
+ fixed-trip prefetch, softmax, denominator, v-fill unroll 66.156 63.539 -3.95%

all three variants: bitwise memcmp pass. raw logs and immutable variant snapshots are in /tmp/sol_r32_qsa/.

candidate confirmation #

pos0 before median ms after median ms change bitwise
0 28.756 27.545 -4.21% pass
2048 59.734 56.475 -5.45% pass
8192 66.322 63.779 -3.84% pass
30000 109.321 112.883 +3.26%, contaminated pass

confirm_8192.log contains a mid-run contention jump in its last two pairs (80–88 ms versus 63–66 ms before); confirm_30000.log is contaminated throughout (99–133 ms). parent confirmed tracks a/c were simultaneously running short gpu parity sweeps and requested handoff now for its own exclusive confirmation. therefore the 30000 timing does not establish either a win or a regression, and final acceptance is pending that exclusive rerun. the exploratory 8192 run and early-position confirmation provide the pre-contention evidence, not an end-to-end claim.

correctness:

  • all four 1984-token comparisons: exact fp16 output memcmp pass.
  • default suite: all pass, including qsa_flash versus fp32 reference at pos0 0/1984/2050/30000 and fused prep memcmp.
  • signed-zero and tiny-cancellation modes: QSA_FLASH_EDGE=1 and =2, each T=1984/pos0=30000/layers=3/pairs=7, both memcmp pass (edge_1.log, edge_2.log). timings contaminated, not used for selection.
  • forced generic fallback: COOP_K4=0 ... --flash-compare 96 30000 ... 1 3, memcmp pass (fallback.log). 5.314 -> 5.460 ms under contention; not an m4 performance claim. m4 hardware untested.
  • two exploratory compile failures were repaired before answering measurements: an over-broad scratch string replacement touched an earlier function, then a duplicated unroll directive. failed logs retained; final diff touches qsa_flash only.

implementation and review #

  • four disjoint S stores meet at one barrier, instead of the prior three. reduction remains exactly ((s0+s1)+(s2+s3))*0.0625f.
  • retain the following barrier before aliasing sp[1] as P. total static threadgroup memory measured by metal: 7616 -> 13760 bytes, below 16 kib. this does not independently prove unchanged register/occupancy limits.
  • pre-add d0 + the lane's first k index once per chunk. cooperative layout probe already guarantees the second half repeats at +16. unrolling the two k steps exposes +0/+16/+32/+48 byte offsets; ks8 remains loaded once.
  • denominator loop is unrolled without reassociation: sequential l += x; += y; += z; += w preserved. no new helper duplicates an existing abstraction; existing cooperative layout conventions reused.
  • final visual review: scratch view_diff plus full relevant view_code context. no test harness source change needed.

handoff #

  • clean patch: /tmp/sol_r32_qsa/sol_r32_qsa.patch (only metal/kernels/qsa_prompt.metal).
  • git -C vendor/strata apply --check /tmp/sol_r32_qsa/sol_r32_qsa.patch: exit 0.
  • recommend this candidate for parent's exclusive confirmation, not an unconditional 30000-position performance acceptance. no server touched and no full-model benchmark run.

source sha256:

4602c462fa5096f3ee9e65b03460c5b441db3f4666c573fe0b30a5ffbf0f2971  base_qsa_prompt.metal
9c141a1b65d5c2fa8bbff84027cd8757ed85cc1d72e80143cc94fe7255414e26  barrier_const_unroll.metal
3217640e820225cf57f9e03d05c6d58284c86ac8a23c7396597bb628bc2424e2  qsa_prompt_parity