ngocdang83 commited on
Commit
6723522
·
verified ·
1 Parent(s): 3cab202

moxhi b647f67

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. assets/addln_embed-C7q7s0KH.js +0 -2
  2. assets/addln_embed-DSGHKDTg.js +2 -0
  3. assets/{addln_embed-C7q7s0KH.js.map → addln_embed-DSGHKDTg.js.map} +1 -1
  4. assets/{adreno_probe-Cmg7uBSr.js → adreno_probe-CqGqVTv4.js} +12 -12
  5. assets/{adreno_probe-Cmg7uBSr.js.map → adreno_probe-CqGqVTv4.js.map} +0 -0
  6. assets/app_stage-BHS27TUf.js +0 -2
  7. assets/app_stage-DrqfcKH2.js +2 -0
  8. assets/{app_stage-BHS27TUf.js.map → app_stage-DrqfcKH2.js.map} +1 -1
  9. assets/argmax-CQZtdTcb.js +0 -2
  10. assets/argmax-DMqT6ikS.js +2 -0
  11. assets/{argmax-CQZtdTcb.js.map → argmax-DMqT6ikS.js.map} +1 -1
  12. assets/argmax_fuse-CKXRwPoI.js +2 -0
  13. assets/{argmax_fuse-DghSWREY.js.map → argmax_fuse-CKXRwPoI.js.map} +1 -1
  14. assets/argmax_fuse-DghSWREY.js +0 -2
  15. assets/{attention-D1W9vlkP.js → attention-1v-Zzb1X.js} +2 -2
  16. assets/{attention-D1W9vlkP.js.map → attention-1v-Zzb1X.js.map} +1 -1
  17. assets/attn_sweep-CxMb0QH-.js +2 -0
  18. assets/{attn_sweep-DYmEfGm0.js.map → attn_sweep-CxMb0QH-.js.map} +1 -1
  19. assets/attn_sweep-DYmEfGm0.js +0 -2
  20. assets/{autotune-DywP5DSc.js → autotune-Bwt_lWMv.js} +2 -2
  21. assets/autotune-Bwt_lWMv.js.map +1 -0
  22. assets/autotune-CVn9SF1X.js +2 -0
  23. assets/autotune-CVn9SF1X.js.map +1 -0
  24. assets/autotune-CgosBVvF.js +0 -2
  25. assets/autotune-CgosBVvF.js.map +0 -1
  26. assets/autotune-DywP5DSc.js.map +0 -1
  27. assets/baseline-DFLF_Mw1.js +2 -0
  28. assets/{baseline-DK6w1rGg.js.map → baseline-DFLF_Mw1.js.map} +1 -1
  29. assets/baseline-DK6w1rGg.js +0 -2
  30. assets/batch_cap_ab-67ewcIZi.js +2 -0
  31. assets/{batch_cap_ab-Dd5N_5qo.js.map → batch_cap_ab-67ewcIZi.js.map} +1 -1
  32. assets/batch_cap_ab-Dd5N_5qo.js +0 -2
  33. assets/{bench-CEDJ-mff.js → bench-BarR4Zp5.js} +4 -4
  34. assets/{bench-CEDJ-mff.js.map → bench-BarR4Zp5.js.map} +1 -1
  35. assets/{bench-D8r1wO6A.js → bench-D3sid5uF.js} +2 -2
  36. assets/{bench-D8r1wO6A.js.map → bench-D3sid5uF.js.map} +1 -1
  37. assets/compact_equiv-DlvjNh2p.js +0 -2
  38. assets/compact_equiv-DlvjNh2p.js.map +0 -1
  39. assets/compact_equiv-ehtvJC3N.js +2 -0
  40. assets/compact_equiv-ehtvJC3N.js.map +1 -0
  41. assets/{constants-C8VbFpic.js → constants-CSVWRdrh.js} +2 -2
  42. assets/{constants-C8VbFpic.js.map → constants-CSVWRdrh.js.map} +1 -1
  43. assets/debug-CPpXXfWA.js +12 -0
  44. assets/debug-CPpXXfWA.js.map +1 -0
  45. assets/debug-C_LNzFrK.js +0 -10
  46. assets/debug-C_LNzFrK.js.map +0 -1
  47. assets/dec_compact_sweep-D5MD5NcK.js +0 -2
  48. assets/dec_compact_sweep-DTumwRLm.js +2 -0
  49. assets/{dec_compact_sweep-D5MD5NcK.js.map → dec_compact_sweep-DTumwRLm.js.map} +1 -1
  50. assets/dec_group_sweep-BQZHA49R.js +0 -2
assets/addln_embed-C7q7s0KH.js DELETED
@@ -1,2 +0,0 @@
1
- import{r as w}from"./debug-C_LNzFrK.js";import{c as C,r as $,a as ee}from"./gpu-utils-BTh3AGTJ.js";import{g as L,a as te,e as ne}from"./pipelines-DJ7cc1m-.js";import{a as re,e as ae}from"./math-DNG-wiC0.js";import{e as M,f as se}from"./f16-wKKZr58e.js";import{L as oe,D as x,c as F,E as R}from"./constants-C8VbFpic.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";function N(n){let e=n>>>0;return()=>{e=e+1831565813|0;let t=Math.imul(e^e>>>15,1|e);return t=t+Math.imul(t^t>>>7,61|t)^t,((t^t>>>14)>>>0)/4294967296}}function S(n,e,t=1){const s=new Float32Array(n);for(let a=0;a<n;a++)s[a]=Math.fround((e()-.5)*t);return s}function fe(n){const e=new Uint16Array(n.length);for(let t=0;t<n.length;t++)e[t]=se(n[t]);return{half:e,ref:M(e)}}function U(n,e){if(e!=="f16")return{data:n,ref:n};const{half:t,ref:s}=fe(n);return{data:t,ref:s}}function I(n,e){const t=n.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});return new Uint32Array(t.getMappedRange()).set(e),t.unmap(),t}function K(n,e,t){const s=e*(t==="f16"?2:4);return n.createBuffer({size:Math.ceil(s/4)*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC})}async function Y(n,e,t,s,a,f,r){const m=n.createBindGroup({layout:e.getBindGroupLayout(0),entries:t.map((g,D)=>({binding:D,resource:{buffer:g}}))}),c=n.createCommandEncoder(),o=c.beginComputePass();o.setPipeline(e),o.setBindGroup(0,m),o.dispatchWorkgroups(s),o.end(),n.queue.submit([c.finish()]);const d=await $(n,a,f*(r==="f16"?2:4));return r==="f16"?M(new Uint16Array(d)):new Float32Array(d)}function z(n,e,t,s){const{failures:a,maxAbsDiff:f,worst:r}=ee(n,e,t);return{pass:a===0,detail:{...s,tol:t,failures:a,maxAbsDiff:String(f),...a>0?{worst:r,got:String(n[r]),want:String(e[r])}:{}}}}async function q(n,{rows:e,t,tol:s,seed:a}){const{device:f}=n,r=x,m=N(a),c=U(S(e*r,m,4),t),o=U(S(e*r,m,4),t),d=U(S(r,m,4),t),g=U(S(r,m,4),t),D=re(c.ref,o.ref,d.ref,g.ref,{rows:e,d:r}),b=L(f,"add_ln",te,{t,wg:256,defines:{D:r,EPS:oe}}),l=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,A=I(f,[e,0,0,0]),B=[c.data,o.data,d.data,g.data].map(_=>C(f,_,l)),P=K(f,e*r,t),y=await Y(f,b,[A,...B,P],e,P,e*r,t);for(const _ of[A,...B,P])_.destroy();return z(y,D,s,{kernel:"add_ln",rows:e,d:r,t})}async function h(n,{t:e,tol:t,seed:s,vocab:a,maxPos:f,enc:r=null,dec:m=null}){const{device:c}=n,o=x,d=N(s),g=U(S(a*o,d),e),D=U(S(f*o,d),e);let b,l,A,B,P,y;if(r){const{B:u,S:i}=r,E=u*i;b=new Uint32Array(E);for(let p=0;p<E;p++)b[p]=Math.floor(d()*a);l=Array.from(b),A=l.map((p,Z)=>Z%i),B=[E,0,u,i],P={D:o,EMBED_SCALE:R,SRC_IDS:!0,DECODE:!1,PACKED:!1,NOPACKED:!0},y={kernel:"embed",mode:"encoder",B:u,S:i,vocab:a,t:e}}else{const{batch:u,step:i,ring:E}=m;b=E,l=[];for(let p=0;p<u;p++)l.push(i===0?F:E[(i-1)*u+p]);A=l.map(()=>i),B=[u,i,u,0],P={D:o,EMBED_SCALE:R,SRC_IDS:!1,DECODE:!0,DECODER_START:F,PACKED:!1,NOPACKED:!0},y={kernel:"embed",mode:"decode",batch:u,step:i,vocab:a,t:e}}const _=B[0],j=ae(l,A,g.ref,D.ref,{d:o,scale:R}),v=L(c,"embed",ne,{t:e,wg:224,defines:P}),O=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,H=I(c,B),J=C(c,b,O),Q=C(c,g.data,O),V=C(c,D.data,O),T=K(c,_*o,e),k=[H,J,Q,V,T],X=await Y(c,v,k,_,T,_*o,e);for(const u of k)u.destroy();return z(X,j,t,y)}function W(n,e,t,s,a){const f=new Uint32Array(n*e).fill(a);return t>0&&f.set(s,(t-1)*e),f}function G(n,e){w(n,t=>t.hasF16?e(t):{skip:!0,reason:"no shader-f16"})}G("addln_f16",n=>q(n,{rows:5,t:"f16",tol:.02,seed:201}));w("addln_f32",n=>q(n,{rows:3,t:"f32",tol:1e-4,seed:202}));G("embed_enc_f16",n=>h(n,{t:"f16",tol:.01,seed:203,vocab:100,maxPos:16,enc:{B:2,S:16}}));G("embed_dec_t0_f16",n=>h(n,{t:"f16",tol:.01,seed:204,vocab:100,maxPos:8,dec:{batch:3,step:0,ring:W(8,3,0,[],55)}}));G("embed_dec_t5_f16",n=>h(n,{t:"f16",tol:.01,seed:205,vocab:100,maxPos:8,dec:{batch:3,step:5,ring:W(8,3,5,[7,42,99],55)}}));w("embed_enc_f32",n=>h(n,{t:"f32",tol:1e-5,seed:206,vocab:100,maxPos:16,enc:{B:1,S:16}}));
2
- //# sourceMappingURL=addln_embed-C7q7s0KH.js.map
 
 
 
assets/addln_embed-DSGHKDTg.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import{r as w}from"./debug-CPpXXfWA.js";import{c as C,r as $,a as ee}from"./gpu-utils-BTh3AGTJ.js";import{g as L,a as te,e as ne}from"./pipelines-BbLc75sB.js";import{a as re,e as ae}from"./math-LI6LFmUv.js";import{e as M,f as se}from"./f16-wKKZr58e.js";import{L as oe,D as x,c as F,E as R}from"./constants-CSVWRdrh.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./safe_storage-BYkOahew.js";function N(n){let e=n>>>0;return()=>{e=e+1831565813|0;let t=Math.imul(e^e>>>15,1|e);return t=t+Math.imul(t^t>>>7,61|t)^t,((t^t>>>14)>>>0)/4294967296}}function S(n,e,t=1){const s=new Float32Array(n);for(let a=0;a<n;a++)s[a]=Math.fround((e()-.5)*t);return s}function fe(n){const e=new Uint16Array(n.length);for(let t=0;t<n.length;t++)e[t]=se(n[t]);return{half:e,ref:M(e)}}function U(n,e){if(e!=="f16")return{data:n,ref:n};const{half:t,ref:s}=fe(n);return{data:t,ref:s}}function I(n,e){const t=n.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});return new Uint32Array(t.getMappedRange()).set(e),t.unmap(),t}function K(n,e,t){const s=e*(t==="f16"?2:4);return n.createBuffer({size:Math.ceil(s/4)*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC})}async function Y(n,e,t,s,a,f,r){const m=n.createBindGroup({layout:e.getBindGroupLayout(0),entries:t.map((g,D)=>({binding:D,resource:{buffer:g}}))}),c=n.createCommandEncoder(),o=c.beginComputePass();o.setPipeline(e),o.setBindGroup(0,m),o.dispatchWorkgroups(s),o.end(),n.queue.submit([c.finish()]);const d=await $(n,a,f*(r==="f16"?2:4));return r==="f16"?M(new Uint16Array(d)):new Float32Array(d)}function z(n,e,t,s){const{failures:a,maxAbsDiff:f,worst:r}=ee(n,e,t);return{pass:a===0,detail:{...s,tol:t,failures:a,maxAbsDiff:String(f),...a>0?{worst:r,got:String(n[r]),want:String(e[r])}:{}}}}async function q(n,{rows:e,t,tol:s,seed:a}){const{device:f}=n,r=x,m=N(a),c=U(S(e*r,m,4),t),o=U(S(e*r,m,4),t),d=U(S(r,m,4),t),g=U(S(r,m,4),t),D=re(c.ref,o.ref,d.ref,g.ref,{rows:e,d:r}),b=L(f,"add_ln",te,{t,wg:256,defines:{D:r,EPS:oe}}),l=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,A=I(f,[e,0,0,0]),B=[c.data,o.data,d.data,g.data].map(_=>C(f,_,l)),P=K(f,e*r,t),y=await Y(f,b,[A,...B,P],e,P,e*r,t);for(const _ of[A,...B,P])_.destroy();return z(y,D,s,{kernel:"add_ln",rows:e,d:r,t})}async function h(n,{t:e,tol:t,seed:s,vocab:a,maxPos:f,enc:r=null,dec:m=null}){const{device:c}=n,o=x,d=N(s),g=U(S(a*o,d),e),D=U(S(f*o,d),e);let b,l,A,B,P,y;if(r){const{B:u,S:i}=r,E=u*i;b=new Uint32Array(E);for(let p=0;p<E;p++)b[p]=Math.floor(d()*a);l=Array.from(b),A=l.map((p,Z)=>Z%i),B=[E,0,u,i],P={D:o,EMBED_SCALE:R,SRC_IDS:!0,DECODE:!1,PACKED:!1,NOPACKED:!0},y={kernel:"embed",mode:"encoder",B:u,S:i,vocab:a,t:e}}else{const{batch:u,step:i,ring:E}=m;b=E,l=[];for(let p=0;p<u;p++)l.push(i===0?F:E[(i-1)*u+p]);A=l.map(()=>i),B=[u,i,u,0],P={D:o,EMBED_SCALE:R,SRC_IDS:!1,DECODE:!0,DECODER_START:F,PACKED:!1,NOPACKED:!0},y={kernel:"embed",mode:"decode",batch:u,step:i,vocab:a,t:e}}const _=B[0],j=ae(l,A,g.ref,D.ref,{d:o,scale:R}),v=L(c,"embed",ne,{t:e,wg:224,defines:P}),O=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,H=I(c,B),J=C(c,b,O),Q=C(c,g.data,O),V=C(c,D.data,O),T=K(c,_*o,e),k=[H,J,Q,V,T],X=await Y(c,v,k,_,T,_*o,e);for(const u of k)u.destroy();return z(X,j,t,y)}function W(n,e,t,s,a){const f=new Uint32Array(n*e).fill(a);return t>0&&f.set(s,(t-1)*e),f}function G(n,e){w(n,t=>t.hasF16?e(t):{skip:!0,reason:"no shader-f16"})}G("addln_f16",n=>q(n,{rows:5,t:"f16",tol:.02,seed:201}));w("addln_f32",n=>q(n,{rows:3,t:"f32",tol:1e-4,seed:202}));G("embed_enc_f16",n=>h(n,{t:"f16",tol:.01,seed:203,vocab:100,maxPos:16,enc:{B:2,S:16}}));G("embed_dec_t0_f16",n=>h(n,{t:"f16",tol:.01,seed:204,vocab:100,maxPos:8,dec:{batch:3,step:0,ring:W(8,3,0,[],55)}}));G("embed_dec_t5_f16",n=>h(n,{t:"f16",tol:.01,seed:205,vocab:100,maxPos:8,dec:{batch:3,step:5,ring:W(8,3,5,[7,42,99],55)}}));w("embed_enc_f32",n=>h(n,{t:"f32",tol:1e-5,seed:206,vocab:100,maxPos:16,enc:{B:1,S:16}}));
2
+ //# sourceMappingURL=addln_embed-DSGHKDTg.js.map
assets/{addln_embed-C7q7s0KH.js.map → addln_embed-DSGHKDTg.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"file":"addln_embed-C7q7s0KH.js","sources":["../../src/debug/tests/addln_embed.js"],"sourcesContent":["// GPU add+LayerNorm and embedding kernels vs the JS f64 references.\r\n// f16 test data is encoded to f16 and decoded back to f32 for the reference\r\n// input, so ref and GPU see IDENTICAL values (pattern from gemm.js).\r\n// Per-call uniform/bind-group creation is test-only plumbing — engine-level\r\n// uniform management arrives in Tasks 13-14.\r\nimport { registerTest } from '../registry.js';\r\nimport { createBuffer, readback, compareLanes } from '../gpu-utils.js';\r\nimport { getPipeline } from '../../engine/pipelines.js';\r\nimport { addLayerNormRef, embedRef } from '../../reference/math.js';\r\nimport { f32ToF16, expandF16 } from '../../engine/f16.js';\r\nimport { D_MODEL, LN_EPS, EMBED_SCALE, DECODER_START } from '../../engine/constants.js';\r\nimport addLnSource from '../../engine/kernels/add_layernorm.wgsl?raw';\r\nimport embedSource from '../../engine/kernels/embed.wgsl?raw';\r\n\r\nfunction mulberry32(seed) {\r\n let a = seed >>> 0;\r\n return () => {\r\n a = (a + 0x6d2b79f5) | 0;\r\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\r\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\r\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\r\n };\r\n}\r\n\r\n// Random f32 in ±scale/2.\r\nfunction randF32(n, rng, scale = 1) {\r\n const out = new Float32Array(n);\r\n for (let i = 0; i < n; i++) out[i] = Math.fround((rng() - 0.5) * scale);\r\n return out;\r\n}\r\n\r\n// Encode to f16 for the GPU and decode back to f32 for the reference.\r\nfunction toF16(f32arr) {\r\n const half = new Uint16Array(f32arr.length);\r\n for (let i = 0; i < f32arr.length; i++) half[i] = f32ToF16(f32arr[i]);\r\n return { half, ref: expandF16(half) };\r\n}\r\n\r\n// {data, ref} pair for a given storage type.\r\nfunction prep(f32arr, t) {\r\n if (t !== 'f16') return { data: f32arr, ref: f32arr };\r\n const { half, ref } = toF16(f32arr);\r\n return { data: half, ref };\r\n}\r\n\r\nfunction makeUniform(device, vals) {\r\n const buf = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.UNIFORM,\r\n mappedAtCreation: true,\r\n });\r\n new Uint32Array(buf.getMappedRange()).set(vals);\r\n buf.unmap();\r\n return buf;\r\n}\r\n\r\nfunction makeOutBuffer(device, elems, t) {\r\n const bytes = elems * (t === 'f16' ? 2 : 4);\r\n return device.createBuffer({\r\n size: Math.ceil(bytes / 4) * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n });\r\n}\r\n\r\n// Run one compute dispatch (nWorkgroups in x) and read back the result.\r\nasync function runAndRead(device, pipeline, buffers, nWorkgroups, outBuf, outElems, t) {\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: buffers.map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.dispatchWorkgroups(nWorkgroups);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n const raw = await readback(device, outBuf, outElems * (t === 'f16' ? 2 : 4));\r\n return t === 'f16' ? expandF16(new Uint16Array(raw)) : new Float32Array(raw);\r\n}\r\n\r\nfunction report(got, want, tol, extra) {\r\n const { failures, maxAbsDiff, worst } = compareLanes(got, want, tol);\r\n return {\r\n pass: failures === 0,\r\n detail: {\r\n ...extra, tol, failures,\r\n maxAbsDiff: String(maxAbsDiff), // string: JSON turns NaN/Infinity into null\r\n ...(failures > 0 ? { worst, got: String(got[worst]), want: String(want[worst]) } : {}),\r\n },\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------- add_ln ---\r\n\r\nasync function runAddLnCase(ctx, { rows, t, tol, seed }) {\r\n const { device } = ctx;\r\n const d = D_MODEL;\r\n const rng = mulberry32(seed);\r\n // ±2 activations to exercise the variance path.\r\n const x = prep(randF32(rows * d, rng, 4), t);\r\n const r = prep(randF32(rows * d, rng, 4), t);\r\n const gamma = prep(randF32(d, rng, 4), t);\r\n const beta = prep(randF32(d, rng, 4), t);\r\n const want = addLayerNormRef(x.ref, r.ref, gamma.ref, beta.ref, { rows, d });\r\n\r\n const pipeline = getPipeline(device, 'add_ln', addLnSource, {\r\n t, wg: 256, defines: { D: d, EPS: LN_EPS },\r\n });\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const params = makeUniform(device, [rows, 0, 0, 0]);\r\n const bufs = [x.data, r.data, gamma.data, beta.data].map((a) => createBuffer(device, a, usage));\r\n const yBuf = makeOutBuffer(device, rows * d, t);\r\n const got = await runAndRead(device, pipeline, [params, ...bufs, yBuf], rows, yBuf, rows * d, t);\r\n for (const b of [params, ...bufs, yBuf]) b.destroy();\r\n return report(got, want, tol, { kernel: 'add_ln', rows, d, t });\r\n}\r\n\r\n// ----------------------------------------------------------------- embed ---\r\n\r\n// mode: {SRC_IDS: true} with {B, S} or {DECODE: true} with {batch, t, ring, tMax}.\r\nasync function runEmbedCase(ctx, { t, tol, seed, vocab, maxPos, enc = null, dec = null }) {\r\n const { device } = ctx;\r\n const d = D_MODEL;\r\n const rng = mulberry32(seed);\r\n const table = prep(randF32(vocab * d, rng), t);\r\n const posT = prep(randF32(maxPos * d, rng), t);\r\n\r\n let idsU32, refIds, refPositions, params, defines, label;\r\n if (enc) {\r\n const { B, S } = enc;\r\n const rows = B * S;\r\n idsU32 = new Uint32Array(rows);\r\n for (let i = 0; i < rows; i++) idsU32[i] = Math.floor(rng() * vocab);\r\n refIds = Array.from(idsU32);\r\n refPositions = refIds.map((_, i) => i % S);\r\n params = [rows, 0, B, S];\r\n defines = { D: d, EMBED_SCALE, SRC_IDS: true, DECODE: false, PACKED: false, NOPACKED: true };\r\n label = { kernel: 'embed', mode: 'encoder', B, S, vocab, t };\r\n } else {\r\n const { batch, step, ring } = dec; // ring: Uint32Array [tMax*batch]\r\n idsU32 = ring;\r\n refIds = [];\r\n for (let b = 0; b < batch; b++) {\r\n refIds.push(step === 0 ? DECODER_START : ring[(step - 1) * batch + b]);\r\n }\r\n refPositions = refIds.map(() => step);\r\n params = [batch, step, batch, 0];\r\n defines = { D: d, EMBED_SCALE, SRC_IDS: false, DECODE: true, DECODER_START, PACKED: false, NOPACKED: true };\r\n label = { kernel: 'embed', mode: 'decode', batch, step, vocab, t };\r\n }\r\n const rows = params[0];\r\n const want = embedRef(refIds, refPositions, table.ref, posT.ref, { d, scale: EMBED_SCALE });\r\n\r\n const pipeline = getPipeline(device, 'embed', embedSource, { t, wg: 224, defines });\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const paramsBuf = makeUniform(device, params);\r\n const idsBuf = createBuffer(device, idsU32, usage);\r\n const tableBuf = createBuffer(device, table.data, usage);\r\n const posBuf = createBuffer(device, posT.data, usage);\r\n const yBuf = makeOutBuffer(device, rows * d, t);\r\n const all = [paramsBuf, idsBuf, tableBuf, posBuf, yBuf];\r\n const got = await runAndRead(device, pipeline, all, rows, yBuf, rows * d, t);\r\n for (const b of all) b.destroy();\r\n return report(got, want, tol, label);\r\n}\r\n\r\n// Decode token ring [tMax*batch]: sentinel-filled so a wrong ring index (or a\r\n// t=0 read of the ring at all) lands on a different embedding row and fails.\r\nfunction makeRing(tMax, batch, step, ids, sentinel) {\r\n const ring = new Uint32Array(tMax * batch).fill(sentinel);\r\n if (step > 0) ring.set(ids, (step - 1) * batch);\r\n return ring;\r\n}\r\n\r\nfunction registerF16(name, fn) {\r\n registerTest(name, (ctx) =>\r\n ctx.hasF16 ? fn(ctx) : { skip: true, reason: 'no shader-f16' });\r\n}\r\n\r\n// f16 tol 0.02 for LN: dividing by σ can grow relative error; embed is a\r\n// scaled gather (one multiply-add per lane), 0.01 covers f16 output rounding\r\n// at |y| ≲ 11 (table ±0.5 · √448).\r\nregisterF16('addln_f16', (ctx) => runAddLnCase(ctx, { rows: 5, t: 'f16', tol: 0.02, seed: 201 }));\r\nregisterTest('addln_f32', (ctx) => runAddLnCase(ctx, { rows: 3, t: 'f32', tol: 1e-4, seed: 202 }));\r\n\r\nregisterF16('embed_enc_f16', (ctx) =>\r\n runEmbedCase(ctx, { t: 'f16', tol: 0.01, seed: 203, vocab: 100, maxPos: 16, enc: { B: 2, S: 16 } }));\r\nregisterF16('embed_dec_t0_f16', (ctx) =>\r\n runEmbedCase(ctx, {\r\n t: 'f16', tol: 0.01, seed: 204, vocab: 100, maxPos: 8,\r\n dec: { batch: 3, step: 0, ring: makeRing(8, 3, 0, [], 55) },\r\n }));\r\nregisterF16('embed_dec_t5_f16', (ctx) =>\r\n runEmbedCase(ctx, {\r\n t: 'f16', tol: 0.01, seed: 205, vocab: 100, maxPos: 8,\r\n dec: { batch: 3, step: 5, ring: makeRing(8, 3, 5, [7, 42, 99], 55) },\r\n }));\r\n// f32 fallback-mode sanity for the embed template.\r\nregisterTest('embed_enc_f32', (ctx) =>\r\n runEmbedCase(ctx, { t: 'f32', tol: 1e-5, seed: 206, vocab: 100, maxPos: 16, enc: { B: 1, S: 16 } }));\r\n"],"names":["mulberry32","seed","a","randF32","rng","scale","out","i","toF16","f32arr","half","f32ToF16","expandF16","prep","t","ref","makeUniform","device","vals","buf","makeOutBuffer","elems","bytes","runAndRead","pipeline","buffers","nWorkgroups","outBuf","outElems","bindGroup","buffer","binding","encoder","pass","raw","readback","report","got","want","tol","extra","failures","maxAbsDiff","worst","compareLanes","runAddLnCase","ctx","rows","d","D_MODEL","x","r","gamma","beta","addLayerNormRef","getPipeline","addLnSource","LN_EPS","usage","params","bufs","createBuffer","yBuf","b","runEmbedCase","vocab","maxPos","enc","dec","table","posT","idsU32","refIds","refPositions","defines","label","B","S","_","EMBED_SCALE","batch","step","ring","DECODER_START","embedRef","embedSource","paramsBuf","idsBuf","tableBuf","posBuf","all","makeRing","tMax","ids","sentinel","registerF16","name","fn","registerTest"],"mappings":"iZAcA,SAASA,EAAWC,EAAM,CACxB,IAAIC,EAAID,IAAS,EACjB,MAAO,IAAM,CACXC,EAAKA,EAAI,WAAc,EACvB,IAAI,EAAI,KAAK,KAAKA,EAAKA,IAAM,GAAK,EAAIA,CAAC,EACvC,SAAK,EAAI,KAAK,KAAK,EAAK,IAAM,EAAI,GAAK,CAAC,EAAK,IACpC,EAAK,IAAM,MAAS,GAAK,UACpC,CACF,CAGA,SAASC,EAAQ,EAAGC,EAAKC,EAAQ,EAAG,CAClC,MAAMC,EAAM,IAAI,aAAa,CAAC,EAC9B,QAASC,EAAI,EAAGA,EAAI,EAAGA,IAAKD,EAAIC,CAAC,EAAI,KAAK,QAAQH,EAAG,EAAK,IAAOC,CAAK,EACtE,OAAOC,CACT,CAGA,SAASE,GAAMC,EAAQ,CACrB,MAAMC,EAAO,IAAI,YAAYD,EAAO,MAAM,EAC1C,QAASF,EAAI,EAAGA,EAAIE,EAAO,OAAQF,IAAKG,EAAKH,CAAC,EAAII,GAASF,EAAOF,CAAC,CAAC,EACpE,MAAO,CAAE,KAAAG,EAAM,IAAKE,EAAUF,CAAI,CAAC,CACrC,CAGA,SAASG,EAAKJ,EAAQK,EAAG,CACvB,GAAIA,IAAM,MAAO,MAAO,CAAE,KAAML,EAAQ,IAAKA,GAC7C,KAAM,CAAE,KAAAC,EAAM,IAAAK,CAAG,EAAKP,GAAMC,CAAM,EAClC,MAAO,CAAE,KAAMC,EAAM,IAAAK,EACvB,CAEA,SAASC,EAAYC,EAAQC,EAAM,CACjC,MAAMC,EAAMF,EAAO,aAAa,CAC9B,KAAM,GACN,MAAO,eAAe,QACtB,iBAAkB,EACtB,CAAG,EACD,WAAI,YAAYE,EAAI,eAAc,CAAE,EAAE,IAAID,CAAI,EAC9CC,EAAI,MAAK,EACFA,CACT,CAEA,SAASC,EAAcH,EAAQI,EAAO,EAAG,CACvC,MAAMC,EAAQD,GAAS,IAAM,MAAQ,EAAI,GACzC,OAAOJ,EAAO,aAAa,CACzB,KAAM,KAAK,KAAKK,EAAQ,CAAC,EAAI,EAC7B,MAAO,eAAe,QAAU,eAAe,QACnD,CAAG,CACH,CAGA,eAAeC,EAAWN,EAAQO,EAAUC,EAASC,EAAaC,EAAQC,EAAUd,EAAG,CACrF,MAAMe,EAAYZ,EAAO,gBAAgB,CACvC,OAAQO,EAAS,mBAAmB,CAAC,EACrC,QAASC,EAAQ,IAAI,CAACK,EAAQC,KAAa,CAAE,QAAAA,EAAS,SAAU,CAAE,OAAAD,CAAM,CAAE,EAAG,CACjF,CAAG,EACKE,EAAUf,EAAO,uBACjBgB,EAAOD,EAAQ,mBACrBC,EAAK,YAAYT,CAAQ,EACzBS,EAAK,aAAa,EAAGJ,CAAS,EAC9BI,EAAK,mBAAmBP,CAAW,EACnCO,EAAK,IAAG,EACRhB,EAAO,MAAM,OAAO,CAACe,EAAQ,OAAM,CAAE,CAAC,EACtC,MAAME,EAAM,MAAMC,EAASlB,EAAQU,EAAQC,GAAYd,IAAM,MAAQ,EAAI,EAAE,EAC3E,OAAOA,IAAM,MAAQF,EAAU,IAAI,YAAYsB,CAAG,CAAC,EAAI,IAAI,aAAaA,CAAG,CAC7E,CAEA,SAASE,EAAOC,EAAKC,EAAMC,EAAKC,EAAO,CACrC,KAAM,CAAE,SAAAC,EAAU,WAAAC,EAAY,MAAAC,CAAK,EAAKC,GAAaP,EAAKC,EAAMC,CAAG,EACnE,MAAO,CACL,KAAME,IAAa,EACnB,OAAQ,CACN,GAAGD,EAAO,IAAAD,EAAK,SAAAE,EACf,WAAY,OAAOC,CAAU,EAC7B,GAAID,EAAW,EAAI,CAAE,MAAAE,EAAO,IAAK,OAAON,EAAIM,CAAK,CAAC,EAAG,KAAM,OAAOL,EAAKK,CAAK,CAAC,CAAC,EAAK,EACzF,CACA,CACA,CAIA,eAAeE,EAAaC,EAAK,CAAE,KAAAC,EAAM,EAAG,IAAAR,EAAK,KAAAtC,GAAQ,CACvD,KAAM,CAAE,OAAAgB,CAAM,EAAK6B,EACbE,EAAIC,EACJ7C,EAAMJ,EAAWC,CAAI,EAErBiD,EAAIrC,EAAKV,EAAQ4C,EAAOC,EAAG5C,EAAK,CAAC,EAAG,CAAC,EACrC+C,EAAItC,EAAKV,EAAQ4C,EAAOC,EAAG5C,EAAK,CAAC,EAAG,CAAC,EACrCgD,EAAQvC,EAAKV,EAAQ6C,EAAG5C,EAAK,CAAC,EAAG,CAAC,EAClCiD,EAAOxC,EAAKV,EAAQ6C,EAAG5C,EAAK,CAAC,EAAG,CAAC,EACjCkC,EAAOgB,GAAgBJ,EAAE,IAAKC,EAAE,IAAKC,EAAM,IAAKC,EAAK,IAAK,CAAE,KAAAN,EAAM,EAAAC,CAAC,CAAE,EAErExB,EAAW+B,EAAYtC,EAAQ,SAAUuC,GAAa,CAC1D,EAAG,GAAI,IAAK,QAAS,CAAE,EAAGR,EAAG,IAAKS,EAAM,CAC5C,CAAG,EACKC,EAAQ,eAAe,QAAU,eAAe,SAChDC,EAAS3C,EAAYC,EAAQ,CAAC8B,EAAM,EAAG,EAAG,CAAC,CAAC,EAC5Ca,EAAO,CAACV,EAAE,KAAMC,EAAE,KAAMC,EAAM,KAAMC,EAAK,IAAI,EAAE,IAAKnD,GAAM2D,EAAa5C,EAAQf,EAAGwD,CAAK,CAAC,EACxFI,EAAO1C,EAAcH,EAAQ8B,EAAOC,EAAG,CAAC,EACxCX,EAAM,MAAMd,EAAWN,EAAQO,EAAU,CAACmC,EAAQ,GAAGC,EAAME,CAAI,EAAGf,EAAMe,EAAMf,EAAOC,EAAG,CAAC,EAC/F,UAAWe,IAAK,CAACJ,EAAQ,GAAGC,EAAME,CAAI,EAAGC,EAAE,UAC3C,OAAO3B,EAAOC,EAAKC,EAAMC,EAAK,CAAE,OAAQ,SAAU,KAAAQ,EAAM,EAAAC,EAAG,CAAC,CAAE,CAChE,CAKA,eAAegB,EAAalB,EAAK,CAAE,EAAAhC,EAAG,IAAAyB,EAAK,KAAAtC,EAAM,MAAAgE,EAAO,OAAAC,EAAQ,IAAAC,EAAM,KAAM,IAAAC,EAAM,IAAI,EAAI,CACxF,KAAM,CAAE,OAAAnD,CAAM,EAAK6B,EACbE,EAAIC,EACJ7C,EAAMJ,EAAWC,CAAI,EACrBoE,EAAQxD,EAAKV,EAAQ8D,EAAQjB,EAAG5C,CAAG,EAAGU,CAAC,EACvCwD,EAAOzD,EAAKV,EAAQ+D,EAASlB,EAAG5C,CAAG,EAAGU,CAAC,EAE7C,IAAIyD,EAAQC,EAAQC,EAAcd,EAAQe,EAASC,EACnD,GAAIR,EAAK,CACP,KAAM,CAAE,EAAAS,EAAG,EAAAC,CAAC,EAAKV,EACXpB,EAAO6B,EAAIC,EACjBN,EAAS,IAAI,YAAYxB,CAAI,EAC7B,QAASxC,EAAI,EAAGA,EAAIwC,EAAMxC,IAAKgE,EAAOhE,CAAC,EAAI,KAAK,MAAMH,EAAG,EAAK6D,CAAK,EACnEO,EAAS,MAAM,KAAKD,CAAM,EAC1BE,EAAeD,EAAO,IAAI,CAACM,EAAGvE,IAAMA,EAAIsE,CAAC,EACzClB,EAAS,CAACZ,EAAM,EAAG6B,EAAGC,CAAC,EACvBH,EAAU,CAAE,EAAG1B,EAAG,YAAA+B,EAAa,QAAS,GAAM,OAAQ,GAAO,OAAQ,GAAO,SAAU,EAAI,EAC1FJ,EAAQ,CAAE,OAAQ,QAAS,KAAM,UAAW,EAAAC,EAAG,EAAAC,EAAG,MAAAZ,EAAO,EAAAnD,EAC3D,KAAO,CACL,KAAM,CAAE,MAAAkE,EAAO,KAAAC,EAAM,KAAAC,CAAI,EAAKd,EAC9BG,EAASW,EACTV,EAAS,CAAA,EACT,QAAST,EAAI,EAAGA,EAAIiB,EAAOjB,IACzBS,EAAO,KAAKS,IAAS,EAAIE,EAAgBD,GAAMD,EAAO,GAAKD,EAAQjB,CAAC,CAAC,EAEvEU,EAAeD,EAAO,IAAI,IAAMS,CAAI,EACpCtB,EAAS,CAACqB,EAAOC,EAAMD,EAAO,CAAC,EAC/BN,EAAU,CAAE,EAAG1B,EAAG,YAAA+B,EAAa,QAAS,GAAO,OAAQ,GAAM,cAAAI,EAAe,OAAQ,GAAO,SAAU,EAAI,EACzGR,EAAQ,CAAE,OAAQ,QAAS,KAAM,SAAU,MAAAK,EAAO,KAAAC,EAAM,MAAAhB,EAAO,EAAAnD,EACjE,CACA,MAAMiC,EAAOY,EAAO,CAAC,EACfrB,EAAO8C,GAASZ,EAAQC,EAAcJ,EAAM,IAAKC,EAAK,IAAK,CAAE,EAAAtB,EAAG,MAAO+B,CAAW,CAAE,EAEpFvD,EAAW+B,EAAYtC,EAAQ,QAASoE,GAAa,CAAE,EAAAvE,EAAG,GAAI,IAAK,QAAA4D,CAAO,CAAE,EAC5EhB,EAAQ,eAAe,QAAU,eAAe,SAChD4B,EAAYtE,EAAYC,EAAQ0C,CAAM,EACtC4B,EAAS1B,EAAa5C,EAAQsD,EAAQb,CAAK,EAC3C8B,EAAW3B,EAAa5C,EAAQoD,EAAM,KAAMX,CAAK,EACjD+B,EAAS5B,EAAa5C,EAAQqD,EAAK,KAAMZ,CAAK,EAC9CI,EAAO1C,EAAcH,EAAQ8B,EAAOC,EAAGlC,CAAC,EACxC4E,EAAM,CAACJ,EAAWC,EAAQC,EAAUC,EAAQ3B,CAAI,EAChDzB,EAAM,MAAMd,EAAWN,EAAQO,EAAUkE,EAAK3C,EAAMe,EAAMf,EAAOC,EAAGlC,CAAC,EAC3E,UAAWiD,KAAK2B,EAAK3B,EAAE,QAAO,EAC9B,OAAO3B,EAAOC,EAAKC,EAAMC,EAAKoC,CAAK,CACrC,CAIA,SAASgB,EAASC,EAAMZ,EAAOC,EAAMY,EAAKC,EAAU,CAClD,MAAMZ,EAAO,IAAI,YAAYU,EAAOZ,CAAK,EAAE,KAAKc,CAAQ,EACxD,OAAIb,EAAO,GAAGC,EAAK,IAAIW,GAAMZ,EAAO,GAAKD,CAAK,EACvCE,CACT,CAEA,SAASa,EAAYC,EAAMC,EAAI,CAC7BC,EAAaF,EAAOlD,GAClBA,EAAI,OAASmD,EAAGnD,CAAG,EAAI,CAAE,KAAM,GAAM,OAAQ,eAAe,CAAE,CAClE,CAKAiD,EAAY,YAAcjD,GAAQD,EAAaC,EAAK,CAAE,KAAM,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,GAAG,CAAE,CAAC,EAChGoD,EAAa,YAAcpD,GAAQD,EAAaC,EAAK,CAAE,KAAM,EAAG,EAAG,MAAO,IAAK,KAAM,KAAM,GAAG,CAAE,CAAC,EAEjGiD,EAAY,gBAAkBjD,GAC5BkB,EAAalB,EAAK,CAAE,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,MAAO,IAAK,OAAQ,GAAI,IAAK,CAAE,EAAG,EAAG,EAAG,GAAI,CAAE,CAAC,EACrGiD,EAAY,mBAAqBjD,GAC/BkB,EAAalB,EAAK,CAChB,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,MAAO,IAAK,OAAQ,EACpD,IAAK,CAAE,MAAO,EAAG,KAAM,EAAG,KAAM6C,EAAS,EAAG,EAAG,EAAG,CAAA,EAAI,EAAE,CAAC,CAC7D,CAAG,CAAC,EACJI,EAAY,mBAAqBjD,GAC/BkB,EAAalB,EAAK,CAChB,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,MAAO,IAAK,OAAQ,EACpD,IAAK,CAAE,MAAO,EAAG,KAAM,EAAG,KAAM6C,EAAS,EAAG,EAAG,EAAG,CAAC,EAAG,GAAI,EAAE,EAAG,EAAE,CAAC,CACtE,CAAG,CAAC,EAEJO,EAAa,gBAAkBpD,GAC7BkB,EAAalB,EAAK,CAAE,EAAG,MAAO,IAAK,KAAM,KAAM,IAAK,MAAO,IAAK,OAAQ,GAAI,IAAK,CAAE,EAAG,EAAG,EAAG,EAAE,CAAE,CAAE,CAAC"}
 
1
+ {"version":3,"file":"addln_embed-DSGHKDTg.js","sources":["../../src/debug/tests/addln_embed.js"],"sourcesContent":["// GPU add+LayerNorm and embedding kernels vs the JS f64 references.\r\n// f16 test data is encoded to f16 and decoded back to f32 for the reference\r\n// input, so ref and GPU see IDENTICAL values (pattern from gemm.js).\r\n// Per-call uniform/bind-group creation is test-only plumbing — engine-level\r\n// uniform management arrives in Tasks 13-14.\r\nimport { registerTest } from '../registry.js';\r\nimport { createBuffer, readback, compareLanes } from '../gpu-utils.js';\r\nimport { getPipeline } from '../../engine/pipelines.js';\r\nimport { addLayerNormRef, embedRef } from '../../reference/math.js';\r\nimport { f32ToF16, expandF16 } from '../../engine/f16.js';\r\nimport { D_MODEL, LN_EPS, EMBED_SCALE, DECODER_START } from '../../engine/constants.js';\r\nimport addLnSource from '../../engine/kernels/add_layernorm.wgsl?raw';\r\nimport embedSource from '../../engine/kernels/embed.wgsl?raw';\r\n\r\nfunction mulberry32(seed) {\r\n let a = seed >>> 0;\r\n return () => {\r\n a = (a + 0x6d2b79f5) | 0;\r\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\r\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\r\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\r\n };\r\n}\r\n\r\n// Random f32 in ±scale/2.\r\nfunction randF32(n, rng, scale = 1) {\r\n const out = new Float32Array(n);\r\n for (let i = 0; i < n; i++) out[i] = Math.fround((rng() - 0.5) * scale);\r\n return out;\r\n}\r\n\r\n// Encode to f16 for the GPU and decode back to f32 for the reference.\r\nfunction toF16(f32arr) {\r\n const half = new Uint16Array(f32arr.length);\r\n for (let i = 0; i < f32arr.length; i++) half[i] = f32ToF16(f32arr[i]);\r\n return { half, ref: expandF16(half) };\r\n}\r\n\r\n// {data, ref} pair for a given storage type.\r\nfunction prep(f32arr, t) {\r\n if (t !== 'f16') return { data: f32arr, ref: f32arr };\r\n const { half, ref } = toF16(f32arr);\r\n return { data: half, ref };\r\n}\r\n\r\nfunction makeUniform(device, vals) {\r\n const buf = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.UNIFORM,\r\n mappedAtCreation: true,\r\n });\r\n new Uint32Array(buf.getMappedRange()).set(vals);\r\n buf.unmap();\r\n return buf;\r\n}\r\n\r\nfunction makeOutBuffer(device, elems, t) {\r\n const bytes = elems * (t === 'f16' ? 2 : 4);\r\n return device.createBuffer({\r\n size: Math.ceil(bytes / 4) * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n });\r\n}\r\n\r\n// Run one compute dispatch (nWorkgroups in x) and read back the result.\r\nasync function runAndRead(device, pipeline, buffers, nWorkgroups, outBuf, outElems, t) {\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: buffers.map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.dispatchWorkgroups(nWorkgroups);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n const raw = await readback(device, outBuf, outElems * (t === 'f16' ? 2 : 4));\r\n return t === 'f16' ? expandF16(new Uint16Array(raw)) : new Float32Array(raw);\r\n}\r\n\r\nfunction report(got, want, tol, extra) {\r\n const { failures, maxAbsDiff, worst } = compareLanes(got, want, tol);\r\n return {\r\n pass: failures === 0,\r\n detail: {\r\n ...extra, tol, failures,\r\n maxAbsDiff: String(maxAbsDiff), // string: JSON turns NaN/Infinity into null\r\n ...(failures > 0 ? { worst, got: String(got[worst]), want: String(want[worst]) } : {}),\r\n },\r\n };\r\n}\r\n\r\n// ---------------------------------------------------------------- add_ln ---\r\n\r\nasync function runAddLnCase(ctx, { rows, t, tol, seed }) {\r\n const { device } = ctx;\r\n const d = D_MODEL;\r\n const rng = mulberry32(seed);\r\n // ±2 activations to exercise the variance path.\r\n const x = prep(randF32(rows * d, rng, 4), t);\r\n const r = prep(randF32(rows * d, rng, 4), t);\r\n const gamma = prep(randF32(d, rng, 4), t);\r\n const beta = prep(randF32(d, rng, 4), t);\r\n const want = addLayerNormRef(x.ref, r.ref, gamma.ref, beta.ref, { rows, d });\r\n\r\n const pipeline = getPipeline(device, 'add_ln', addLnSource, {\r\n t, wg: 256, defines: { D: d, EPS: LN_EPS },\r\n });\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const params = makeUniform(device, [rows, 0, 0, 0]);\r\n const bufs = [x.data, r.data, gamma.data, beta.data].map((a) => createBuffer(device, a, usage));\r\n const yBuf = makeOutBuffer(device, rows * d, t);\r\n const got = await runAndRead(device, pipeline, [params, ...bufs, yBuf], rows, yBuf, rows * d, t);\r\n for (const b of [params, ...bufs, yBuf]) b.destroy();\r\n return report(got, want, tol, { kernel: 'add_ln', rows, d, t });\r\n}\r\n\r\n// ----------------------------------------------------------------- embed ---\r\n\r\n// mode: {SRC_IDS: true} with {B, S} or {DECODE: true} with {batch, t, ring, tMax}.\r\nasync function runEmbedCase(ctx, { t, tol, seed, vocab, maxPos, enc = null, dec = null }) {\r\n const { device } = ctx;\r\n const d = D_MODEL;\r\n const rng = mulberry32(seed);\r\n const table = prep(randF32(vocab * d, rng), t);\r\n const posT = prep(randF32(maxPos * d, rng), t);\r\n\r\n let idsU32, refIds, refPositions, params, defines, label;\r\n if (enc) {\r\n const { B, S } = enc;\r\n const rows = B * S;\r\n idsU32 = new Uint32Array(rows);\r\n for (let i = 0; i < rows; i++) idsU32[i] = Math.floor(rng() * vocab);\r\n refIds = Array.from(idsU32);\r\n refPositions = refIds.map((_, i) => i % S);\r\n params = [rows, 0, B, S];\r\n defines = { D: d, EMBED_SCALE, SRC_IDS: true, DECODE: false, PACKED: false, NOPACKED: true };\r\n label = { kernel: 'embed', mode: 'encoder', B, S, vocab, t };\r\n } else {\r\n const { batch, step, ring } = dec; // ring: Uint32Array [tMax*batch]\r\n idsU32 = ring;\r\n refIds = [];\r\n for (let b = 0; b < batch; b++) {\r\n refIds.push(step === 0 ? DECODER_START : ring[(step - 1) * batch + b]);\r\n }\r\n refPositions = refIds.map(() => step);\r\n params = [batch, step, batch, 0];\r\n defines = { D: d, EMBED_SCALE, SRC_IDS: false, DECODE: true, DECODER_START, PACKED: false, NOPACKED: true };\r\n label = { kernel: 'embed', mode: 'decode', batch, step, vocab, t };\r\n }\r\n const rows = params[0];\r\n const want = embedRef(refIds, refPositions, table.ref, posT.ref, { d, scale: EMBED_SCALE });\r\n\r\n const pipeline = getPipeline(device, 'embed', embedSource, { t, wg: 224, defines });\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const paramsBuf = makeUniform(device, params);\r\n const idsBuf = createBuffer(device, idsU32, usage);\r\n const tableBuf = createBuffer(device, table.data, usage);\r\n const posBuf = createBuffer(device, posT.data, usage);\r\n const yBuf = makeOutBuffer(device, rows * d, t);\r\n const all = [paramsBuf, idsBuf, tableBuf, posBuf, yBuf];\r\n const got = await runAndRead(device, pipeline, all, rows, yBuf, rows * d, t);\r\n for (const b of all) b.destroy();\r\n return report(got, want, tol, label);\r\n}\r\n\r\n// Decode token ring [tMax*batch]: sentinel-filled so a wrong ring index (or a\r\n// t=0 read of the ring at all) lands on a different embedding row and fails.\r\nfunction makeRing(tMax, batch, step, ids, sentinel) {\r\n const ring = new Uint32Array(tMax * batch).fill(sentinel);\r\n if (step > 0) ring.set(ids, (step - 1) * batch);\r\n return ring;\r\n}\r\n\r\nfunction registerF16(name, fn) {\r\n registerTest(name, (ctx) =>\r\n ctx.hasF16 ? fn(ctx) : { skip: true, reason: 'no shader-f16' });\r\n}\r\n\r\n// f16 tol 0.02 for LN: dividing by σ can grow relative error; embed is a\r\n// scaled gather (one multiply-add per lane), 0.01 covers f16 output rounding\r\n// at |y| ≲ 11 (table ±0.5 · √448).\r\nregisterF16('addln_f16', (ctx) => runAddLnCase(ctx, { rows: 5, t: 'f16', tol: 0.02, seed: 201 }));\r\nregisterTest('addln_f32', (ctx) => runAddLnCase(ctx, { rows: 3, t: 'f32', tol: 1e-4, seed: 202 }));\r\n\r\nregisterF16('embed_enc_f16', (ctx) =>\r\n runEmbedCase(ctx, { t: 'f16', tol: 0.01, seed: 203, vocab: 100, maxPos: 16, enc: { B: 2, S: 16 } }));\r\nregisterF16('embed_dec_t0_f16', (ctx) =>\r\n runEmbedCase(ctx, {\r\n t: 'f16', tol: 0.01, seed: 204, vocab: 100, maxPos: 8,\r\n dec: { batch: 3, step: 0, ring: makeRing(8, 3, 0, [], 55) },\r\n }));\r\nregisterF16('embed_dec_t5_f16', (ctx) =>\r\n runEmbedCase(ctx, {\r\n t: 'f16', tol: 0.01, seed: 205, vocab: 100, maxPos: 8,\r\n dec: { batch: 3, step: 5, ring: makeRing(8, 3, 5, [7, 42, 99], 55) },\r\n }));\r\n// f32 fallback-mode sanity for the embed template.\r\nregisterTest('embed_enc_f32', (ctx) =>\r\n runEmbedCase(ctx, { t: 'f32', tol: 1e-5, seed: 206, vocab: 100, maxPos: 16, enc: { B: 1, S: 16 } }));\r\n"],"names":["mulberry32","seed","a","randF32","rng","scale","out","i","toF16","f32arr","half","f32ToF16","expandF16","prep","t","ref","makeUniform","device","vals","buf","makeOutBuffer","elems","bytes","runAndRead","pipeline","buffers","nWorkgroups","outBuf","outElems","bindGroup","buffer","binding","encoder","pass","raw","readback","report","got","want","tol","extra","failures","maxAbsDiff","worst","compareLanes","runAddLnCase","ctx","rows","d","D_MODEL","x","r","gamma","beta","addLayerNormRef","getPipeline","addLnSource","LN_EPS","usage","params","bufs","createBuffer","yBuf","b","runEmbedCase","vocab","maxPos","enc","dec","table","posT","idsU32","refIds","refPositions","defines","label","B","S","_","EMBED_SCALE","batch","step","ring","DECODER_START","embedRef","embedSource","paramsBuf","idsBuf","tableBuf","posBuf","all","makeRing","tMax","ids","sentinel","registerF16","name","fn","registerTest"],"mappings":"obAcA,SAASA,EAAWC,EAAM,CACxB,IAAIC,EAAID,IAAS,EACjB,MAAO,IAAM,CACXC,EAAKA,EAAI,WAAc,EACvB,IAAI,EAAI,KAAK,KAAKA,EAAKA,IAAM,GAAK,EAAIA,CAAC,EACvC,SAAK,EAAI,KAAK,KAAK,EAAK,IAAM,EAAI,GAAK,CAAC,EAAK,IACpC,EAAK,IAAM,MAAS,GAAK,UACpC,CACF,CAGA,SAASC,EAAQ,EAAGC,EAAKC,EAAQ,EAAG,CAClC,MAAMC,EAAM,IAAI,aAAa,CAAC,EAC9B,QAASC,EAAI,EAAGA,EAAI,EAAGA,IAAKD,EAAIC,CAAC,EAAI,KAAK,QAAQH,EAAG,EAAK,IAAOC,CAAK,EACtE,OAAOC,CACT,CAGA,SAASE,GAAMC,EAAQ,CACrB,MAAMC,EAAO,IAAI,YAAYD,EAAO,MAAM,EAC1C,QAASF,EAAI,EAAGA,EAAIE,EAAO,OAAQF,IAAKG,EAAKH,CAAC,EAAII,GAASF,EAAOF,CAAC,CAAC,EACpE,MAAO,CAAE,KAAAG,EAAM,IAAKE,EAAUF,CAAI,CAAC,CACrC,CAGA,SAASG,EAAKJ,EAAQK,EAAG,CACvB,GAAIA,IAAM,MAAO,MAAO,CAAE,KAAML,EAAQ,IAAKA,GAC7C,KAAM,CAAE,KAAAC,EAAM,IAAAK,CAAG,EAAKP,GAAMC,CAAM,EAClC,MAAO,CAAE,KAAMC,EAAM,IAAAK,EACvB,CAEA,SAASC,EAAYC,EAAQC,EAAM,CACjC,MAAMC,EAAMF,EAAO,aAAa,CAC9B,KAAM,GACN,MAAO,eAAe,QACtB,iBAAkB,EACtB,CAAG,EACD,WAAI,YAAYE,EAAI,eAAc,CAAE,EAAE,IAAID,CAAI,EAC9CC,EAAI,MAAK,EACFA,CACT,CAEA,SAASC,EAAcH,EAAQI,EAAO,EAAG,CACvC,MAAMC,EAAQD,GAAS,IAAM,MAAQ,EAAI,GACzC,OAAOJ,EAAO,aAAa,CACzB,KAAM,KAAK,KAAKK,EAAQ,CAAC,EAAI,EAC7B,MAAO,eAAe,QAAU,eAAe,QACnD,CAAG,CACH,CAGA,eAAeC,EAAWN,EAAQO,EAAUC,EAASC,EAAaC,EAAQC,EAAUd,EAAG,CACrF,MAAMe,EAAYZ,EAAO,gBAAgB,CACvC,OAAQO,EAAS,mBAAmB,CAAC,EACrC,QAASC,EAAQ,IAAI,CAACK,EAAQC,KAAa,CAAE,QAAAA,EAAS,SAAU,CAAE,OAAAD,CAAM,CAAE,EAAG,CACjF,CAAG,EACKE,EAAUf,EAAO,uBACjBgB,EAAOD,EAAQ,mBACrBC,EAAK,YAAYT,CAAQ,EACzBS,EAAK,aAAa,EAAGJ,CAAS,EAC9BI,EAAK,mBAAmBP,CAAW,EACnCO,EAAK,IAAG,EACRhB,EAAO,MAAM,OAAO,CAACe,EAAQ,OAAM,CAAE,CAAC,EACtC,MAAME,EAAM,MAAMC,EAASlB,EAAQU,EAAQC,GAAYd,IAAM,MAAQ,EAAI,EAAE,EAC3E,OAAOA,IAAM,MAAQF,EAAU,IAAI,YAAYsB,CAAG,CAAC,EAAI,IAAI,aAAaA,CAAG,CAC7E,CAEA,SAASE,EAAOC,EAAKC,EAAMC,EAAKC,EAAO,CACrC,KAAM,CAAE,SAAAC,EAAU,WAAAC,EAAY,MAAAC,CAAK,EAAKC,GAAaP,EAAKC,EAAMC,CAAG,EACnE,MAAO,CACL,KAAME,IAAa,EACnB,OAAQ,CACN,GAAGD,EAAO,IAAAD,EAAK,SAAAE,EACf,WAAY,OAAOC,CAAU,EAC7B,GAAID,EAAW,EAAI,CAAE,MAAAE,EAAO,IAAK,OAAON,EAAIM,CAAK,CAAC,EAAG,KAAM,OAAOL,EAAKK,CAAK,CAAC,CAAC,EAAK,EACzF,CACA,CACA,CAIA,eAAeE,EAAaC,EAAK,CAAE,KAAAC,EAAM,EAAG,IAAAR,EAAK,KAAAtC,GAAQ,CACvD,KAAM,CAAE,OAAAgB,CAAM,EAAK6B,EACbE,EAAIC,EACJ7C,EAAMJ,EAAWC,CAAI,EAErBiD,EAAIrC,EAAKV,EAAQ4C,EAAOC,EAAG5C,EAAK,CAAC,EAAG,CAAC,EACrC+C,EAAItC,EAAKV,EAAQ4C,EAAOC,EAAG5C,EAAK,CAAC,EAAG,CAAC,EACrCgD,EAAQvC,EAAKV,EAAQ6C,EAAG5C,EAAK,CAAC,EAAG,CAAC,EAClCiD,EAAOxC,EAAKV,EAAQ6C,EAAG5C,EAAK,CAAC,EAAG,CAAC,EACjCkC,EAAOgB,GAAgBJ,EAAE,IAAKC,EAAE,IAAKC,EAAM,IAAKC,EAAK,IAAK,CAAE,KAAAN,EAAM,EAAAC,CAAC,CAAE,EAErExB,EAAW+B,EAAYtC,EAAQ,SAAUuC,GAAa,CAC1D,EAAG,GAAI,IAAK,QAAS,CAAE,EAAGR,EAAG,IAAKS,EAAM,CAC5C,CAAG,EACKC,EAAQ,eAAe,QAAU,eAAe,SAChDC,EAAS3C,EAAYC,EAAQ,CAAC8B,EAAM,EAAG,EAAG,CAAC,CAAC,EAC5Ca,EAAO,CAACV,EAAE,KAAMC,EAAE,KAAMC,EAAM,KAAMC,EAAK,IAAI,EAAE,IAAKnD,GAAM2D,EAAa5C,EAAQf,EAAGwD,CAAK,CAAC,EACxFI,EAAO1C,EAAcH,EAAQ8B,EAAOC,EAAG,CAAC,EACxCX,EAAM,MAAMd,EAAWN,EAAQO,EAAU,CAACmC,EAAQ,GAAGC,EAAME,CAAI,EAAGf,EAAMe,EAAMf,EAAOC,EAAG,CAAC,EAC/F,UAAWe,IAAK,CAACJ,EAAQ,GAAGC,EAAME,CAAI,EAAGC,EAAE,UAC3C,OAAO3B,EAAOC,EAAKC,EAAMC,EAAK,CAAE,OAAQ,SAAU,KAAAQ,EAAM,EAAAC,EAAG,CAAC,CAAE,CAChE,CAKA,eAAegB,EAAalB,EAAK,CAAE,EAAAhC,EAAG,IAAAyB,EAAK,KAAAtC,EAAM,MAAAgE,EAAO,OAAAC,EAAQ,IAAAC,EAAM,KAAM,IAAAC,EAAM,IAAI,EAAI,CACxF,KAAM,CAAE,OAAAnD,CAAM,EAAK6B,EACbE,EAAIC,EACJ7C,EAAMJ,EAAWC,CAAI,EACrBoE,EAAQxD,EAAKV,EAAQ8D,EAAQjB,EAAG5C,CAAG,EAAGU,CAAC,EACvCwD,EAAOzD,EAAKV,EAAQ+D,EAASlB,EAAG5C,CAAG,EAAGU,CAAC,EAE7C,IAAIyD,EAAQC,EAAQC,EAAcd,EAAQe,EAASC,EACnD,GAAIR,EAAK,CACP,KAAM,CAAE,EAAAS,EAAG,EAAAC,CAAC,EAAKV,EACXpB,EAAO6B,EAAIC,EACjBN,EAAS,IAAI,YAAYxB,CAAI,EAC7B,QAASxC,EAAI,EAAGA,EAAIwC,EAAMxC,IAAKgE,EAAOhE,CAAC,EAAI,KAAK,MAAMH,EAAG,EAAK6D,CAAK,EACnEO,EAAS,MAAM,KAAKD,CAAM,EAC1BE,EAAeD,EAAO,IAAI,CAACM,EAAGvE,IAAMA,EAAIsE,CAAC,EACzClB,EAAS,CAACZ,EAAM,EAAG6B,EAAGC,CAAC,EACvBH,EAAU,CAAE,EAAG1B,EAAG,YAAA+B,EAAa,QAAS,GAAM,OAAQ,GAAO,OAAQ,GAAO,SAAU,EAAI,EAC1FJ,EAAQ,CAAE,OAAQ,QAAS,KAAM,UAAW,EAAAC,EAAG,EAAAC,EAAG,MAAAZ,EAAO,EAAAnD,EAC3D,KAAO,CACL,KAAM,CAAE,MAAAkE,EAAO,KAAAC,EAAM,KAAAC,CAAI,EAAKd,EAC9BG,EAASW,EACTV,EAAS,CAAA,EACT,QAAST,EAAI,EAAGA,EAAIiB,EAAOjB,IACzBS,EAAO,KAAKS,IAAS,EAAIE,EAAgBD,GAAMD,EAAO,GAAKD,EAAQjB,CAAC,CAAC,EAEvEU,EAAeD,EAAO,IAAI,IAAMS,CAAI,EACpCtB,EAAS,CAACqB,EAAOC,EAAMD,EAAO,CAAC,EAC/BN,EAAU,CAAE,EAAG1B,EAAG,YAAA+B,EAAa,QAAS,GAAO,OAAQ,GAAM,cAAAI,EAAe,OAAQ,GAAO,SAAU,EAAI,EACzGR,EAAQ,CAAE,OAAQ,QAAS,KAAM,SAAU,MAAAK,EAAO,KAAAC,EAAM,MAAAhB,EAAO,EAAAnD,EACjE,CACA,MAAMiC,EAAOY,EAAO,CAAC,EACfrB,EAAO8C,GAASZ,EAAQC,EAAcJ,EAAM,IAAKC,EAAK,IAAK,CAAE,EAAAtB,EAAG,MAAO+B,CAAW,CAAE,EAEpFvD,EAAW+B,EAAYtC,EAAQ,QAASoE,GAAa,CAAE,EAAAvE,EAAG,GAAI,IAAK,QAAA4D,CAAO,CAAE,EAC5EhB,EAAQ,eAAe,QAAU,eAAe,SAChD4B,EAAYtE,EAAYC,EAAQ0C,CAAM,EACtC4B,EAAS1B,EAAa5C,EAAQsD,EAAQb,CAAK,EAC3C8B,EAAW3B,EAAa5C,EAAQoD,EAAM,KAAMX,CAAK,EACjD+B,EAAS5B,EAAa5C,EAAQqD,EAAK,KAAMZ,CAAK,EAC9CI,EAAO1C,EAAcH,EAAQ8B,EAAOC,EAAGlC,CAAC,EACxC4E,EAAM,CAACJ,EAAWC,EAAQC,EAAUC,EAAQ3B,CAAI,EAChDzB,EAAM,MAAMd,EAAWN,EAAQO,EAAUkE,EAAK3C,EAAMe,EAAMf,EAAOC,EAAGlC,CAAC,EAC3E,UAAWiD,KAAK2B,EAAK3B,EAAE,QAAO,EAC9B,OAAO3B,EAAOC,EAAKC,EAAMC,EAAKoC,CAAK,CACrC,CAIA,SAASgB,EAASC,EAAMZ,EAAOC,EAAMY,EAAKC,EAAU,CAClD,MAAMZ,EAAO,IAAI,YAAYU,EAAOZ,CAAK,EAAE,KAAKc,CAAQ,EACxD,OAAIb,EAAO,GAAGC,EAAK,IAAIW,GAAMZ,EAAO,GAAKD,CAAK,EACvCE,CACT,CAEA,SAASa,EAAYC,EAAMC,EAAI,CAC7BC,EAAaF,EAAOlD,GAClBA,EAAI,OAASmD,EAAGnD,CAAG,EAAI,CAAE,KAAM,GAAM,OAAQ,eAAe,CAAE,CAClE,CAKAiD,EAAY,YAAcjD,GAAQD,EAAaC,EAAK,CAAE,KAAM,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,GAAG,CAAE,CAAC,EAChGoD,EAAa,YAAcpD,GAAQD,EAAaC,EAAK,CAAE,KAAM,EAAG,EAAG,MAAO,IAAK,KAAM,KAAM,GAAG,CAAE,CAAC,EAEjGiD,EAAY,gBAAkBjD,GAC5BkB,EAAalB,EAAK,CAAE,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,MAAO,IAAK,OAAQ,GAAI,IAAK,CAAE,EAAG,EAAG,EAAG,GAAI,CAAE,CAAC,EACrGiD,EAAY,mBAAqBjD,GAC/BkB,EAAalB,EAAK,CAChB,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,MAAO,IAAK,OAAQ,EACpD,IAAK,CAAE,MAAO,EAAG,KAAM,EAAG,KAAM6C,EAAS,EAAG,EAAG,EAAG,CAAA,EAAI,EAAE,CAAC,CAC7D,CAAG,CAAC,EACJI,EAAY,mBAAqBjD,GAC/BkB,EAAalB,EAAK,CAChB,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,MAAO,IAAK,OAAQ,EACpD,IAAK,CAAE,MAAO,EAAG,KAAM,EAAG,KAAM6C,EAAS,EAAG,EAAG,EAAG,CAAC,EAAG,GAAI,EAAE,EAAG,EAAE,CAAC,CACtE,CAAG,CAAC,EAEJO,EAAa,gBAAkBpD,GAC7BkB,EAAalB,EAAK,CAAE,EAAG,MAAO,IAAK,KAAM,KAAM,IAAK,MAAO,IAAK,OAAQ,GAAI,IAAK,CAAE,EAAG,EAAG,EAAG,EAAE,CAAE,CAAE,CAAC"}
assets/{adreno_probe-Cmg7uBSr.js → adreno_probe-CqGqVTv4.js} RENAMED
@@ -1,9 +1,9 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/autotune-DywP5DSc.js","assets/encoder-I9sHImnR.js","assets/pipelines-DJ7cc1m-.js","assets/constants-C8VbFpic.js","assets/decoder-CI9o-EVx.js","assets/device-BotbBNoe.js"])))=>i.map(i=>d[i]);
2
- import{_ as he}from"./preload-helper-BXl3LOEh.js";import{r as S}from"./debug-C_LNzFrK.js";import{c as K,r as V}from"./gpu-utils-BTh3AGTJ.js";import{g as ee,a as le,b as Ge,c as ke,d as Be}from"./pipelines-DJ7cc1m-.js";import{L as J,D as ye}from"./constants-C8VbFpic.js";import{e as fe,f as Se}from"./f16-wKKZr58e.js";import"./modulepreload-polyfill-B5Qt9EMX.js";const re=256,z=4,N=(e,o)=>(Math.imul(e+1,2654435761)^Math.imul(o+1,40503))>>>0&1023,Pe=`
3
  fn vhash(tid: u32, g: u32) -> f32 {
4
  return f32((((tid + 1u) * 2654435761u) ^ ((g + 1u) * 40503u)) & 1023u);
5
  }
6
- `;async function x(e,o,{wg:r,outPerGroup:t,want:n,tol:i=0,dispatchY:l=1}){const _=e.createShaderModule({code:o}),b=(await _.getCompilationInfo()).messages.filter(A=>A.type==="error");if(b.length)return{pass:!1,detail:{compileErrors:b.map(A=>A.message).slice(0,3)}};const p=e.createComputePipeline({layout:"auto",compute:{module:_,entryPoint:"main"}}),c=re*l,f=c*t,P=e.createBuffer({size:f*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),h=e.createBindGroup({layout:p.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:P}}]});let F=0;const M=new Set;let W=null;const D=[];for(let A=0;A<z;A++){const s=e.createCommandEncoder(),u=s.beginComputePass();u.setPipeline(p),u.setBindGroup(0,h),u.dispatchWorkgroups(re,l),u.end(),e.queue.submit([s.finish()]);const a=new Float32Array(await V(e,P,f*4));let G=0;for(let k=0;k<c;k++)for(let w=0;w<t;w++){const v=n(k,w),d=a[k*t+w];Math.abs(d-v)<=i||(G++,M.add(k),W||(W={rep:A,g:k,lane:w,got:d,want:v}))}D.push(G),F+=G}return P.destroy(),{pass:F===0,detail:{wg:r,groups:c,reps:z,badLanes:F,badGroups:M.size,badPerRep:D,...W?{firstBad:W}:{}}}}const T=e=>`
7
  @group(0) @binding(0) var<storage, read_write> out: array<f32>;
8
  const WG: u32 = ${e}u;
9
  ${Pe}
@@ -19,7 +19,7 @@ fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid
19
  workgroupBarrier();
20
  }
21
  out[g * WG + tid] = red[0];
22
- }`}const ne=e=>o=>{let r=-1/0;for(let t=0;t<e;t++)r=Math.max(r,N(t,o));return r},ge=e=>o=>{let r=0;for(let t=0;t<e;t++)r+=N(t,o);return r};S("adreno_probe_tree_bcast_wg64",e=>x(e.device,ve(64),{wg:64,outPerGroup:64,want:ne(64)}));S("adreno_probe_tree_bcast_wg128",e=>x(e.device,ve(128),{wg:128,outPerGroup:128,want:ne(128)}));S("adreno_probe_tree_sum_wg256",e=>{const o=`${T(256)}
23
  var<workgroup> red: array<f32, WG>;
24
  @compute @workgroup_size(256)
25
  fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
@@ -31,7 +31,7 @@ fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid
31
  workgroupBarrier();
32
  }
33
  out[g * WG + tid] = red[0];
34
- }`;return x(e.device,o,{wg:256,outPerGroup:256,want:ge(256)})});S("adreno_probe_tree_single_wg128",e=>{const o=`${T(128)}
35
  var<workgroup> red: array<f32, WG>;
36
  @compute @workgroup_size(128)
37
  fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
@@ -119,12 +119,12 @@ fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid
119
  var total = 0.0;
120
  for (var i = 0u; i < nSg; i = i + 1u) { total = total + sgSum[i]; }
121
  out[g * WG + tid] = total;
122
- }`;return x(e.device,o,{wg:256,outPerGroup:256,want:ge(256)})});const Y=448,me=`
123
  fn xval(i: u32, g: u32) -> f32 { return (vhash(i, g) - 512.0) / 256.0; }
124
  fn rval(i: u32, g: u32) -> f32 { return (vhash(i + 7777u, g) - 512.0) / 256.0; }
125
  fn gval(i: u32) -> f32 { return 1.0 + (vhash(i, 12345u) - 512.0) / 1024.0; }
126
  fn bval(i: u32) -> f32 { return (vhash(i, 54321u) - 512.0) / 512.0; }
127
- `,Z=(e,o)=>(N(e,o)-512)/256,te=(e,o)=>(N(e+7777,o)-512)/256,oe=e=>1+(N(e,12345)-512)/1024,ae=e=>(N(e,54321)-512)/512;function ie(e,o){const r=new Map;return(t,n)=>{let i=r.get(t);if(!i){const l=new Float64Array(e);let _=0;for(let c=0;c<e;c++)l[c]=Z(c,t)+te(c,t),_+=l[c];const B=_/e;let b=0;for(let c=0;c<e;c++)b+=(l[c]-B)*(l[c]-B);const p=1/Math.sqrt(b/e+J);i=new Float64Array(e);for(let c=0;c<e;c++)i[c]=o?l[c]-B:oe(c)*(l[c]-B)*p+ae(c);r.set(t,i)}return i[n]}}function _e(e){return`${T(256)}
128
  const D: u32 = ${Y}u;
129
  const EPS: f32 = ${J};
130
  ${me}
@@ -166,7 +166,7 @@ ${e?`
166
  out[g * D + i] = gval(i) * (vbuf[i] - mu) * inv + bval(i);
167
  }
168
  `}
169
- }`}S("adreno_probe2_addln_gen",e=>x(e.device,_e(!1),{wg:256,outPerGroup:Y,want:ie(Y,!1),tol:.001}));S("adreno_probe2_addln_gen_mu",e=>x(e.device,_e(!0),{wg:256,outPerGroup:Y,want:ie(Y,!0),tol:.001}));async function be(e,o){const{device:r}=e,t=ye,n=re,i=new Float32Array(n*t),l=new Float32Array(n*t),_=new Float32Array(t),B=new Float32Array(t);for(let u=0;u<n;u++)for(let a=0;a<t;a++)i[u*t+a]=Z(a,u),l[u*t+a]=te(a,u);for(let u=0;u<t;u++)_[u]=oe(u),B[u]=ae(u);const b=ie(t,!1),p=ee(r,"add_ln",le,{t:"f32",wg:256,sg:o,defines:{D:t,EPS:J}}),c=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,f=r.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(f.getMappedRange()).set([n,0,0,0]),f.unmap();const P=[i,l,_,B].map(u=>K(r,u,c)),h=r.createBuffer({size:n*t*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),F=r.createBindGroup({layout:p.getBindGroupLayout(0),entries:[f,...P,h].map((u,a)=>({binding:a,resource:{buffer:u}}))}),M=.001;let W=0;const D=new Set;let A=null;const s=[];for(let u=0;u<z;u++){const a=r.createCommandEncoder(),G=a.beginComputePass();G.setPipeline(p),G.setBindGroup(0,F),G.dispatchWorkgroups(n),G.end(),r.queue.submit([a.finish()]);const k=new Float32Array(await V(r,h,n*t*4));let w=0;for(let v=0;v<n;v++)for(let d=0;d<t;d++){const y=b(v,d),m=k[v*t+d];Math.abs(m-y)<=M||(w++,D.add(v),A||(A={rep:u,g:v,lane:d,got:m,want:y}))}s.push(w),W+=w}for(const u of[f,...P,h])u.destroy();return{pass:W===0,detail:{kernel:o?"add_ln (real, f32, sg)":"add_ln (real, f32)",rows:n,d:t,reps:z,tol:M,badLanes:W,badGroups:D.size,badPerRep:s,...A?{firstBad:A}:{}}}}S("adreno_probe2_addln_real",e=>be(e,!1));const U={D:56,D4:14,WG:128,H:4,LEN:3},ce=(e,o,r)=>(N(e,o+3*r)-512)/512;function pe(e){return`${T(U.WG)}
170
  const D: u32 = ${U.D}u;
171
  const D4: u32 = ${U.D4}u;
172
  const H: u32 = ${U.H}u;
@@ -246,7 +246,7 @@ ${e?`
246
  out[yoff + 3u] = o.w;
247
  }
248
  `}
249
- }`}function ue(e){const{D:o,H:r,LEN:t}=U,n=Math.floor(e/r),i=e%r,l=new Float64Array(o);for(let f=0;f<o;f++)l[f]=ce(i*64+f,11,n);const _=new Float64Array(t);for(let f=0;f<t;f++){let P=0;for(let h=0;h<o;h++)P+=l[h]*ce((f*r+i)*64+h,22,n);_[f]=P/Math.sqrt(o)}const B=Math.max(..._),b=_.map(f=>Math.exp(f-B)),p=b.reduce((f,P)=>f+P,0),c=new Float64Array(o);for(let f=0;f<o;f++){let P=0;for(let h=0;h<t;h++)P+=b[h]*ce((h*r+i)*64+f,33,n);c[f]=P/p}return{rowMax:B,denom:p,out:c}}S("adreno_probe2_attn_gen",e=>{const o=new Map,r=(t,n)=>(o.has(t)||o.set(t,ue(t)),o.get(t).out[n]);return x(e.device,pe(!1),{wg:U.WG,outPerGroup:U.D,want:r,tol:.001,dispatchY:U.H})});S("adreno_probe2_attn_gen_p12",e=>{const o=new Map,r=t=>{if(!o.has(t)){const{rowMax:n,denom:i}=ue(t);o.set(t,n+i)}return o.get(t)};return x(e.device,pe(!0),{wg:U.WG,outPerGroup:U.WG,want:r,tol:.001,dispatchY:U.H})});S("adreno_probe3_addln_real_sg",e=>e.hasSubgroups?be(e,!0):{skip:!0,reason:"subgroups feature unavailable"});S("adreno_probe3_addln_gen_uload",e=>{const o=`${T(256)}
250
  const D: u32 = ${Y}u;
251
  const EPS: f32 = ${J};
252
  ${me}
@@ -359,7 +359,7 @@ fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid
359
  out[yoff + 2u] = o.z;
360
  out[yoff + 3u] = o.w;
361
  }
362
- }`,r=new Map,t=(n,i)=>(r.has(n)||r.set(n,ue(n)),r.get(n).out[i]);return x(e.device,o,{wg:U.WG,outPerGroup:U.D,want:t,tol:.001,dispatchY:U.H})});S("adreno_probe3_attn_gen_uload",e=>{const o=pe(!1).replace(`let rowMax = red[0];
363
  workgroupBarrier();`,"let rowMax = workgroupUniformLoad(&red[0]);").replace("let denom = red[0];","let denom = workgroupUniformLoad(&red[0]);");if(!o.includes("workgroupUniformLoad"))throw new Error("uload rewrite did not apply");const r=new Map,t=(n,i)=>(r.has(n)||r.set(n,ue(n)),r.get(n).out[i]);return x(e.device,o,{wg:U.WG,outPerGroup:U.D,want:t,tol:.001,dispatchY:U.H})});S("adreno_probe3_striped_sum_wg256",e=>{const o=`${T(256)}
364
  const D: u32 = ${Y}u;
365
  var<workgroup> red: array<f32, WG>;
@@ -389,5 +389,5 @@ fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid
389
  workgroupBarrier();
390
  }
391
  out[g * WG + tid] = red[0] + vbuf[(tid + 64u) % WG];
392
- }`,r=(t,n)=>ge(256)(t)+N((n+64)%256,t);return x(e.device,o,{wg:256,outPerGroup:256,want:r})});S("adreno_probe4_detect",async e=>{const{detectTreeReductionBug:o}=await he(async()=>{const{detectTreeReductionBug:t}=await import("./autotune-DywP5DSc.js");return{detectTreeReductionBug:t}},__vite__mapDeps([0,1,2,3,4,5])),r=await o(e.device);return{pass:typeof r=="boolean",detail:{treeBug:r,sgAvailable:!!e.hasSubgroups,willForceSg:r&&!!e.hasSubgroups}}});S("adreno_probe5_addln_sg_d576",async e=>{if(!e.hasSubgroups)return{skip:!0,reason:"subgroups feature unavailable"};const{device:o}=e,r=576,t=re,n=new Float32Array(t*r),i=new Float32Array(t*r),l=new Float32Array(r),_=new Float32Array(r);for(let s=0;s<t;s++)for(let u=0;u<r;u++)n[s*r+u]=Z(u,s),i[s*r+u]=te(u,s);for(let s=0;s<r;s++)l[s]=oe(s),_[s]=ae(s);const B=new Map,b=(s,u)=>{if(!B.has(s)){const a=new Float64Array(r);let G=0;for(let d=0;d<r;d++)a[d]=Z(d,s)+te(d,s),G+=a[d];const k=G/r;let w=0;for(let d=0;d<r;d++)w+=(a[d]-k)*(a[d]-k);const v=1/Math.sqrt(w/r+J);B.set(s,a.map((d,y)=>oe(y)*(d-k)*v+ae(y)))}return B.get(s)[u]},p=ee(o,"add_ln",le,{t:"f32",wg:256,sg:!0,defines:{D:r,EPS:J}}),c=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,f=o.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(f.getMappedRange()).set([t,0,0,0]),f.unmap();const P=[n,i,l,_].map(s=>K(o,s,c)),h=o.createBuffer({size:t*r*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),F=o.createBindGroup({layout:p.getBindGroupLayout(0),entries:[f,...P,h].map((s,u)=>({binding:u,resource:{buffer:s}}))}),M=.001;let W=0,D=null;const A=[];for(let s=0;s<z;s++){const u=o.createCommandEncoder(),a=u.beginComputePass();a.setPipeline(p),a.setBindGroup(0,F),a.dispatchWorkgroups(t),a.end(),o.queue.submit([u.finish()]);const G=new Float32Array(await V(o,h,t*r*4));let k=0;for(let w=0;w<t;w++)for(let v=0;v<r;v++){const d=b(w,v);Math.abs(G[w*r+v]-d)<=M||(k++,D||(D={rep:s,g:w,lane:v,got:G[w*r+v],want:d}))}A.push(k),W+=k}for(const s of[f,...P,h])s.destroy();return{pass:W===0,detail:{kernel:"add_ln (real, f32, sg, D=576)",rows:t,d:r,reps:z,tol:M,badLanes:W,badPerRep:A,...D?{firstBad:D}:{}}}});const I=(e,o)=>(N(e&1048575,o)-512)/512,we=e=>{const o=new Uint16Array(e.length);for(let r=0;r<e.length;r++)o[r]=Se(e[r]);return o};async function de(e,{H:o,D:r,B:t,M:n,L:i,lens:l,sg:_,t:B="f32"}){const{device:b}=e,p=o*r,c=t*n,f=new Float32Array(c*p),P=new Float32Array(t*i*p),h=new Float32Array(t*i*p);for(let m=0;m<f.length;m++)f[m]=I(m,51);for(let m=0;m<P.length;m++)P[m]=I(m,52);for(let m=0;m<h.length;m++)h[m]=I(m,53);const F=1/Math.sqrt(r),M=new Float64Array(c*p);for(let m=0;m<t;m++)for(let g=0;g<n;g++){const R=m*n+g;for(let j=0;j<o;j++){const q=l[m],O=new Float64Array(q);for(let $=0;$<q;$++){let E=0;for(let L=0;L<r;L++)E+=f[R*p+j*r+L]*P[(m*i+$)*p+j*r+L];O[$]=E*F}const C=Math.max(...O),H=O.map($=>Math.exp($-C)),se=H.reduce(($,E)=>$+E,0);for(let $=0;$<r;$++){let E=0;for(let L=0;L<q;L++)E+=H[L]*h[(m*i+L)*p+j*r+$];M[R*p+j*r+$]=E/se}}}const W=ee(b,"attention",ke,{t:B,wg:128,sg:_,defines:{H:o,D:r,SCORES_CAP:352,ATTN_SCALE:F,Q_STRIDE:p,Q_OFF:0,KV_STRIDE:p,K_OFF:0,V_OFF:0}}),D=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,A=b.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(A.getMappedRange()).set([t,n,i,1,0,0,0,0]),A.unmap();const s=B==="f16"?2:4,u=[f,P,h].map(m=>K(b,B==="f16"?we(m):m,D)),a=K(b,new Uint32Array(l),D),G=b.createBuffer({size:c*p*s,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),k=b.createBindGroup({layout:W.getBindGroupLayout(0),entries:[A,...u,a,G].map((m,g)=>({binding:g,resource:{buffer:m}}))}),w=B==="f16"?.01:.001;let v=0,d=null;const y=[];for(let m=0;m<z;m++){const g=b.createCommandEncoder(),R=g.beginComputePass();R.setPipeline(W),R.setBindGroup(0,k),R.dispatchWorkgroups(c,o),R.end(),b.queue.submit([g.finish()]);const j=await V(b,G,c*p*s),q=B==="f16"?fe(new Uint16Array(j)):new Float32Array(j);let O=0;for(let C=0;C<M.length;C++)Math.abs(q[C]-M[C])<=w||(O++,d||(d={rep:m,i:C,got:q[C],want:M[C]}));y.push(O),v+=O}for(const m of[A,...u,a,G])m.destroy();return{pass:v===0,detail:{kernel:`attention (real, ${B}, sg, H${o} D${r})`,B:t,M:n,L:i,lens:l.join(","),reps:z,tol:w,badLanes:v,badPerRep:y,...d?{firstBad:d}:{}}}}S("adreno_probe6_attn_sg_h60_short",e=>e.hasSubgroups?de(e,{H:8,D:72,B:2,M:16,L:16,lens:[16,9],sg:!0}):{skip:!0,reason:"subgroups feature unavailable"});S("adreno_probe6_attn_sg_h60_long",e=>e.hasSubgroups?de(e,{H:8,D:72,B:2,M:4,L:224,lens:[224,131],sg:!0}):{skip:!0,reason:"subgroups feature unavailable"});S("adreno_probe6_rowln_sg_d576",async e=>{if(!e.hasSubgroups)return{skip:!0,reason:"subgroups feature unavailable"};const{device:o}=e,r=576,t=576,n=64,i=new Float32Array(n*r),l=new Float32Array(r*t),_=new Float32Array(t),B=new Float32Array(n*t),b=new Float32Array(t),p=new Float32Array(t);for(let a=0;a<i.length;a++)i[a]=I(a,61)*2;for(let a=0;a<l.length;a++)l[a]=I(a,62);for(let a=0;a<B.length;a++)B[a]=I(a,63)*2;for(let a=0;a<t;a++)_[a]=I(a,64),b[a]=1+I(a,65)/2,p[a]=I(a,66);const c=new Float64Array(n*t);for(let a=0;a<n;a++){const G=new Float64Array(t);let k=0;for(let y=0;y<t;y++){let m=0;for(let g=0;g<r;g++)m+=i[a*r+g]*l[g*t+y];G[y]=m+_[y]+B[a*t+y],k+=G[y]}const w=k/t;let v=0;for(let y=0;y<t;y++)v+=(G[y]-w)*(G[y]-w);const d=1/Math.sqrt(v/t+J);for(let y=0;y<t;y++)c[a*t+y]=b[y]*(G[y]-w)*d+p[y]}const f=ee(o,"gemm_row_ln",Ge,{t:"f32",wg:128,sg:!0,defines:{KDIM:r,D:t,EPS:J}}),P=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,h=o.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(h.getMappedRange()).set([n,0,0,0]),h.unmap();const F=[i,l,_,B,b,p].map(a=>K(o,a,P)),M=o.createBuffer({size:n*t*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),W=o.createBindGroup({layout:f.getBindGroupLayout(0),entries:[h,...F,M].map((a,G)=>({binding:G,resource:{buffer:a}}))}),D=.002;let A=0,s=null;const u=[];for(let a=0;a<z;a++){const G=o.createCommandEncoder(),k=G.beginComputePass();k.setPipeline(f),k.setBindGroup(0,W),k.dispatchWorkgroups(n),k.end(),o.queue.submit([G.finish()]);const w=new Float32Array(await V(o,M,n*t*4));let v=0;for(let d=0;d<c.length;d++)Math.abs(w[d]-c[d])<=D||(v++,s||(s={rep:a,i:d,got:w[d],want:c[d]}));u.push(v),A+=v}for(const a of[h,...F,M])a.destroy();return{pass:A===0,detail:{kernel:"gemm_row_ln (real, f32, sg, K=D=576)",M:n,reps:z,tol:D,badLanes:A,badPerRep:u,...s?{firstBad:s}:{}}}});S("adreno_probe7_attn_sg_h60_short_f16",e=>e.hasSubgroups?e.hasF16?de(e,{H:8,D:72,B:2,M:16,L:16,lens:[16,9],sg:!0,t:"f16"}):{skip:!0,reason:"no shader-f16"}:{skip:!0,reason:"subgroups feature unavailable"});S("adreno_probe7_attn_sg_h60_long_f16",e=>e.hasSubgroups?e.hasF16?de(e,{H:8,D:72,B:2,M:4,L:224,lens:[224,131],sg:!0,t:"f16"}):{skip:!0,reason:"no shader-f16"}:{skip:!0,reason:"subgroups feature unavailable"});S("adreno_probe7_addln_sg_d576_f16",async e=>{if(!e.hasSubgroups)return{skip:!0,reason:"subgroups feature unavailable"};if(!e.hasF16)return{skip:!0,reason:"no shader-f16"};const{device:o}=e,r=576,t=re,n=new Float32Array(t*r),i=new Float32Array(t*r),l=new Float32Array(r),_=new Float32Array(r);for(let s=0;s<t;s++)for(let u=0;u<r;u++)n[s*r+u]=Z(u,s)/2,i[s*r+u]=te(u,s)/2;for(let s=0;s<r;s++)l[s]=oe(s),_[s]=ae(s);const B=new Map,b=(s,u)=>{if(!B.has(s)){const a=new Float64Array(r);let G=0;for(let d=0;d<r;d++)a[d]=n[s*r+d]+i[s*r+d],G+=a[d];const k=G/r;let w=0;for(let d=0;d<r;d++)w+=(a[d]-k)*(a[d]-k);const v=1/Math.sqrt(w/r+J);B.set(s,a.map((d,y)=>l[y]*(d-k)*v+_[y]))}return B.get(s)[u]},p=ee(o,"add_ln",le,{t:"f16",wg:256,sg:!0,defines:{D:r,EPS:J}}),c=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,f=o.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(f.getMappedRange()).set([t,0,0,0]),f.unmap();const P=[n,i,l,_].map(s=>K(o,we(s),c)),h=o.createBuffer({size:t*r*2,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),F=o.createBindGroup({layout:p.getBindGroupLayout(0),entries:[f,...P,h].map((s,u)=>({binding:u,resource:{buffer:s}}))}),M=.02;let W=0,D=null;const A=[];for(let s=0;s<z;s++){const u=o.createCommandEncoder(),a=u.beginComputePass();a.setPipeline(p),a.setBindGroup(0,F),a.dispatchWorkgroups(t),a.end(),o.queue.submit([u.finish()]);const G=fe(new Uint16Array(await V(o,h,t*r*2)));let k=0;for(let w=0;w<t;w++)for(let v=0;v<r;v++){const d=b(w,v);Math.abs(G[w*r+v]-d)<=M||(k++,D||(D={rep:s,g:w,lane:v,got:G[w*r+v],want:d}))}A.push(k),W+=k}for(const s of[f,...P,h])s.destroy();return{pass:W===0,detail:{kernel:"add_ln (real, f16, sg, D=576)",rows:t,d:r,reps:z,tol:M,badLanes:W,badPerRep:A,...D?{firstBad:D}:{}}}});async function X(e,{H:o,D:r,QB:t,JB:n,B:i,M:l,L:_,lens:B,t:b="f16"}){const{device:p}=e,c=o*r,f=i*l,P=new Float32Array(f*c),h=new Float32Array(i*_*c),F=new Float32Array(i*_*c);for(let g=0;g<P.length;g++)P[g]=I(g,71);for(let g=0;g<h.length;g++)h[g]=I(g,72);for(let g=0;g<F.length;g++)F[g]=I(g,73);const M=1/Math.sqrt(r),W=new Float64Array(f*c);for(let g=0;g<i;g++)for(let R=0;R<l;R++){const j=g*l+R;for(let q=0;q<o;q++){const O=B[g],C=new Float64Array(O);for(let E=0;E<O;E++){let L=0;for(let Q=0;Q<r;Q++)L+=P[j*c+q*r+Q]*h[(g*_+E)*c+q*r+Q];C[E]=L*M}const H=Math.max(...C),se=C.map(E=>Math.exp(E-H)),$=se.reduce((E,L)=>E+L,0);for(let E=0;E<r;E++){let L=0;for(let Q=0;Q<O;Q++)L+=se[Q]*F[(g*_+Q)*c+q*r+E];W[j*c+q*r+E]=L/$}}}const D=ee(p,"attention_block",Be,{t:b,defines:{H:o,D:r,QB:t,JB:n,ATTN_SCALE:M,Q_STRIDE:c,Q_OFF:0,KV_STRIDE:c,K_OFF:0,V_OFF:0,PACKED:!1,NOPACKED:!0}}),A=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,s=p.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(s.getMappedRange()).set([i,l,_,1,0,0,0,0]),s.unmap();const u=b==="f16"?2:4,a=[P,h,F].map(g=>K(p,b==="f16"?we(g):g,A)),G=K(p,new Uint32Array(B),A),k=p.createBuffer({size:f*c*u,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),w=p.createBindGroup({layout:D.getBindGroupLayout(0),entries:[s,...a,G,k].map((g,R)=>({binding:R,resource:{buffer:g}}))}),v=b==="f16"?.01:.001;let d=0,y=null;const m=[];for(let g=0;g<z;g++){const R=p.createCommandEncoder(),j=R.beginComputePass();j.setPipeline(D),j.setBindGroup(0,w),j.dispatchWorkgroups(Math.ceil(l/t),o,i),j.end(),p.queue.submit([R.finish()]);const q=await V(p,k,f*c*u),O=b==="f16"?fe(new Uint16Array(q)):new Float32Array(q);let C=0;for(let H=0;H<W.length;H++)Math.abs(O[H]-W[H])<=v||(C++,y||(y={rep:g,i:H,got:O[H],want:W[H]}));m.push(C),d+=C}for(const g of[s,...a,G,k])g.destroy();return{pass:d===0,detail:{kernel:`attention_block (real, ${b}, H${o} D${r} QB${t} JB${n})`,B:i,M:l,L:_,lens:B.join(","),reps:z,tol:v,badLanes:d,badPerRep:m,...y?{firstBad:y}:{}}}}S("adreno_probe8_attnblock_h60_f16",e=>e.hasF16?X(e,{H:8,D:72,QB:14,JB:32,B:2,M:33,L:33,lens:[33,17],t:"f16"}):{skip:!0,reason:"no shader-f16"});S("adreno_probe8_attnblock_h60_big_f16",e=>e.hasF16?X(e,{H:8,D:72,QB:14,JB:32,B:2,M:96,L:96,lens:[96,49],t:"f16"}):{skip:!0,reason:"no shader-f16"});S("adreno_probe8_weights_hash",async()=>{const e=(t,n)=>{for(let i=0;i<n.length;i++)t^=n[i],t=Math.imul(t,16777619)>>>0;return t},o=async t=>{const i=(await(await fetch(`${t}/manifest.json`)).json()).bins??["weights.bin"];let l=2166136261,_=0;for(const B of i){const b=new Uint8Array(await(await fetch(`${t}/${B}`)).arrayBuffer());_+=b.length,l=e(l,b)}return{hash:l.toString(16),bytes:_,bins:i.length}},r={moxhi:await o("/weights")};try{r.hachimi60=await o("/weights/hachimi60")}catch(t){r.hachimi60={error:String(t?.message??t)}}return{pass:!0,detail:r}});S("adreno_probe8b_attnblock_h60_qb8",e=>e.hasF16?X(e,{H:8,D:72,QB:8,JB:32,B:2,M:33,L:33,lens:[33,17],t:"f16"}):{skip:!0,reason:"no shader-f16"});S("adreno_probe8b_attnblock_h60_qb12",e=>e.hasF16?X(e,{H:8,D:72,QB:12,JB:32,B:2,M:33,L:33,lens:[33,17],t:"f16"}):{skip:!0,reason:"no shader-f16"});S("adreno_probe8b_attnblock_h60_qb14_jb16",e=>e.hasF16?X(e,{H:8,D:72,QB:14,JB:16,B:2,M:33,L:33,lens:[33,17],t:"f16"}):{skip:!0,reason:"no shader-f16"});S("adreno_probe8b_attnblock_h60_qb14_f32",e=>X(e,{H:8,D:72,QB:14,JB:32,B:2,M:33,L:33,lens:[33,17],t:"f32"}));S("adreno_probe8b_attnblock_d56_qb14",e=>e.hasF16?X(e,{H:8,D:56,QB:14,JB:32,B:2,M:33,L:33,lens:[33,17],t:"f16"}):{skip:!0,reason:"no shader-f16"});
393
- //# sourceMappingURL=adreno_probe-Cmg7uBSr.js.map
 
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/autotune-Bwt_lWMv.js","assets/encoder-CZXKGzzg.js","assets/pipelines-BbLc75sB.js","assets/constants-CSVWRdrh.js","assets/decoder-BUiaGDqb.js","assets/device-BotbBNoe.js"])))=>i.map(i=>d[i]);
2
+ import{_ as he}from"./preload-helper-BXl3LOEh.js";import{r as S}from"./debug-CPpXXfWA.js";import{c as K,r as V}from"./gpu-utils-BTh3AGTJ.js";import{g as ee,a as le,b as Ge,c as ke,d as Be}from"./pipelines-BbLc75sB.js";import{L as J,D as ye}from"./constants-CSVWRdrh.js";import{e as fe,f as Se}from"./f16-wKKZr58e.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./safe_storage-BYkOahew.js";const re=256,z=4,N=(e,o)=>(Math.imul(e+1,2654435761)^Math.imul(o+1,40503))>>>0&1023,Pe=`
3
  fn vhash(tid: u32, g: u32) -> f32 {
4
  return f32((((tid + 1u) * 2654435761u) ^ ((g + 1u) * 40503u)) & 1023u);
5
  }
6
+ `;async function x(e,o,{wg:r,outPerGroup:t,want:n,tol:i=0,dispatchY:l=1}){const _=e.createShaderModule({code:o}),b=(await _.getCompilationInfo()).messages.filter(A=>A.type==="error");if(b.length)return{pass:!1,detail:{compileErrors:b.map(A=>A.message).slice(0,3)}};const g=e.createComputePipeline({layout:"auto",compute:{module:_,entryPoint:"main"}}),c=re*l,f=c*t,P=e.createBuffer({size:f*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),h=e.createBindGroup({layout:g.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:P}}]});let F=0;const M=new Set;let W=null;const D=[];for(let A=0;A<z;A++){const s=e.createCommandEncoder(),u=s.beginComputePass();u.setPipeline(g),u.setBindGroup(0,h),u.dispatchWorkgroups(re,l),u.end(),e.queue.submit([s.finish()]);const a=new Float32Array(await V(e,P,f*4));let G=0;for(let k=0;k<c;k++)for(let w=0;w<t;w++){const v=n(k,w),d=a[k*t+w];Math.abs(d-v)<=i||(G++,M.add(k),W||(W={rep:A,g:k,lane:w,got:d,want:v}))}D.push(G),F+=G}return P.destroy(),{pass:F===0,detail:{wg:r,groups:c,reps:z,badLanes:F,badGroups:M.size,badPerRep:D,...W?{firstBad:W}:{}}}}const T=e=>`
7
  @group(0) @binding(0) var<storage, read_write> out: array<f32>;
8
  const WG: u32 = ${e}u;
9
  ${Pe}
 
19
  workgroupBarrier();
20
  }
21
  out[g * WG + tid] = red[0];
22
+ }`}const ne=e=>o=>{let r=-1/0;for(let t=0;t<e;t++)r=Math.max(r,N(t,o));return r},pe=e=>o=>{let r=0;for(let t=0;t<e;t++)r+=N(t,o);return r};S("adreno_probe_tree_bcast_wg64",e=>x(e.device,ve(64),{wg:64,outPerGroup:64,want:ne(64)}));S("adreno_probe_tree_bcast_wg128",e=>x(e.device,ve(128),{wg:128,outPerGroup:128,want:ne(128)}));S("adreno_probe_tree_sum_wg256",e=>{const o=`${T(256)}
23
  var<workgroup> red: array<f32, WG>;
24
  @compute @workgroup_size(256)
25
  fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
 
31
  workgroupBarrier();
32
  }
33
  out[g * WG + tid] = red[0];
34
+ }`;return x(e.device,o,{wg:256,outPerGroup:256,want:pe(256)})});S("adreno_probe_tree_single_wg128",e=>{const o=`${T(128)}
35
  var<workgroup> red: array<f32, WG>;
36
  @compute @workgroup_size(128)
37
  fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
 
119
  var total = 0.0;
120
  for (var i = 0u; i < nSg; i = i + 1u) { total = total + sgSum[i]; }
121
  out[g * WG + tid] = total;
122
+ }`;return x(e.device,o,{wg:256,outPerGroup:256,want:pe(256)})});const Y=448,me=`
123
  fn xval(i: u32, g: u32) -> f32 { return (vhash(i, g) - 512.0) / 256.0; }
124
  fn rval(i: u32, g: u32) -> f32 { return (vhash(i + 7777u, g) - 512.0) / 256.0; }
125
  fn gval(i: u32) -> f32 { return 1.0 + (vhash(i, 12345u) - 512.0) / 1024.0; }
126
  fn bval(i: u32) -> f32 { return (vhash(i, 54321u) - 512.0) / 512.0; }
127
+ `,Z=(e,o)=>(N(e,o)-512)/256,te=(e,o)=>(N(e+7777,o)-512)/256,oe=e=>1+(N(e,12345)-512)/1024,ae=e=>(N(e,54321)-512)/512;function ie(e,o){const r=new Map;return(t,n)=>{let i=r.get(t);if(!i){const l=new Float64Array(e);let _=0;for(let c=0;c<e;c++)l[c]=Z(c,t)+te(c,t),_+=l[c];const B=_/e;let b=0;for(let c=0;c<e;c++)b+=(l[c]-B)*(l[c]-B);const g=1/Math.sqrt(b/e+J);i=new Float64Array(e);for(let c=0;c<e;c++)i[c]=o?l[c]-B:oe(c)*(l[c]-B)*g+ae(c);r.set(t,i)}return i[n]}}function _e(e){return`${T(256)}
128
  const D: u32 = ${Y}u;
129
  const EPS: f32 = ${J};
130
  ${me}
 
166
  out[g * D + i] = gval(i) * (vbuf[i] - mu) * inv + bval(i);
167
  }
168
  `}
169
+ }`}S("adreno_probe2_addln_gen",e=>x(e.device,_e(!1),{wg:256,outPerGroup:Y,want:ie(Y,!1),tol:.001}));S("adreno_probe2_addln_gen_mu",e=>x(e.device,_e(!0),{wg:256,outPerGroup:Y,want:ie(Y,!0),tol:.001}));async function be(e,o){const{device:r}=e,t=ye,n=re,i=new Float32Array(n*t),l=new Float32Array(n*t),_=new Float32Array(t),B=new Float32Array(t);for(let u=0;u<n;u++)for(let a=0;a<t;a++)i[u*t+a]=Z(a,u),l[u*t+a]=te(a,u);for(let u=0;u<t;u++)_[u]=oe(u),B[u]=ae(u);const b=ie(t,!1),g=ee(r,"add_ln",le,{t:"f32",wg:256,sg:o,defines:{D:t,EPS:J}}),c=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,f=r.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(f.getMappedRange()).set([n,0,0,0]),f.unmap();const P=[i,l,_,B].map(u=>K(r,u,c)),h=r.createBuffer({size:n*t*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),F=r.createBindGroup({layout:g.getBindGroupLayout(0),entries:[f,...P,h].map((u,a)=>({binding:a,resource:{buffer:u}}))}),M=.001;let W=0;const D=new Set;let A=null;const s=[];for(let u=0;u<z;u++){const a=r.createCommandEncoder(),G=a.beginComputePass();G.setPipeline(g),G.setBindGroup(0,F),G.dispatchWorkgroups(n),G.end(),r.queue.submit([a.finish()]);const k=new Float32Array(await V(r,h,n*t*4));let w=0;for(let v=0;v<n;v++)for(let d=0;d<t;d++){const y=b(v,d),m=k[v*t+d];Math.abs(m-y)<=M||(w++,D.add(v),A||(A={rep:u,g:v,lane:d,got:m,want:y}))}s.push(w),W+=w}for(const u of[f,...P,h])u.destroy();return{pass:W===0,detail:{kernel:o?"add_ln (real, f32, sg)":"add_ln (real, f32)",rows:n,d:t,reps:z,tol:M,badLanes:W,badGroups:D.size,badPerRep:s,...A?{firstBad:A}:{}}}}S("adreno_probe2_addln_real",e=>be(e,!1));const U={D:56,D4:14,WG:128,H:4,LEN:3},ce=(e,o,r)=>(N(e,o+3*r)-512)/512;function ge(e){return`${T(U.WG)}
170
  const D: u32 = ${U.D}u;
171
  const D4: u32 = ${U.D4}u;
172
  const H: u32 = ${U.H}u;
 
246
  out[yoff + 3u] = o.w;
247
  }
248
  `}
249
+ }`}function ue(e){const{D:o,H:r,LEN:t}=U,n=Math.floor(e/r),i=e%r,l=new Float64Array(o);for(let f=0;f<o;f++)l[f]=ce(i*64+f,11,n);const _=new Float64Array(t);for(let f=0;f<t;f++){let P=0;for(let h=0;h<o;h++)P+=l[h]*ce((f*r+i)*64+h,22,n);_[f]=P/Math.sqrt(o)}const B=Math.max(..._),b=_.map(f=>Math.exp(f-B)),g=b.reduce((f,P)=>f+P,0),c=new Float64Array(o);for(let f=0;f<o;f++){let P=0;for(let h=0;h<t;h++)P+=b[h]*ce((h*r+i)*64+f,33,n);c[f]=P/g}return{rowMax:B,denom:g,out:c}}S("adreno_probe2_attn_gen",e=>{const o=new Map,r=(t,n)=>(o.has(t)||o.set(t,ue(t)),o.get(t).out[n]);return x(e.device,ge(!1),{wg:U.WG,outPerGroup:U.D,want:r,tol:.001,dispatchY:U.H})});S("adreno_probe2_attn_gen_p12",e=>{const o=new Map,r=t=>{if(!o.has(t)){const{rowMax:n,denom:i}=ue(t);o.set(t,n+i)}return o.get(t)};return x(e.device,ge(!0),{wg:U.WG,outPerGroup:U.WG,want:r,tol:.001,dispatchY:U.H})});S("adreno_probe3_addln_real_sg",e=>e.hasSubgroups?be(e,!0):{skip:!0,reason:"subgroups feature unavailable"});S("adreno_probe3_addln_gen_uload",e=>{const o=`${T(256)}
250
  const D: u32 = ${Y}u;
251
  const EPS: f32 = ${J};
252
  ${me}
 
359
  out[yoff + 2u] = o.z;
360
  out[yoff + 3u] = o.w;
361
  }
362
+ }`,r=new Map,t=(n,i)=>(r.has(n)||r.set(n,ue(n)),r.get(n).out[i]);return x(e.device,o,{wg:U.WG,outPerGroup:U.D,want:t,tol:.001,dispatchY:U.H})});S("adreno_probe3_attn_gen_uload",e=>{const o=ge(!1).replace(`let rowMax = red[0];
363
  workgroupBarrier();`,"let rowMax = workgroupUniformLoad(&red[0]);").replace("let denom = red[0];","let denom = workgroupUniformLoad(&red[0]);");if(!o.includes("workgroupUniformLoad"))throw new Error("uload rewrite did not apply");const r=new Map,t=(n,i)=>(r.has(n)||r.set(n,ue(n)),r.get(n).out[i]);return x(e.device,o,{wg:U.WG,outPerGroup:U.D,want:t,tol:.001,dispatchY:U.H})});S("adreno_probe3_striped_sum_wg256",e=>{const o=`${T(256)}
364
  const D: u32 = ${Y}u;
365
  var<workgroup> red: array<f32, WG>;
 
389
  workgroupBarrier();
390
  }
391
  out[g * WG + tid] = red[0] + vbuf[(tid + 64u) % WG];
392
+ }`,r=(t,n)=>pe(256)(t)+N((n+64)%256,t);return x(e.device,o,{wg:256,outPerGroup:256,want:r})});S("adreno_probe4_detect",async e=>{const{detectTreeReductionBug:o}=await he(async()=>{const{detectTreeReductionBug:t}=await import("./autotune-Bwt_lWMv.js");return{detectTreeReductionBug:t}},__vite__mapDeps([0,1,2,3,4,5])),r=await o(e.device);return{pass:typeof r=="boolean",detail:{treeBug:r,sgAvailable:!!e.hasSubgroups,willForceSg:r&&!!e.hasSubgroups}}});S("adreno_probe5_addln_sg_d576",async e=>{if(!e.hasSubgroups)return{skip:!0,reason:"subgroups feature unavailable"};const{device:o}=e,r=576,t=re,n=new Float32Array(t*r),i=new Float32Array(t*r),l=new Float32Array(r),_=new Float32Array(r);for(let s=0;s<t;s++)for(let u=0;u<r;u++)n[s*r+u]=Z(u,s),i[s*r+u]=te(u,s);for(let s=0;s<r;s++)l[s]=oe(s),_[s]=ae(s);const B=new Map,b=(s,u)=>{if(!B.has(s)){const a=new Float64Array(r);let G=0;for(let d=0;d<r;d++)a[d]=Z(d,s)+te(d,s),G+=a[d];const k=G/r;let w=0;for(let d=0;d<r;d++)w+=(a[d]-k)*(a[d]-k);const v=1/Math.sqrt(w/r+J);B.set(s,a.map((d,y)=>oe(y)*(d-k)*v+ae(y)))}return B.get(s)[u]},g=ee(o,"add_ln",le,{t:"f32",wg:256,sg:!0,defines:{D:r,EPS:J}}),c=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,f=o.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(f.getMappedRange()).set([t,0,0,0]),f.unmap();const P=[n,i,l,_].map(s=>K(o,s,c)),h=o.createBuffer({size:t*r*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),F=o.createBindGroup({layout:g.getBindGroupLayout(0),entries:[f,...P,h].map((s,u)=>({binding:u,resource:{buffer:s}}))}),M=.001;let W=0,D=null;const A=[];for(let s=0;s<z;s++){const u=o.createCommandEncoder(),a=u.beginComputePass();a.setPipeline(g),a.setBindGroup(0,F),a.dispatchWorkgroups(t),a.end(),o.queue.submit([u.finish()]);const G=new Float32Array(await V(o,h,t*r*4));let k=0;for(let w=0;w<t;w++)for(let v=0;v<r;v++){const d=b(w,v);Math.abs(G[w*r+v]-d)<=M||(k++,D||(D={rep:s,g:w,lane:v,got:G[w*r+v],want:d}))}A.push(k),W+=k}for(const s of[f,...P,h])s.destroy();return{pass:W===0,detail:{kernel:"add_ln (real, f32, sg, D=576)",rows:t,d:r,reps:z,tol:M,badLanes:W,badPerRep:A,...D?{firstBad:D}:{}}}});const I=(e,o)=>(N(e&1048575,o)-512)/512,we=e=>{const o=new Uint16Array(e.length);for(let r=0;r<e.length;r++)o[r]=Se(e[r]);return o};async function de(e,{H:o,D:r,B:t,M:n,L:i,lens:l,sg:_,t:B="f32"}){const{device:b}=e,g=o*r,c=t*n,f=new Float32Array(c*g),P=new Float32Array(t*i*g),h=new Float32Array(t*i*g);for(let m=0;m<f.length;m++)f[m]=I(m,51);for(let m=0;m<P.length;m++)P[m]=I(m,52);for(let m=0;m<h.length;m++)h[m]=I(m,53);const F=1/Math.sqrt(r),M=new Float64Array(c*g);for(let m=0;m<t;m++)for(let p=0;p<n;p++){const R=m*n+p;for(let j=0;j<o;j++){const q=l[m],O=new Float64Array(q);for(let $=0;$<q;$++){let E=0;for(let L=0;L<r;L++)E+=f[R*g+j*r+L]*P[(m*i+$)*g+j*r+L];O[$]=E*F}const C=Math.max(...O),H=O.map($=>Math.exp($-C)),se=H.reduce(($,E)=>$+E,0);for(let $=0;$<r;$++){let E=0;for(let L=0;L<q;L++)E+=H[L]*h[(m*i+L)*g+j*r+$];M[R*g+j*r+$]=E/se}}}const W=ee(b,"attention",ke,{t:B,wg:128,sg:_,defines:{H:o,D:r,SCORES_CAP:352,ATTN_SCALE:F,Q_STRIDE:g,Q_OFF:0,KV_STRIDE:g,K_OFF:0,V_OFF:0}}),D=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,A=b.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(A.getMappedRange()).set([t,n,i,1,0,0,0,0]),A.unmap();const s=B==="f16"?2:4,u=[f,P,h].map(m=>K(b,B==="f16"?we(m):m,D)),a=K(b,new Uint32Array(l),D),G=b.createBuffer({size:c*g*s,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),k=b.createBindGroup({layout:W.getBindGroupLayout(0),entries:[A,...u,a,G].map((m,p)=>({binding:p,resource:{buffer:m}}))}),w=B==="f16"?.01:.001;let v=0,d=null;const y=[];for(let m=0;m<z;m++){const p=b.createCommandEncoder(),R=p.beginComputePass();R.setPipeline(W),R.setBindGroup(0,k),R.dispatchWorkgroups(c,o),R.end(),b.queue.submit([p.finish()]);const j=await V(b,G,c*g*s),q=B==="f16"?fe(new Uint16Array(j)):new Float32Array(j);let O=0;for(let C=0;C<M.length;C++)Math.abs(q[C]-M[C])<=w||(O++,d||(d={rep:m,i:C,got:q[C],want:M[C]}));y.push(O),v+=O}for(const m of[A,...u,a,G])m.destroy();return{pass:v===0,detail:{kernel:`attention (real, ${B}, sg, H${o} D${r})`,B:t,M:n,L:i,lens:l.join(","),reps:z,tol:w,badLanes:v,badPerRep:y,...d?{firstBad:d}:{}}}}S("adreno_probe6_attn_sg_h60_short",e=>e.hasSubgroups?de(e,{H:8,D:72,B:2,M:16,L:16,lens:[16,9],sg:!0}):{skip:!0,reason:"subgroups feature unavailable"});S("adreno_probe6_attn_sg_h60_long",e=>e.hasSubgroups?de(e,{H:8,D:72,B:2,M:4,L:224,lens:[224,131],sg:!0}):{skip:!0,reason:"subgroups feature unavailable"});S("adreno_probe6_rowln_sg_d576",async e=>{if(!e.hasSubgroups)return{skip:!0,reason:"subgroups feature unavailable"};const{device:o}=e,r=576,t=576,n=64,i=new Float32Array(n*r),l=new Float32Array(r*t),_=new Float32Array(t),B=new Float32Array(n*t),b=new Float32Array(t),g=new Float32Array(t);for(let a=0;a<i.length;a++)i[a]=I(a,61)*2;for(let a=0;a<l.length;a++)l[a]=I(a,62);for(let a=0;a<B.length;a++)B[a]=I(a,63)*2;for(let a=0;a<t;a++)_[a]=I(a,64),b[a]=1+I(a,65)/2,g[a]=I(a,66);const c=new Float64Array(n*t);for(let a=0;a<n;a++){const G=new Float64Array(t);let k=0;for(let y=0;y<t;y++){let m=0;for(let p=0;p<r;p++)m+=i[a*r+p]*l[p*t+y];G[y]=m+_[y]+B[a*t+y],k+=G[y]}const w=k/t;let v=0;for(let y=0;y<t;y++)v+=(G[y]-w)*(G[y]-w);const d=1/Math.sqrt(v/t+J);for(let y=0;y<t;y++)c[a*t+y]=b[y]*(G[y]-w)*d+g[y]}const f=ee(o,"gemm_row_ln",Ge,{t:"f32",wg:128,sg:!0,defines:{KDIM:r,D:t,EPS:J}}),P=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,h=o.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(h.getMappedRange()).set([n,0,0,0]),h.unmap();const F=[i,l,_,B,b,g].map(a=>K(o,a,P)),M=o.createBuffer({size:n*t*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),W=o.createBindGroup({layout:f.getBindGroupLayout(0),entries:[h,...F,M].map((a,G)=>({binding:G,resource:{buffer:a}}))}),D=.002;let A=0,s=null;const u=[];for(let a=0;a<z;a++){const G=o.createCommandEncoder(),k=G.beginComputePass();k.setPipeline(f),k.setBindGroup(0,W),k.dispatchWorkgroups(n),k.end(),o.queue.submit([G.finish()]);const w=new Float32Array(await V(o,M,n*t*4));let v=0;for(let d=0;d<c.length;d++)Math.abs(w[d]-c[d])<=D||(v++,s||(s={rep:a,i:d,got:w[d],want:c[d]}));u.push(v),A+=v}for(const a of[h,...F,M])a.destroy();return{pass:A===0,detail:{kernel:"gemm_row_ln (real, f32, sg, K=D=576)",M:n,reps:z,tol:D,badLanes:A,badPerRep:u,...s?{firstBad:s}:{}}}});S("adreno_probe7_attn_sg_h60_short_f16",e=>e.hasSubgroups?e.hasF16?de(e,{H:8,D:72,B:2,M:16,L:16,lens:[16,9],sg:!0,t:"f16"}):{skip:!0,reason:"no shader-f16"}:{skip:!0,reason:"subgroups feature unavailable"});S("adreno_probe7_attn_sg_h60_long_f16",e=>e.hasSubgroups?e.hasF16?de(e,{H:8,D:72,B:2,M:4,L:224,lens:[224,131],sg:!0,t:"f16"}):{skip:!0,reason:"no shader-f16"}:{skip:!0,reason:"subgroups feature unavailable"});S("adreno_probe7_addln_sg_d576_f16",async e=>{if(!e.hasSubgroups)return{skip:!0,reason:"subgroups feature unavailable"};if(!e.hasF16)return{skip:!0,reason:"no shader-f16"};const{device:o}=e,r=576,t=re,n=new Float32Array(t*r),i=new Float32Array(t*r),l=new Float32Array(r),_=new Float32Array(r);for(let s=0;s<t;s++)for(let u=0;u<r;u++)n[s*r+u]=Z(u,s)/2,i[s*r+u]=te(u,s)/2;for(let s=0;s<r;s++)l[s]=oe(s),_[s]=ae(s);const B=new Map,b=(s,u)=>{if(!B.has(s)){const a=new Float64Array(r);let G=0;for(let d=0;d<r;d++)a[d]=n[s*r+d]+i[s*r+d],G+=a[d];const k=G/r;let w=0;for(let d=0;d<r;d++)w+=(a[d]-k)*(a[d]-k);const v=1/Math.sqrt(w/r+J);B.set(s,a.map((d,y)=>l[y]*(d-k)*v+_[y]))}return B.get(s)[u]},g=ee(o,"add_ln",le,{t:"f16",wg:256,sg:!0,defines:{D:r,EPS:J}}),c=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,f=o.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(f.getMappedRange()).set([t,0,0,0]),f.unmap();const P=[n,i,l,_].map(s=>K(o,we(s),c)),h=o.createBuffer({size:t*r*2,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),F=o.createBindGroup({layout:g.getBindGroupLayout(0),entries:[f,...P,h].map((s,u)=>({binding:u,resource:{buffer:s}}))}),M=.02;let W=0,D=null;const A=[];for(let s=0;s<z;s++){const u=o.createCommandEncoder(),a=u.beginComputePass();a.setPipeline(g),a.setBindGroup(0,F),a.dispatchWorkgroups(t),a.end(),o.queue.submit([u.finish()]);const G=fe(new Uint16Array(await V(o,h,t*r*2)));let k=0;for(let w=0;w<t;w++)for(let v=0;v<r;v++){const d=b(w,v);Math.abs(G[w*r+v]-d)<=M||(k++,D||(D={rep:s,g:w,lane:v,got:G[w*r+v],want:d}))}A.push(k),W+=k}for(const s of[f,...P,h])s.destroy();return{pass:W===0,detail:{kernel:"add_ln (real, f16, sg, D=576)",rows:t,d:r,reps:z,tol:M,badLanes:W,badPerRep:A,...D?{firstBad:D}:{}}}});async function X(e,{H:o,D:r,QB:t,JB:n,B:i,M:l,L:_,lens:B,t:b="f16"}){const{device:g}=e,c=o*r,f=i*l,P=new Float32Array(f*c),h=new Float32Array(i*_*c),F=new Float32Array(i*_*c);for(let p=0;p<P.length;p++)P[p]=I(p,71);for(let p=0;p<h.length;p++)h[p]=I(p,72);for(let p=0;p<F.length;p++)F[p]=I(p,73);const M=1/Math.sqrt(r),W=new Float64Array(f*c);for(let p=0;p<i;p++)for(let R=0;R<l;R++){const j=p*l+R;for(let q=0;q<o;q++){const O=B[p],C=new Float64Array(O);for(let E=0;E<O;E++){let L=0;for(let Q=0;Q<r;Q++)L+=P[j*c+q*r+Q]*h[(p*_+E)*c+q*r+Q];C[E]=L*M}const H=Math.max(...C),se=C.map(E=>Math.exp(E-H)),$=se.reduce((E,L)=>E+L,0);for(let E=0;E<r;E++){let L=0;for(let Q=0;Q<O;Q++)L+=se[Q]*F[(p*_+Q)*c+q*r+E];W[j*c+q*r+E]=L/$}}}const D=ee(g,"attention_block",Be,{t:b,defines:{H:o,D:r,QB:t,JB:n,ATTN_SCALE:M,Q_STRIDE:c,Q_OFF:0,KV_STRIDE:c,K_OFF:0,V_OFF:0,PACKED:!1,NOPACKED:!0}}),A=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,s=g.createBuffer({size:32,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});new Uint32Array(s.getMappedRange()).set([i,l,_,1,0,0,0,0]),s.unmap();const u=b==="f16"?2:4,a=[P,h,F].map(p=>K(g,b==="f16"?we(p):p,A)),G=K(g,new Uint32Array(B),A),k=g.createBuffer({size:f*c*u,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),w=g.createBindGroup({layout:D.getBindGroupLayout(0),entries:[s,...a,G,k].map((p,R)=>({binding:R,resource:{buffer:p}}))}),v=b==="f16"?.01:.001;let d=0,y=null;const m=[];for(let p=0;p<z;p++){const R=g.createCommandEncoder(),j=R.beginComputePass();j.setPipeline(D),j.setBindGroup(0,w),j.dispatchWorkgroups(Math.ceil(l/t),o,i),j.end(),g.queue.submit([R.finish()]);const q=await V(g,k,f*c*u),O=b==="f16"?fe(new Uint16Array(q)):new Float32Array(q);let C=0;for(let H=0;H<W.length;H++)Math.abs(O[H]-W[H])<=v||(C++,y||(y={rep:p,i:H,got:O[H],want:W[H]}));m.push(C),d+=C}for(const p of[s,...a,G,k])p.destroy();return{pass:d===0,detail:{kernel:`attention_block (real, ${b}, H${o} D${r} QB${t} JB${n})`,B:i,M:l,L:_,lens:B.join(","),reps:z,tol:v,badLanes:d,badPerRep:m,...y?{firstBad:y}:{}}}}S("adreno_probe8_attnblock_h60_f16",e=>e.hasF16?X(e,{H:8,D:72,QB:14,JB:32,B:2,M:33,L:33,lens:[33,17],t:"f16"}):{skip:!0,reason:"no shader-f16"});S("adreno_probe8_attnblock_h60_big_f16",e=>e.hasF16?X(e,{H:8,D:72,QB:14,JB:32,B:2,M:96,L:96,lens:[96,49],t:"f16"}):{skip:!0,reason:"no shader-f16"});S("adreno_probe8_weights_hash",async()=>{const e=(t,n)=>{for(let i=0;i<n.length;i++)t^=n[i],t=Math.imul(t,16777619)>>>0;return t},o=async t=>{const i=(await(await fetch(`${t}/manifest.json`)).json()).bins??["weights.bin"];let l=2166136261,_=0;for(const B of i){const b=new Uint8Array(await(await fetch(`${t}/${B}`)).arrayBuffer());_+=b.length,l=e(l,b)}return{hash:l.toString(16),bytes:_,bins:i.length}},r={moxhi:await o("/weights")};try{r.hachimi60=await o("/weights/hachimi60")}catch(t){r.hachimi60={error:String(t?.message??t)}}return{pass:!0,detail:r}});S("adreno_probe8b_attnblock_h60_qb8",e=>e.hasF16?X(e,{H:8,D:72,QB:8,JB:32,B:2,M:33,L:33,lens:[33,17],t:"f16"}):{skip:!0,reason:"no shader-f16"});S("adreno_probe8b_attnblock_h60_qb12",e=>e.hasF16?X(e,{H:8,D:72,QB:12,JB:32,B:2,M:33,L:33,lens:[33,17],t:"f16"}):{skip:!0,reason:"no shader-f16"});S("adreno_probe8b_attnblock_h60_qb14_jb16",e=>e.hasF16?X(e,{H:8,D:72,QB:14,JB:16,B:2,M:33,L:33,lens:[33,17],t:"f16"}):{skip:!0,reason:"no shader-f16"});S("adreno_probe8b_attnblock_h60_qb14_f32",e=>X(e,{H:8,D:72,QB:14,JB:32,B:2,M:33,L:33,lens:[33,17],t:"f32"}));S("adreno_probe8b_attnblock_d56_qb14",e=>e.hasF16?X(e,{H:8,D:56,QB:14,JB:32,B:2,M:33,L:33,lens:[33,17],t:"f16"}):{skip:!0,reason:"no shader-f16"});
393
+ //# sourceMappingURL=adreno_probe-CqGqVTv4.js.map
assets/{adreno_probe-Cmg7uBSr.js.map → adreno_probe-CqGqVTv4.js.map} RENAMED
The diff for this file is too large to render. See raw diff
 
assets/app_stage-BHS27TUf.js DELETED
@@ -1,2 +0,0 @@
1
- import{r as K}from"./debug-C_LNzFrK.js";import{l as L}from"./weights-D8qtuKag.js";import{l as U,t as V}from"./tokenizer-Ex1u7wXD.js";import{t as X}from"./generate-BIP3NpbY.js";import{autotuneRouting as Y,tunedOptions as Z}from"./autotune-DywP5DSc.js";import{e as $}from"./shortlist-C151mR5c.js";import{g as tt}from"./constants-C8VbFpic.js";import{t as et,s as st,p as ot}from"./t2s-DjPa3Hpi.js";import{l as nt,p as rt}from"./engine-D57xjIIN.js";import{c as at}from"./chapter3k-DSdzHZt5.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./shapes-BCQ9D81L.js";import"./f16-wKKZr58e.js";import"./encoder-I9sHImnR.js";import"./pipelines-DJ7cc1m-.js";import"./decoder-CI9o-EVx.js";import"./device-BotbBNoe.js";const ct=a=>{const c=[...a].sort((f,d)=>f-d),s=c.length>>1;return c.length%2?c[s]:(c[s-1]+c[s])/2},M=a=>Math.round(a*10)/10;K("app_stage",async a=>{const{device:c}=a;if(!a.hasF16)return{skip:!0,reason:"production stack needs shader-f16"};let s=null,f="chapter3k×48";try{const l=await fetch("/local/qingshan.txt");l.ok&&(s=await l.text(),f="qingshan_local")}catch{}s||(s=at.repeat(48));const d=await U(),g=await L(c,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0,projWT:!0,lmHeadIds:$(d.idToToken)});try{const l={...a,dtype:"f16"},q=performance.now(),{tuned:E}=await Y(l,g),F=performance.now()-q,H=performance.now(),N=et(s),O=st(N.text),n=ot(O.sentences,O.paras,200).rows,T=n.map(o=>o.length),G=performance.now()-H,z=async o=>{const h=nt(T),i=rt(h.map(t=>T[t]),l,2),e={tokenizeMs:0,encoderMs:0,decodeMs:0,detokMs:0,gapMs:0},v=new Array(n.length),C=[];let j=0,B=0,S=0,W=0;const A=performance.now();let b=A;for(let t=0;t<i.length;t++){const[r,I]=i[t],R=h.slice(r,I),_=performance.now();e.gapMs+=_-b;const{rows:J,metrics:p}=await X(l,g,d,R.map(m=>n[m]),{...Z(E,I-r),maxNewTokens:tt,overlapEnc:o,onPrimed:o&&t+1<i.length?()=>{const m=h.slice(i[t+1][0],i[t+1][1]);V(d,m.map(y=>n[y])).catch(()=>{})}:null});b=performance.now(),C.push(b-_),J.forEach((m,y)=>{v[R[y]]=m.text.normalize("NFC"),m.forcedEos&&W++}),e.tokenizeMs+=p.tokenizeMs,e.encoderMs+=p.encoderMs,e.decodeMs+=p.decodeMs,e.detokMs+=p.detokMs,j+=p.tokensGenerated,B+=p.steps,S+=p.compactions}const u=performance.now()-A,Q=e.tokenizeMs+e.encoderMs+e.decodeMs+e.detokMs+e.gapMs,D=t=>M(t/u*100);return{batches:i.length,maxB:Math.max(...i.map(([t,r])=>r-t)),wallMs:Math.round(u),wallCharsPerSec:Math.round(s.length/u*1e3),gpuOnlyCharsPerSec:Math.round(s.length/(e.encoderMs+e.decodeMs)*1e3),tokens:j,steps:B,compactions:S,forcedEos:W,stagesMs:Object.fromEntries(Object.entries(e).map(([t,r])=>[t,Math.round(r)])),stagesPct:{...Object.fromEntries(Object.entries(e).map(([t,r])=>[t,D(r)])),otherMs:D(u-Q)},batchWallMedianMs:M(ct(C)),texts:v}},w=await z(!1),k=await z(!0);let x=0;for(let o=0;o<n.length;o++)w.texts[o]!==k.texts[o]&&x++;const P=({texts:o,...h})=>h;return{pass:!0,detail:{source:f,chars:s.length,rows:n.length,avgRowChars:M(s.length/n.length),autotuneMs:Math.round(F),prepMs:Math.round(G),drained:P(w),overlap:P(k),overlapSpeedup:M(w.wallMs/k.wallMs),mismatchRows:x,mismatchPct:M(x/n.length*100),tuned:E}}}finally{g.buffer.destroy()}},{slow:!0});
2
- //# sourceMappingURL=app_stage-BHS27TUf.js.map
 
 
 
assets/app_stage-DrqfcKH2.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import{r as K}from"./debug-CPpXXfWA.js";import{l as L}from"./weights-DxIJF1EY.js";import{l as U,t as V}from"./tokenizer-BmI7pHmp.js";import{t as X}from"./generate-Ca3ORHiA.js";import{autotuneRouting as Y,tunedOptions as Z}from"./autotune-Bwt_lWMv.js";import{e as $}from"./shortlist-C151mR5c.js";import{f as tt}from"./constants-CSVWRdrh.js";import{t as et,s as st,p as ot}from"./t2s-DjPa3Hpi.js";import{b as nt,p as rt}from"./engine-C4r8fF2d.js";import{c as at}from"./chapter3k-DSdzHZt5.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./safe_storage-BYkOahew.js";import"./shapes-ClGtK-ia.js";import"./f16-wKKZr58e.js";import"./encoder-CZXKGzzg.js";import"./pipelines-BbLc75sB.js";import"./decoder-BUiaGDqb.js";import"./device-BotbBNoe.js";const ct=a=>{const c=[...a].sort((M,d)=>M-d),s=c.length>>1;return c.length%2?c[s]:(c[s-1]+c[s])/2},f=a=>Math.round(a*10)/10;K("app_stage",async a=>{const{device:c}=a;if(!a.hasF16)return{skip:!0,reason:"production stack needs shader-f16"};let s=null,M="chapter3k×48";try{const l=await fetch("/local/qingshan.txt");l.ok&&(s=await l.text(),M="qingshan_local")}catch{}s||(s=at.repeat(48));const d=await U(),g=await L(c,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0,projWT:!0,lmHeadIds:$(d.idToToken)});try{const l={...a,dtype:"f16"},q=performance.now(),{tuned:E}=await Y(l,g),F=performance.now()-q,H=performance.now(),N=et(s),O=st(N.text),n=ot(O.sentences,O.paras,200).rows,T=n.map(o=>o.length),G=performance.now()-H,z=async o=>{const h=nt(T),i=rt(h.map(t=>T[t]),l,2),e={tokenizeMs:0,encoderMs:0,decodeMs:0,detokMs:0,gapMs:0},v=new Array(n.length),C=[];let j=0,B=0,S=0,W=0;const A=performance.now();let b=A;for(let t=0;t<i.length;t++){const[r,I]=i[t],R=h.slice(r,I),_=performance.now();e.gapMs+=_-b;const{rows:J,metrics:p}=await X(l,g,d,R.map(m=>n[m]),{...Z(E,I-r),maxNewTokens:tt,overlapEnc:o,onPrimed:o&&t+1<i.length?()=>{const m=h.slice(i[t+1][0],i[t+1][1]);V(d,m.map(y=>n[y])).catch(()=>{})}:null});b=performance.now(),C.push(b-_),J.forEach((m,y)=>{v[R[y]]=m.text.normalize("NFC"),m.forcedEos&&W++}),e.tokenizeMs+=p.tokenizeMs,e.encoderMs+=p.encoderMs,e.decodeMs+=p.decodeMs,e.detokMs+=p.detokMs,j+=p.tokensGenerated,B+=p.steps,S+=p.compactions}const u=performance.now()-A,Q=e.tokenizeMs+e.encoderMs+e.decodeMs+e.detokMs+e.gapMs,D=t=>f(t/u*100);return{batches:i.length,maxB:Math.max(...i.map(([t,r])=>r-t)),wallMs:Math.round(u),wallCharsPerSec:Math.round(s.length/u*1e3),gpuOnlyCharsPerSec:Math.round(s.length/(e.encoderMs+e.decodeMs)*1e3),tokens:j,steps:B,compactions:S,forcedEos:W,stagesMs:Object.fromEntries(Object.entries(e).map(([t,r])=>[t,Math.round(r)])),stagesPct:{...Object.fromEntries(Object.entries(e).map(([t,r])=>[t,D(r)])),otherMs:D(u-Q)},batchWallMedianMs:f(ct(C)),texts:v}},w=await z(!1),k=await z(!0);let x=0;for(let o=0;o<n.length;o++)w.texts[o]!==k.texts[o]&&x++;const P=({texts:o,...h})=>h;return{pass:!0,detail:{source:M,chars:s.length,rows:n.length,avgRowChars:f(s.length/n.length),autotuneMs:Math.round(F),prepMs:Math.round(G),drained:P(w),overlap:P(k),overlapSpeedup:f(w.wallMs/k.wallMs),mismatchRows:x,mismatchPct:f(x/n.length*100),tuned:E}}}finally{g.buffer.destroy()}},{slow:!0});
2
+ //# sourceMappingURL=app_stage-DrqfcKH2.js.map
assets/{app_stage-BHS27TUf.js.map → app_stage-DrqfcKH2.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"file":"app_stage-BHS27TUf.js","sources":["../../src/debug/tests/app_stage.js"],"sourcesContent":["// app_stage: wall-clock stage breakdown of the app's FILE-mode pipeline on a\r\n// large text, as an A/B over one batching/pipelining axis per round. Both\r\n// arms translate in LENGTH order with the S-aware cap (production since\r\n// 137e3e4 — the sort round measured 2.02×, the cap round 1.21×; both retired\r\n// to notes-m4-tuning.md). The axis under test now is the PIPELINE BUBBLES:\r\n// drained (overlapEnc:false, no pre-tokenize — the old behavior) vs overlap\r\n// (decode groups recorded while the GPU still encodes + the next batch\r\n// pre-tokenized into the SPM LRU at onPrimed). Both arms mirror\r\n// translateText exactly (t2s → segment → pack200 → planBatches →\r\n// translateBatch with tunedOptions + maxNewTokens=DECODE_CAP + NFC).\r\n//\r\n// Row texts may legally differ between arms on near-tie argmaxes (batch\r\n// shape changes routing thresholds and reduction order — the known f16\r\n// reality); mismatchPct in the detail tracks how many rows flipped. In the\r\n// overlap arm the per-stage sums double-count a few ms per batch\r\n// (encoderMs/decodeMs overlap by design) — wallMs is the honest number.\r\n//\r\n// Text source: /local/qingshan.txt when present (a real novel dropped into\r\n// public/local/ — NOT committed), else chapter3k × 48 (~141k chars).\r\nimport { registerTest } from '../registry.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { loadTokenizer, tokenizeBatch } from '../../engine/tokenizer.js';\r\nimport { translateBatch } from '../../engine/generate.js';\r\nimport { autotuneRouting, tunedOptions } from '../../engine/autotune.js';\r\nimport { emittableIds } from '../../engine/shortlist.js';\r\nimport { DECODE_CAP } from '../../engine/constants.js';\r\nimport { segmentSource, packSentences } from '../../app/split.js';\r\nimport { planBatches, lengthOrder } from '../../app/engine.js';\r\nimport { t2s } from '../../app/t2s.js';\r\nimport chapterText from '../../../fixtures/chapter3k.txt?raw';\r\n\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\nconst r1 = (x) => Math.round(x * 10) / 10;\r\n\r\nregisterTest('app_stage', async (ctx) => {\r\n const { device } = ctx;\r\n if (!ctx.hasF16) return { skip: true, reason: 'production stack needs shader-f16' };\r\n\r\n let text = null;\r\n let source = 'chapter3k×48';\r\n try {\r\n const res = await fetch('/local/qingshan.txt');\r\n if (res.ok) {\r\n text = await res.text();\r\n source = 'qingshan_local';\r\n }\r\n } catch { /* fall through to the fixture */ }\r\n if (!text) text = chapterText.repeat(48);\r\n\r\n // Mirror production (src/app/engine.js): tokenizer first, its emittable\r\n // classification feeds the shortlisted q8 lm_head — both arms carry it, the\r\n // A/B axis here stays the pipeline bubbles.\r\n const tok = await loadTokenizer();\r\n const weights = await loadWeights(device, '/weights', {\r\n targetDtype: 'f16', lmHeadQ8: true, ffnWT: true, projWT: true,\r\n lmHeadIds: emittableIds(tok.idToToken),\r\n });\r\n try {\r\n const gctx = { ...ctx, dtype: 'f16' };\r\n const tTune0 = performance.now();\r\n const { tuned } = await autotuneRouting(gctx, weights);\r\n const autotuneMs = performance.now() - tTune0;\r\n\r\n // -- prep: exactly translateText's front half (shared by both arms) --\r\n const tPrep0 = performance.now();\r\n const conv = t2s(text);\r\n const seg = segmentSource(conv.text);\r\n const packed = packSentences(seg.sentences, seg.paras, 200);\r\n const rows = packed.rows;\r\n const lens = rows.map((r) => r.length);\r\n const prepMs = performance.now() - tPrep0;\r\n\r\n const runArm = async (overlap) => {\r\n const order = lengthOrder(lens);\r\n const ranges = planBatches(order.map((i) => lens[i]), gctx, 2);\r\n const stages = { tokenizeMs: 0, encoderMs: 0, decodeMs: 0, detokMs: 0, gapMs: 0 };\r\n const texts = new Array(rows.length);\r\n const batchWalls = [];\r\n let tokens = 0;\r\n let steps = 0;\r\n let compactions = 0;\r\n let forcedEos = 0;\r\n const t0 = performance.now();\r\n let lastEnd = t0;\r\n for (let bi = 0; bi < ranges.length; bi++) {\r\n const [s, e] = ranges[bi];\r\n const idx = order.slice(s, e);\r\n const tB0 = performance.now();\r\n stages.gapMs += tB0 - lastEnd;\r\n const { rows: out, metrics } = await translateBatch(\r\n gctx, weights, tok, idx.map((i) => rows[i]),\r\n {\r\n ...tunedOptions(tuned, e - s), maxNewTokens: DECODE_CAP,\r\n overlapEnc: overlap,\r\n onPrimed: overlap && bi + 1 < ranges.length ? () => {\r\n const nIdx = order.slice(ranges[bi + 1][0], ranges[bi + 1][1]);\r\n tokenizeBatch(tok, nIdx.map((i) => rows[i])).catch(() => {});\r\n } : null,\r\n },\r\n );\r\n lastEnd = performance.now();\r\n batchWalls.push(lastEnd - tB0);\r\n // app cost parity: NFC-normalize every row like translateText does\r\n out.forEach((r, i) => {\r\n texts[idx[i]] = r.text.normalize('NFC');\r\n if (r.forcedEos) forcedEos++;\r\n });\r\n stages.tokenizeMs += metrics.tokenizeMs;\r\n stages.encoderMs += metrics.encoderMs;\r\n stages.decodeMs += metrics.decodeMs;\r\n stages.detokMs += metrics.detokMs;\r\n tokens += metrics.tokensGenerated;\r\n steps += metrics.steps;\r\n compactions += metrics.compactions;\r\n }\r\n const wallMs = performance.now() - t0;\r\n const sumMs = stages.tokenizeMs + stages.encoderMs + stages.decodeMs\r\n + stages.detokMs + stages.gapMs;\r\n const pctOf = (v) => r1((v / wallMs) * 100);\r\n return {\r\n batches: ranges.length,\r\n maxB: Math.max(...ranges.map(([s, e]) => e - s)),\r\n wallMs: Math.round(wallMs),\r\n wallCharsPerSec: Math.round((text.length / wallMs) * 1000),\r\n gpuOnlyCharsPerSec: Math.round((text.length / (stages.encoderMs + stages.decodeMs)) * 1000),\r\n tokens,\r\n steps,\r\n compactions,\r\n forcedEos,\r\n stagesMs: Object.fromEntries(Object.entries(stages).map(([k, v]) => [k, Math.round(v)])),\r\n stagesPct: {\r\n ...Object.fromEntries(Object.entries(stages).map(([k, v]) => [k, pctOf(v)])),\r\n otherMs: pctOf(wallMs - sumMs),\r\n },\r\n batchWallMedianMs: r1(median(batchWalls)),\r\n texts,\r\n };\r\n };\r\n\r\n // baseline (drained) first, overlap second — the hot-GPU penalty lands\r\n // on the candidate arm, so an overlap win is a floor, not thermal luck.\r\n const drained = await runArm(false);\r\n const overlap = await runArm(true);\r\n let mismatch = 0;\r\n for (let i = 0; i < rows.length; i++) {\r\n if (drained.texts[i] !== overlap.texts[i]) mismatch++;\r\n }\r\n const strip = ({ texts, ...rest }) => rest;\r\n\r\n return {\r\n pass: true,\r\n detail: {\r\n source,\r\n chars: text.length,\r\n rows: rows.length,\r\n avgRowChars: r1(text.length / rows.length),\r\n autotuneMs: Math.round(autotuneMs),\r\n prepMs: Math.round(prepMs),\r\n drained: strip(drained),\r\n overlap: strip(overlap),\r\n overlapSpeedup: r1(drained.wallMs / overlap.wallMs),\r\n mismatchRows: mismatch,\r\n mismatchPct: r1((mismatch / rows.length) * 100),\r\n tuned,\r\n },\r\n };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n}, { slow: true });\r\n"],"names":["median","xs","s","a","b","m","r1","x","registerTest","ctx","device","text","source","res","chapterText","tok","loadTokenizer","weights","loadWeights","emittableIds","gctx","tTune0","tuned","autotuneRouting","autotuneMs","tPrep0","conv","t2s","seg","segmentSource","rows","packSentences","lens","r","prepMs","runArm","overlap","order","lengthOrder","ranges","planBatches","i","stages","texts","batchWalls","tokens","steps","compactions","forcedEos","t0","lastEnd","bi","e","idx","tB0","out","metrics","translateBatch","tunedOptions","DECODE_CAP","nIdx","tokenizeBatch","wallMs","sumMs","pctOf","v","k","drained","mismatch","strip","rest"],"mappings":"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"}
 
1
+ {"version":3,"file":"app_stage-DrqfcKH2.js","sources":["../../src/debug/tests/app_stage.js"],"sourcesContent":["// app_stage: wall-clock stage breakdown of the app's FILE-mode pipeline on a\r\n// large text, as an A/B over one batching/pipelining axis per round. Both\r\n// arms translate in LENGTH order with the S-aware cap (production since\r\n// 137e3e4 — the sort round measured 2.02×, the cap round 1.21×; both retired\r\n// to notes-m4-tuning.md). The axis under test now is the PIPELINE BUBBLES:\r\n// drained (overlapEnc:false, no pre-tokenize — the old behavior) vs overlap\r\n// (decode groups recorded while the GPU still encodes + the next batch\r\n// pre-tokenized into the SPM LRU at onPrimed). Both arms mirror\r\n// translateText exactly (t2s → segment → pack200 → planBatches →\r\n// translateBatch with tunedOptions + maxNewTokens=DECODE_CAP + NFC).\r\n//\r\n// Row texts may legally differ between arms on near-tie argmaxes (batch\r\n// shape changes routing thresholds and reduction order — the known f16\r\n// reality); mismatchPct in the detail tracks how many rows flipped. In the\r\n// overlap arm the per-stage sums double-count a few ms per batch\r\n// (encoderMs/decodeMs overlap by design) — wallMs is the honest number.\r\n//\r\n// Text source: /local/qingshan.txt when present (a real novel dropped into\r\n// public/local/ — NOT committed), else chapter3k × 48 (~141k chars).\r\nimport { registerTest } from '../registry.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { loadTokenizer, tokenizeBatch } from '../../engine/tokenizer.js';\r\nimport { translateBatch } from '../../engine/generate.js';\r\nimport { autotuneRouting, tunedOptions } from '../../engine/autotune.js';\r\nimport { emittableIds } from '../../engine/shortlist.js';\r\nimport { DECODE_CAP } from '../../engine/constants.js';\r\nimport { segmentSource, packSentences } from '../../app/split.js';\r\nimport { planBatches, lengthOrder } from '../../app/engine.js';\r\nimport { t2s } from '../../app/t2s.js';\r\nimport chapterText from '../../../fixtures/chapter3k.txt?raw';\r\n\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\nconst r1 = (x) => Math.round(x * 10) / 10;\r\n\r\nregisterTest('app_stage', async (ctx) => {\r\n const { device } = ctx;\r\n if (!ctx.hasF16) return { skip: true, reason: 'production stack needs shader-f16' };\r\n\r\n let text = null;\r\n let source = 'chapter3k×48';\r\n try {\r\n const res = await fetch('/local/qingshan.txt');\r\n if (res.ok) {\r\n text = await res.text();\r\n source = 'qingshan_local';\r\n }\r\n } catch { /* fall through to the fixture */ }\r\n if (!text) text = chapterText.repeat(48);\r\n\r\n // Mirror production (src/app/engine.js): tokenizer first, its emittable\r\n // classification feeds the shortlisted q8 lm_head — both arms carry it, the\r\n // A/B axis here stays the pipeline bubbles.\r\n const tok = await loadTokenizer();\r\n const weights = await loadWeights(device, '/weights', {\r\n targetDtype: 'f16', lmHeadQ8: true, ffnWT: true, projWT: true,\r\n lmHeadIds: emittableIds(tok.idToToken),\r\n });\r\n try {\r\n const gctx = { ...ctx, dtype: 'f16' };\r\n const tTune0 = performance.now();\r\n const { tuned } = await autotuneRouting(gctx, weights);\r\n const autotuneMs = performance.now() - tTune0;\r\n\r\n // -- prep: exactly translateText's front half (shared by both arms) --\r\n const tPrep0 = performance.now();\r\n const conv = t2s(text);\r\n const seg = segmentSource(conv.text);\r\n const packed = packSentences(seg.sentences, seg.paras, 200);\r\n const rows = packed.rows;\r\n const lens = rows.map((r) => r.length);\r\n const prepMs = performance.now() - tPrep0;\r\n\r\n const runArm = async (overlap) => {\r\n const order = lengthOrder(lens);\r\n const ranges = planBatches(order.map((i) => lens[i]), gctx, 2);\r\n const stages = { tokenizeMs: 0, encoderMs: 0, decodeMs: 0, detokMs: 0, gapMs: 0 };\r\n const texts = new Array(rows.length);\r\n const batchWalls = [];\r\n let tokens = 0;\r\n let steps = 0;\r\n let compactions = 0;\r\n let forcedEos = 0;\r\n const t0 = performance.now();\r\n let lastEnd = t0;\r\n for (let bi = 0; bi < ranges.length; bi++) {\r\n const [s, e] = ranges[bi];\r\n const idx = order.slice(s, e);\r\n const tB0 = performance.now();\r\n stages.gapMs += tB0 - lastEnd;\r\n const { rows: out, metrics } = await translateBatch(\r\n gctx, weights, tok, idx.map((i) => rows[i]),\r\n {\r\n ...tunedOptions(tuned, e - s), maxNewTokens: DECODE_CAP,\r\n overlapEnc: overlap,\r\n onPrimed: overlap && bi + 1 < ranges.length ? () => {\r\n const nIdx = order.slice(ranges[bi + 1][0], ranges[bi + 1][1]);\r\n tokenizeBatch(tok, nIdx.map((i) => rows[i])).catch(() => {});\r\n } : null,\r\n },\r\n );\r\n lastEnd = performance.now();\r\n batchWalls.push(lastEnd - tB0);\r\n // app cost parity: NFC-normalize every row like translateText does\r\n out.forEach((r, i) => {\r\n texts[idx[i]] = r.text.normalize('NFC');\r\n if (r.forcedEos) forcedEos++;\r\n });\r\n stages.tokenizeMs += metrics.tokenizeMs;\r\n stages.encoderMs += metrics.encoderMs;\r\n stages.decodeMs += metrics.decodeMs;\r\n stages.detokMs += metrics.detokMs;\r\n tokens += metrics.tokensGenerated;\r\n steps += metrics.steps;\r\n compactions += metrics.compactions;\r\n }\r\n const wallMs = performance.now() - t0;\r\n const sumMs = stages.tokenizeMs + stages.encoderMs + stages.decodeMs\r\n + stages.detokMs + stages.gapMs;\r\n const pctOf = (v) => r1((v / wallMs) * 100);\r\n return {\r\n batches: ranges.length,\r\n maxB: Math.max(...ranges.map(([s, e]) => e - s)),\r\n wallMs: Math.round(wallMs),\r\n wallCharsPerSec: Math.round((text.length / wallMs) * 1000),\r\n gpuOnlyCharsPerSec: Math.round((text.length / (stages.encoderMs + stages.decodeMs)) * 1000),\r\n tokens,\r\n steps,\r\n compactions,\r\n forcedEos,\r\n stagesMs: Object.fromEntries(Object.entries(stages).map(([k, v]) => [k, Math.round(v)])),\r\n stagesPct: {\r\n ...Object.fromEntries(Object.entries(stages).map(([k, v]) => [k, pctOf(v)])),\r\n otherMs: pctOf(wallMs - sumMs),\r\n },\r\n batchWallMedianMs: r1(median(batchWalls)),\r\n texts,\r\n };\r\n };\r\n\r\n // baseline (drained) first, overlap second — the hot-GPU penalty lands\r\n // on the candidate arm, so an overlap win is a floor, not thermal luck.\r\n const drained = await runArm(false);\r\n const overlap = await runArm(true);\r\n let mismatch = 0;\r\n for (let i = 0; i < rows.length; i++) {\r\n if (drained.texts[i] !== overlap.texts[i]) mismatch++;\r\n }\r\n const strip = ({ texts, ...rest }) => rest;\r\n\r\n return {\r\n pass: true,\r\n detail: {\r\n source,\r\n chars: text.length,\r\n rows: rows.length,\r\n avgRowChars: r1(text.length / rows.length),\r\n autotuneMs: Math.round(autotuneMs),\r\n prepMs: Math.round(prepMs),\r\n drained: strip(drained),\r\n overlap: strip(overlap),\r\n overlapSpeedup: r1(drained.wallMs / overlap.wallMs),\r\n mismatchRows: mismatch,\r\n mismatchPct: r1((mismatch / rows.length) * 100),\r\n tuned,\r\n },\r\n };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n}, { slow: true });\r\n"],"names":["median","xs","s","a","b","m","r1","x","registerTest","ctx","device","text","source","res","chapterText","tok","loadTokenizer","weights","loadWeights","emittableIds","gctx","tTune0","tuned","autotuneRouting","autotuneMs","tPrep0","conv","t2s","seg","segmentSource","rows","packSentences","lens","r","prepMs","runArm","overlap","order","lengthOrder","ranges","planBatches","i","stages","texts","batchWalls","tokens","steps","compactions","forcedEos","t0","lastEnd","bi","e","idx","tB0","out","metrics","translateBatch","tunedOptions","DECODE_CAP","nIdx","tokenizeBatch","wallMs","sumMs","pctOf","v","k","drained","mismatch","strip","rest"],"mappings":"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"}
assets/argmax-CQZtdTcb.js DELETED
@@ -1,2 +0,0 @@
1
- import{r as g}from"./debug-C_LNzFrK.js";import{c as b,r as P}from"./gpu-utils-BTh3AGTJ.js";import{g as V,f as H}from"./pipelines-DJ7cc1m-.js";import{p as I}from"./math-DNG-wiC0.js";import{V as K,B as q,P as O,e as d,R as M}from"./constants-C8VbFpic.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";const u=K,c=q,j=256;function J(n){let a=n>>>0;return()=>{a=a+1831565813|0;let t=Math.imul(a^a>>>15,1|a);return t=t+Math.imul(t^t>>>7,61|t)^t,((t^t>>>14)>>>0)/4294967296}}function B(n,a){const t=new Float32Array(n*u);return a.forEach((s,o)=>{for(const[r,e]of s)t[o*u+r]=Math.fround(e)}),t}function R(n,a,t){n[a*c+(t>>5)]|=1<<(t&31)}function w(n,a,t){return n[a*c+(t>>5)]>>>(t&31)&1}function p(n,{B:a,bias:t,bitmask:s,done:o}){const r=new Uint32Array(n.length*a);let e=s,i=o;return n.forEach((l,f)=>{const k=I(l,t,e,i,{B:a,V:u,penalty:M});r.set(k.tokens,f*a),e=k.newBitmaskWords,i=k.newDone}),{tokens:r,done:i,bitmask:e}}function Q(n,a){const t=n.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});return new Uint32Array(t.getMappedRange()).set(a),t.unmap(),t}async function m(n,{B:a,stepsLogits:t,bias:s,bitmask:o,done:r}){const e=t.length,i=V(n,"argmax_penalty",H,{wg:j,defines:{V:u,EOS:d,PAD:O,PENALTY:M,MASK_WORDS:c,SHORT:!1,NOSHORT:!0}}),l=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,f=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,k=b(n,s??new Float32Array(u),f),U=b(n,o??new Uint32Array(a*c),l),_=b(n,r??new Uint32Array(a),l),h=b(n,new Uint32Array(e*a).fill(3735928559),l),T=[],S=n.createCommandEncoder(),A=S.beginComputePass();A.setPipeline(i),t.forEach((x,W)=>{const G=Q(n,[a,W,0,0]),E=b(n,x,f);T.push(G,E);const N=n.createBindGroup({layout:i.getBindGroupLayout(0),entries:[G,E,k,U,_,h].map((Y,z)=>({binding:z,resource:{buffer:Y}}))});A.setBindGroup(0,N),A.dispatchWorkgroups(a)}),A.end(),n.queue.submit([S.finish()]);const F=new Uint32Array(await P(n,h,e*a*4)),C=new Uint32Array(await P(n,_,a*4)),L=new Uint32Array(await P(n,U,a*c*4));for(const x of[k,U,_,h,...T])x.destroy();return{tokens:F,done:C,bitmask:L}}function D(n,a){let t=0,s=-1;for(let o=0;o<a.length;o++)n[o]!==a[o]&&(t++,s<0&&(s=o));return{mismatches:t,first:s}}function y(n,a,t,s=[]){const o={...t};let r=!0;for(const[e,i]of[["tokens",a.tokens],["done",a.done],["bitmask",a.bitmask]]){const{mismatches:l,first:f}=D(n[e],i);l>0&&(r=!1,o[e]={mismatches:l,first:f,got:n[e][f],want:i[f]})}for(const[e,i,l]of s)i!==l&&(r=!1,o[e]={got:i,want:l});return{pass:r,detail:o}}g("argmax_random",async({device:n})=>{const t=J(1207),s=new Float32Array(4*u);for(let i=0;i<s.length;i++)s[i]=Math.fround((t()-.5)*20);const r=await m(n,{...{B:4,bias:null,bitmask:null,done:null},stepsLogits:[s]}),e=p([s],{B:4,bias:new Float32Array(u),bitmask:new Uint32Array(4*c),done:new Uint32Array(4)});return y(r,e,{kernel:"argmax_penalty",B:4,V:u,tokens:Array.from(r.tokens)})});g("argmax_penalty_flip",async({device:n})=>{const t=B(1,[[[7,5],[100,4.5]]]),s=new Uint32Array(1*c);R(s,0,7);const o=await m(n,{B:1,stepsLogits:[t],bias:null,bitmask:s,done:null}),r=p([t],{B:1,bias:new Float32Array(u),bitmask:s,done:new Uint32Array(1)});return y(o,r,{kernel:"argmax_penalty",case:"penalty_flip"},[["token",o.tokens[0],100]])});g("argmax_bias",async({device:n})=>{const t=B(1,[[[10,3],[200,2.5]]]),s=new Float32Array(u);s[200]=1;const o=await m(n,{B:1,stepsLogits:[t],bias:null,bitmask:null,done:null}),r=await m(n,{B:1,stepsLogits:[t],bias:s,bitmask:null,done:null}),e=p([t],{B:1,bias:s,bitmask:new Uint32Array(1*c),done:new Uint32Array(1)});return y(r,e,{kernel:"argmax_penalty",case:"bias"},[["zeroBiasToken",o.tokens[0],10],["biasedToken",r.tokens[0],200]])});g("argmax_done_row",async({device:n})=>{const t=B(3,[[[6,2]],[[7,9]],[[500,1.5]]]),s=new Uint32Array(3*c);R(s,1,7),R(s,1,12345);const o=Uint32Array.of(0,1,0),r=Uint32Array.from(s),e=await m(n,{B:3,stepsLogits:[t],bias:null,bitmask:s,done:o}),i=p([t],{B:3,bias:new Float32Array(u),bitmask:s,done:o}),l=D(e.bitmask.slice(c,2*c),r.slice(c,2*c));return y(e,i,{kernel:"argmax_penalty",case:"done_row"},[["row0Token",e.tokens[0],6],["row1Token",e.tokens[1],O],["row2Token",e.tokens[2],500],["row1Done",e.done[1],1],["row1MaskMismatches",l.mismatches,0],["row0Bit6",w(e.bitmask,0,6),1],["row2Bit500",w(e.bitmask,2,500),1]])});g("argmax_eos_then_pad",async({device:n})=>{const t=B(2,[[[d,6]],[[40,5],[41,4.5]]]),s=B(2,[[[5,7]],[[40,5],[41,4.5]]]),o=await m(n,{B:2,stepsLogits:[t,s],bias:null,bitmask:null,done:null}),r=p([t,s],{B:2,bias:new Float32Array(u),bitmask:new Uint32Array(2*c),done:new Uint32Array(2)});return y(o,r,{kernel:"argmax_penalty",case:"eos_then_pad"},[["t0Row0",o.tokens[0],d],["t0Row1",o.tokens[1],40],["t1Row0",o.tokens[2],O],["t1Row1",o.tokens[3],41],["row0Done",o.done[0],1],["row1Done",o.done[1],0],["row0EosBit",w(o.bitmask,0,d),1],["row0NoBit5",w(o.bitmask,0,5),0],["row1Bit40",w(o.bitmask,1,40),1],["row1Bit41",w(o.bitmask,1,41),1]])});g("argmax_tie_break",async({device:n})=>{const t=B(1,[[[100,7.5],[2e4,7.5]]]),s=await m(n,{B:1,stepsLogits:[t],bias:null,bitmask:null,done:null}),o=p([t],{B:1,bias:new Float32Array(u),bitmask:new Uint32Array(1*c),done:new Uint32Array(1)});return y(s,o,{kernel:"argmax_penalty",case:"tie_break"},[["token",s.tokens[0],100]])});
2
- //# sourceMappingURL=argmax-CQZtdTcb.js.map
 
 
 
assets/argmax-DMqT6ikS.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import{r as g}from"./debug-CPpXXfWA.js";import{c as b,r as P}from"./gpu-utils-BTh3AGTJ.js";import{g as V,f as H}from"./pipelines-BbLc75sB.js";import{p as I}from"./math-LI6LFmUv.js";import{V as K,B as q,P as O,e as d,R as M}from"./constants-CSVWRdrh.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./safe_storage-BYkOahew.js";const u=K,c=q,j=256;function J(n){let a=n>>>0;return()=>{a=a+1831565813|0;let t=Math.imul(a^a>>>15,1|a);return t=t+Math.imul(t^t>>>7,61|t)^t,((t^t>>>14)>>>0)/4294967296}}function B(n,a){const t=new Float32Array(n*u);return a.forEach((s,o)=>{for(const[r,e]of s)t[o*u+r]=Math.fround(e)}),t}function R(n,a,t){n[a*c+(t>>5)]|=1<<(t&31)}function w(n,a,t){return n[a*c+(t>>5)]>>>(t&31)&1}function p(n,{B:a,bias:t,bitmask:s,done:o}){const r=new Uint32Array(n.length*a);let e=s,i=o;return n.forEach((l,f)=>{const k=I(l,t,e,i,{B:a,V:u,penalty:M});r.set(k.tokens,f*a),e=k.newBitmaskWords,i=k.newDone}),{tokens:r,done:i,bitmask:e}}function Q(n,a){const t=n.createBuffer({size:16,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});return new Uint32Array(t.getMappedRange()).set(a),t.unmap(),t}async function m(n,{B:a,stepsLogits:t,bias:s,bitmask:o,done:r}){const e=t.length,i=V(n,"argmax_penalty",H,{wg:j,defines:{V:u,EOS:d,PAD:O,PENALTY:M,MASK_WORDS:c,SHORT:!1,NOSHORT:!0}}),l=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,f=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,k=b(n,s??new Float32Array(u),f),U=b(n,o??new Uint32Array(a*c),l),_=b(n,r??new Uint32Array(a),l),h=b(n,new Uint32Array(e*a).fill(3735928559),l),T=[],S=n.createCommandEncoder(),A=S.beginComputePass();A.setPipeline(i),t.forEach((x,W)=>{const G=Q(n,[a,W,0,0]),E=b(n,x,f);T.push(G,E);const N=n.createBindGroup({layout:i.getBindGroupLayout(0),entries:[G,E,k,U,_,h].map((Y,z)=>({binding:z,resource:{buffer:Y}}))});A.setBindGroup(0,N),A.dispatchWorkgroups(a)}),A.end(),n.queue.submit([S.finish()]);const F=new Uint32Array(await P(n,h,e*a*4)),C=new Uint32Array(await P(n,_,a*4)),L=new Uint32Array(await P(n,U,a*c*4));for(const x of[k,U,_,h,...T])x.destroy();return{tokens:F,done:C,bitmask:L}}function D(n,a){let t=0,s=-1;for(let o=0;o<a.length;o++)n[o]!==a[o]&&(t++,s<0&&(s=o));return{mismatches:t,first:s}}function y(n,a,t,s=[]){const o={...t};let r=!0;for(const[e,i]of[["tokens",a.tokens],["done",a.done],["bitmask",a.bitmask]]){const{mismatches:l,first:f}=D(n[e],i);l>0&&(r=!1,o[e]={mismatches:l,first:f,got:n[e][f],want:i[f]})}for(const[e,i,l]of s)i!==l&&(r=!1,o[e]={got:i,want:l});return{pass:r,detail:o}}g("argmax_random",async({device:n})=>{const t=J(1207),s=new Float32Array(4*u);for(let i=0;i<s.length;i++)s[i]=Math.fround((t()-.5)*20);const r=await m(n,{...{B:4,bias:null,bitmask:null,done:null},stepsLogits:[s]}),e=p([s],{B:4,bias:new Float32Array(u),bitmask:new Uint32Array(4*c),done:new Uint32Array(4)});return y(r,e,{kernel:"argmax_penalty",B:4,V:u,tokens:Array.from(r.tokens)})});g("argmax_penalty_flip",async({device:n})=>{const t=B(1,[[[7,5],[100,4.5]]]),s=new Uint32Array(1*c);R(s,0,7);const o=await m(n,{B:1,stepsLogits:[t],bias:null,bitmask:s,done:null}),r=p([t],{B:1,bias:new Float32Array(u),bitmask:s,done:new Uint32Array(1)});return y(o,r,{kernel:"argmax_penalty",case:"penalty_flip"},[["token",o.tokens[0],100]])});g("argmax_bias",async({device:n})=>{const t=B(1,[[[10,3],[200,2.5]]]),s=new Float32Array(u);s[200]=1;const o=await m(n,{B:1,stepsLogits:[t],bias:null,bitmask:null,done:null}),r=await m(n,{B:1,stepsLogits:[t],bias:s,bitmask:null,done:null}),e=p([t],{B:1,bias:s,bitmask:new Uint32Array(1*c),done:new Uint32Array(1)});return y(r,e,{kernel:"argmax_penalty",case:"bias"},[["zeroBiasToken",o.tokens[0],10],["biasedToken",r.tokens[0],200]])});g("argmax_done_row",async({device:n})=>{const t=B(3,[[[6,2]],[[7,9]],[[500,1.5]]]),s=new Uint32Array(3*c);R(s,1,7),R(s,1,12345);const o=Uint32Array.of(0,1,0),r=Uint32Array.from(s),e=await m(n,{B:3,stepsLogits:[t],bias:null,bitmask:s,done:o}),i=p([t],{B:3,bias:new Float32Array(u),bitmask:s,done:o}),l=D(e.bitmask.slice(c,2*c),r.slice(c,2*c));return y(e,i,{kernel:"argmax_penalty",case:"done_row"},[["row0Token",e.tokens[0],6],["row1Token",e.tokens[1],O],["row2Token",e.tokens[2],500],["row1Done",e.done[1],1],["row1MaskMismatches",l.mismatches,0],["row0Bit6",w(e.bitmask,0,6),1],["row2Bit500",w(e.bitmask,2,500),1]])});g("argmax_eos_then_pad",async({device:n})=>{const t=B(2,[[[d,6]],[[40,5],[41,4.5]]]),s=B(2,[[[5,7]],[[40,5],[41,4.5]]]),o=await m(n,{B:2,stepsLogits:[t,s],bias:null,bitmask:null,done:null}),r=p([t,s],{B:2,bias:new Float32Array(u),bitmask:new Uint32Array(2*c),done:new Uint32Array(2)});return y(o,r,{kernel:"argmax_penalty",case:"eos_then_pad"},[["t0Row0",o.tokens[0],d],["t0Row1",o.tokens[1],40],["t1Row0",o.tokens[2],O],["t1Row1",o.tokens[3],41],["row0Done",o.done[0],1],["row1Done",o.done[1],0],["row0EosBit",w(o.bitmask,0,d),1],["row0NoBit5",w(o.bitmask,0,5),0],["row1Bit40",w(o.bitmask,1,40),1],["row1Bit41",w(o.bitmask,1,41),1]])});g("argmax_tie_break",async({device:n})=>{const t=B(1,[[[100,7.5],[2e4,7.5]]]),s=await m(n,{B:1,stepsLogits:[t],bias:null,bitmask:null,done:null}),o=p([t],{B:1,bias:new Float32Array(u),bitmask:new Uint32Array(1*c),done:new Uint32Array(1)});return y(s,o,{kernel:"argmax_penalty",case:"tie_break"},[["token",s.tokens[0],100]])});
2
+ //# sourceMappingURL=argmax-DMqT6ikS.js.map
assets/{argmax-CQZtdTcb.js.map → argmax-DMqT6ikS.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"file":"argmax-CQZtdTcb.js","sources":["../../src/debug/tests/argmax.js"],"sourcesContent":["// GPU penalty+argmax+writeback kernel vs the JS reference — EXACT integer\r\n// comparisons (no tolerance): token picks, done flags, and bitmask words must\r\n// match penaltyArgmaxRef bit-for-bit (the ref frounds every op, mirroring the\r\n// kernel's f32 adds/divides/multiplies). Crafted cases also assert hard-coded\r\n// winners so a bug shared by ref and kernel can't hide.\r\n// Per-call uniform/bind-group creation is test-only plumbing — engine-level\r\n// uniform management arrives in Tasks 13-14.\r\nimport { registerTest } from '../registry.js';\r\nimport { createBuffer, readback } from '../gpu-utils.js';\r\nimport { getPipeline } from '../../engine/pipelines.js';\r\nimport { penaltyArgmaxRef } from '../../reference/math.js';\r\nimport { VOCAB, EOS, PAD, REP_PENALTY, BITMASK_WORDS } from '../../engine/constants.js';\r\nimport argmaxSource from '../../engine/kernels/argmax_penalty.wgsl?raw';\r\n\r\nconst V = VOCAB;\r\nconst WORDS = BITMASK_WORDS;\r\nconst WG = 256;\r\n\r\nfunction mulberry32(seed) {\r\n let a = seed >>> 0;\r\n return () => {\r\n a = (a + 0x6d2b79f5) | 0;\r\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\r\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\r\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\r\n };\r\n}\r\n\r\n// Float32Array [B·V]: rows[b] = [[v, logit], ...], unlisted lanes 0.\r\nfunction craftLogits(B, rows) {\r\n const a = new Float32Array(B * V);\r\n rows.forEach((entries, b) => {\r\n for (const [v, x] of entries) a[b * V + v] = Math.fround(x);\r\n });\r\n return a;\r\n}\r\n\r\nfunction setBit(mask, b, v) { mask[b * WORDS + (v >> 5)] |= 1 << (v & 31); }\r\nfunction getBit(mask, b, v) { return (mask[b * WORDS + (v >> 5)] >>> (v & 31)) & 1; }\r\n\r\n// Chain the reference over sequential steps (bitmask/done carry over).\r\n// Returns {tokens: Uint32Array[steps·B] (ring layout t·B+b), done, bitmask}.\r\nfunction refChain(stepsLogits, { B, bias, bitmask, done }) {\r\n const tokens = new Uint32Array(stepsLogits.length * B);\r\n let mask = bitmask, dn = done;\r\n stepsLogits.forEach((logits, t) => {\r\n const out = penaltyArgmaxRef(logits, bias, mask, dn, { B, V, penalty: REP_PENALTY });\r\n tokens.set(out.tokens, t * B);\r\n mask = out.newBitmaskWords;\r\n dn = out.newDone;\r\n });\r\n return { tokens, done: dn, bitmask: mask };\r\n}\r\n\r\nfunction makeUniform(device, vals) {\r\n const buf = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.UNIFORM,\r\n mappedAtCreation: true,\r\n });\r\n new Uint32Array(buf.getMappedRange()).set(vals);\r\n buf.unmap();\r\n return buf;\r\n}\r\n\r\n// Run stepsLogits.length sequential dispatches sharing bitmask/done/token-ring\r\n// state (one pass — WebGPU orders storage writes between dispatches, and queue\r\n// order covers cross-dispatch bitmask visibility). Ring is sentinel-filled so\r\n// a wrong t·B+b slot or a missed write fails the exact compare.\r\nasync function runArgmax(device, { B, stepsLogits, bias, bitmask, done }) {\r\n const tMax = stepsLogits.length;\r\n const pipeline = getPipeline(device, 'argmax_penalty', argmaxSource, {\r\n wg: WG,\r\n defines: { V, EOS, PAD, PENALTY: REP_PENALTY, MASK_WORDS: WORDS, SHORT: false, NOSHORT: true },\r\n });\r\n const rw = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC;\r\n const ro = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const biasBuf = createBuffer(device, bias ?? new Float32Array(V), ro);\r\n const maskBuf = createBuffer(device, bitmask ?? new Uint32Array(B * WORDS), rw);\r\n const doneBuf = createBuffer(device, done ?? new Uint32Array(B), rw);\r\n const ringBuf = createBuffer(device, new Uint32Array(tMax * B).fill(0xdeadbeef), rw);\r\n\r\n const scratch = [];\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(pipeline);\r\n stepsLogits.forEach((logits, t) => {\r\n const params = makeUniform(device, [B, t, 0, 0]);\r\n const logitsBuf = createBuffer(device, logits, ro);\r\n scratch.push(params, logitsBuf);\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [params, logitsBuf, biasBuf, maskBuf, doneBuf, ringBuf]\r\n .map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n pass.setBindGroup(0, bindGroup);\r\n pass.dispatchWorkgroups(B);\r\n });\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n\r\n const tokens = new Uint32Array(await readback(device, ringBuf, tMax * B * 4));\r\n const doneOut = new Uint32Array(await readback(device, doneBuf, B * 4));\r\n const maskOut = new Uint32Array(await readback(device, maskBuf, B * WORDS * 4));\r\n for (const b of [biasBuf, maskBuf, doneBuf, ringBuf, ...scratch]) b.destroy();\r\n return { tokens, done: doneOut, bitmask: maskOut };\r\n}\r\n\r\nfunction diffU32(got, want) {\r\n let mismatches = 0, first = -1;\r\n for (let i = 0; i < want.length; i++) {\r\n if (got[i] !== want[i]) {\r\n mismatches++;\r\n if (first < 0) first = i;\r\n }\r\n }\r\n return { mismatches, first };\r\n}\r\n\r\n// Exact-compare GPU state against the chained ref plus hard-coded expectations\r\n// (`expect` = [name, gotValue, wantValue] triples).\r\nfunction report(gpu, ref, extra, expectations = []) {\r\n const detail = { ...extra };\r\n let pass = true;\r\n for (const [field, w] of [['tokens', ref.tokens], ['done', ref.done], ['bitmask', ref.bitmask]]) {\r\n const { mismatches, first } = diffU32(gpu[field], w);\r\n if (mismatches > 0) {\r\n pass = false;\r\n detail[field] = { mismatches, first, got: gpu[field][first], want: w[first] };\r\n }\r\n }\r\n for (const [name, got, want] of expectations) {\r\n if (got !== want) {\r\n pass = false;\r\n detail[name] = { got, want };\r\n }\r\n }\r\n return { pass, detail };\r\n}\r\n\r\nregisterTest('argmax_random', async ({ device }) => {\r\n const B = 4;\r\n const rng = mulberry32(1207);\r\n const logits = new Float32Array(B * V);\r\n for (let i = 0; i < logits.length; i++) logits[i] = Math.fround((rng() - 0.5) * 20);\r\n const args = { B, bias: null, bitmask: null, done: null };\r\n const gpu = await runArgmax(device, { ...args, stepsLogits: [logits] });\r\n const ref = refChain([logits], {\r\n B, bias: new Float32Array(V), bitmask: new Uint32Array(B * WORDS), done: new Uint32Array(B),\r\n });\r\n return report(gpu, ref, { kernel: 'argmax_penalty', B, V, tokens: Array.from(gpu.tokens) });\r\n});\r\n\r\nregisterTest('argmax_penalty_flip', async ({ device }) => {\r\n // Seen 5.0 → 5/1.2 ≈ 4.1667 loses to unseen 4.5: only the pre-set bit\r\n // can make 100 win.\r\n const B = 1;\r\n const logits = craftLogits(B, [[[7, 5.0], [100, 4.5]]]);\r\n const bitmask = new Uint32Array(B * WORDS);\r\n setBit(bitmask, 0, 7);\r\n const gpu = await runArgmax(device, { B, stepsLogits: [logits], bias: null, bitmask, done: null });\r\n const ref = refChain([logits], {\r\n B, bias: new Float32Array(V), bitmask, done: new Uint32Array(B),\r\n });\r\n return report(gpu, ref, { kernel: 'argmax_penalty', case: 'penalty_flip' },\r\n [['token', gpu.tokens[0], 100]]);\r\n});\r\n\r\nregisterTest('argmax_bias', async ({ device }) => {\r\n // Same logits, zero vs crafted bias — the bias must change the winner.\r\n const B = 1;\r\n const logits = craftLogits(B, [[[10, 3.0], [200, 2.5]]]);\r\n const bias = new Float32Array(V);\r\n bias[200] = 1.0; // 2.5 + 1.0 = 3.5 > 3.0\r\n const zero = await runArgmax(device, { B, stepsLogits: [logits], bias: null, bitmask: null, done: null });\r\n const biased = await runArgmax(device, { B, stepsLogits: [logits], bias, bitmask: null, done: null });\r\n const ref = refChain([logits], {\r\n B, bias, bitmask: new Uint32Array(B * WORDS), done: new Uint32Array(B),\r\n });\r\n return report(biased, ref, { kernel: 'argmax_penalty', case: 'bias' }, [\r\n ['zeroBiasToken', zero.tokens[0], 10],\r\n ['biasedToken', biased.tokens[0], 200],\r\n ]);\r\n});\r\n\r\nregisterTest('argmax_done_row', async ({ device }) => {\r\n // done[1] pre-set → row 1 emits PAD and its bitmask words stay untouched;\r\n // rows 0 and 2 proceed normally.\r\n const B = 3;\r\n const logits = craftLogits(B, [[[6, 2.0]], [[7, 9.0]], [[500, 1.5]]]);\r\n const bitmask = new Uint32Array(B * WORDS);\r\n setBit(bitmask, 1, 7);\r\n setBit(bitmask, 1, 12345);\r\n const done = Uint32Array.of(0, 1, 0);\r\n const maskBefore = Uint32Array.from(bitmask);\r\n const gpu = await runArgmax(device, { B, stepsLogits: [logits], bias: null, bitmask, done });\r\n const ref = refChain([logits], {\r\n B, bias: new Float32Array(V), bitmask, done,\r\n });\r\n const row1Unchanged = diffU32(gpu.bitmask.slice(WORDS, 2 * WORDS), maskBefore.slice(WORDS, 2 * WORDS));\r\n return report(gpu, ref, { kernel: 'argmax_penalty', case: 'done_row' }, [\r\n ['row0Token', gpu.tokens[0], 6],\r\n ['row1Token', gpu.tokens[1], PAD],\r\n ['row2Token', gpu.tokens[2], 500],\r\n ['row1Done', gpu.done[1], 1],\r\n ['row1MaskMismatches', row1Unchanged.mismatches, 0],\r\n ['row0Bit6', getBit(gpu.bitmask, 0, 6), 1],\r\n ['row2Bit500', getBit(gpu.bitmask, 2, 500), 1],\r\n ]);\r\n});\r\n\r\nregisterTest('argmax_eos_then_pad', async ({ device }) => {\r\n // Two sequential dispatches sharing GPU state.\r\n // Row 0: picks EOS at t=0 → done; at t=1 (where v=5 would win) it must emit\r\n // PAD and set NO new bit.\r\n // Row 1: t=0 winner v=40; t=1 re-offers 40 (5.0) with runner-up 41 (4.5) —\r\n // 40 wins again UNLESS its t=0 bit persisted into the t=1 dispatch\r\n // (5/1.2 ≈ 4.1667 < 4.5), proving cross-dispatch bitmask writeback.\r\n const B = 2;\r\n const t0 = craftLogits(B, [[[EOS, 6.0]], [[40, 5.0], [41, 4.5]]]);\r\n const t1 = craftLogits(B, [[[5, 7.0]], [[40, 5.0], [41, 4.5]]]);\r\n const gpu = await runArgmax(device, { B, stepsLogits: [t0, t1], bias: null, bitmask: null, done: null });\r\n const ref = refChain([t0, t1], {\r\n B, bias: new Float32Array(V), bitmask: new Uint32Array(B * WORDS), done: new Uint32Array(B),\r\n });\r\n return report(gpu, ref, { kernel: 'argmax_penalty', case: 'eos_then_pad' }, [\r\n ['t0Row0', gpu.tokens[0 * B + 0], EOS],\r\n ['t0Row1', gpu.tokens[0 * B + 1], 40],\r\n ['t1Row0', gpu.tokens[1 * B + 0], PAD],\r\n ['t1Row1', gpu.tokens[1 * B + 1], 41],\r\n ['row0Done', gpu.done[0], 1],\r\n ['row1Done', gpu.done[1], 0],\r\n ['row0EosBit', getBit(gpu.bitmask, 0, EOS), 1],\r\n ['row0NoBit5', getBit(gpu.bitmask, 0, 5), 0],\r\n ['row1Bit40', getBit(gpu.bitmask, 1, 40), 1],\r\n ['row1Bit41', getBit(gpu.bitmask, 1, 41), 1],\r\n ]);\r\n});\r\n\r\nregisterTest('argmax_tie_break', async ({ device }) => {\r\n // Two exactly-equal maxima (7.5 is exact in f32) far apart, landing in\r\n // DIFFERENT threads' strides (100 % 256 = 100, 20000 % 256 = 32) — the tie\r\n // must be broken in the reduction comparator, not within one thread's scan.\r\n const B = 1;\r\n const logits = craftLogits(B, [[[100, 7.5], [20000, 7.5]]]);\r\n const gpu = await runArgmax(device, { B, stepsLogits: [logits], bias: null, bitmask: null, done: null });\r\n const ref = refChain([logits], {\r\n B, bias: new Float32Array(V), bitmask: new Uint32Array(B * WORDS), done: new Uint32Array(B),\r\n });\r\n return report(gpu, ref, { kernel: 'argmax_penalty', case: 'tie_break' },\r\n [['token', gpu.tokens[0], 100]]);\r\n});\r\n"],"names":["V","VOCAB","WORDS","BITMASK_WORDS","WG","mulberry32","seed","craftLogits","B","rows","a","entries","b","v","x","setBit","mask","getBit","refChain","stepsLogits","bias","bitmask","done","tokens","dn","logits","t","out","penaltyArgmaxRef","REP_PENALTY","makeUniform","device","vals","buf","runArgmax","tMax","pipeline","getPipeline","argmaxSource","EOS","PAD","rw","ro","biasBuf","createBuffer","maskBuf","doneBuf","ringBuf","scratch","encoder","pass","params","logitsBuf","bindGroup","buffer","binding","readback","doneOut","maskOut","diffU32","got","want","mismatches","first","i","report","gpu","ref","extra","expectations","detail","field","w","name","registerTest","rng","zero","biased","maskBefore","row1Unchanged","t0","t1"],"mappings":"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"}
 
1
+ {"version":3,"file":"argmax-DMqT6ikS.js","sources":["../../src/debug/tests/argmax.js"],"sourcesContent":["// GPU penalty+argmax+writeback kernel vs the JS reference — EXACT integer\r\n// comparisons (no tolerance): token picks, done flags, and bitmask words must\r\n// match penaltyArgmaxRef bit-for-bit (the ref frounds every op, mirroring the\r\n// kernel's f32 adds/divides/multiplies). Crafted cases also assert hard-coded\r\n// winners so a bug shared by ref and kernel can't hide.\r\n// Per-call uniform/bind-group creation is test-only plumbing — engine-level\r\n// uniform management arrives in Tasks 13-14.\r\nimport { registerTest } from '../registry.js';\r\nimport { createBuffer, readback } from '../gpu-utils.js';\r\nimport { getPipeline } from '../../engine/pipelines.js';\r\nimport { penaltyArgmaxRef } from '../../reference/math.js';\r\nimport { VOCAB, EOS, PAD, REP_PENALTY, BITMASK_WORDS } from '../../engine/constants.js';\r\nimport argmaxSource from '../../engine/kernels/argmax_penalty.wgsl?raw';\r\n\r\nconst V = VOCAB;\r\nconst WORDS = BITMASK_WORDS;\r\nconst WG = 256;\r\n\r\nfunction mulberry32(seed) {\r\n let a = seed >>> 0;\r\n return () => {\r\n a = (a + 0x6d2b79f5) | 0;\r\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\r\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\r\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\r\n };\r\n}\r\n\r\n// Float32Array [B·V]: rows[b] = [[v, logit], ...], unlisted lanes 0.\r\nfunction craftLogits(B, rows) {\r\n const a = new Float32Array(B * V);\r\n rows.forEach((entries, b) => {\r\n for (const [v, x] of entries) a[b * V + v] = Math.fround(x);\r\n });\r\n return a;\r\n}\r\n\r\nfunction setBit(mask, b, v) { mask[b * WORDS + (v >> 5)] |= 1 << (v & 31); }\r\nfunction getBit(mask, b, v) { return (mask[b * WORDS + (v >> 5)] >>> (v & 31)) & 1; }\r\n\r\n// Chain the reference over sequential steps (bitmask/done carry over).\r\n// Returns {tokens: Uint32Array[steps·B] (ring layout t·B+b), done, bitmask}.\r\nfunction refChain(stepsLogits, { B, bias, bitmask, done }) {\r\n const tokens = new Uint32Array(stepsLogits.length * B);\r\n let mask = bitmask, dn = done;\r\n stepsLogits.forEach((logits, t) => {\r\n const out = penaltyArgmaxRef(logits, bias, mask, dn, { B, V, penalty: REP_PENALTY });\r\n tokens.set(out.tokens, t * B);\r\n mask = out.newBitmaskWords;\r\n dn = out.newDone;\r\n });\r\n return { tokens, done: dn, bitmask: mask };\r\n}\r\n\r\nfunction makeUniform(device, vals) {\r\n const buf = device.createBuffer({\r\n size: 16,\r\n usage: GPUBufferUsage.UNIFORM,\r\n mappedAtCreation: true,\r\n });\r\n new Uint32Array(buf.getMappedRange()).set(vals);\r\n buf.unmap();\r\n return buf;\r\n}\r\n\r\n// Run stepsLogits.length sequential dispatches sharing bitmask/done/token-ring\r\n// state (one pass — WebGPU orders storage writes between dispatches, and queue\r\n// order covers cross-dispatch bitmask visibility). Ring is sentinel-filled so\r\n// a wrong t·B+b slot or a missed write fails the exact compare.\r\nasync function runArgmax(device, { B, stepsLogits, bias, bitmask, done }) {\r\n const tMax = stepsLogits.length;\r\n const pipeline = getPipeline(device, 'argmax_penalty', argmaxSource, {\r\n wg: WG,\r\n defines: { V, EOS, PAD, PENALTY: REP_PENALTY, MASK_WORDS: WORDS, SHORT: false, NOSHORT: true },\r\n });\r\n const rw = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC;\r\n const ro = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const biasBuf = createBuffer(device, bias ?? new Float32Array(V), ro);\r\n const maskBuf = createBuffer(device, bitmask ?? new Uint32Array(B * WORDS), rw);\r\n const doneBuf = createBuffer(device, done ?? new Uint32Array(B), rw);\r\n const ringBuf = createBuffer(device, new Uint32Array(tMax * B).fill(0xdeadbeef), rw);\r\n\r\n const scratch = [];\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(pipeline);\r\n stepsLogits.forEach((logits, t) => {\r\n const params = makeUniform(device, [B, t, 0, 0]);\r\n const logitsBuf = createBuffer(device, logits, ro);\r\n scratch.push(params, logitsBuf);\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [params, logitsBuf, biasBuf, maskBuf, doneBuf, ringBuf]\r\n .map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n pass.setBindGroup(0, bindGroup);\r\n pass.dispatchWorkgroups(B);\r\n });\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n\r\n const tokens = new Uint32Array(await readback(device, ringBuf, tMax * B * 4));\r\n const doneOut = new Uint32Array(await readback(device, doneBuf, B * 4));\r\n const maskOut = new Uint32Array(await readback(device, maskBuf, B * WORDS * 4));\r\n for (const b of [biasBuf, maskBuf, doneBuf, ringBuf, ...scratch]) b.destroy();\r\n return { tokens, done: doneOut, bitmask: maskOut };\r\n}\r\n\r\nfunction diffU32(got, want) {\r\n let mismatches = 0, first = -1;\r\n for (let i = 0; i < want.length; i++) {\r\n if (got[i] !== want[i]) {\r\n mismatches++;\r\n if (first < 0) first = i;\r\n }\r\n }\r\n return { mismatches, first };\r\n}\r\n\r\n// Exact-compare GPU state against the chained ref plus hard-coded expectations\r\n// (`expect` = [name, gotValue, wantValue] triples).\r\nfunction report(gpu, ref, extra, expectations = []) {\r\n const detail = { ...extra };\r\n let pass = true;\r\n for (const [field, w] of [['tokens', ref.tokens], ['done', ref.done], ['bitmask', ref.bitmask]]) {\r\n const { mismatches, first } = diffU32(gpu[field], w);\r\n if (mismatches > 0) {\r\n pass = false;\r\n detail[field] = { mismatches, first, got: gpu[field][first], want: w[first] };\r\n }\r\n }\r\n for (const [name, got, want] of expectations) {\r\n if (got !== want) {\r\n pass = false;\r\n detail[name] = { got, want };\r\n }\r\n }\r\n return { pass, detail };\r\n}\r\n\r\nregisterTest('argmax_random', async ({ device }) => {\r\n const B = 4;\r\n const rng = mulberry32(1207);\r\n const logits = new Float32Array(B * V);\r\n for (let i = 0; i < logits.length; i++) logits[i] = Math.fround((rng() - 0.5) * 20);\r\n const args = { B, bias: null, bitmask: null, done: null };\r\n const gpu = await runArgmax(device, { ...args, stepsLogits: [logits] });\r\n const ref = refChain([logits], {\r\n B, bias: new Float32Array(V), bitmask: new Uint32Array(B * WORDS), done: new Uint32Array(B),\r\n });\r\n return report(gpu, ref, { kernel: 'argmax_penalty', B, V, tokens: Array.from(gpu.tokens) });\r\n});\r\n\r\nregisterTest('argmax_penalty_flip', async ({ device }) => {\r\n // Seen 5.0 → 5/1.2 ≈ 4.1667 loses to unseen 4.5: only the pre-set bit\r\n // can make 100 win.\r\n const B = 1;\r\n const logits = craftLogits(B, [[[7, 5.0], [100, 4.5]]]);\r\n const bitmask = new Uint32Array(B * WORDS);\r\n setBit(bitmask, 0, 7);\r\n const gpu = await runArgmax(device, { B, stepsLogits: [logits], bias: null, bitmask, done: null });\r\n const ref = refChain([logits], {\r\n B, bias: new Float32Array(V), bitmask, done: new Uint32Array(B),\r\n });\r\n return report(gpu, ref, { kernel: 'argmax_penalty', case: 'penalty_flip' },\r\n [['token', gpu.tokens[0], 100]]);\r\n});\r\n\r\nregisterTest('argmax_bias', async ({ device }) => {\r\n // Same logits, zero vs crafted bias — the bias must change the winner.\r\n const B = 1;\r\n const logits = craftLogits(B, [[[10, 3.0], [200, 2.5]]]);\r\n const bias = new Float32Array(V);\r\n bias[200] = 1.0; // 2.5 + 1.0 = 3.5 > 3.0\r\n const zero = await runArgmax(device, { B, stepsLogits: [logits], bias: null, bitmask: null, done: null });\r\n const biased = await runArgmax(device, { B, stepsLogits: [logits], bias, bitmask: null, done: null });\r\n const ref = refChain([logits], {\r\n B, bias, bitmask: new Uint32Array(B * WORDS), done: new Uint32Array(B),\r\n });\r\n return report(biased, ref, { kernel: 'argmax_penalty', case: 'bias' }, [\r\n ['zeroBiasToken', zero.tokens[0], 10],\r\n ['biasedToken', biased.tokens[0], 200],\r\n ]);\r\n});\r\n\r\nregisterTest('argmax_done_row', async ({ device }) => {\r\n // done[1] pre-set → row 1 emits PAD and its bitmask words stay untouched;\r\n // rows 0 and 2 proceed normally.\r\n const B = 3;\r\n const logits = craftLogits(B, [[[6, 2.0]], [[7, 9.0]], [[500, 1.5]]]);\r\n const bitmask = new Uint32Array(B * WORDS);\r\n setBit(bitmask, 1, 7);\r\n setBit(bitmask, 1, 12345);\r\n const done = Uint32Array.of(0, 1, 0);\r\n const maskBefore = Uint32Array.from(bitmask);\r\n const gpu = await runArgmax(device, { B, stepsLogits: [logits], bias: null, bitmask, done });\r\n const ref = refChain([logits], {\r\n B, bias: new Float32Array(V), bitmask, done,\r\n });\r\n const row1Unchanged = diffU32(gpu.bitmask.slice(WORDS, 2 * WORDS), maskBefore.slice(WORDS, 2 * WORDS));\r\n return report(gpu, ref, { kernel: 'argmax_penalty', case: 'done_row' }, [\r\n ['row0Token', gpu.tokens[0], 6],\r\n ['row1Token', gpu.tokens[1], PAD],\r\n ['row2Token', gpu.tokens[2], 500],\r\n ['row1Done', gpu.done[1], 1],\r\n ['row1MaskMismatches', row1Unchanged.mismatches, 0],\r\n ['row0Bit6', getBit(gpu.bitmask, 0, 6), 1],\r\n ['row2Bit500', getBit(gpu.bitmask, 2, 500), 1],\r\n ]);\r\n});\r\n\r\nregisterTest('argmax_eos_then_pad', async ({ device }) => {\r\n // Two sequential dispatches sharing GPU state.\r\n // Row 0: picks EOS at t=0 → done; at t=1 (where v=5 would win) it must emit\r\n // PAD and set NO new bit.\r\n // Row 1: t=0 winner v=40; t=1 re-offers 40 (5.0) with runner-up 41 (4.5) —\r\n // 40 wins again UNLESS its t=0 bit persisted into the t=1 dispatch\r\n // (5/1.2 ≈ 4.1667 < 4.5), proving cross-dispatch bitmask writeback.\r\n const B = 2;\r\n const t0 = craftLogits(B, [[[EOS, 6.0]], [[40, 5.0], [41, 4.5]]]);\r\n const t1 = craftLogits(B, [[[5, 7.0]], [[40, 5.0], [41, 4.5]]]);\r\n const gpu = await runArgmax(device, { B, stepsLogits: [t0, t1], bias: null, bitmask: null, done: null });\r\n const ref = refChain([t0, t1], {\r\n B, bias: new Float32Array(V), bitmask: new Uint32Array(B * WORDS), done: new Uint32Array(B),\r\n });\r\n return report(gpu, ref, { kernel: 'argmax_penalty', case: 'eos_then_pad' }, [\r\n ['t0Row0', gpu.tokens[0 * B + 0], EOS],\r\n ['t0Row1', gpu.tokens[0 * B + 1], 40],\r\n ['t1Row0', gpu.tokens[1 * B + 0], PAD],\r\n ['t1Row1', gpu.tokens[1 * B + 1], 41],\r\n ['row0Done', gpu.done[0], 1],\r\n ['row1Done', gpu.done[1], 0],\r\n ['row0EosBit', getBit(gpu.bitmask, 0, EOS), 1],\r\n ['row0NoBit5', getBit(gpu.bitmask, 0, 5), 0],\r\n ['row1Bit40', getBit(gpu.bitmask, 1, 40), 1],\r\n ['row1Bit41', getBit(gpu.bitmask, 1, 41), 1],\r\n ]);\r\n});\r\n\r\nregisterTest('argmax_tie_break', async ({ device }) => {\r\n // Two exactly-equal maxima (7.5 is exact in f32) far apart, landing in\r\n // DIFFERENT threads' strides (100 % 256 = 100, 20000 % 256 = 32) — the tie\r\n // must be broken in the reduction comparator, not within one thread's scan.\r\n const B = 1;\r\n const logits = craftLogits(B, [[[100, 7.5], [20000, 7.5]]]);\r\n const gpu = await runArgmax(device, { B, stepsLogits: [logits], bias: null, bitmask: null, done: null });\r\n const ref = refChain([logits], {\r\n B, bias: new Float32Array(V), bitmask: new Uint32Array(B * WORDS), done: new Uint32Array(B),\r\n });\r\n return report(gpu, ref, { kernel: 'argmax_penalty', case: 'tie_break' },\r\n [['token', gpu.tokens[0], 100]]);\r\n});\r\n"],"names":["V","VOCAB","WORDS","BITMASK_WORDS","WG","mulberry32","seed","craftLogits","B","rows","a","entries","b","v","x","setBit","mask","getBit","refChain","stepsLogits","bias","bitmask","done","tokens","dn","logits","t","out","penaltyArgmaxRef","REP_PENALTY","makeUniform","device","vals","buf","runArgmax","tMax","pipeline","getPipeline","argmaxSource","EOS","PAD","rw","ro","biasBuf","createBuffer","maskBuf","doneBuf","ringBuf","scratch","encoder","pass","params","logitsBuf","bindGroup","buffer","binding","readback","doneOut","maskOut","diffU32","got","want","mismatches","first","i","report","gpu","ref","extra","expectations","detail","field","w","name","registerTest","rng","zero","biased","maskBefore","row1Unchanged","t0","t1"],"mappings":"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"}
assets/argmax_fuse-CKXRwPoI.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import{r as P}from"./debug-CPpXXfWA.js";import{c as _,r as R}from"./gpu-utils-BTh3AGTJ.js";import{i as J,j as X,k as Z}from"./pipelines-BbLc75sB.js";import{l as j,q as M}from"./weights-DxIJF1EY.js";import{l as K,t as v}from"./tokenizer-BmI7pHmp.js";import{t as H}from"./generate-Ca3ORHiA.js";import{r as tt}from"./encoder-CZXKGzzg.js";import{c as st}from"./decoder-BUiaGDqb.js";import{t as ot}from"./profile-9RIrShZy.js";import{p as Q}from"./bench-BarR4Zp5.js";import{f as G}from"./f16-wKKZr58e.js";import{D as et,V as nt,P as W,B as rt}from"./constants-CSVWRdrh.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./safe_storage-BYkOahew.js";import"./shapes-ClGtK-ia.js";import"./device-BotbBNoe.js";import"./autotune-Bwt_lWMv.js";import"./chapter3k-DSdzHZt5.js";const U=nt,T=et,F=rt,at=64,q=Math.ceil(U/at);function it(t){let o=t>>>0;return()=>{o=o+1831565813|0;let s=Math.imul(o^o>>>15,1|o);return s=s+Math.imul(s^s>>>7,61|s)^s,((s^s>>>14)>>>0)/4294967296}}const x=(t,o,s)=>{t[o*F+(s>>5)]|=1<<(s&31)},C=(t,o,s)=>t[o*F+(s>>>5)]>>>(s&31)&1;function ft(t,o){let s=0,n=-1;for(let i=0;i<o.length;i++)t[i]!==o[i]&&(s++,n<0&&(n=i));return{mismatches:s,first:n}}async function z(t,{fused:o,wq8:s,M:n,x:i,w:k,lbias:p,bitmask:b,done:y,t:a,tm8:f}){const m=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,d=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,r=_(t,i,d),h=_(t,s?k.packed:k.half,d),u=s?_(t,k.scales,d):null,w=_(t,p,d),B=_(t,b,m),c=_(t,y,m),A=_(t,new Uint32Array((a+1)*n).fill(3735928559),m),S=o?null:t.createBuffer({size:n*U*4,usage:m}),O=o?t.createBuffer({size:n*q*8,usage:m}):null,e={t:"f16",outT:"f32",wt:!0,tiled:!0,...s?{wq8:!0}:{},tm8:f},l=[],g=t.createCommandEncoder(),D=g.beginComputePass();l.push(...J(t,D,{x:r,w:h,...s?{scales:u}:{},y:S,...o?{fusedArgmax:{partials:O,lbias:w,seen:B}}:{},M:n,K:T,N:U,flags:e}).scratch),l.push(...(o?X(t,D,{partials:O,bitmask:B,done:c,tokens:A,B:n,t:a,NT:q}):Z(t,D,{logits:S,bias:w,bitmask:B,done:c,tokens:A,B:n,t:a})).scratch),D.end(),t.queue.submit([g.finish()]);const Y=new Uint32Array(await R(t,A,(a+1)*n*4)),I=new Uint32Array(await R(t,c,n*4)),L=new Uint32Array(await R(t,B,n*F*4));for(const $ of[r,h,u,w,B,c,A,S,O,...l])$?.destroy();return{tokens:Y.subarray(a*n),done:I,bitmask:L}}async function V(t,{wq8:o,tm8:s,seed:n}){const{device:i}=t,k=it(n),p=65,b=2,y=new Uint16Array(p*T);for(let e=0;e<y.length;e++)y[e]=G(k()-.5);const a=new Float32Array(U*T);for(let e=0;e<a.length;e++)a[e]=k()-.5;const f=4097,m=[4098,12e3,U-1];for(const e of m)a.copyWithin(e*T,f*T,f*T+T);const d=new Float32Array(U);for(let e=0;e<U;e++)d[e]=k()-.5;for(const e of[f,...m])d[e]=50;let r;if(o)r=M(a,U,T);else{const e=new Uint16Array(U*T);for(let l=0;l<a.length;l++)e[l]=G(a[l]);r={half:e}}const h=new Set([f,...m]),u=new Uint32Array(p*F);for(let e=0;e<p;e++){x(u,e,0);for(let l=0;l<500;l++){const g=Math.floor(k()*U);h.has(g)||x(u,e,g)}}x(u,2,f);const w=new Uint32Array(p);w[3]=1,w[64]=1;const B={wq8:o,M:p,x:y,w:r,lbias:d,t:b,tm8:s},c=await z(i,{...B,fused:!0,bitmask:Uint32Array.from(u),done:Uint32Array.from(w)}),A=await z(i,{...B,fused:!1,bitmask:Uint32Array.from(u),done:Uint32Array.from(w)}),S={wq8:o,tm8:s,M:p,t:b,DUP:f,sampleTokens:Array.from(c.tokens.subarray(0,8))};let O=!0;for(const e of["tokens","done","bitmask"]){const{mismatches:l,first:g}=ft(c[e],A[e]);l>0&&(O=!1,S[e]={mismatches:l,first:g,fused:c[e][g],plain:A[e][g]})}for(const[e,l,g]of[["row0Token",c.tokens[0],f],["row1Token",c.tokens[1],f],["row2Token",c.tokens[2],m[0]],["row3Token",c.tokens[3],W],["row64Token",c.tokens[64],W],["row0Bit",C(c.bitmask,0,f),1],["row2Bit",C(c.bitmask,2,m[0]),1],["row3BitUntouched",C(c.bitmask,3,f),0]])l!==g&&(O=!1,S[e]={got:l,want:g});return{pass:O,detail:S}}P("argmax_fuse_kernel",t=>t.hasF16?V(t,{wq8:!1,tm8:!1,seed:501}):{skip:!0,reason:"no shader-f16"});P("argmax_fuse_kernel_q8_tm8",t=>t.hasF16?V(t,{wq8:!0,tm8:!0,seed:502}):{skip:!0,reason:"no shader-f16"});P("argmax_fuse_equiv",async t=>{const{device:o}=t;if(!t.hasF16)return{skip:!0,reason:"no shader-f16"};const s={device:o,dtype:"f16",limits:t.limits},n=[...Q("file23k")].slice(0,32),i=await K(),k=[{name:"f16_tiled",loadOpts:{},runOpts:{lmHead:"tiled"}},{name:"q8_prod",loadOpts:{lmHeadQ8:!0,ffnWT:!0},runOpts:{lmHead:"auto",ffn:"auto"}}],p={};let b=!0;for(const{name:y,loadOpts:a,runOpts:f}of k){const m=await j(o,"/weights",{targetDtype:"f16",...a});try{const d=await H(s,m,i,n,{...f,lmHeadFuse:"off"}),r=await H(s,m,i,n,{...f,lmHeadFuse:"auto"});let h=0,u=-1;for(let w=0;w<n.length;w++){const B=d.rows[w].ids,c=r.rows[w].ids;(B.length!==c.length||B.some((A,S)=>A!==c[S]))&&(h++,u<0&&(u=w))}p[y]={mismatches:h,...u>=0?{firstRow:u,off:d.rows[u].text,on:r.rows[u].text}:{},compactions:{off:d.metrics.compactions,on:r.metrics.compactions}},h>0&&(b=!1)}finally{m.buffer.destroy()}}return{pass:b,detail:p}});const N=7,E=50,ct=[16,32,64,128],mt=t=>{const o=[...t].sort((n,i)=>n-i),s=o.length>>1;return o.length%2?o[s]:(o[s-1]+o[s])/2};P("argmax_fuse_sweep",async t=>{const{device:o}=t;if(!t.hasF16)return{skip:!0,reason:"no shader-f16"};const s=await j(o,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0});try{const n=await K(),i={device:o,dtype:"f16",limits:t.limits},k=[...Q("file23k")].sort((y,a)=>a.length-y.length),p=[{name:"off",lmHeadFuse:"off"},{name:"fused",lmHeadFuse:"auto"}],b=[];for(const y of ct){const a=await v(n,k.slice(0,y)),f=await tt(i,s,a);await o.queue.onSubmittedWorkDone();try{const m=async({lmHeadFuse:r})=>{const h=st(i,s,{B:a.B,S:f.S,maxSteps:E,lmHeadFuse:r}),{stepUs:u}=await ot(i,s,f,h,{steps:E});return h.destroy(),u};for(const r of p)await m(r);const d=Object.fromEntries(p.map(r=>[r.name,[]]));for(let r=0;r<N;r++)for(const h of p)d[h.name].push(await m(h));b.push({B:a.B,...Object.fromEntries(p.map(r=>[`${r.name}StepUs`,Number(mt(d[r.name]).toFixed(1))])),runs:d})}finally{f.arena.destroy()}}return{pass:!0,detail:{steps:E,rounds:N,table:b}}}finally{s.buffer.destroy()}});
2
+ //# sourceMappingURL=argmax_fuse-CKXRwPoI.js.map
assets/{argmax_fuse-DghSWREY.js.map → argmax_fuse-CKXRwPoI.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"file":"argmax_fuse-DghSWREY.js","sources":["../../src/debug/tests/argmax_fuse.js"],"sourcesContent":["// Fused lm_head argmax (gemm_tiled2 IF_ARGMAX + argmax_reduce) vs the unfused\r\n// store-logits + argmax_penalty path. The fused path performs the SAME f32\r\n// ops in the same (val, lowest idx) order, so all three gates here are EXACT\r\n// integer comparisons — no tolerance:\r\n// argmax_fuse_kernel one dispatch pair on crafted data: duplicated W rows\r\n// with equal boosted bias force exact ties (intra-quad,\r\n// cross-tile, and at vocab id V-1), a pre-seen bit must\r\n// penalty-flip one row's winner, done rows must emit\r\n// PAD. Fused vs unfused state must match bit-for-bit\r\n// AND hit the hard-coded winners.\r\n// argmax_fuse_equiv e2e translateBatch fused vs unfused (f16-tiled and\r\n// the production q8 config): token-exact.\r\n// argmax_fuse_sweep interleaved step-wall A/B at B=16..128 (perf only).\r\nimport { registerTest } from '../registry.js';\r\nimport { createBuffer, readback } from '../gpu-utils.js';\r\nimport { dispatchGemm, dispatchArgmaxPenalty, dispatchArgmaxReduce } from '../../engine/pipelines.js';\r\nimport { loadWeights, quantizeQ8Rows } from '../../engine/weights.js';\r\nimport { loadTokenizer, tokenizeBatch } from '../../engine/tokenizer.js';\r\nimport { translateBatch } from '../../engine/generate.js';\r\nimport { runEncoder } from '../../engine/encoder.js';\r\nimport { createDecodeState } from '../../engine/decoder.js';\r\nimport { timeDecodeSteps } from '../../bench/profile.js';\r\nimport { presetChunks } from '../../bench/bench.js';\r\nimport { f32ToF16 } from '../../engine/f16.js';\r\nimport { VOCAB, D_MODEL, PAD, BITMASK_WORDS } from '../../engine/constants.js';\r\n\r\nconst V = VOCAB;\r\nconst K = D_MODEL;\r\nconst WORDS = BITMASK_WORDS;\r\nconst BN = 64;\r\nconst NT = Math.ceil(V / BN); // 375\r\n\r\nfunction mulberry32(seed) {\r\n let a = seed >>> 0;\r\n return () => {\r\n a = (a + 0x6d2b79f5) | 0;\r\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\r\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\r\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\r\n };\r\n}\r\n\r\nconst setBit = (mask, b, v) => { mask[b * WORDS + (v >> 5)] |= 1 << (v & 31); };\r\nconst getBit = (mask, b, v) => (mask[b * WORDS + (v >>> 5)] >>> (v & 31)) & 1;\r\n\r\nfunction diffU32(got, want) {\r\n let mismatches = 0;\r\n let first = -1;\r\n for (let i = 0; i < want.length; i++) {\r\n if (got[i] !== want[i]) {\r\n mismatches++;\r\n if (first < 0) first = i;\r\n }\r\n }\r\n return { mismatches, first };\r\n}\r\n\r\n// One lm_head + argmax step, fused or unfused, on private bitmask/done/ring\r\n// copies. Returns the readbacks. `w` is {half} (f16 [N,K]) or {packed,\r\n// scales} (wq8).\r\nasync function runArm(device, { fused, wq8, M, x, w, lbias, bitmask, done, t, tm8 }) {\r\n const rw = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC;\r\n const ro = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const xBuf = createBuffer(device, x, ro);\r\n const wBuf = createBuffer(device, wq8 ? w.packed : w.half, ro);\r\n const sBuf = wq8 ? createBuffer(device, w.scales, ro) : null;\r\n const lbBuf = createBuffer(device, lbias, ro);\r\n const maskBuf = createBuffer(device, bitmask, rw);\r\n const doneBuf = createBuffer(device, done, rw);\r\n const ringBuf = createBuffer(device, new Uint32Array((t + 1) * M).fill(0xdeadbeef), rw);\r\n const yBuf = fused ? null : device.createBuffer({ size: M * V * 4, usage: rw });\r\n const pBuf = fused ? device.createBuffer({ size: M * NT * 8, usage: rw }) : null;\r\n\r\n const flags = { t: 'f16', outT: 'f32', wt: true, tiled: true, ...(wq8 ? { wq8: true } : {}), tm8 };\r\n const scratch = [];\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n scratch.push(...dispatchGemm(device, pass, {\r\n x: xBuf, w: wBuf, ...(wq8 ? { scales: sBuf } : {}), y: yBuf,\r\n ...(fused ? { fusedArgmax: { partials: pBuf, lbias: lbBuf, seen: maskBuf } } : {}),\r\n M, K, N: V, flags,\r\n }).scratch);\r\n scratch.push(...(fused\r\n ? dispatchArgmaxReduce(device, pass, {\r\n partials: pBuf, bitmask: maskBuf, done: doneBuf, tokens: ringBuf, B: M, t, NT,\r\n })\r\n : dispatchArgmaxPenalty(device, pass, {\r\n logits: yBuf, bias: lbBuf, bitmask: maskBuf, done: doneBuf, tokens: ringBuf, B: M, t,\r\n })).scratch);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n\r\n const tokens = new Uint32Array(await readback(device, ringBuf, (t + 1) * M * 4));\r\n const doneOut = new Uint32Array(await readback(device, doneBuf, M * 4));\r\n const maskOut = new Uint32Array(await readback(device, maskBuf, M * WORDS * 4));\r\n for (const b of [xBuf, wBuf, sBuf, lbBuf, maskBuf, doneBuf, ringBuf, yBuf, pBuf, ...scratch]) b?.destroy();\r\n return { tokens: tokens.subarray(t * M), done: doneOut, bitmask: maskOut };\r\n}\r\n\r\nasync function fuseKernelCase(ctx, { wq8, tm8, seed }) {\r\n const { device } = ctx;\r\n const rng = mulberry32(seed);\r\n const M = 65; // row tail: grid y = 2, second workgroup only 1 valid row\r\n const t = 2;\r\n\r\n const x = new Uint16Array(M * K);\r\n for (let i = 0; i < x.length; i++) x[i] = f32ToF16(rng() - 0.5);\r\n const wF = new Float32Array(V * K); // [N,K] row-major (wt layout)\r\n for (let i = 0; i < wF.length; i++) wF[i] = rng() - 0.5;\r\n // Exact ties: duplicate row DUP into an intra-quad neighbor, a far tile,\r\n // and the last vocab id; equal boosted bias makes them the global max.\r\n const DUP = 4097;\r\n const DUPS = [4098, 12000, V - 1];\r\n for (const d of DUPS) wF.copyWithin(d * K, DUP * K, DUP * K + K);\r\n const lbias = new Float32Array(V);\r\n for (let i = 0; i < V; i++) lbias[i] = rng() - 0.5;\r\n for (const d of [DUP, ...DUPS]) lbias[d] = 50.0;\r\n\r\n let w;\r\n if (wq8) {\r\n w = quantizeQ8Rows(wF, V, K); // duplicated rows quantize identically\r\n } else {\r\n const half = new Uint16Array(V * K);\r\n for (let i = 0; i < wF.length; i++) half[i] = f32ToF16(wF[i]);\r\n w = { half };\r\n }\r\n\r\n // ~500 random seen bits per row (never on the tie ids), bit 0 like\r\n // production, DUP seen for row 2 → its winner must penalty-flip to 4098.\r\n const noTouch = new Set([DUP, ...DUPS]);\r\n const bitmask = new Uint32Array(M * WORDS);\r\n for (let b = 0; b < M; b++) {\r\n setBit(bitmask, b, 0);\r\n for (let i = 0; i < 500; i++) {\r\n const v = Math.floor(rng() * V);\r\n if (!noTouch.has(v)) setBit(bitmask, b, v);\r\n }\r\n }\r\n setBit(bitmask, 2, DUP);\r\n const done = new Uint32Array(M);\r\n done[3] = 1;\r\n done[64] = 1;\r\n\r\n const args = { wq8, M, x, w, lbias, t, tm8 };\r\n const fusedR = await runArm(device, { ...args, fused: true, bitmask: Uint32Array.from(bitmask), done: Uint32Array.from(done) });\r\n const plainR = await runArm(device, { ...args, fused: false, bitmask: Uint32Array.from(bitmask), done: Uint32Array.from(done) });\r\n\r\n const detail = { wq8, tm8, M, t, DUP, sampleTokens: Array.from(fusedR.tokens.subarray(0, 8)) };\r\n let pass = true;\r\n for (const field of ['tokens', 'done', 'bitmask']) {\r\n const { mismatches, first } = diffU32(fusedR[field], plainR[field]);\r\n if (mismatches > 0) {\r\n pass = false;\r\n detail[field] = { mismatches, first, fused: fusedR[field][first], plain: plainR[field][first] };\r\n }\r\n }\r\n // Hard-coded winners so a bug shared by both arms can't hide: ties break to\r\n // the LOWEST id, row 2's penalty flips it to the unpenalized duplicate,\r\n // done rows emit PAD and stay unmasked.\r\n for (const [name, got, want] of [\r\n ['row0Token', fusedR.tokens[0], DUP],\r\n ['row1Token', fusedR.tokens[1], DUP],\r\n ['row2Token', fusedR.tokens[2], DUPS[0]],\r\n ['row3Token', fusedR.tokens[3], PAD],\r\n ['row64Token', fusedR.tokens[64], PAD],\r\n ['row0Bit', getBit(fusedR.bitmask, 0, DUP), 1],\r\n ['row2Bit', getBit(fusedR.bitmask, 2, DUPS[0]), 1],\r\n ['row3BitUntouched', getBit(fusedR.bitmask, 3, DUP), 0],\r\n ]) {\r\n if (got !== want) {\r\n pass = false;\r\n detail[name] = { got, want };\r\n }\r\n }\r\n return { pass, detail };\r\n}\r\n\r\nregisterTest('argmax_fuse_kernel', (ctx) => (ctx.hasF16\r\n ? fuseKernelCase(ctx, { wq8: false, tm8: false, seed: 501 })\r\n : { skip: true, reason: 'no shader-f16' }));\r\nregisterTest('argmax_fuse_kernel_q8_tm8', (ctx) => (ctx.hasF16\r\n ? fuseKernelCase(ctx, { wq8: true, tm8: true, seed: 502 })\r\n : { skip: true, reason: 'no shader-f16' }));\r\n\r\n// e2e: fused vs unfused must be TOKEN-EXACT through ragged batches (EOS\r\n// compaction fires and must pin the fuse flag) in both the plain f16-tiled\r\n// and the production q8 lm_head configs.\r\nregisterTest('argmax_fuse_equiv', async (ctx) => {\r\n const { device } = ctx;\r\n if (!ctx.hasF16) return { skip: true, reason: 'no shader-f16' };\r\n const gctx = { device, dtype: 'f16', limits: ctx.limits };\r\n const chunks = [...presetChunks('file23k')].slice(0, 32); // unsorted → ragged\r\n const tok = await loadTokenizer();\r\n\r\n const configs = [\r\n { name: 'f16_tiled', loadOpts: {}, runOpts: { lmHead: 'tiled' } },\r\n { name: 'q8_prod', loadOpts: { lmHeadQ8: true, ffnWT: true }, runOpts: { lmHead: 'auto', ffn: 'auto' } },\r\n ];\r\n const detail = {};\r\n let pass = true;\r\n for (const { name, loadOpts, runOpts } of configs) {\r\n const weights = await loadWeights(device, '/weights', { targetDtype: 'f16', ...loadOpts });\r\n try {\r\n const off = await translateBatch(gctx, weights, tok, chunks, { ...runOpts, lmHeadFuse: 'off' });\r\n const on = await translateBatch(gctx, weights, tok, chunks, { ...runOpts, lmHeadFuse: 'auto' });\r\n let mismatches = 0;\r\n let firstRow = -1;\r\n for (let i = 0; i < chunks.length; i++) {\r\n const a = off.rows[i].ids;\r\n const b = on.rows[i].ids;\r\n if (a.length !== b.length || a.some((v, j) => v !== b[j])) {\r\n mismatches++;\r\n if (firstRow < 0) firstRow = i;\r\n }\r\n }\r\n detail[name] = {\r\n mismatches,\r\n ...(firstRow >= 0 ? { firstRow, off: off.rows[firstRow].text, on: on.rows[firstRow].text } : {}),\r\n compactions: { off: off.metrics.compactions, on: on.metrics.compactions },\r\n };\r\n if (mismatches > 0) pass = false;\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n }\r\n return { pass, detail };\r\n});\r\n\r\n// Perf A/B: production weights, arms interleaved per round in ONE session\r\n// (sequential runs drift ±30% with laptop thermals), medians of ROUNDS.\r\nconst ROUNDS = 7;\r\nconst STEPS = 50;\r\nconst BATCHES = [16, 32, 64, 128];\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\n\r\nregisterTest('argmax_fuse_sweep', async (ctx) => {\r\n const { device } = ctx;\r\n if (!ctx.hasF16) return { skip: true, reason: 'no shader-f16' };\r\n const weights = await loadWeights(device, '/weights', { targetDtype: 'f16', lmHeadQ8: true, ffnWT: true });\r\n try {\r\n const tok = await loadTokenizer();\r\n const gctx = { device, dtype: 'f16', limits: ctx.limits };\r\n const chunks = [...presetChunks('file23k')].sort((a, b) => b.length - a.length);\r\n\r\n const ARMS = [\r\n { name: 'off', lmHeadFuse: 'off' },\r\n { name: 'fused', lmHeadFuse: 'auto' },\r\n ];\r\n const table = [];\r\n for (const B of BATCHES) {\r\n const batch = await tokenizeBatch(tok, chunks.slice(0, B));\r\n const encRun = await runEncoder(gctx, weights, batch);\r\n await device.queue.onSubmittedWorkDone();\r\n try {\r\n const timeArm = async ({ lmHeadFuse }) => {\r\n const state = createDecodeState(gctx, weights, {\r\n B: batch.B, S: encRun.S, maxSteps: STEPS, lmHeadFuse,\r\n });\r\n const { stepUs } = await timeDecodeSteps(gctx, weights, encRun, state, { steps: STEPS });\r\n state.destroy();\r\n return stepUs;\r\n };\r\n for (const arm of ARMS) await timeArm(arm); // pipeline warmup\r\n const times = Object.fromEntries(ARMS.map((a) => [a.name, []]));\r\n for (let r = 0; r < ROUNDS; r++) {\r\n for (const arm of ARMS) times[arm.name].push(await timeArm(arm));\r\n }\r\n table.push({\r\n B: batch.B,\r\n ...Object.fromEntries(ARMS.map((a) => [`${a.name}StepUs`, Number(median(times[a.name]).toFixed(1))])),\r\n runs: times,\r\n });\r\n } finally {\r\n encRun.arena.destroy();\r\n }\r\n }\r\n return { pass: true, detail: { steps: STEPS, rounds: ROUNDS, table } };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n});\r\n"],"names":["V","VOCAB","K","D_MODEL","WORDS","BITMASK_WORDS","BN","NT","mulberry32","seed","a","t","setBit","mask","b","v","getBit","diffU32","got","want","mismatches","first","i","runArm","device","fused","wq8","M","x","w","lbias","bitmask","done","tm8","rw","ro","xBuf","createBuffer","wBuf","sBuf","lbBuf","maskBuf","doneBuf","ringBuf","yBuf","pBuf","flags","scratch","encoder","pass","dispatchGemm","dispatchArgmaxReduce","dispatchArgmaxPenalty","tokens","readback","doneOut","maskOut","fuseKernelCase","ctx","rng","f32ToF16","wF","DUP","DUPS","d","quantizeQ8Rows","half","noTouch","args","fusedR","plainR","detail","field","name","PAD","registerTest","gctx","chunks","presetChunks","tok","loadTokenizer","configs","loadOpts","runOpts","weights","loadWeights","off","translateBatch","on","firstRow","j","ROUNDS","STEPS","BATCHES","median","xs","s","m","ARMS","table","B","batch","tokenizeBatch","encRun","runEncoder","timeArm","lmHeadFuse","state","createDecodeState","stepUs","timeDecodeSteps","arm","times"],"mappings":"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"}
 
1
+ {"version":3,"file":"argmax_fuse-CKXRwPoI.js","sources":["../../src/debug/tests/argmax_fuse.js"],"sourcesContent":["// Fused lm_head argmax (gemm_tiled2 IF_ARGMAX + argmax_reduce) vs the unfused\r\n// store-logits + argmax_penalty path. The fused path performs the SAME f32\r\n// ops in the same (val, lowest idx) order, so all three gates here are EXACT\r\n// integer comparisons — no tolerance:\r\n// argmax_fuse_kernel one dispatch pair on crafted data: duplicated W rows\r\n// with equal boosted bias force exact ties (intra-quad,\r\n// cross-tile, and at vocab id V-1), a pre-seen bit must\r\n// penalty-flip one row's winner, done rows must emit\r\n// PAD. Fused vs unfused state must match bit-for-bit\r\n// AND hit the hard-coded winners.\r\n// argmax_fuse_equiv e2e translateBatch fused vs unfused (f16-tiled and\r\n// the production q8 config): token-exact.\r\n// argmax_fuse_sweep interleaved step-wall A/B at B=16..128 (perf only).\r\nimport { registerTest } from '../registry.js';\r\nimport { createBuffer, readback } from '../gpu-utils.js';\r\nimport { dispatchGemm, dispatchArgmaxPenalty, dispatchArgmaxReduce } from '../../engine/pipelines.js';\r\nimport { loadWeights, quantizeQ8Rows } from '../../engine/weights.js';\r\nimport { loadTokenizer, tokenizeBatch } from '../../engine/tokenizer.js';\r\nimport { translateBatch } from '../../engine/generate.js';\r\nimport { runEncoder } from '../../engine/encoder.js';\r\nimport { createDecodeState } from '../../engine/decoder.js';\r\nimport { timeDecodeSteps } from '../../bench/profile.js';\r\nimport { presetChunks } from '../../bench/bench.js';\r\nimport { f32ToF16 } from '../../engine/f16.js';\r\nimport { VOCAB, D_MODEL, PAD, BITMASK_WORDS } from '../../engine/constants.js';\r\n\r\nconst V = VOCAB;\r\nconst K = D_MODEL;\r\nconst WORDS = BITMASK_WORDS;\r\nconst BN = 64;\r\nconst NT = Math.ceil(V / BN); // 375\r\n\r\nfunction mulberry32(seed) {\r\n let a = seed >>> 0;\r\n return () => {\r\n a = (a + 0x6d2b79f5) | 0;\r\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\r\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\r\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\r\n };\r\n}\r\n\r\nconst setBit = (mask, b, v) => { mask[b * WORDS + (v >> 5)] |= 1 << (v & 31); };\r\nconst getBit = (mask, b, v) => (mask[b * WORDS + (v >>> 5)] >>> (v & 31)) & 1;\r\n\r\nfunction diffU32(got, want) {\r\n let mismatches = 0;\r\n let first = -1;\r\n for (let i = 0; i < want.length; i++) {\r\n if (got[i] !== want[i]) {\r\n mismatches++;\r\n if (first < 0) first = i;\r\n }\r\n }\r\n return { mismatches, first };\r\n}\r\n\r\n// One lm_head + argmax step, fused or unfused, on private bitmask/done/ring\r\n// copies. Returns the readbacks. `w` is {half} (f16 [N,K]) or {packed,\r\n// scales} (wq8).\r\nasync function runArm(device, { fused, wq8, M, x, w, lbias, bitmask, done, t, tm8 }) {\r\n const rw = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC;\r\n const ro = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const xBuf = createBuffer(device, x, ro);\r\n const wBuf = createBuffer(device, wq8 ? w.packed : w.half, ro);\r\n const sBuf = wq8 ? createBuffer(device, w.scales, ro) : null;\r\n const lbBuf = createBuffer(device, lbias, ro);\r\n const maskBuf = createBuffer(device, bitmask, rw);\r\n const doneBuf = createBuffer(device, done, rw);\r\n const ringBuf = createBuffer(device, new Uint32Array((t + 1) * M).fill(0xdeadbeef), rw);\r\n const yBuf = fused ? null : device.createBuffer({ size: M * V * 4, usage: rw });\r\n const pBuf = fused ? device.createBuffer({ size: M * NT * 8, usage: rw }) : null;\r\n\r\n const flags = { t: 'f16', outT: 'f32', wt: true, tiled: true, ...(wq8 ? { wq8: true } : {}), tm8 };\r\n const scratch = [];\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n scratch.push(...dispatchGemm(device, pass, {\r\n x: xBuf, w: wBuf, ...(wq8 ? { scales: sBuf } : {}), y: yBuf,\r\n ...(fused ? { fusedArgmax: { partials: pBuf, lbias: lbBuf, seen: maskBuf } } : {}),\r\n M, K, N: V, flags,\r\n }).scratch);\r\n scratch.push(...(fused\r\n ? dispatchArgmaxReduce(device, pass, {\r\n partials: pBuf, bitmask: maskBuf, done: doneBuf, tokens: ringBuf, B: M, t, NT,\r\n })\r\n : dispatchArgmaxPenalty(device, pass, {\r\n logits: yBuf, bias: lbBuf, bitmask: maskBuf, done: doneBuf, tokens: ringBuf, B: M, t,\r\n })).scratch);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n\r\n const tokens = new Uint32Array(await readback(device, ringBuf, (t + 1) * M * 4));\r\n const doneOut = new Uint32Array(await readback(device, doneBuf, M * 4));\r\n const maskOut = new Uint32Array(await readback(device, maskBuf, M * WORDS * 4));\r\n for (const b of [xBuf, wBuf, sBuf, lbBuf, maskBuf, doneBuf, ringBuf, yBuf, pBuf, ...scratch]) b?.destroy();\r\n return { tokens: tokens.subarray(t * M), done: doneOut, bitmask: maskOut };\r\n}\r\n\r\nasync function fuseKernelCase(ctx, { wq8, tm8, seed }) {\r\n const { device } = ctx;\r\n const rng = mulberry32(seed);\r\n const M = 65; // row tail: grid y = 2, second workgroup only 1 valid row\r\n const t = 2;\r\n\r\n const x = new Uint16Array(M * K);\r\n for (let i = 0; i < x.length; i++) x[i] = f32ToF16(rng() - 0.5);\r\n const wF = new Float32Array(V * K); // [N,K] row-major (wt layout)\r\n for (let i = 0; i < wF.length; i++) wF[i] = rng() - 0.5;\r\n // Exact ties: duplicate row DUP into an intra-quad neighbor, a far tile,\r\n // and the last vocab id; equal boosted bias makes them the global max.\r\n const DUP = 4097;\r\n const DUPS = [4098, 12000, V - 1];\r\n for (const d of DUPS) wF.copyWithin(d * K, DUP * K, DUP * K + K);\r\n const lbias = new Float32Array(V);\r\n for (let i = 0; i < V; i++) lbias[i] = rng() - 0.5;\r\n for (const d of [DUP, ...DUPS]) lbias[d] = 50.0;\r\n\r\n let w;\r\n if (wq8) {\r\n w = quantizeQ8Rows(wF, V, K); // duplicated rows quantize identically\r\n } else {\r\n const half = new Uint16Array(V * K);\r\n for (let i = 0; i < wF.length; i++) half[i] = f32ToF16(wF[i]);\r\n w = { half };\r\n }\r\n\r\n // ~500 random seen bits per row (never on the tie ids), bit 0 like\r\n // production, DUP seen for row 2 → its winner must penalty-flip to 4098.\r\n const noTouch = new Set([DUP, ...DUPS]);\r\n const bitmask = new Uint32Array(M * WORDS);\r\n for (let b = 0; b < M; b++) {\r\n setBit(bitmask, b, 0);\r\n for (let i = 0; i < 500; i++) {\r\n const v = Math.floor(rng() * V);\r\n if (!noTouch.has(v)) setBit(bitmask, b, v);\r\n }\r\n }\r\n setBit(bitmask, 2, DUP);\r\n const done = new Uint32Array(M);\r\n done[3] = 1;\r\n done[64] = 1;\r\n\r\n const args = { wq8, M, x, w, lbias, t, tm8 };\r\n const fusedR = await runArm(device, { ...args, fused: true, bitmask: Uint32Array.from(bitmask), done: Uint32Array.from(done) });\r\n const plainR = await runArm(device, { ...args, fused: false, bitmask: Uint32Array.from(bitmask), done: Uint32Array.from(done) });\r\n\r\n const detail = { wq8, tm8, M, t, DUP, sampleTokens: Array.from(fusedR.tokens.subarray(0, 8)) };\r\n let pass = true;\r\n for (const field of ['tokens', 'done', 'bitmask']) {\r\n const { mismatches, first } = diffU32(fusedR[field], plainR[field]);\r\n if (mismatches > 0) {\r\n pass = false;\r\n detail[field] = { mismatches, first, fused: fusedR[field][first], plain: plainR[field][first] };\r\n }\r\n }\r\n // Hard-coded winners so a bug shared by both arms can't hide: ties break to\r\n // the LOWEST id, row 2's penalty flips it to the unpenalized duplicate,\r\n // done rows emit PAD and stay unmasked.\r\n for (const [name, got, want] of [\r\n ['row0Token', fusedR.tokens[0], DUP],\r\n ['row1Token', fusedR.tokens[1], DUP],\r\n ['row2Token', fusedR.tokens[2], DUPS[0]],\r\n ['row3Token', fusedR.tokens[3], PAD],\r\n ['row64Token', fusedR.tokens[64], PAD],\r\n ['row0Bit', getBit(fusedR.bitmask, 0, DUP), 1],\r\n ['row2Bit', getBit(fusedR.bitmask, 2, DUPS[0]), 1],\r\n ['row3BitUntouched', getBit(fusedR.bitmask, 3, DUP), 0],\r\n ]) {\r\n if (got !== want) {\r\n pass = false;\r\n detail[name] = { got, want };\r\n }\r\n }\r\n return { pass, detail };\r\n}\r\n\r\nregisterTest('argmax_fuse_kernel', (ctx) => (ctx.hasF16\r\n ? fuseKernelCase(ctx, { wq8: false, tm8: false, seed: 501 })\r\n : { skip: true, reason: 'no shader-f16' }));\r\nregisterTest('argmax_fuse_kernel_q8_tm8', (ctx) => (ctx.hasF16\r\n ? fuseKernelCase(ctx, { wq8: true, tm8: true, seed: 502 })\r\n : { skip: true, reason: 'no shader-f16' }));\r\n\r\n// e2e: fused vs unfused must be TOKEN-EXACT through ragged batches (EOS\r\n// compaction fires and must pin the fuse flag) in both the plain f16-tiled\r\n// and the production q8 lm_head configs.\r\nregisterTest('argmax_fuse_equiv', async (ctx) => {\r\n const { device } = ctx;\r\n if (!ctx.hasF16) return { skip: true, reason: 'no shader-f16' };\r\n const gctx = { device, dtype: 'f16', limits: ctx.limits };\r\n const chunks = [...presetChunks('file23k')].slice(0, 32); // unsorted → ragged\r\n const tok = await loadTokenizer();\r\n\r\n const configs = [\r\n { name: 'f16_tiled', loadOpts: {}, runOpts: { lmHead: 'tiled' } },\r\n { name: 'q8_prod', loadOpts: { lmHeadQ8: true, ffnWT: true }, runOpts: { lmHead: 'auto', ffn: 'auto' } },\r\n ];\r\n const detail = {};\r\n let pass = true;\r\n for (const { name, loadOpts, runOpts } of configs) {\r\n const weights = await loadWeights(device, '/weights', { targetDtype: 'f16', ...loadOpts });\r\n try {\r\n const off = await translateBatch(gctx, weights, tok, chunks, { ...runOpts, lmHeadFuse: 'off' });\r\n const on = await translateBatch(gctx, weights, tok, chunks, { ...runOpts, lmHeadFuse: 'auto' });\r\n let mismatches = 0;\r\n let firstRow = -1;\r\n for (let i = 0; i < chunks.length; i++) {\r\n const a = off.rows[i].ids;\r\n const b = on.rows[i].ids;\r\n if (a.length !== b.length || a.some((v, j) => v !== b[j])) {\r\n mismatches++;\r\n if (firstRow < 0) firstRow = i;\r\n }\r\n }\r\n detail[name] = {\r\n mismatches,\r\n ...(firstRow >= 0 ? { firstRow, off: off.rows[firstRow].text, on: on.rows[firstRow].text } : {}),\r\n compactions: { off: off.metrics.compactions, on: on.metrics.compactions },\r\n };\r\n if (mismatches > 0) pass = false;\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n }\r\n return { pass, detail };\r\n});\r\n\r\n// Perf A/B: production weights, arms interleaved per round in ONE session\r\n// (sequential runs drift ±30% with laptop thermals), medians of ROUNDS.\r\nconst ROUNDS = 7;\r\nconst STEPS = 50;\r\nconst BATCHES = [16, 32, 64, 128];\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\n\r\nregisterTest('argmax_fuse_sweep', async (ctx) => {\r\n const { device } = ctx;\r\n if (!ctx.hasF16) return { skip: true, reason: 'no shader-f16' };\r\n const weights = await loadWeights(device, '/weights', { targetDtype: 'f16', lmHeadQ8: true, ffnWT: true });\r\n try {\r\n const tok = await loadTokenizer();\r\n const gctx = { device, dtype: 'f16', limits: ctx.limits };\r\n const chunks = [...presetChunks('file23k')].sort((a, b) => b.length - a.length);\r\n\r\n const ARMS = [\r\n { name: 'off', lmHeadFuse: 'off' },\r\n { name: 'fused', lmHeadFuse: 'auto' },\r\n ];\r\n const table = [];\r\n for (const B of BATCHES) {\r\n const batch = await tokenizeBatch(tok, chunks.slice(0, B));\r\n const encRun = await runEncoder(gctx, weights, batch);\r\n await device.queue.onSubmittedWorkDone();\r\n try {\r\n const timeArm = async ({ lmHeadFuse }) => {\r\n const state = createDecodeState(gctx, weights, {\r\n B: batch.B, S: encRun.S, maxSteps: STEPS, lmHeadFuse,\r\n });\r\n const { stepUs } = await timeDecodeSteps(gctx, weights, encRun, state, { steps: STEPS });\r\n state.destroy();\r\n return stepUs;\r\n };\r\n for (const arm of ARMS) await timeArm(arm); // pipeline warmup\r\n const times = Object.fromEntries(ARMS.map((a) => [a.name, []]));\r\n for (let r = 0; r < ROUNDS; r++) {\r\n for (const arm of ARMS) times[arm.name].push(await timeArm(arm));\r\n }\r\n table.push({\r\n B: batch.B,\r\n ...Object.fromEntries(ARMS.map((a) => [`${a.name}StepUs`, Number(median(times[a.name]).toFixed(1))])),\r\n runs: times,\r\n });\r\n } finally {\r\n encRun.arena.destroy();\r\n }\r\n }\r\n return { pass: true, detail: { steps: STEPS, rounds: ROUNDS, table } };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n});\r\n"],"names":["V","VOCAB","K","D_MODEL","WORDS","BITMASK_WORDS","BN","NT","mulberry32","seed","a","t","setBit","mask","b","v","getBit","diffU32","got","want","mismatches","first","runArm","device","fused","wq8","M","x","w","lbias","bitmask","done","tm8","rw","ro","xBuf","createBuffer","wBuf","sBuf","lbBuf","maskBuf","doneBuf","ringBuf","yBuf","pBuf","flags","scratch","encoder","pass","dispatchGemm","dispatchArgmaxReduce","dispatchArgmaxPenalty","tokens","readback","doneOut","maskOut","fuseKernelCase","ctx","rng","i","f32ToF16","wF","DUP","DUPS","d","quantizeQ8Rows","half","noTouch","args","fusedR","plainR","detail","field","name","PAD","registerTest","gctx","chunks","presetChunks","tok","loadTokenizer","configs","loadOpts","runOpts","weights","loadWeights","off","translateBatch","on","firstRow","j","ROUNDS","STEPS","BATCHES","median","xs","s","m","ARMS","table","B","batch","tokenizeBatch","encRun","runEncoder","timeArm","lmHeadFuse","state","createDecodeState","stepUs","timeDecodeSteps","arm","times"],"mappings":"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"}
assets/argmax_fuse-DghSWREY.js DELETED
@@ -1,2 +0,0 @@
1
- import{r as P}from"./debug-C_LNzFrK.js";import{c as _,r as R}from"./gpu-utils-BTh3AGTJ.js";import{h as J,i as X,j as Z}from"./pipelines-DJ7cc1m-.js";import{l as j,q as M}from"./weights-D8qtuKag.js";import{l as K,t as v}from"./tokenizer-Ex1u7wXD.js";import{t as H}from"./generate-BIP3NpbY.js";import{r as tt}from"./encoder-I9sHImnR.js";import{c as st}from"./decoder-CI9o-EVx.js";import{t as ot}from"./profile-Cs9YyiDl.js";import{p as Q}from"./bench-CEDJ-mff.js";import{f as G}from"./f16-wKKZr58e.js";import{D as et,V as nt,P as W,B as rt}from"./constants-C8VbFpic.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./shapes-BCQ9D81L.js";import"./device-BotbBNoe.js";import"./autotune-DywP5DSc.js";import"./chapter3k-DSdzHZt5.js";const U=nt,T=et,F=rt,at=64,q=Math.ceil(U/at);function ft(t){let o=t>>>0;return()=>{o=o+1831565813|0;let s=Math.imul(o^o>>>15,1|o);return s=s+Math.imul(s^s>>>7,61|s)^s,((s^s>>>14)>>>0)/4294967296}}const x=(t,o,s)=>{t[o*F+(s>>5)]|=1<<(s&31)},C=(t,o,s)=>t[o*F+(s>>>5)]>>>(s&31)&1;function it(t,o){let s=0,n=-1;for(let f=0;f<o.length;f++)t[f]!==o[f]&&(s++,n<0&&(n=f));return{mismatches:s,first:n}}async function z(t,{fused:o,wq8:s,M:n,x:f,w:k,lbias:p,bitmask:b,done:y,t:a,tm8:i}){const m=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,d=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,r=_(t,f,d),h=_(t,s?k.packed:k.half,d),u=s?_(t,k.scales,d):null,w=_(t,p,d),B=_(t,b,m),c=_(t,y,m),A=_(t,new Uint32Array((a+1)*n).fill(3735928559),m),S=o?null:t.createBuffer({size:n*U*4,usage:m}),O=o?t.createBuffer({size:n*q*8,usage:m}):null,e={t:"f16",outT:"f32",wt:!0,tiled:!0,...s?{wq8:!0}:{},tm8:i},l=[],g=t.createCommandEncoder(),D=g.beginComputePass();l.push(...J(t,D,{x:r,w:h,...s?{scales:u}:{},y:S,...o?{fusedArgmax:{partials:O,lbias:w,seen:B}}:{},M:n,K:T,N:U,flags:e}).scratch),l.push(...(o?X(t,D,{partials:O,bitmask:B,done:c,tokens:A,B:n,t:a,NT:q}):Z(t,D,{logits:S,bias:w,bitmask:B,done:c,tokens:A,B:n,t:a})).scratch),D.end(),t.queue.submit([g.finish()]);const Y=new Uint32Array(await R(t,A,(a+1)*n*4)),I=new Uint32Array(await R(t,c,n*4)),L=new Uint32Array(await R(t,B,n*F*4));for(const $ of[r,h,u,w,B,c,A,S,O,...l])$?.destroy();return{tokens:Y.subarray(a*n),done:I,bitmask:L}}async function V(t,{wq8:o,tm8:s,seed:n}){const{device:f}=t,k=ft(n),p=65,b=2,y=new Uint16Array(p*T);for(let e=0;e<y.length;e++)y[e]=G(k()-.5);const a=new Float32Array(U*T);for(let e=0;e<a.length;e++)a[e]=k()-.5;const i=4097,m=[4098,12e3,U-1];for(const e of m)a.copyWithin(e*T,i*T,i*T+T);const d=new Float32Array(U);for(let e=0;e<U;e++)d[e]=k()-.5;for(const e of[i,...m])d[e]=50;let r;if(o)r=M(a,U,T);else{const e=new Uint16Array(U*T);for(let l=0;l<a.length;l++)e[l]=G(a[l]);r={half:e}}const h=new Set([i,...m]),u=new Uint32Array(p*F);for(let e=0;e<p;e++){x(u,e,0);for(let l=0;l<500;l++){const g=Math.floor(k()*U);h.has(g)||x(u,e,g)}}x(u,2,i);const w=new Uint32Array(p);w[3]=1,w[64]=1;const B={wq8:o,M:p,x:y,w:r,lbias:d,t:b,tm8:s},c=await z(f,{...B,fused:!0,bitmask:Uint32Array.from(u),done:Uint32Array.from(w)}),A=await z(f,{...B,fused:!1,bitmask:Uint32Array.from(u),done:Uint32Array.from(w)}),S={wq8:o,tm8:s,M:p,t:b,DUP:i,sampleTokens:Array.from(c.tokens.subarray(0,8))};let O=!0;for(const e of["tokens","done","bitmask"]){const{mismatches:l,first:g}=it(c[e],A[e]);l>0&&(O=!1,S[e]={mismatches:l,first:g,fused:c[e][g],plain:A[e][g]})}for(const[e,l,g]of[["row0Token",c.tokens[0],i],["row1Token",c.tokens[1],i],["row2Token",c.tokens[2],m[0]],["row3Token",c.tokens[3],W],["row64Token",c.tokens[64],W],["row0Bit",C(c.bitmask,0,i),1],["row2Bit",C(c.bitmask,2,m[0]),1],["row3BitUntouched",C(c.bitmask,3,i),0]])l!==g&&(O=!1,S[e]={got:l,want:g});return{pass:O,detail:S}}P("argmax_fuse_kernel",t=>t.hasF16?V(t,{wq8:!1,tm8:!1,seed:501}):{skip:!0,reason:"no shader-f16"});P("argmax_fuse_kernel_q8_tm8",t=>t.hasF16?V(t,{wq8:!0,tm8:!0,seed:502}):{skip:!0,reason:"no shader-f16"});P("argmax_fuse_equiv",async t=>{const{device:o}=t;if(!t.hasF16)return{skip:!0,reason:"no shader-f16"};const s={device:o,dtype:"f16",limits:t.limits},n=[...Q("file23k")].slice(0,32),f=await K(),k=[{name:"f16_tiled",loadOpts:{},runOpts:{lmHead:"tiled"}},{name:"q8_prod",loadOpts:{lmHeadQ8:!0,ffnWT:!0},runOpts:{lmHead:"auto",ffn:"auto"}}],p={};let b=!0;for(const{name:y,loadOpts:a,runOpts:i}of k){const m=await j(o,"/weights",{targetDtype:"f16",...a});try{const d=await H(s,m,f,n,{...i,lmHeadFuse:"off"}),r=await H(s,m,f,n,{...i,lmHeadFuse:"auto"});let h=0,u=-1;for(let w=0;w<n.length;w++){const B=d.rows[w].ids,c=r.rows[w].ids;(B.length!==c.length||B.some((A,S)=>A!==c[S]))&&(h++,u<0&&(u=w))}p[y]={mismatches:h,...u>=0?{firstRow:u,off:d.rows[u].text,on:r.rows[u].text}:{},compactions:{off:d.metrics.compactions,on:r.metrics.compactions}},h>0&&(b=!1)}finally{m.buffer.destroy()}}return{pass:b,detail:p}});const N=7,E=50,ct=[16,32,64,128],mt=t=>{const o=[...t].sort((n,f)=>n-f),s=o.length>>1;return o.length%2?o[s]:(o[s-1]+o[s])/2};P("argmax_fuse_sweep",async t=>{const{device:o}=t;if(!t.hasF16)return{skip:!0,reason:"no shader-f16"};const s=await j(o,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0});try{const n=await K(),f={device:o,dtype:"f16",limits:t.limits},k=[...Q("file23k")].sort((y,a)=>a.length-y.length),p=[{name:"off",lmHeadFuse:"off"},{name:"fused",lmHeadFuse:"auto"}],b=[];for(const y of ct){const a=await v(n,k.slice(0,y)),i=await tt(f,s,a);await o.queue.onSubmittedWorkDone();try{const m=async({lmHeadFuse:r})=>{const h=st(f,s,{B:a.B,S:i.S,maxSteps:E,lmHeadFuse:r}),{stepUs:u}=await ot(f,s,i,h,{steps:E});return h.destroy(),u};for(const r of p)await m(r);const d=Object.fromEntries(p.map(r=>[r.name,[]]));for(let r=0;r<N;r++)for(const h of p)d[h.name].push(await m(h));b.push({B:a.B,...Object.fromEntries(p.map(r=>[`${r.name}StepUs`,Number(mt(d[r.name]).toFixed(1))])),runs:d})}finally{i.arena.destroy()}}return{pass:!0,detail:{steps:E,rounds:N,table:b}}}finally{s.buffer.destroy()}});
2
- //# sourceMappingURL=argmax_fuse-DghSWREY.js.map
 
 
 
assets/{attention-D1W9vlkP.js → attention-1v-Zzb1X.js} RENAMED
@@ -1,4 +1,4 @@
1
- import{r as F}from"./debug-C_LNzFrK.js";import{c as w,r as X,a as Z}from"./gpu-utils-BTh3AGTJ.js";import{g as N,d as ee,c as ne}from"./pipelines-DJ7cc1m-.js";import{b as q}from"./math-DNG-wiC0.js";import{f as te,e as W}from"./f16-wKKZr58e.js";import{H as re,d as se,A as $,S as ae}from"./constants-C8VbFpic.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";const oe=`// Scatter fused projection output into [B, L, H, D] K/V buffers. One thread\r
2
  // per (row, h·D+d) element, plain index math, no barriers. Within a fused row\r
3
  // each 448-wide chunk is laid out h*D + d — identical to the H,D tail of the\r
4
  // [B, L, H, D] cache index ((b*L + j)*H + h)*D + d = (b*L + j)*H*D + (h*D + d),\r
@@ -62,4 +62,4 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {\r
62
  {{/IF_SPLIT}}\r
63
  }\r
64
  `,S=se,k=re,n=S*k;function v(e){let t=e>>>0;return()=>{t=t+1831565813|0;let r=Math.imul(t^t>>>15,1|t);return r=r+Math.imul(r^r>>>7,61|r)^r,((r^r>>>14)>>>0)/4294967296}}function L(e,t){const r=new Float32Array(e);for(let s=0;s<e;s++)r[s]=Math.fround(t()-.5);return r}function T(e,t){if(t!=="f16")return{data:e,ref:e};const r=new Uint16Array(e.length);for(let s=0;s<e.length;s++)r[s]=te(e[s]);return{data:r,ref:W(r)}}function z(e,t){const r=Math.ceil(t.length*4/16)*16,s=e.createBuffer({size:r,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});return new Uint32Array(s.getMappedRange()).set(t),s.unmap(),s}function C(e){return e==="f16"?2:4}function fe(e,t,r={},s=!1){return N(e,"attention",ne,{t,wg:128,sg:s,defines:{H:S,D:k,SCORES_CAP:ae,ATTN_SCALE:$,Q_STRIDE:n,Q_OFF:0,KV_STRIDE:n,K_OFF:0,V_OFF:0,...r}})}function ue(e,t,{qb:r,jb:s},o={}){return N(e,"attention_block",ee,{t,defines:{H:S,D:k,QB:r,JB:s,ATTN_SCALE:$,Q_STRIDE:n,Q_OFF:0,KV_STRIDE:n,K_OFF:0,V_OFF:0,PACKED:!1,NOPACKED:!0,...o}})}function x(e,t,r){return N(e,"kv_append",oe,{t,wg:128,defines:{H:S,D:k,APPEND:r==="append",SPLIT:r==="split"}})}function K(e,t,r,s,o=1,g=1){const b=e.createBindGroup({layout:t.getBindGroupLayout(0),entries:r.map((B,i)=>({binding:i,resource:{buffer:B}}))}),d=e.createCommandEncoder(),a=d.beginComputePass();a.setPipeline(t),a.setBindGroup(0,b),a.dispatchWorkgroups(s,o,g),a.end(),e.queue.submit([d.finish()])}async function V(e,t,{qBuf:r,kBuf:s,vBuf:o,lensBuf:g,B:b,M:d,L:a,lenMode:B,step:i,strides:c,block:l,sg:h},P,A,_){const D=l?ue(e,t,l,c):fe(e,t,c,h),m=z(e,[b,d,a,B,i??0,0,0,0]),y=[m];let f=g;f||(f=e.createBuffer({label:"attn dummy lens",size:4,usage:GPUBufferUsage.STORAGE}),y.push(f));const E=b*d*n,p=e.createBuffer({size:Math.ceil(E*C(t)/4)*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC});l?K(e,D,[m,r,s,o,f,p],Math.ceil(d/l.qb),S,b):K(e,D,[m,r,s,o,f,p],b*d,S);const H=await X(e,p,E*C(t)),G=t==="f16"?W(new Uint16Array(H)):new Float32Array(H);for(const J of[...y,p])J.destroy();const{failures:R,maxAbsDiff:u,worst:M}=Z(G,P,A);return{pass:R===0,detail:{..._,tol:A,failures:R,maxAbsDiff:String(u),...R>0?{worst:M,got:String(G[M]),want:String(P[M])}:{}}}}async function U(e,{B:t,M:r,L:s,lens:o,t:g,tol:b,seed:d,block:a,sg:B=!1}){const{device:i}=e,c=v(d),l=T(L(t*r*n,c),g),h=T(L(t*s*n,c),g),P=T(L(t*s*n,c),g),A=q(l.ref,h.ref,P.ref,{B:t,M:r,H:S,D:k,L:s,lens:o}),_=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,D=w(i,l.data,_),m=w(i,h.data,_),y=w(i,P.data,_),f=w(i,new Uint32Array(o),_),E=await V(i,g,{qBuf:D,kBuf:m,vBuf:y,lensBuf:f,B:t,M:r,L:s,lenMode:1,block:a,sg:B},A,b,{kernel:a?`attention_block qb${a.qb} jb${a.jb}`:"attention",mode:"encoder",B:t,M:r,L:s,lens:o.join(","),t:g});for(const p of[D,m,y,f])p.destroy();return E}async function Q(e,{B:t,S:r,lens:s,t:o,tol:g,seed:b,block:d}){const{device:a}=e,B=v(b),i=t*r,c=T(L(i*3*n,B),o),l=new Float32Array(i*n),h=new Float32Array(i*n),P=new Float32Array(i*n);for(let f=0;f<i;f++)l.set(c.ref.subarray(f*3*n,f*3*n+n),f*n),h.set(c.ref.subarray(f*3*n+n,f*3*n+2*n),f*n),P.set(c.ref.subarray(f*3*n+2*n,f*3*n+3*n),f*n);const A=q(l,h,P,{B:t,M:r,H:S,D:k,L:r,lens:s}),_=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,D=w(a,c.data,_),m=w(a,new Uint32Array(s),_),y=await V(a,o,{qBuf:D,kBuf:D,vBuf:D,lensBuf:m,B:t,M:r,L:r,lenMode:1,block:d,strides:{Q_STRIDE:3*n,Q_OFF:0,KV_STRIDE:3*n,K_OFF:n,V_OFF:2*n}},A,g,{kernel:d?`attention_block qb${d.qb} jb${d.jb}`:"attention",mode:"encoder-fused",B:t,S:r,lens:s.join(","),t:o});for(const f of[D,m])f.destroy();return y}async function j(e,{B:t,Lmax:r,steps:s,t:o,tol:g,seed:b,sg:d=!1}){const{device:a}=e,B=v(b),i=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,c=t*r*n*C(o),l=a.createBuffer({size:c,usage:GPUBufferUsage.STORAGE}),h=a.createBuffer({size:c,usage:GPUBufferUsage.STORAGE}),P=x(a,o,"append"),A=new Float32Array(t*r*n),_=new Float32Array(t*r*n),D=new Float32Array(t*n);for(let p=0;p<s;p++){const H=T(L(t*3*n,B),o),G=w(a,H.data,i),R=z(a,[t,p,r,0]);K(a,P,[R,G,l,h],Math.ceil(t*n/128));for(let u=0;u<t;u++){const M=(u*r+p)*n;A.set(H.ref.subarray(u*3*n+n,u*3*n+2*n),M),_.set(H.ref.subarray(u*3*n+2*n,u*3*n+3*n),M),p===s-1&&D.set(H.ref.subarray(u*3*n,u*3*n+n),u*n)}G.destroy()}const m=T(D,o),y=w(a,m.data,i),f=q(m.ref,A,_,{B:t,M:1,H:S,D:k,L:r,lens:Array(t).fill(s)}),E=await V(a,o,{qBuf:y,kBuf:l,vBuf:h,lensBuf:null,B:t,M:1,L:r,lenMode:0,step:s-1,sg:d},f,g,{kernel:"kv_append+attention",mode:"decode",B:t,Lmax:r,steps:s,t:o});for(const p of[y,l,h])p.destroy();return E}async function Y(e,{B:t,S:r,lens:s,t:o,tol:g,seed:b,sg:d=!1}){const{device:a}=e,B=v(b),i=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,c=t*r,l=T(L(c*2*n,B),o),h=w(a,l.data,i),P=c*n*C(o),A=a.createBuffer({size:P,usage:GPUBufferUsage.STORAGE}),_=a.createBuffer({size:P,usage:GPUBufferUsage.STORAGE}),D=x(a,o,"split"),m=z(a,[t,0,0,c]);K(a,D,[m,h,A,_],Math.ceil(c*n/128));const y=new Float32Array(c*n),f=new Float32Array(c*n);for(let u=0;u<c;u++)y.set(l.ref.subarray(u*2*n,u*2*n+n),u*n),f.set(l.ref.subarray(u*2*n+n,u*2*n+2*n),u*n);const E=T(L(t*n,B),o),p=w(a,E.data,i),H=w(a,new Uint32Array(s),i),G=q(E.ref,y,f,{B:t,M:1,H:S,D:k,L:r,lens:s}),R=await V(a,o,{qBuf:p,kBuf:A,vBuf:_,lensBuf:H,B:t,M:1,L:r,lenMode:1,sg:d},G,g,{kernel:"kv_split+attention",mode:"cross",B:t,S:r,lens:s.join(","),t:o});for(const u of[h,p,A,_,H])u.destroy();return R}function O(e,t){F(e,r=>r.hasF16?t(r):{skip:!0,reason:"no shader-f16"})}O("attn_encoder_f16",e=>U(e,{B:2,M:16,L:16,lens:[16,9],t:"f16",tol:.03,seed:301}));O("attn_encoder_fused_f16",e=>Q(e,{B:2,S:16,lens:[16,9],t:"f16",tol:.03,seed:305}));O("attn_decode_f16",e=>j(e,{B:3,Lmax:32,steps:5,t:"f16",tol:.03,seed:302}));O("attn_cross_f16",e=>Y(e,{B:2,S:32,lens:[32,20],t:"f16",tol:.03,seed:303}));F("attn_encoder_f32",e=>U(e,{B:1,M:4,L:4,lens:[3],t:"f32",tol:1e-4,seed:304}));O("attn_block_encoder_f16",e=>U(e,{B:2,M:20,L:20,lens:[20,9],t:"f16",tol:.03,seed:311,block:{qb:8,jb:16}}));O("attn_block_encoder_fused_f16",e=>Q(e,{B:3,S:33,lens:[33,17,5],t:"f16",tol:.03,seed:312,block:{qb:16,jb:32}}));O("attn_block_encoder_fused_jb48_f16",e=>Q(e,{B:2,S:50,lens:[50,49],t:"f16",tol:.03,seed:313,block:{qb:8,jb:48}}));F("attn_block_encoder_f32",e=>U(e,{B:2,M:9,L:12,lens:[12,3],t:"f32",tol:1e-4,seed:314,block:{qb:8,jb:16}}));const I=e=>e.hasSubgroups?null:{skip:!0,reason:"subgroups feature unavailable"};F("attn_sg_encoder_f16",e=>I(e)??(e.hasF16?U(e,{B:2,M:16,L:16,lens:[16,9],t:"f16",tol:.03,seed:301,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_sg_decode_f16",e=>I(e)??(e.hasF16?j(e,{B:3,Lmax:32,steps:5,t:"f16",tol:.03,seed:302,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_sg_cross_f16",e=>I(e)??(e.hasF16?Y(e,{B:2,S:32,lens:[32,20],t:"f16",tol:.03,seed:303,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_sg_encoder_f32",e=>I(e)??U(e,{B:1,M:4,L:4,lens:[3],t:"f32",tol:1e-4,seed:304,sg:!0}));F("attn_sg_long_encoder_f16",e=>I(e)??(e.hasF16?U(e,{B:2,M:8,L:224,lens:[224,131],t:"f16",tol:.03,seed:321,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_sg_long_decode_f16",e=>I(e)??(e.hasF16?j(e,{B:2,Lmax:224,steps:160,t:"f16",tol:.03,seed:322,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_sg_long_cross_f16",e=>I(e)??(e.hasF16?Y(e,{B:2,S:192,lens:[192,130],t:"f16",tol:.03,seed:323,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_long_encoder_f16",e=>e.hasF16?U(e,{B:2,M:8,L:224,lens:[224,131],t:"f16",tol:.03,seed:321}):{skip:!0,reason:"no shader-f16"});F("attn_long_decode_f16",e=>e.hasF16?j(e,{B:2,Lmax:224,steps:160,t:"f16",tol:.03,seed:322}):{skip:!0,reason:"no shader-f16"});
65
- //# sourceMappingURL=attention-D1W9vlkP.js.map
 
1
+ import{r as F}from"./debug-CPpXXfWA.js";import{c as w,r as X,a as Z}from"./gpu-utils-BTh3AGTJ.js";import{g as N,d as ee,c as ne}from"./pipelines-BbLc75sB.js";import{b as q}from"./math-LI6LFmUv.js";import{f as te,e as W}from"./f16-wKKZr58e.js";import{H as re,d as se,A as $,S as ae}from"./constants-CSVWRdrh.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./safe_storage-BYkOahew.js";const oe=`// Scatter fused projection output into [B, L, H, D] K/V buffers. One thread\r
2
  // per (row, h·D+d) element, plain index math, no barriers. Within a fused row\r
3
  // each 448-wide chunk is laid out h*D + d — identical to the H,D tail of the\r
4
  // [B, L, H, D] cache index ((b*L + j)*H + h)*D + d = (b*L + j)*H*D + (h*D + d),\r
 
62
  {{/IF_SPLIT}}\r
63
  }\r
64
  `,S=se,k=re,n=S*k;function v(e){let t=e>>>0;return()=>{t=t+1831565813|0;let r=Math.imul(t^t>>>15,1|t);return r=r+Math.imul(r^r>>>7,61|r)^r,((r^r>>>14)>>>0)/4294967296}}function L(e,t){const r=new Float32Array(e);for(let s=0;s<e;s++)r[s]=Math.fround(t()-.5);return r}function T(e,t){if(t!=="f16")return{data:e,ref:e};const r=new Uint16Array(e.length);for(let s=0;s<e.length;s++)r[s]=te(e[s]);return{data:r,ref:W(r)}}function z(e,t){const r=Math.ceil(t.length*4/16)*16,s=e.createBuffer({size:r,usage:GPUBufferUsage.UNIFORM,mappedAtCreation:!0});return new Uint32Array(s.getMappedRange()).set(t),s.unmap(),s}function C(e){return e==="f16"?2:4}function fe(e,t,r={},s=!1){return N(e,"attention",ne,{t,wg:128,sg:s,defines:{H:S,D:k,SCORES_CAP:ae,ATTN_SCALE:$,Q_STRIDE:n,Q_OFF:0,KV_STRIDE:n,K_OFF:0,V_OFF:0,...r}})}function ue(e,t,{qb:r,jb:s},o={}){return N(e,"attention_block",ee,{t,defines:{H:S,D:k,QB:r,JB:s,ATTN_SCALE:$,Q_STRIDE:n,Q_OFF:0,KV_STRIDE:n,K_OFF:0,V_OFF:0,PACKED:!1,NOPACKED:!0,...o}})}function x(e,t,r){return N(e,"kv_append",oe,{t,wg:128,defines:{H:S,D:k,APPEND:r==="append",SPLIT:r==="split"}})}function K(e,t,r,s,o=1,g=1){const b=e.createBindGroup({layout:t.getBindGroupLayout(0),entries:r.map((B,i)=>({binding:i,resource:{buffer:B}}))}),d=e.createCommandEncoder(),a=d.beginComputePass();a.setPipeline(t),a.setBindGroup(0,b),a.dispatchWorkgroups(s,o,g),a.end(),e.queue.submit([d.finish()])}async function V(e,t,{qBuf:r,kBuf:s,vBuf:o,lensBuf:g,B:b,M:d,L:a,lenMode:B,step:i,strides:c,block:l,sg:h},P,A,_){const D=l?ue(e,t,l,c):fe(e,t,c,h),m=z(e,[b,d,a,B,i??0,0,0,0]),y=[m];let f=g;f||(f=e.createBuffer({label:"attn dummy lens",size:4,usage:GPUBufferUsage.STORAGE}),y.push(f));const E=b*d*n,p=e.createBuffer({size:Math.ceil(E*C(t)/4)*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC});l?K(e,D,[m,r,s,o,f,p],Math.ceil(d/l.qb),S,b):K(e,D,[m,r,s,o,f,p],b*d,S);const H=await X(e,p,E*C(t)),G=t==="f16"?W(new Uint16Array(H)):new Float32Array(H);for(const J of[...y,p])J.destroy();const{failures:R,maxAbsDiff:u,worst:M}=Z(G,P,A);return{pass:R===0,detail:{..._,tol:A,failures:R,maxAbsDiff:String(u),...R>0?{worst:M,got:String(G[M]),want:String(P[M])}:{}}}}async function U(e,{B:t,M:r,L:s,lens:o,t:g,tol:b,seed:d,block:a,sg:B=!1}){const{device:i}=e,c=v(d),l=T(L(t*r*n,c),g),h=T(L(t*s*n,c),g),P=T(L(t*s*n,c),g),A=q(l.ref,h.ref,P.ref,{B:t,M:r,H:S,D:k,L:s,lens:o}),_=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,D=w(i,l.data,_),m=w(i,h.data,_),y=w(i,P.data,_),f=w(i,new Uint32Array(o),_),E=await V(i,g,{qBuf:D,kBuf:m,vBuf:y,lensBuf:f,B:t,M:r,L:s,lenMode:1,block:a,sg:B},A,b,{kernel:a?`attention_block qb${a.qb} jb${a.jb}`:"attention",mode:"encoder",B:t,M:r,L:s,lens:o.join(","),t:g});for(const p of[D,m,y,f])p.destroy();return E}async function Q(e,{B:t,S:r,lens:s,t:o,tol:g,seed:b,block:d}){const{device:a}=e,B=v(b),i=t*r,c=T(L(i*3*n,B),o),l=new Float32Array(i*n),h=new Float32Array(i*n),P=new Float32Array(i*n);for(let f=0;f<i;f++)l.set(c.ref.subarray(f*3*n,f*3*n+n),f*n),h.set(c.ref.subarray(f*3*n+n,f*3*n+2*n),f*n),P.set(c.ref.subarray(f*3*n+2*n,f*3*n+3*n),f*n);const A=q(l,h,P,{B:t,M:r,H:S,D:k,L:r,lens:s}),_=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,D=w(a,c.data,_),m=w(a,new Uint32Array(s),_),y=await V(a,o,{qBuf:D,kBuf:D,vBuf:D,lensBuf:m,B:t,M:r,L:r,lenMode:1,block:d,strides:{Q_STRIDE:3*n,Q_OFF:0,KV_STRIDE:3*n,K_OFF:n,V_OFF:2*n}},A,g,{kernel:d?`attention_block qb${d.qb} jb${d.jb}`:"attention",mode:"encoder-fused",B:t,S:r,lens:s.join(","),t:o});for(const f of[D,m])f.destroy();return y}async function j(e,{B:t,Lmax:r,steps:s,t:o,tol:g,seed:b,sg:d=!1}){const{device:a}=e,B=v(b),i=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,c=t*r*n*C(o),l=a.createBuffer({size:c,usage:GPUBufferUsage.STORAGE}),h=a.createBuffer({size:c,usage:GPUBufferUsage.STORAGE}),P=x(a,o,"append"),A=new Float32Array(t*r*n),_=new Float32Array(t*r*n),D=new Float32Array(t*n);for(let p=0;p<s;p++){const H=T(L(t*3*n,B),o),G=w(a,H.data,i),R=z(a,[t,p,r,0]);K(a,P,[R,G,l,h],Math.ceil(t*n/128));for(let u=0;u<t;u++){const M=(u*r+p)*n;A.set(H.ref.subarray(u*3*n+n,u*3*n+2*n),M),_.set(H.ref.subarray(u*3*n+2*n,u*3*n+3*n),M),p===s-1&&D.set(H.ref.subarray(u*3*n,u*3*n+n),u*n)}G.destroy()}const m=T(D,o),y=w(a,m.data,i),f=q(m.ref,A,_,{B:t,M:1,H:S,D:k,L:r,lens:Array(t).fill(s)}),E=await V(a,o,{qBuf:y,kBuf:l,vBuf:h,lensBuf:null,B:t,M:1,L:r,lenMode:0,step:s-1,sg:d},f,g,{kernel:"kv_append+attention",mode:"decode",B:t,Lmax:r,steps:s,t:o});for(const p of[y,l,h])p.destroy();return E}async function Y(e,{B:t,S:r,lens:s,t:o,tol:g,seed:b,sg:d=!1}){const{device:a}=e,B=v(b),i=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,c=t*r,l=T(L(c*2*n,B),o),h=w(a,l.data,i),P=c*n*C(o),A=a.createBuffer({size:P,usage:GPUBufferUsage.STORAGE}),_=a.createBuffer({size:P,usage:GPUBufferUsage.STORAGE}),D=x(a,o,"split"),m=z(a,[t,0,0,c]);K(a,D,[m,h,A,_],Math.ceil(c*n/128));const y=new Float32Array(c*n),f=new Float32Array(c*n);for(let u=0;u<c;u++)y.set(l.ref.subarray(u*2*n,u*2*n+n),u*n),f.set(l.ref.subarray(u*2*n+n,u*2*n+2*n),u*n);const E=T(L(t*n,B),o),p=w(a,E.data,i),H=w(a,new Uint32Array(s),i),G=q(E.ref,y,f,{B:t,M:1,H:S,D:k,L:r,lens:s}),R=await V(a,o,{qBuf:p,kBuf:A,vBuf:_,lensBuf:H,B:t,M:1,L:r,lenMode:1,sg:d},G,g,{kernel:"kv_split+attention",mode:"cross",B:t,S:r,lens:s.join(","),t:o});for(const u of[h,p,A,_,H])u.destroy();return R}function O(e,t){F(e,r=>r.hasF16?t(r):{skip:!0,reason:"no shader-f16"})}O("attn_encoder_f16",e=>U(e,{B:2,M:16,L:16,lens:[16,9],t:"f16",tol:.03,seed:301}));O("attn_encoder_fused_f16",e=>Q(e,{B:2,S:16,lens:[16,9],t:"f16",tol:.03,seed:305}));O("attn_decode_f16",e=>j(e,{B:3,Lmax:32,steps:5,t:"f16",tol:.03,seed:302}));O("attn_cross_f16",e=>Y(e,{B:2,S:32,lens:[32,20],t:"f16",tol:.03,seed:303}));F("attn_encoder_f32",e=>U(e,{B:1,M:4,L:4,lens:[3],t:"f32",tol:1e-4,seed:304}));O("attn_block_encoder_f16",e=>U(e,{B:2,M:20,L:20,lens:[20,9],t:"f16",tol:.03,seed:311,block:{qb:8,jb:16}}));O("attn_block_encoder_fused_f16",e=>Q(e,{B:3,S:33,lens:[33,17,5],t:"f16",tol:.03,seed:312,block:{qb:16,jb:32}}));O("attn_block_encoder_fused_jb48_f16",e=>Q(e,{B:2,S:50,lens:[50,49],t:"f16",tol:.03,seed:313,block:{qb:8,jb:48}}));F("attn_block_encoder_f32",e=>U(e,{B:2,M:9,L:12,lens:[12,3],t:"f32",tol:1e-4,seed:314,block:{qb:8,jb:16}}));const I=e=>e.hasSubgroups?null:{skip:!0,reason:"subgroups feature unavailable"};F("attn_sg_encoder_f16",e=>I(e)??(e.hasF16?U(e,{B:2,M:16,L:16,lens:[16,9],t:"f16",tol:.03,seed:301,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_sg_decode_f16",e=>I(e)??(e.hasF16?j(e,{B:3,Lmax:32,steps:5,t:"f16",tol:.03,seed:302,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_sg_cross_f16",e=>I(e)??(e.hasF16?Y(e,{B:2,S:32,lens:[32,20],t:"f16",tol:.03,seed:303,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_sg_encoder_f32",e=>I(e)??U(e,{B:1,M:4,L:4,lens:[3],t:"f32",tol:1e-4,seed:304,sg:!0}));F("attn_sg_long_encoder_f16",e=>I(e)??(e.hasF16?U(e,{B:2,M:8,L:224,lens:[224,131],t:"f16",tol:.03,seed:321,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_sg_long_decode_f16",e=>I(e)??(e.hasF16?j(e,{B:2,Lmax:224,steps:160,t:"f16",tol:.03,seed:322,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_sg_long_cross_f16",e=>I(e)??(e.hasF16?Y(e,{B:2,S:192,lens:[192,130],t:"f16",tol:.03,seed:323,sg:!0}):{skip:!0,reason:"no shader-f16"}));F("attn_long_encoder_f16",e=>e.hasF16?U(e,{B:2,M:8,L:224,lens:[224,131],t:"f16",tol:.03,seed:321}):{skip:!0,reason:"no shader-f16"});F("attn_long_decode_f16",e=>e.hasF16?j(e,{B:2,Lmax:224,steps:160,t:"f16",tol:.03,seed:322}):{skip:!0,reason:"no shader-f16"});
65
+ //# sourceMappingURL=attention-1v-Zzb1X.js.map
assets/{attention-D1W9vlkP.js.map → attention-1v-Zzb1X.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"file":"attention-D1W9vlkP.js","sources":["../../src/engine/kernels/kv_append.wgsl?raw","../../src/debug/tests/attention.js"],"sourcesContent":["export default \"// Scatter fused projection output into [B, L, H, D] K/V buffers. One thread\\r\\n// per (row, h·D+d) element, plain index math, no barriers. Within a fused row\\r\\n// each 448-wide chunk is laid out h*D + d — identical to the H,D tail of the\\r\\n// [B, L, H, D] cache index ((b*L + j)*H + h)*D + d = (b*L + j)*H*D + (h*D + d),\\r\\n// so the copy is a contiguous-chunk scatter with no per-element shuffling.\\r\\n//\\r\\n// Two build-time modes (exactly one of APPEND / SPLIT):\\r\\n// APPEND (decode step): fused is fusedQKV [B, 3·H·D] (q at 0, k at H·D,\\r\\n// v at 2·H·D). Thread (b, i) writes BOTH caches at position t:\\r\\n// Kc[(b*Lmax + t)*H*D + i] = fused[b*3HD + HD + i]\\r\\n// Vc[(b*Lmax + t)*H*D + i] = fused[b*3HD + 2HD + i]\\r\\n// Total threads B·H·D. Uses params.B, params.t, params.Lmax.\\r\\n// SPLIT — currently unused by the engine (attention reads fused K/V buffers\\r\\n// directly via its Q_STRIDE/KV_STRIDE/*_OFF defines); kept for tests and\\r\\n// as a fallback. Cross K/V after encoder: fused is fusedKV [B·S, 2·H·D] (k at 0,\\r\\n// v at H·D). Here the [B, L, H, D] buffers have L = S exactly (allocated\\r\\n// to the padded bucket length), so row = b·S + j indexes both sides:\\r\\n// Kc[row*H*D + i] = fused[row*2HD + i]\\r\\n// Vc[row*H*D + i] = fused[row*2HD + HD + i]\\r\\n// Total threads rows·H·D. Uses params.rows only.\\r\\n//\\r\\n// Template placeholders (buildShader in pipelines.js):\\r\\n// ENABLE_F16 the f16 enable directive when T is f16, else empty\\r\\n// T storage type of fused/Kc/Vc (f16|f32) — straight copy,\\r\\n// no conversion\\r\\n// WG workgroup size\\r\\n// H, D heads (8), head dim (56)\\r\\n// IF_APPEND/IF_SPLIT mode blocks\\r\\n{{ENABLE_IMMEDIATE}}\\r\\n{{ENABLE_F16}}\\r\\n\\r\\nstruct Params {\\r\\n B: u32, // APPEND: batch\\r\\n t: u32, // APPEND: decode step (write position)\\r\\n Lmax: u32, // APPEND: K/V cache position capacity (stride)\\r\\n rows: u32, // SPLIT: B·S fused rows\\r\\n}\\r\\n\\r\\n{{PARAM_BINDING}}var<{{PARAM_ADDRESS}}> params: Params;\\r\\n@group(0) @binding(1) var<storage, read> fused: array<{{T}}>;\\r\\n@group(0) @binding(2) var<storage, read_write> Kc: array<{{T}}>;\\r\\n@group(0) @binding(3) var<storage, read_write> Vc: array<{{T}}>;\\r\\n\\r\\nconst HD: u32 = {{H}}u * {{D}}u;\\r\\n\\r\\n@compute @workgroup_size({{WG}})\\r\\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\\r\\n{{IF_APPEND}}\\r\\n if (gid.x >= params.B * HD) { return; }\\r\\n let b = gid.x / HD;\\r\\n let i = gid.x % HD; // h*D + d\\r\\n let dst = (b * params.Lmax + params.t) * HD + i;\\r\\n Kc[dst] = fused[b * 3u * HD + HD + i];\\r\\n Vc[dst] = fused[b * 3u * HD + 2u * HD + i];\\r\\n{{/IF_APPEND}}\\r\\n{{IF_SPLIT}}\\r\\n if (gid.x >= params.rows * HD) { return; }\\r\\n let r = gid.x / HD; // b*S + j\\r\\n let i = gid.x % HD; // h*D + d\\r\\n Kc[r * HD + i] = fused[r * 2u * HD + i];\\r\\n Vc[r * HD + i] = fused[r * 2u * HD + HD + i];\\r\\n{{/IF_SPLIT}}\\r\\n}\\r\\n\"","// GPU unified-attention + kv_append kernels vs the JS f64 reference\r\n// (attentionRef). f16 test data is encoded to f16 and decoded back to f32 for\r\n// the reference input, so ref and GPU see IDENTICAL values (pattern from\r\n// gemm.js). The decode test drives kv_append APPEND across 5 simulated steps\r\n// and validates its indexing THROUGH attention — the way the engine uses it.\r\n// Per-call uniform/bind-group creation is test-only plumbing.\r\nimport { registerTest } from '../registry.js';\r\nimport { createBuffer, readback, compareLanes } from '../gpu-utils.js';\r\nimport { getPipeline } from '../../engine/pipelines.js';\r\nimport { attentionRef } from '../../reference/math.js';\r\nimport { f32ToF16, expandF16 } from '../../engine/f16.js';\r\nimport { HEADS, HEAD_DIM, ATTN_SCALE, SCORES_CAP } from '../../engine/constants.js';\r\nimport attentionSource from '../../engine/kernels/attention.wgsl?raw';\r\nimport attentionBlockSource from '../../engine/kernels/attention_block.wgsl?raw';\r\nimport kvAppendSource from '../../engine/kernels/kv_append.wgsl?raw';\r\n\r\nconst H = HEADS, D = HEAD_DIM, HD = H * D; // 8 · 56 = 448 = D_MODEL\r\n\r\nfunction mulberry32(seed) {\r\n let a = seed >>> 0;\r\n return () => {\r\n a = (a + 0x6d2b79f5) | 0;\r\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\r\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\r\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\r\n };\r\n}\r\n\r\nfunction randF32(n, rng) {\r\n const out = new Float32Array(n);\r\n for (let i = 0; i < n; i++) out[i] = Math.fround(rng() - 0.5); // ~±0.5\r\n return out;\r\n}\r\n\r\n// {data, ref} pair for a given storage type: encode to f16 for the GPU and\r\n// decode back to f32 for the reference so both see identical values.\r\nfunction prep(f32arr, t) {\r\n if (t !== 'f16') return { data: f32arr, ref: f32arr };\r\n const half = new Uint16Array(f32arr.length);\r\n for (let i = 0; i < f32arr.length; i++) half[i] = f32ToF16(f32arr[i]);\r\n return { data: half, ref: expandF16(half) };\r\n}\r\n\r\nfunction makeUniform(device, vals) {\r\n const size = Math.ceil((vals.length * 4) / 16) * 16;\r\n const buf = device.createBuffer({ size, usage: GPUBufferUsage.UNIFORM, mappedAtCreation: true });\r\n new Uint32Array(buf.getMappedRange()).set(vals);\r\n buf.unmap();\r\n return buf;\r\n}\r\n\r\nfunction elemBytes(t) { return t === 'f16' ? 2 : 4; }\r\n\r\n// strides overrides the default compact layouts (Q [B·M, HD], K/V [B, L, H, D])\r\n// with fused-buffer strides/offsets — see attention.wgsl.\r\nfunction attentionPipeline(device, t, strides = {}, sg = false) {\r\n return getPipeline(device, 'attention', attentionSource, {\r\n t, wg: 128, sg,\r\n defines: {\r\n H, D, SCORES_CAP, ATTN_SCALE,\r\n Q_STRIDE: HD, Q_OFF: 0, KV_STRIDE: HD, K_OFF: 0, V_OFF: 0,\r\n ...strides,\r\n },\r\n });\r\n}\r\n\r\n// Blocked encoder variant (attention_block.wgsl) — grid (ceil(M/QB), H, B).\r\nfunction attentionBlockPipeline(device, t, { qb, jb }, strides = {}) {\r\n return getPipeline(device, 'attention_block', attentionBlockSource, {\r\n t,\r\n defines: {\r\n H, D, QB: qb, JB: jb, ATTN_SCALE,\r\n Q_STRIDE: HD, Q_OFF: 0, KV_STRIDE: HD, K_OFF: 0, V_OFF: 0,\r\n PACKED: false, NOPACKED: true,\r\n ...strides,\r\n },\r\n });\r\n}\r\n\r\nfunction kvAppendPipeline(device, t, mode) {\r\n return getPipeline(device, 'kv_append', kvAppendSource, {\r\n t, wg: 128, defines: { H, D, APPEND: mode === 'append', SPLIT: mode === 'split' },\r\n });\r\n}\r\n\r\nfunction dispatch(device, pipeline, buffers, wgX, wgY = 1, wgZ = 1) {\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: buffers.map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.dispatchWorkgroups(wgX, wgY, wgZ);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n}\r\n\r\n// Run attention (grid B·M × H, or (ceil(M/QB), H, B) when block = {qb, jb}),\r\n// read back Y [B·M, HD], compare to ref.\r\nasync function runAttentionAndCompare(device, t, { qBuf, kBuf, vBuf, lensBuf, B, M, L, lenMode, step, strides, block, sg }, want, tol, label) {\r\n const pipeline = block\r\n ? attentionBlockPipeline(device, t, block, strides)\r\n : attentionPipeline(device, t, strides, sg);\r\n const params = makeUniform(device, [B, M, L, lenMode, step ?? 0, 0, 0, 0]);\r\n const scratch = [params];\r\n let lens = lensBuf;\r\n if (!lens) { // lenMode 0: dummy 4-byte buffer, never indexed\r\n lens = device.createBuffer({ label: 'attn dummy lens', size: 4, usage: GPUBufferUsage.STORAGE });\r\n scratch.push(lens);\r\n }\r\n const outElems = B * M * HD;\r\n const yBuf = device.createBuffer({\r\n size: Math.ceil((outElems * elemBytes(t)) / 4) * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n });\r\n if (block) {\r\n dispatch(device, pipeline, [params, qBuf, kBuf, vBuf, lens, yBuf], Math.ceil(M / block.qb), H, B);\r\n } else {\r\n dispatch(device, pipeline, [params, qBuf, kBuf, vBuf, lens, yBuf], B * M, H);\r\n }\r\n const raw = await readback(device, yBuf, outElems * elemBytes(t));\r\n const got = t === 'f16' ? expandF16(new Uint16Array(raw)) : new Float32Array(raw);\r\n for (const b of [...scratch, yBuf]) b.destroy();\r\n\r\n const { failures, maxAbsDiff, worst } = compareLanes(got, want, tol);\r\n return {\r\n pass: failures === 0,\r\n detail: {\r\n ...label, tol, failures,\r\n maxAbsDiff: String(maxAbsDiff), // string: JSON turns NaN/Infinity into null\r\n ...(failures > 0 ? { worst, got: String(got[worst]), want: String(want[worst]) } : {}),\r\n },\r\n };\r\n}\r\n\r\n// --------------------------------------------------- encoder self / direct ---\r\n\r\n// K/V built directly in [B, L, H, D] layout; ragged lens via lenMode 1.\r\n// block = {qb, jb} routes through the blocked kernel instead.\r\nasync function runEncoderCase(ctx, { B, M, L, lens, t, tol, seed, block, sg = false }) {\r\n const { device } = ctx;\r\n const rng = mulberry32(seed);\r\n const q = prep(randF32(B * M * HD, rng), t);\r\n const k = prep(randF32(B * L * HD, rng), t);\r\n const v = prep(randF32(B * L * HD, rng), t);\r\n const want = attentionRef(q.ref, k.ref, v.ref, { B, M, H, D, L, lens });\r\n\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const qBuf = createBuffer(device, q.data, usage);\r\n const kBuf = createBuffer(device, k.data, usage);\r\n const vBuf = createBuffer(device, v.data, usage);\r\n const lensBuf = createBuffer(device, new Uint32Array(lens), usage);\r\n const result = await runAttentionAndCompare(\r\n device, t, { qBuf, kBuf, vBuf, lensBuf, B, M, L, lenMode: 1, block, sg },\r\n want, tol, {\r\n kernel: block ? `attention_block qb${block.qb} jb${block.jb}` : 'attention',\r\n mode: 'encoder', B, M, L, lens: lens.join(','), t,\r\n });\r\n for (const b of [qBuf, kBuf, vBuf, lensBuf]) b.destroy();\r\n return result;\r\n}\r\n\r\n// ----------------------------------------------------- encoder self, fused ---\r\n\r\n// Attention reads q/k/v slices DIRECTLY from the fused QKV projection output\r\n// [B·S, 3·HD] via Q_STRIDE/KV_STRIDE + offsets (Q=K=V= the same buffer) — the\r\n// way the encoder pass uses it. Reference gets the slices extracted in JS.\r\nasync function runEncoderFusedCase(ctx, { B, S, lens, t, tol, seed, block }) {\r\n const { device } = ctx;\r\n const rng = mulberry32(seed);\r\n const rows = B * S;\r\n const fused = prep(randF32(rows * 3 * HD, rng), t);\r\n const qRef = new Float32Array(rows * HD);\r\n const kRef = new Float32Array(rows * HD); // [B, S, H, D] == per-row slices\r\n const vRef = new Float32Array(rows * HD);\r\n for (let r = 0; r < rows; r++) {\r\n qRef.set(fused.ref.subarray(r * 3 * HD, r * 3 * HD + HD), r * HD);\r\n kRef.set(fused.ref.subarray(r * 3 * HD + HD, r * 3 * HD + 2 * HD), r * HD);\r\n vRef.set(fused.ref.subarray(r * 3 * HD + 2 * HD, r * 3 * HD + 3 * HD), r * HD);\r\n }\r\n const want = attentionRef(qRef, kRef, vRef, { B, M: S, H, D, L: S, lens });\r\n\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const fusedBuf = createBuffer(device, fused.data, usage);\r\n const lensBuf = createBuffer(device, new Uint32Array(lens), usage);\r\n const result = await runAttentionAndCompare(\r\n device, t,\r\n {\r\n qBuf: fusedBuf, kBuf: fusedBuf, vBuf: fusedBuf, lensBuf, B, M: S, L: S, lenMode: 1, block,\r\n strides: { Q_STRIDE: 3 * HD, Q_OFF: 0, KV_STRIDE: 3 * HD, K_OFF: HD, V_OFF: 2 * HD },\r\n },\r\n want, tol, {\r\n kernel: block ? `attention_block qb${block.qb} jb${block.jb}` : 'attention',\r\n mode: 'encoder-fused', B, S, lens: lens.join(','), t,\r\n });\r\n for (const b of [fusedBuf, lensBuf]) b.destroy();\r\n return result;\r\n}\r\n\r\n// ------------------------------------------- decode: kv_append + attention ---\r\n\r\n// Simulates 5 decode steps: each appends a random fused [B, 3·HD] row into the\r\n// K/V caches via kv_append APPEND, then attention runs with lenMode 0, t=4.\r\n// The reference assembles k/v in JS from the SAME fused rows, so kv_append's\r\n// cache indexing is cross-validated through attention.\r\nasync function runDecodeCase(ctx, { B, Lmax, steps, t, tol, seed, sg = false }) {\r\n const { device } = ctx;\r\n const rng = mulberry32(seed);\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n\r\n // Zero-initialized caches, [B, Lmax, H, D]. Positions >= steps stay zero and\r\n // must never be read (len = t+1 = steps).\r\n const cacheBytes = B * Lmax * HD * elemBytes(t);\r\n const kBuf = device.createBuffer({ size: cacheBytes, usage: GPUBufferUsage.STORAGE });\r\n const vBuf = device.createBuffer({ size: cacheBytes, usage: GPUBufferUsage.STORAGE });\r\n\r\n const appendPipe = kvAppendPipeline(device, t, 'append');\r\n const kRef = new Float32Array(B * Lmax * HD);\r\n const vRef = new Float32Array(B * Lmax * HD);\r\n const qF32 = new Float32Array(B * HD);\r\n for (let step = 0; step < steps; step++) {\r\n const fused = prep(randF32(B * 3 * HD, rng), t); // [B, q|k|v]\r\n const fusedBuf = createBuffer(device, fused.data, usage);\r\n const params = makeUniform(device, [B, step, Lmax, 0]);\r\n dispatch(device, appendPipe, [params, fusedBuf, kBuf, vBuf], Math.ceil((B * HD) / 128));\r\n for (let b = 0; b < B; b++) {\r\n const dst = (b * Lmax + step) * HD;\r\n kRef.set(fused.ref.subarray(b * 3 * HD + HD, b * 3 * HD + 2 * HD), dst);\r\n vRef.set(fused.ref.subarray(b * 3 * HD + 2 * HD, b * 3 * HD + 3 * HD), dst);\r\n if (step === steps - 1) {\r\n // The last step's q slice feeds attention — matches how the engine\r\n // consumes the fused QKV projection during decode.\r\n qF32.set(fused.ref.subarray(b * 3 * HD, b * 3 * HD + HD), b * HD);\r\n }\r\n }\r\n fusedBuf.destroy();\r\n }\r\n const q = prep(qF32, t); // ref values are already f16-exact; re-encode is lossless\r\n const qBuf = createBuffer(device, q.data, usage);\r\n const want = attentionRef(q.ref, kRef, vRef, {\r\n B, M: 1, H, D, L: Lmax, lens: Array(B).fill(steps),\r\n });\r\n const result = await runAttentionAndCompare(\r\n device, t, { qBuf, kBuf, vBuf, lensBuf: null, B, M: 1, L: Lmax, lenMode: 0, step: steps - 1, sg },\r\n want, tol, { kernel: 'kv_append+attention', mode: 'decode', B, Lmax, steps, t });\r\n for (const b of [qBuf, kBuf, vBuf]) b.destroy();\r\n return result;\r\n}\r\n\r\n// -------------------------------------------- cross: kv_split + attention ---\r\n\r\n// kv_append SPLIT scatters fused [B·S, 2·HD] into K/V [B, S, H, D] (L = S),\r\n// then attention runs with lenMode 1 and ragged lens.\r\nasync function runCrossCase(ctx, { B, S, lens, t, tol, seed, sg = false }) {\r\n const { device } = ctx;\r\n const rng = mulberry32(seed);\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const rows = B * S;\r\n\r\n const fused = prep(randF32(rows * 2 * HD, rng), t);\r\n const fusedBuf = createBuffer(device, fused.data, usage);\r\n const cacheBytes = rows * HD * elemBytes(t);\r\n const kBuf = device.createBuffer({ size: cacheBytes, usage: GPUBufferUsage.STORAGE });\r\n const vBuf = device.createBuffer({ size: cacheBytes, usage: GPUBufferUsage.STORAGE });\r\n const splitPipe = kvAppendPipeline(device, t, 'split');\r\n const params = makeUniform(device, [B, 0, 0, rows]);\r\n dispatch(device, splitPipe, [params, fusedBuf, kBuf, vBuf], Math.ceil((rows * HD) / 128));\r\n\r\n const kRef = new Float32Array(rows * HD);\r\n const vRef = new Float32Array(rows * HD);\r\n for (let r = 0; r < rows; r++) {\r\n kRef.set(fused.ref.subarray(r * 2 * HD, r * 2 * HD + HD), r * HD);\r\n vRef.set(fused.ref.subarray(r * 2 * HD + HD, r * 2 * HD + 2 * HD), r * HD);\r\n }\r\n const q = prep(randF32(B * HD, rng), t);\r\n const qBuf = createBuffer(device, q.data, usage);\r\n const lensBuf = createBuffer(device, new Uint32Array(lens), usage);\r\n const want = attentionRef(q.ref, kRef, vRef, { B, M: 1, H, D, L: S, lens });\r\n const result = await runAttentionAndCompare(\r\n device, t, { qBuf, kBuf, vBuf, lensBuf, B, M: 1, L: S, lenMode: 1, sg },\r\n want, tol, { kernel: 'kv_split+attention', mode: 'cross', B, S, lens: lens.join(','), t });\r\n for (const b of [fusedBuf, qBuf, kBuf, vBuf, lensBuf]) b.destroy();\r\n return result;\r\n}\r\n\r\nfunction registerF16(name, fn) {\r\n registerTest(name, (ctx) =>\r\n ctx.hasF16 ? fn(ctx) : { skip: true, reason: 'no shader-f16' });\r\n}\r\n\r\n// f16 tol 0.03: D=56 dots and up-to-352-term weighted sums accumulate in f32,\r\n// but f16 output rounding + softmax weight sensitivity warrant slack.\r\nregisterF16('attn_encoder_f16', (ctx) =>\r\n runEncoderCase(ctx, { B: 2, M: 16, L: 16, lens: [16, 9], t: 'f16', tol: 0.03, seed: 301 }));\r\nregisterF16('attn_encoder_fused_f16', (ctx) =>\r\n runEncoderFusedCase(ctx, { B: 2, S: 16, lens: [16, 9], t: 'f16', tol: 0.03, seed: 305 }));\r\nregisterF16('attn_decode_f16', (ctx) =>\r\n runDecodeCase(ctx, { B: 3, Lmax: 32, steps: 5, t: 'f16', tol: 0.03, seed: 302 }));\r\nregisterF16('attn_cross_f16', (ctx) =>\r\n runCrossCase(ctx, { B: 2, S: 32, lens: [32, 20], t: 'f16', tol: 0.03, seed: 303 }));\r\n// f32 fallback-mode sanity for the template.\r\nregisterTest('attn_encoder_f32', (ctx) =>\r\n runEncoderCase(ctx, { B: 1, M: 4, L: 4, lens: [3], t: 'f32', tol: 1e-4, seed: 304 }));\r\n\r\n// Blocked encoder kernel (attention_block.wgsl). Shapes chosen to exercise\r\n// every guard: M not a multiple of QB (query tail block), lens crossing\r\n// several JB tiles with a partial last tile, ragged lens including a len < JB\r\n// row, and both compact and fused-QKV layouts. Tol matches the unblocked f16\r\n// cases — online softmax changes summation order, not precision class.\r\nregisterF16('attn_block_encoder_f16', (ctx) =>\r\n runEncoderCase(ctx, {\r\n B: 2, M: 20, L: 20, lens: [20, 9], t: 'f16', tol: 0.03, seed: 311,\r\n block: { qb: 8, jb: 16 },\r\n }));\r\nregisterF16('attn_block_encoder_fused_f16', (ctx) =>\r\n runEncoderFusedCase(ctx, {\r\n B: 3, S: 33, lens: [33, 17, 5], t: 'f16', tol: 0.03, seed: 312,\r\n block: { qb: 16, jb: 32 },\r\n }));\r\nregisterF16('attn_block_encoder_fused_jb48_f16', (ctx) =>\r\n runEncoderFusedCase(ctx, {\r\n B: 2, S: 50, lens: [50, 49], t: 'f16', tol: 0.03, seed: 313,\r\n block: { qb: 8, jb: 48 },\r\n }));\r\nregisterTest('attn_block_encoder_f32', (ctx) =>\r\n runEncoderCase(ctx, {\r\n B: 2, M: 9, L: 12, lens: [12, 3], t: 'f32', tol: 1e-4, seed: 314,\r\n block: { qb: 8, jb: 16 },\r\n }));\r\n\r\n// Subgroup-reduction attention (flags.sg — IF_SG variant): tolerance-equal\r\n// to the tree (reduction order differs), and the CORRECTNESS route on\r\n// Adreno 7xx, whose driver miscompiles this kernel's tree reduce (2026-07\r\n// Android round; autotune force-enables sg there). Shapes mirror the plain\r\n// cases, same seeds → same data.\r\nconst sgSkip = (ctx) => (ctx.hasSubgroups ? null : { skip: true, reason: 'subgroups feature unavailable' });\r\nregisterTest('attn_sg_encoder_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runEncoderCase(ctx, { B: 2, M: 16, L: 16, lens: [16, 9], t: 'f16', tol: 0.03, seed: 301, sg: true })));\r\nregisterTest('attn_sg_decode_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runDecodeCase(ctx, { B: 3, Lmax: 32, steps: 5, t: 'f16', tol: 0.03, seed: 302, sg: true })));\r\nregisterTest('attn_sg_cross_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runCrossCase(ctx, { B: 2, S: 32, lens: [32, 20], t: 'f16', tol: 0.03, seed: 303, sg: true })));\r\nregisterTest('attn_sg_encoder_f32', (ctx) => sgSkip(ctx)\r\n ?? runEncoderCase(ctx, { B: 1, M: 4, L: 4, lens: [3], t: 'f32', tol: 1e-4, seed: 304, sg: true }));\r\n\r\n// Long-L sg arms — the production shape the short goldens miss: app rows are\r\n// ~200 chars → decode self-attn len grows past WG=128 (the scan loop turns\r\n// multi-trip per thread) and cross len ≈ S ≈ 100-192. The Adreno miscompile\r\n// family is context-sensitive (multi-trip strided loops were an ingredient),\r\n// so the sg variant must be proven AT THESE LENGTHS on-device, not just at\r\n// golden-sentence lengths.\r\nregisterTest('attn_sg_long_encoder_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runEncoderCase(ctx, { B: 2, M: 8, L: 224, lens: [224, 131], t: 'f16', tol: 0.03, seed: 321, sg: true })));\r\nregisterTest('attn_sg_long_decode_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runDecodeCase(ctx, { B: 2, Lmax: 224, steps: 160, t: 'f16', tol: 0.03, seed: 322, sg: true })));\r\nregisterTest('attn_sg_long_cross_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runCrossCase(ctx, { B: 2, S: 192, lens: [192, 130], t: 'f16', tol: 0.03, seed: 323, sg: true })));\r\n// Tree twins at the same long shapes: FAIL expected on the affected Adreno\r\n// (tree broken there) — they double as the on-device control that the long\r\n// shapes do exercise the broken paths.\r\nregisterTest('attn_long_encoder_f16', (ctx) => (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runEncoderCase(ctx, { B: 2, M: 8, L: 224, lens: [224, 131], t: 'f16', tol: 0.03, seed: 321 })));\r\nregisterTest('attn_long_decode_f16', (ctx) => (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runDecodeCase(ctx, { B: 2, Lmax: 224, steps: 160, t: 'f16', tol: 0.03, seed: 322 })));\r\n"],"names":["kvAppendSource","H","HEADS","D","HEAD_DIM","HD","mulberry32","seed","a","t","randF32","n","rng","out","i","prep","f32arr","half","f32ToF16","expandF16","makeUniform","device","vals","size","buf","elemBytes","attentionPipeline","strides","sg","getPipeline","attentionSource","SCORES_CAP","ATTN_SCALE","attentionBlockPipeline","qb","jb","attentionBlockSource","kvAppendPipeline","mode","dispatch","pipeline","buffers","wgX","wgY","wgZ","bindGroup","buffer","binding","encoder","pass","runAttentionAndCompare","qBuf","kBuf","vBuf","lensBuf","B","M","L","lenMode","step","block","want","tol","label","params","scratch","lens","outElems","yBuf","raw","readback","got","b","failures","maxAbsDiff","worst","compareLanes","runEncoderCase","ctx","q","k","v","attentionRef","usage","createBuffer","result","runEncoderFusedCase","S","rows","fused","qRef","kRef","vRef","r","fusedBuf","runDecodeCase","Lmax","steps","cacheBytes","appendPipe","qF32","dst","runCrossCase","splitPipe","registerF16","name","fn","registerTest","sgSkip"],"mappings":"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"}
 
1
+ {"version":3,"file":"attention-1v-Zzb1X.js","sources":["../../src/engine/kernels/kv_append.wgsl?raw","../../src/debug/tests/attention.js"],"sourcesContent":["export default \"// Scatter fused projection output into [B, L, H, D] K/V buffers. One thread\\r\\n// per (row, h·D+d) element, plain index math, no barriers. Within a fused row\\r\\n// each 448-wide chunk is laid out h*D + d — identical to the H,D tail of the\\r\\n// [B, L, H, D] cache index ((b*L + j)*H + h)*D + d = (b*L + j)*H*D + (h*D + d),\\r\\n// so the copy is a contiguous-chunk scatter with no per-element shuffling.\\r\\n//\\r\\n// Two build-time modes (exactly one of APPEND / SPLIT):\\r\\n// APPEND (decode step): fused is fusedQKV [B, 3·H·D] (q at 0, k at H·D,\\r\\n// v at 2·H·D). Thread (b, i) writes BOTH caches at position t:\\r\\n// Kc[(b*Lmax + t)*H*D + i] = fused[b*3HD + HD + i]\\r\\n// Vc[(b*Lmax + t)*H*D + i] = fused[b*3HD + 2HD + i]\\r\\n// Total threads B·H·D. Uses params.B, params.t, params.Lmax.\\r\\n// SPLIT — currently unused by the engine (attention reads fused K/V buffers\\r\\n// directly via its Q_STRIDE/KV_STRIDE/*_OFF defines); kept for tests and\\r\\n// as a fallback. Cross K/V after encoder: fused is fusedKV [B·S, 2·H·D] (k at 0,\\r\\n// v at H·D). Here the [B, L, H, D] buffers have L = S exactly (allocated\\r\\n// to the padded bucket length), so row = b·S + j indexes both sides:\\r\\n// Kc[row*H*D + i] = fused[row*2HD + i]\\r\\n// Vc[row*H*D + i] = fused[row*2HD + HD + i]\\r\\n// Total threads rows·H·D. Uses params.rows only.\\r\\n//\\r\\n// Template placeholders (buildShader in pipelines.js):\\r\\n// ENABLE_F16 the f16 enable directive when T is f16, else empty\\r\\n// T storage type of fused/Kc/Vc (f16|f32) — straight copy,\\r\\n// no conversion\\r\\n// WG workgroup size\\r\\n// H, D heads (8), head dim (56)\\r\\n// IF_APPEND/IF_SPLIT mode blocks\\r\\n{{ENABLE_IMMEDIATE}}\\r\\n{{ENABLE_F16}}\\r\\n\\r\\nstruct Params {\\r\\n B: u32, // APPEND: batch\\r\\n t: u32, // APPEND: decode step (write position)\\r\\n Lmax: u32, // APPEND: K/V cache position capacity (stride)\\r\\n rows: u32, // SPLIT: B·S fused rows\\r\\n}\\r\\n\\r\\n{{PARAM_BINDING}}var<{{PARAM_ADDRESS}}> params: Params;\\r\\n@group(0) @binding(1) var<storage, read> fused: array<{{T}}>;\\r\\n@group(0) @binding(2) var<storage, read_write> Kc: array<{{T}}>;\\r\\n@group(0) @binding(3) var<storage, read_write> Vc: array<{{T}}>;\\r\\n\\r\\nconst HD: u32 = {{H}}u * {{D}}u;\\r\\n\\r\\n@compute @workgroup_size({{WG}})\\r\\nfn main(@builtin(global_invocation_id) gid: vec3<u32>) {\\r\\n{{IF_APPEND}}\\r\\n if (gid.x >= params.B * HD) { return; }\\r\\n let b = gid.x / HD;\\r\\n let i = gid.x % HD; // h*D + d\\r\\n let dst = (b * params.Lmax + params.t) * HD + i;\\r\\n Kc[dst] = fused[b * 3u * HD + HD + i];\\r\\n Vc[dst] = fused[b * 3u * HD + 2u * HD + i];\\r\\n{{/IF_APPEND}}\\r\\n{{IF_SPLIT}}\\r\\n if (gid.x >= params.rows * HD) { return; }\\r\\n let r = gid.x / HD; // b*S + j\\r\\n let i = gid.x % HD; // h*D + d\\r\\n Kc[r * HD + i] = fused[r * 2u * HD + i];\\r\\n Vc[r * HD + i] = fused[r * 2u * HD + HD + i];\\r\\n{{/IF_SPLIT}}\\r\\n}\\r\\n\"","// GPU unified-attention + kv_append kernels vs the JS f64 reference\r\n// (attentionRef). f16 test data is encoded to f16 and decoded back to f32 for\r\n// the reference input, so ref and GPU see IDENTICAL values (pattern from\r\n// gemm.js). The decode test drives kv_append APPEND across 5 simulated steps\r\n// and validates its indexing THROUGH attention — the way the engine uses it.\r\n// Per-call uniform/bind-group creation is test-only plumbing.\r\nimport { registerTest } from '../registry.js';\r\nimport { createBuffer, readback, compareLanes } from '../gpu-utils.js';\r\nimport { getPipeline } from '../../engine/pipelines.js';\r\nimport { attentionRef } from '../../reference/math.js';\r\nimport { f32ToF16, expandF16 } from '../../engine/f16.js';\r\nimport { HEADS, HEAD_DIM, ATTN_SCALE, SCORES_CAP } from '../../engine/constants.js';\r\nimport attentionSource from '../../engine/kernels/attention.wgsl?raw';\r\nimport attentionBlockSource from '../../engine/kernels/attention_block.wgsl?raw';\r\nimport kvAppendSource from '../../engine/kernels/kv_append.wgsl?raw';\r\n\r\nconst H = HEADS, D = HEAD_DIM, HD = H * D; // 8 · 56 = 448 = D_MODEL\r\n\r\nfunction mulberry32(seed) {\r\n let a = seed >>> 0;\r\n return () => {\r\n a = (a + 0x6d2b79f5) | 0;\r\n let t = Math.imul(a ^ (a >>> 15), 1 | a);\r\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\r\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\r\n };\r\n}\r\n\r\nfunction randF32(n, rng) {\r\n const out = new Float32Array(n);\r\n for (let i = 0; i < n; i++) out[i] = Math.fround(rng() - 0.5); // ~±0.5\r\n return out;\r\n}\r\n\r\n// {data, ref} pair for a given storage type: encode to f16 for the GPU and\r\n// decode back to f32 for the reference so both see identical values.\r\nfunction prep(f32arr, t) {\r\n if (t !== 'f16') return { data: f32arr, ref: f32arr };\r\n const half = new Uint16Array(f32arr.length);\r\n for (let i = 0; i < f32arr.length; i++) half[i] = f32ToF16(f32arr[i]);\r\n return { data: half, ref: expandF16(half) };\r\n}\r\n\r\nfunction makeUniform(device, vals) {\r\n const size = Math.ceil((vals.length * 4) / 16) * 16;\r\n const buf = device.createBuffer({ size, usage: GPUBufferUsage.UNIFORM, mappedAtCreation: true });\r\n new Uint32Array(buf.getMappedRange()).set(vals);\r\n buf.unmap();\r\n return buf;\r\n}\r\n\r\nfunction elemBytes(t) { return t === 'f16' ? 2 : 4; }\r\n\r\n// strides overrides the default compact layouts (Q [B·M, HD], K/V [B, L, H, D])\r\n// with fused-buffer strides/offsets — see attention.wgsl.\r\nfunction attentionPipeline(device, t, strides = {}, sg = false) {\r\n return getPipeline(device, 'attention', attentionSource, {\r\n t, wg: 128, sg,\r\n defines: {\r\n H, D, SCORES_CAP, ATTN_SCALE,\r\n Q_STRIDE: HD, Q_OFF: 0, KV_STRIDE: HD, K_OFF: 0, V_OFF: 0,\r\n ...strides,\r\n },\r\n });\r\n}\r\n\r\n// Blocked encoder variant (attention_block.wgsl) — grid (ceil(M/QB), H, B).\r\nfunction attentionBlockPipeline(device, t, { qb, jb }, strides = {}) {\r\n return getPipeline(device, 'attention_block', attentionBlockSource, {\r\n t,\r\n defines: {\r\n H, D, QB: qb, JB: jb, ATTN_SCALE,\r\n Q_STRIDE: HD, Q_OFF: 0, KV_STRIDE: HD, K_OFF: 0, V_OFF: 0,\r\n PACKED: false, NOPACKED: true,\r\n ...strides,\r\n },\r\n });\r\n}\r\n\r\nfunction kvAppendPipeline(device, t, mode) {\r\n return getPipeline(device, 'kv_append', kvAppendSource, {\r\n t, wg: 128, defines: { H, D, APPEND: mode === 'append', SPLIT: mode === 'split' },\r\n });\r\n}\r\n\r\nfunction dispatch(device, pipeline, buffers, wgX, wgY = 1, wgZ = 1) {\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: buffers.map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.dispatchWorkgroups(wgX, wgY, wgZ);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n}\r\n\r\n// Run attention (grid B·M × H, or (ceil(M/QB), H, B) when block = {qb, jb}),\r\n// read back Y [B·M, HD], compare to ref.\r\nasync function runAttentionAndCompare(device, t, { qBuf, kBuf, vBuf, lensBuf, B, M, L, lenMode, step, strides, block, sg }, want, tol, label) {\r\n const pipeline = block\r\n ? attentionBlockPipeline(device, t, block, strides)\r\n : attentionPipeline(device, t, strides, sg);\r\n const params = makeUniform(device, [B, M, L, lenMode, step ?? 0, 0, 0, 0]);\r\n const scratch = [params];\r\n let lens = lensBuf;\r\n if (!lens) { // lenMode 0: dummy 4-byte buffer, never indexed\r\n lens = device.createBuffer({ label: 'attn dummy lens', size: 4, usage: GPUBufferUsage.STORAGE });\r\n scratch.push(lens);\r\n }\r\n const outElems = B * M * HD;\r\n const yBuf = device.createBuffer({\r\n size: Math.ceil((outElems * elemBytes(t)) / 4) * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n });\r\n if (block) {\r\n dispatch(device, pipeline, [params, qBuf, kBuf, vBuf, lens, yBuf], Math.ceil(M / block.qb), H, B);\r\n } else {\r\n dispatch(device, pipeline, [params, qBuf, kBuf, vBuf, lens, yBuf], B * M, H);\r\n }\r\n const raw = await readback(device, yBuf, outElems * elemBytes(t));\r\n const got = t === 'f16' ? expandF16(new Uint16Array(raw)) : new Float32Array(raw);\r\n for (const b of [...scratch, yBuf]) b.destroy();\r\n\r\n const { failures, maxAbsDiff, worst } = compareLanes(got, want, tol);\r\n return {\r\n pass: failures === 0,\r\n detail: {\r\n ...label, tol, failures,\r\n maxAbsDiff: String(maxAbsDiff), // string: JSON turns NaN/Infinity into null\r\n ...(failures > 0 ? { worst, got: String(got[worst]), want: String(want[worst]) } : {}),\r\n },\r\n };\r\n}\r\n\r\n// --------------------------------------------------- encoder self / direct ---\r\n\r\n// K/V built directly in [B, L, H, D] layout; ragged lens via lenMode 1.\r\n// block = {qb, jb} routes through the blocked kernel instead.\r\nasync function runEncoderCase(ctx, { B, M, L, lens, t, tol, seed, block, sg = false }) {\r\n const { device } = ctx;\r\n const rng = mulberry32(seed);\r\n const q = prep(randF32(B * M * HD, rng), t);\r\n const k = prep(randF32(B * L * HD, rng), t);\r\n const v = prep(randF32(B * L * HD, rng), t);\r\n const want = attentionRef(q.ref, k.ref, v.ref, { B, M, H, D, L, lens });\r\n\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const qBuf = createBuffer(device, q.data, usage);\r\n const kBuf = createBuffer(device, k.data, usage);\r\n const vBuf = createBuffer(device, v.data, usage);\r\n const lensBuf = createBuffer(device, new Uint32Array(lens), usage);\r\n const result = await runAttentionAndCompare(\r\n device, t, { qBuf, kBuf, vBuf, lensBuf, B, M, L, lenMode: 1, block, sg },\r\n want, tol, {\r\n kernel: block ? `attention_block qb${block.qb} jb${block.jb}` : 'attention',\r\n mode: 'encoder', B, M, L, lens: lens.join(','), t,\r\n });\r\n for (const b of [qBuf, kBuf, vBuf, lensBuf]) b.destroy();\r\n return result;\r\n}\r\n\r\n// ----------------------------------------------------- encoder self, fused ---\r\n\r\n// Attention reads q/k/v slices DIRECTLY from the fused QKV projection output\r\n// [B·S, 3·HD] via Q_STRIDE/KV_STRIDE + offsets (Q=K=V= the same buffer) — the\r\n// way the encoder pass uses it. Reference gets the slices extracted in JS.\r\nasync function runEncoderFusedCase(ctx, { B, S, lens, t, tol, seed, block }) {\r\n const { device } = ctx;\r\n const rng = mulberry32(seed);\r\n const rows = B * S;\r\n const fused = prep(randF32(rows * 3 * HD, rng), t);\r\n const qRef = new Float32Array(rows * HD);\r\n const kRef = new Float32Array(rows * HD); // [B, S, H, D] == per-row slices\r\n const vRef = new Float32Array(rows * HD);\r\n for (let r = 0; r < rows; r++) {\r\n qRef.set(fused.ref.subarray(r * 3 * HD, r * 3 * HD + HD), r * HD);\r\n kRef.set(fused.ref.subarray(r * 3 * HD + HD, r * 3 * HD + 2 * HD), r * HD);\r\n vRef.set(fused.ref.subarray(r * 3 * HD + 2 * HD, r * 3 * HD + 3 * HD), r * HD);\r\n }\r\n const want = attentionRef(qRef, kRef, vRef, { B, M: S, H, D, L: S, lens });\r\n\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const fusedBuf = createBuffer(device, fused.data, usage);\r\n const lensBuf = createBuffer(device, new Uint32Array(lens), usage);\r\n const result = await runAttentionAndCompare(\r\n device, t,\r\n {\r\n qBuf: fusedBuf, kBuf: fusedBuf, vBuf: fusedBuf, lensBuf, B, M: S, L: S, lenMode: 1, block,\r\n strides: { Q_STRIDE: 3 * HD, Q_OFF: 0, KV_STRIDE: 3 * HD, K_OFF: HD, V_OFF: 2 * HD },\r\n },\r\n want, tol, {\r\n kernel: block ? `attention_block qb${block.qb} jb${block.jb}` : 'attention',\r\n mode: 'encoder-fused', B, S, lens: lens.join(','), t,\r\n });\r\n for (const b of [fusedBuf, lensBuf]) b.destroy();\r\n return result;\r\n}\r\n\r\n// ------------------------------------------- decode: kv_append + attention ---\r\n\r\n// Simulates 5 decode steps: each appends a random fused [B, 3·HD] row into the\r\n// K/V caches via kv_append APPEND, then attention runs with lenMode 0, t=4.\r\n// The reference assembles k/v in JS from the SAME fused rows, so kv_append's\r\n// cache indexing is cross-validated through attention.\r\nasync function runDecodeCase(ctx, { B, Lmax, steps, t, tol, seed, sg = false }) {\r\n const { device } = ctx;\r\n const rng = mulberry32(seed);\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n\r\n // Zero-initialized caches, [B, Lmax, H, D]. Positions >= steps stay zero and\r\n // must never be read (len = t+1 = steps).\r\n const cacheBytes = B * Lmax * HD * elemBytes(t);\r\n const kBuf = device.createBuffer({ size: cacheBytes, usage: GPUBufferUsage.STORAGE });\r\n const vBuf = device.createBuffer({ size: cacheBytes, usage: GPUBufferUsage.STORAGE });\r\n\r\n const appendPipe = kvAppendPipeline(device, t, 'append');\r\n const kRef = new Float32Array(B * Lmax * HD);\r\n const vRef = new Float32Array(B * Lmax * HD);\r\n const qF32 = new Float32Array(B * HD);\r\n for (let step = 0; step < steps; step++) {\r\n const fused = prep(randF32(B * 3 * HD, rng), t); // [B, q|k|v]\r\n const fusedBuf = createBuffer(device, fused.data, usage);\r\n const params = makeUniform(device, [B, step, Lmax, 0]);\r\n dispatch(device, appendPipe, [params, fusedBuf, kBuf, vBuf], Math.ceil((B * HD) / 128));\r\n for (let b = 0; b < B; b++) {\r\n const dst = (b * Lmax + step) * HD;\r\n kRef.set(fused.ref.subarray(b * 3 * HD + HD, b * 3 * HD + 2 * HD), dst);\r\n vRef.set(fused.ref.subarray(b * 3 * HD + 2 * HD, b * 3 * HD + 3 * HD), dst);\r\n if (step === steps - 1) {\r\n // The last step's q slice feeds attention — matches how the engine\r\n // consumes the fused QKV projection during decode.\r\n qF32.set(fused.ref.subarray(b * 3 * HD, b * 3 * HD + HD), b * HD);\r\n }\r\n }\r\n fusedBuf.destroy();\r\n }\r\n const q = prep(qF32, t); // ref values are already f16-exact; re-encode is lossless\r\n const qBuf = createBuffer(device, q.data, usage);\r\n const want = attentionRef(q.ref, kRef, vRef, {\r\n B, M: 1, H, D, L: Lmax, lens: Array(B).fill(steps),\r\n });\r\n const result = await runAttentionAndCompare(\r\n device, t, { qBuf, kBuf, vBuf, lensBuf: null, B, M: 1, L: Lmax, lenMode: 0, step: steps - 1, sg },\r\n want, tol, { kernel: 'kv_append+attention', mode: 'decode', B, Lmax, steps, t });\r\n for (const b of [qBuf, kBuf, vBuf]) b.destroy();\r\n return result;\r\n}\r\n\r\n// -------------------------------------------- cross: kv_split + attention ---\r\n\r\n// kv_append SPLIT scatters fused [B·S, 2·HD] into K/V [B, S, H, D] (L = S),\r\n// then attention runs with lenMode 1 and ragged lens.\r\nasync function runCrossCase(ctx, { B, S, lens, t, tol, seed, sg = false }) {\r\n const { device } = ctx;\r\n const rng = mulberry32(seed);\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const rows = B * S;\r\n\r\n const fused = prep(randF32(rows * 2 * HD, rng), t);\r\n const fusedBuf = createBuffer(device, fused.data, usage);\r\n const cacheBytes = rows * HD * elemBytes(t);\r\n const kBuf = device.createBuffer({ size: cacheBytes, usage: GPUBufferUsage.STORAGE });\r\n const vBuf = device.createBuffer({ size: cacheBytes, usage: GPUBufferUsage.STORAGE });\r\n const splitPipe = kvAppendPipeline(device, t, 'split');\r\n const params = makeUniform(device, [B, 0, 0, rows]);\r\n dispatch(device, splitPipe, [params, fusedBuf, kBuf, vBuf], Math.ceil((rows * HD) / 128));\r\n\r\n const kRef = new Float32Array(rows * HD);\r\n const vRef = new Float32Array(rows * HD);\r\n for (let r = 0; r < rows; r++) {\r\n kRef.set(fused.ref.subarray(r * 2 * HD, r * 2 * HD + HD), r * HD);\r\n vRef.set(fused.ref.subarray(r * 2 * HD + HD, r * 2 * HD + 2 * HD), r * HD);\r\n }\r\n const q = prep(randF32(B * HD, rng), t);\r\n const qBuf = createBuffer(device, q.data, usage);\r\n const lensBuf = createBuffer(device, new Uint32Array(lens), usage);\r\n const want = attentionRef(q.ref, kRef, vRef, { B, M: 1, H, D, L: S, lens });\r\n const result = await runAttentionAndCompare(\r\n device, t, { qBuf, kBuf, vBuf, lensBuf, B, M: 1, L: S, lenMode: 1, sg },\r\n want, tol, { kernel: 'kv_split+attention', mode: 'cross', B, S, lens: lens.join(','), t });\r\n for (const b of [fusedBuf, qBuf, kBuf, vBuf, lensBuf]) b.destroy();\r\n return result;\r\n}\r\n\r\nfunction registerF16(name, fn) {\r\n registerTest(name, (ctx) =>\r\n ctx.hasF16 ? fn(ctx) : { skip: true, reason: 'no shader-f16' });\r\n}\r\n\r\n// f16 tol 0.03: D=56 dots and up-to-352-term weighted sums accumulate in f32,\r\n// but f16 output rounding + softmax weight sensitivity warrant slack.\r\nregisterF16('attn_encoder_f16', (ctx) =>\r\n runEncoderCase(ctx, { B: 2, M: 16, L: 16, lens: [16, 9], t: 'f16', tol: 0.03, seed: 301 }));\r\nregisterF16('attn_encoder_fused_f16', (ctx) =>\r\n runEncoderFusedCase(ctx, { B: 2, S: 16, lens: [16, 9], t: 'f16', tol: 0.03, seed: 305 }));\r\nregisterF16('attn_decode_f16', (ctx) =>\r\n runDecodeCase(ctx, { B: 3, Lmax: 32, steps: 5, t: 'f16', tol: 0.03, seed: 302 }));\r\nregisterF16('attn_cross_f16', (ctx) =>\r\n runCrossCase(ctx, { B: 2, S: 32, lens: [32, 20], t: 'f16', tol: 0.03, seed: 303 }));\r\n// f32 fallback-mode sanity for the template.\r\nregisterTest('attn_encoder_f32', (ctx) =>\r\n runEncoderCase(ctx, { B: 1, M: 4, L: 4, lens: [3], t: 'f32', tol: 1e-4, seed: 304 }));\r\n\r\n// Blocked encoder kernel (attention_block.wgsl). Shapes chosen to exercise\r\n// every guard: M not a multiple of QB (query tail block), lens crossing\r\n// several JB tiles with a partial last tile, ragged lens including a len < JB\r\n// row, and both compact and fused-QKV layouts. Tol matches the unblocked f16\r\n// cases — online softmax changes summation order, not precision class.\r\nregisterF16('attn_block_encoder_f16', (ctx) =>\r\n runEncoderCase(ctx, {\r\n B: 2, M: 20, L: 20, lens: [20, 9], t: 'f16', tol: 0.03, seed: 311,\r\n block: { qb: 8, jb: 16 },\r\n }));\r\nregisterF16('attn_block_encoder_fused_f16', (ctx) =>\r\n runEncoderFusedCase(ctx, {\r\n B: 3, S: 33, lens: [33, 17, 5], t: 'f16', tol: 0.03, seed: 312,\r\n block: { qb: 16, jb: 32 },\r\n }));\r\nregisterF16('attn_block_encoder_fused_jb48_f16', (ctx) =>\r\n runEncoderFusedCase(ctx, {\r\n B: 2, S: 50, lens: [50, 49], t: 'f16', tol: 0.03, seed: 313,\r\n block: { qb: 8, jb: 48 },\r\n }));\r\nregisterTest('attn_block_encoder_f32', (ctx) =>\r\n runEncoderCase(ctx, {\r\n B: 2, M: 9, L: 12, lens: [12, 3], t: 'f32', tol: 1e-4, seed: 314,\r\n block: { qb: 8, jb: 16 },\r\n }));\r\n\r\n// Subgroup-reduction attention (flags.sg — IF_SG variant): tolerance-equal\r\n// to the tree (reduction order differs), and the CORRECTNESS route on\r\n// Adreno 7xx, whose driver miscompiles this kernel's tree reduce (2026-07\r\n// Android round; autotune force-enables sg there). Shapes mirror the plain\r\n// cases, same seeds → same data.\r\nconst sgSkip = (ctx) => (ctx.hasSubgroups ? null : { skip: true, reason: 'subgroups feature unavailable' });\r\nregisterTest('attn_sg_encoder_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runEncoderCase(ctx, { B: 2, M: 16, L: 16, lens: [16, 9], t: 'f16', tol: 0.03, seed: 301, sg: true })));\r\nregisterTest('attn_sg_decode_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runDecodeCase(ctx, { B: 3, Lmax: 32, steps: 5, t: 'f16', tol: 0.03, seed: 302, sg: true })));\r\nregisterTest('attn_sg_cross_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runCrossCase(ctx, { B: 2, S: 32, lens: [32, 20], t: 'f16', tol: 0.03, seed: 303, sg: true })));\r\nregisterTest('attn_sg_encoder_f32', (ctx) => sgSkip(ctx)\r\n ?? runEncoderCase(ctx, { B: 1, M: 4, L: 4, lens: [3], t: 'f32', tol: 1e-4, seed: 304, sg: true }));\r\n\r\n// Long-L sg arms — the production shape the short goldens miss: app rows are\r\n// ~200 chars → decode self-attn len grows past WG=128 (the scan loop turns\r\n// multi-trip per thread) and cross len ≈ S ≈ 100-192. The Adreno miscompile\r\n// family is context-sensitive (multi-trip strided loops were an ingredient),\r\n// so the sg variant must be proven AT THESE LENGTHS on-device, not just at\r\n// golden-sentence lengths.\r\nregisterTest('attn_sg_long_encoder_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runEncoderCase(ctx, { B: 2, M: 8, L: 224, lens: [224, 131], t: 'f16', tol: 0.03, seed: 321, sg: true })));\r\nregisterTest('attn_sg_long_decode_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runDecodeCase(ctx, { B: 2, Lmax: 224, steps: 160, t: 'f16', tol: 0.03, seed: 322, sg: true })));\r\nregisterTest('attn_sg_long_cross_f16', (ctx) => sgSkip(ctx)\r\n ?? (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runCrossCase(ctx, { B: 2, S: 192, lens: [192, 130], t: 'f16', tol: 0.03, seed: 323, sg: true })));\r\n// Tree twins at the same long shapes: FAIL expected on the affected Adreno\r\n// (tree broken there) — they double as the on-device control that the long\r\n// shapes do exercise the broken paths.\r\nregisterTest('attn_long_encoder_f16', (ctx) => (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runEncoderCase(ctx, { B: 2, M: 8, L: 224, lens: [224, 131], t: 'f16', tol: 0.03, seed: 321 })));\r\nregisterTest('attn_long_decode_f16', (ctx) => (!ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runDecodeCase(ctx, { B: 2, Lmax: 224, steps: 160, t: 'f16', tol: 0.03, seed: 322 })));\r\n"],"names":["kvAppendSource","H","HEADS","D","HEAD_DIM","HD","mulberry32","seed","a","t","randF32","n","rng","out","i","prep","f32arr","half","f32ToF16","expandF16","makeUniform","device","vals","size","buf","elemBytes","attentionPipeline","strides","sg","getPipeline","attentionSource","SCORES_CAP","ATTN_SCALE","attentionBlockPipeline","qb","jb","attentionBlockSource","kvAppendPipeline","mode","dispatch","pipeline","buffers","wgX","wgY","wgZ","bindGroup","buffer","binding","encoder","pass","runAttentionAndCompare","qBuf","kBuf","vBuf","lensBuf","B","M","L","lenMode","step","block","want","tol","label","params","scratch","lens","outElems","yBuf","raw","readback","got","b","failures","maxAbsDiff","worst","compareLanes","runEncoderCase","ctx","q","k","v","attentionRef","usage","createBuffer","result","runEncoderFusedCase","S","rows","fused","qRef","kRef","vRef","r","fusedBuf","runDecodeCase","Lmax","steps","cacheBytes","appendPipe","qF32","dst","runCrossCase","splitPipe","registerF16","name","fn","registerTest","sgSkip"],"mappings":"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"}
assets/attn_sweep-CxMb0QH-.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import{r as D}from"./debug-CPpXXfWA.js";import{r as S,a as x}from"./gpu-utils-BTh3AGTJ.js";import{l as A}from"./weights-DxIJF1EY.js";import{l as F,t as B}from"./tokenizer-BmI7pHmp.js";import{r as E}from"./encoder-CZXKGzzg.js";import{e as L}from"./f16-wKKZr58e.js";import{D as M}from"./constants-CSVWRdrh.js";import{p as N}from"./bench-BarR4Zp5.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./safe_storage-BYkOahew.js";import"./shapes-ClGtK-ia.js";import"./pipelines-BbLc75sB.js";import"./generate-Ca3ORHiA.js";import"./decoder-BUiaGDqb.js";import"./device-BotbBNoe.js";import"./autotune-Bwt_lWMv.js";import"./chapter3k-DSdzHZt5.js";const g=7,y=.02,a=[{name:"v1",overrides:{block:!1}},{name:"qb8jb32",overrides:{qb:8,jb:32}},{name:"qb16jb32",overrides:{qb:16,jb:32}},{name:"qb8jb48",overrides:{qb:8,jb:48}},{name:"qb16jb16",overrides:{qb:16,jb:16}}],T=n=>{const e=[...n].sort((i,c)=>i-c),o=e.length>>1;return e.length%2?e[o]:(e[o-1]+e[o])/2};D("attn_sweep",async n=>{const{device:e}=n,o=n.hasF16?"f16":"f32",i=await A(e,"/weights",{targetDtype:o});try{const c=await F(),h={device:e,dtype:o},v=[...N("file23k")].sort((t,r)=>r.length-t.length),m=await B(c,v.slice(0,64)),f=async(t,{grabOut:r=!1}={})=>{const u=performance.now(),s=await E(h,i,m,{attnOverrides:t});await e.queue.onSubmittedWorkDone();const k=performance.now()-u;let d=null;if(r){const q=m.B*s.S*M*(o==="f16"?2:4),w=await S(e,s.encOut,q);d=o==="f16"?L(new Uint16Array(w)):new Float32Array(w)}return s.arena.destroy(),{ms:k,out:d}},O=(await f(a[0].overrides,{grabOut:!0})).out,p={};for(const t of a.slice(1)){const{out:r}=await f(t.overrides,{grabOut:!0}),{failures:u,maxAbsDiff:s}=x(r,O,y);p[t.name]={failures:u,maxAbsDiff:String(s)}}const b=Object.fromEntries(a.map(t=>[t.name,[]]));for(let t=0;t<g;t++)for(const r of a)b[r.name].push((await f(r.overrides)).ms);const j=a.map(t=>({config:t.name,medianMs:Number(T(b[t.name]).toFixed(1)),runs:b[t.name].map(r=>Number(r.toFixed(1)))})),l=Object.values(p).every(t=>t.failures===0);return{pass:l,detail:{dtype:o,B:m.B,S:m.S,rounds:g,tol:y,parityOk:l,parity:p,table:j}}}finally{i.buffer.destroy()}});
2
+ //# sourceMappingURL=attn_sweep-CxMb0QH-.js.map
assets/{attn_sweep-DYmEfGm0.js.map → attn_sweep-CxMb0QH-.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"file":"attn_sweep-DYmEfGm0.js","sources":["../../src/debug/tests/attn_sweep.js"],"sourcesContent":["// Blocked-attention A/B for the encoder self-attention site: unblocked v1\r\n// control vs QB×JB tile shapes of attention_block.wgsl — picks the default\r\n// QB/JB in pipelines.js. Arms measured ROUND-ROBIN in one session (sequential\r\n// runner invocations drift ±30% with laptop thermals); wall clock per run =\r\n// runEncoder submit → onSubmittedWorkDone, medians over ROUNDS.\r\n//\r\n// Correctness gate: every arm's encOut must match the v1 control within TOL\r\n// (online softmax reorders f32 sums — bit-equality is not expected, but after\r\n// 8 layers of f16 storage rounding the drift stays ~1e-3).\r\nimport { registerTest } from '../registry.js';\r\nimport { readback, compareLanes } from '../gpu-utils.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { loadTokenizer, tokenizeBatch } from '../../engine/tokenizer.js';\r\nimport { runEncoder } from '../../engine/encoder.js';\r\nimport { expandF16 } from '../../engine/f16.js';\r\nimport { D_MODEL } from '../../engine/constants.js';\r\nimport { presetChunks } from '../../bench/bench.js';\r\n\r\nconst ROUNDS = 7;\r\nconst TOL = 0.02;\r\nconst ARMS = [\r\n { name: 'v1', overrides: { block: false } },\r\n { name: 'qb8jb32', overrides: { qb: 8, jb: 32 } },\r\n { name: 'qb16jb32', overrides: { qb: 16, jb: 32 } },\r\n { name: 'qb8jb48', overrides: { qb: 8, jb: 48 } },\r\n { name: 'qb16jb16', overrides: { qb: 16, jb: 16 } },\r\n];\r\n\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\n\r\nregisterTest('attn_sweep', async (ctx) => {\r\n const { device } = ctx;\r\n const dtype = ctx.hasF16 ? 'f16' : 'f32';\r\n const weights = await loadWeights(device, '/weights', { targetDtype: dtype });\r\n try {\r\n const tok = await loadTokenizer();\r\n const gctx = { device, dtype };\r\n const chunks = [...presetChunks('file23k')].sort((a, b) => b.length - a.length);\r\n const batch = await tokenizeBatch(tok, chunks.slice(0, 64));\r\n\r\n const runOne = async (overrides, { grabOut = false } = {}) => {\r\n const t0 = performance.now();\r\n const run = await runEncoder(gctx, weights, batch, { attnOverrides: overrides });\r\n await device.queue.onSubmittedWorkDone();\r\n const ms = performance.now() - t0;\r\n let out = null;\r\n if (grabOut) {\r\n const bytes = batch.B * run.S * D_MODEL * (dtype === 'f16' ? 2 : 4);\r\n const raw = await readback(device, run.encOut, bytes);\r\n out = dtype === 'f16' ? expandF16(new Uint16Array(raw)) : new Float32Array(raw);\r\n }\r\n run.arena.destroy();\r\n return { ms, out };\r\n };\r\n\r\n // Warmup (pipeline compiles) + parity gate vs the v1 control.\r\n const base = (await runOne(ARMS[0].overrides, { grabOut: true })).out;\r\n const parity = {};\r\n for (const arm of ARMS.slice(1)) {\r\n const { out } = await runOne(arm.overrides, { grabOut: true });\r\n const { failures, maxAbsDiff } = compareLanes(out, base, TOL);\r\n parity[arm.name] = { failures, maxAbsDiff: String(maxAbsDiff) };\r\n }\r\n\r\n const times = Object.fromEntries(ARMS.map((a) => [a.name, []]));\r\n for (let r = 0; r < ROUNDS; r++) {\r\n for (const a of ARMS) times[a.name].push((await runOne(a.overrides)).ms);\r\n }\r\n\r\n const table = ARMS.map((a) => ({\r\n config: a.name,\r\n medianMs: Number(median(times[a.name]).toFixed(1)),\r\n runs: times[a.name].map((x) => Number(x.toFixed(1))),\r\n }));\r\n const parityOk = Object.values(parity).every((p) => p.failures === 0);\r\n return { pass: parityOk, detail: { dtype, B: batch.B, S: batch.S, rounds: ROUNDS, tol: TOL, parityOk, parity, table } };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n});\r\n"],"names":["ROUNDS","TOL","ARMS","median","xs","s","a","b","m","registerTest","ctx","device","dtype","weights","loadWeights","tok","loadTokenizer","gctx","chunks","presetChunks","batch","tokenizeBatch","runOne","overrides","grabOut","t0","run","runEncoder","ms","out","bytes","D_MODEL","raw","readback","expandF16","base","parity","arm","failures","maxAbsDiff","compareLanes","times","r","table","x","parityOk","p"],"mappings":"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"}
 
1
+ {"version":3,"file":"attn_sweep-CxMb0QH-.js","sources":["../../src/debug/tests/attn_sweep.js"],"sourcesContent":["// Blocked-attention A/B for the encoder self-attention site: unblocked v1\r\n// control vs QB×JB tile shapes of attention_block.wgsl — picks the default\r\n// QB/JB in pipelines.js. Arms measured ROUND-ROBIN in one session (sequential\r\n// runner invocations drift ±30% with laptop thermals); wall clock per run =\r\n// runEncoder submit → onSubmittedWorkDone, medians over ROUNDS.\r\n//\r\n// Correctness gate: every arm's encOut must match the v1 control within TOL\r\n// (online softmax reorders f32 sums — bit-equality is not expected, but after\r\n// 8 layers of f16 storage rounding the drift stays ~1e-3).\r\nimport { registerTest } from '../registry.js';\r\nimport { readback, compareLanes } from '../gpu-utils.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { loadTokenizer, tokenizeBatch } from '../../engine/tokenizer.js';\r\nimport { runEncoder } from '../../engine/encoder.js';\r\nimport { expandF16 } from '../../engine/f16.js';\r\nimport { D_MODEL } from '../../engine/constants.js';\r\nimport { presetChunks } from '../../bench/bench.js';\r\n\r\nconst ROUNDS = 7;\r\nconst TOL = 0.02;\r\nconst ARMS = [\r\n { name: 'v1', overrides: { block: false } },\r\n { name: 'qb8jb32', overrides: { qb: 8, jb: 32 } },\r\n { name: 'qb16jb32', overrides: { qb: 16, jb: 32 } },\r\n { name: 'qb8jb48', overrides: { qb: 8, jb: 48 } },\r\n { name: 'qb16jb16', overrides: { qb: 16, jb: 16 } },\r\n];\r\n\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\n\r\nregisterTest('attn_sweep', async (ctx) => {\r\n const { device } = ctx;\r\n const dtype = ctx.hasF16 ? 'f16' : 'f32';\r\n const weights = await loadWeights(device, '/weights', { targetDtype: dtype });\r\n try {\r\n const tok = await loadTokenizer();\r\n const gctx = { device, dtype };\r\n const chunks = [...presetChunks('file23k')].sort((a, b) => b.length - a.length);\r\n const batch = await tokenizeBatch(tok, chunks.slice(0, 64));\r\n\r\n const runOne = async (overrides, { grabOut = false } = {}) => {\r\n const t0 = performance.now();\r\n const run = await runEncoder(gctx, weights, batch, { attnOverrides: overrides });\r\n await device.queue.onSubmittedWorkDone();\r\n const ms = performance.now() - t0;\r\n let out = null;\r\n if (grabOut) {\r\n const bytes = batch.B * run.S * D_MODEL * (dtype === 'f16' ? 2 : 4);\r\n const raw = await readback(device, run.encOut, bytes);\r\n out = dtype === 'f16' ? expandF16(new Uint16Array(raw)) : new Float32Array(raw);\r\n }\r\n run.arena.destroy();\r\n return { ms, out };\r\n };\r\n\r\n // Warmup (pipeline compiles) + parity gate vs the v1 control.\r\n const base = (await runOne(ARMS[0].overrides, { grabOut: true })).out;\r\n const parity = {};\r\n for (const arm of ARMS.slice(1)) {\r\n const { out } = await runOne(arm.overrides, { grabOut: true });\r\n const { failures, maxAbsDiff } = compareLanes(out, base, TOL);\r\n parity[arm.name] = { failures, maxAbsDiff: String(maxAbsDiff) };\r\n }\r\n\r\n const times = Object.fromEntries(ARMS.map((a) => [a.name, []]));\r\n for (let r = 0; r < ROUNDS; r++) {\r\n for (const a of ARMS) times[a.name].push((await runOne(a.overrides)).ms);\r\n }\r\n\r\n const table = ARMS.map((a) => ({\r\n config: a.name,\r\n medianMs: Number(median(times[a.name]).toFixed(1)),\r\n runs: times[a.name].map((x) => Number(x.toFixed(1))),\r\n }));\r\n const parityOk = Object.values(parity).every((p) => p.failures === 0);\r\n return { pass: parityOk, detail: { dtype, B: batch.B, S: batch.S, rounds: ROUNDS, tol: TOL, parityOk, parity, table } };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n});\r\n"],"names":["ROUNDS","TOL","ARMS","median","xs","s","a","b","m","registerTest","ctx","device","dtype","weights","loadWeights","tok","loadTokenizer","gctx","chunks","presetChunks","batch","tokenizeBatch","runOne","overrides","grabOut","t0","run","runEncoder","ms","out","bytes","D_MODEL","raw","readback","expandF16","base","parity","arm","failures","maxAbsDiff","compareLanes","times","r","table","x","parityOk","p"],"mappings":"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"}
assets/attn_sweep-DYmEfGm0.js DELETED
@@ -1,2 +0,0 @@
1
- import{r as D}from"./debug-C_LNzFrK.js";import{r as S,a as x}from"./gpu-utils-BTh3AGTJ.js";import{l as A}from"./weights-D8qtuKag.js";import{l as F,t as B}from"./tokenizer-Ex1u7wXD.js";import{r as E}from"./encoder-I9sHImnR.js";import{e as L}from"./f16-wKKZr58e.js";import{D as M}from"./constants-C8VbFpic.js";import{p as N}from"./bench-CEDJ-mff.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./shapes-BCQ9D81L.js";import"./pipelines-DJ7cc1m-.js";import"./generate-BIP3NpbY.js";import"./decoder-CI9o-EVx.js";import"./device-BotbBNoe.js";import"./autotune-DywP5DSc.js";import"./chapter3k-DSdzHZt5.js";const g=7,y=.02,a=[{name:"v1",overrides:{block:!1}},{name:"qb8jb32",overrides:{qb:8,jb:32}},{name:"qb16jb32",overrides:{qb:16,jb:32}},{name:"qb8jb48",overrides:{qb:8,jb:48}},{name:"qb16jb16",overrides:{qb:16,jb:16}}],T=n=>{const e=[...n].sort((i,c)=>i-c),o=e.length>>1;return e.length%2?e[o]:(e[o-1]+e[o])/2};D("attn_sweep",async n=>{const{device:e}=n,o=n.hasF16?"f16":"f32",i=await A(e,"/weights",{targetDtype:o});try{const c=await F(),h={device:e,dtype:o},v=[...N("file23k")].sort((t,r)=>r.length-t.length),m=await B(c,v.slice(0,64)),f=async(t,{grabOut:r=!1}={})=>{const u=performance.now(),s=await E(h,i,m,{attnOverrides:t});await e.queue.onSubmittedWorkDone();const k=performance.now()-u;let d=null;if(r){const q=m.B*s.S*M*(o==="f16"?2:4),w=await S(e,s.encOut,q);d=o==="f16"?L(new Uint16Array(w)):new Float32Array(w)}return s.arena.destroy(),{ms:k,out:d}},O=(await f(a[0].overrides,{grabOut:!0})).out,p={};for(const t of a.slice(1)){const{out:r}=await f(t.overrides,{grabOut:!0}),{failures:u,maxAbsDiff:s}=x(r,O,y);p[t.name]={failures:u,maxAbsDiff:String(s)}}const b=Object.fromEntries(a.map(t=>[t.name,[]]));for(let t=0;t<g;t++)for(const r of a)b[r.name].push((await f(r.overrides)).ms);const j=a.map(t=>({config:t.name,medianMs:Number(T(b[t.name]).toFixed(1)),runs:b[t.name].map(r=>Number(r.toFixed(1)))})),l=Object.values(p).every(t=>t.failures===0);return{pass:l,detail:{dtype:o,B:m.B,S:m.S,rounds:g,tol:y,parityOk:l,parity:p,table:j}}}finally{i.buffer.destroy()}});
2
- //# sourceMappingURL=attn_sweep-DYmEfGm0.js.map
 
 
 
assets/{autotune-DywP5DSc.js → autotune-Bwt_lWMv.js} RENAMED
@@ -1,4 +1,4 @@
1
- import{r as L}from"./encoder-I9sHImnR.js";import{c as q,e as z}from"./decoder-CI9o-EVx.js";import{l as F,s as I,m as V}from"./pipelines-DJ7cc1m-.js";import{V as Y,e as J}from"./constants-C8VbFpic.js";import"./device-BotbBNoe.js";const R=["fc1","fc2","self_out","cross_q","cross_out"],D=Object.freeze({fuseLnMaxB:4,lmHeadMinB:16,lmHeadFuse:"auto",projTiledMinB:128,projTiledKinds:["fc1","fc2"],decodeMega:"auto",sg:"off"}),Q=.95,ce=12,A=e=>{const t=[...e].sort((o,r)=>o-r),n=t.length>>1;return t.length%2?t[n]:(t[n-1]+t[n])/2};class X extends Error{constructor(t,n){super(t),this.name="ReductionSafetyError",this.code="WEBMT_NO_SAFE_REDUCTION",this.verdicts=n}}function $({treeBug:e,sgMismap:t,sgFeature:n}){const o=a=>a===!0||a===!1||a===null;if(!o(e)||!o(t))throw new Error(`invalid reduction verdicts: treeBug=${e}, sgMismap=${t}`);const r=e===!1,i=!!n&&t===!1;if(r&&i)return{status:"both-safe",retry:!1,sgOk:!0,forceSg:!1};if(r)return{status:"tree-safe",retry:!1,sgOk:!1,forceSg:!1};if(i)return{status:"subgroup-safe",retry:!1,sgOk:!0,forceSg:!0};const s=e===null||!!n&&t===null;return{status:s?"unresolved":"unsafe",retry:s,sgOk:!1,forceSg:!1}}function Z(e,t){if(!e.length)return[];const n=(t%e.length+e.length)%e.length;return[...e.slice(n),...e.slice(0,n)]}function T(e,t,n="def"){const o=e[t],r=e[n];if(!Array.isArray(o)||!Array.isArray(r)||o.length!==r.length||!o.length)throw new Error(`pairedRatios: ${t}/${n} need equal non-empty run arrays`);return o.map((i,s)=>i/r[s])}function C(e,t,n="def"){const o=T(e,t,n),r=A(o),i=o.filter(a=>a<1).length;if(o.length<=3)return r<=.9&&i===o.length?"win":r>=.98&&Math.min(...o)>=.95?"keep":"more";const s=Math.ceil(o.length*(2/3));return r<Q&&i>=s?"win":"keep"}function x(e,t="sgOn",n="def"){const o=T(e,t,n);if(o.length<7)return!1;const r=o.filter(i=>i<1).length;return A(o)<=.9&&r===o.length}function K(e,t){const n=new Uint32Array(e*t);let o=2654435769;for(let r=0;r<n.length;r++)o=Math.imul(o,1664525)+1013904223>>>0,n[r]=100+o%(Y-200);for(let r=0;r<e;r++)n[r*t+t-1]=J;return{ids:n,lens:new Uint32Array(e).fill(t),B:e,S:t}}function N(e,t){let n=null,o=!1,r=0;return{poolFor(i){if(o)throw new Error("autotune uniform-pool session is destroyed");return I(t,i)?(n??=V(e.device,{banks:2}),n):null},recordDecodeUniformDelta(i){r+=Math.max(0,i)},invalidateBindings(){return n?.invalidateBindings()??0},snapshot(){return{decodeTransientUniforms:r}},destroy(){o||(n?.destroy(),n=null,o=!0)}}}async function U(e,t,n,o,r,i,s){const{device:a}=e,l=q(e,t,{B:o,S:n.S,maxSteps:r,...i});let m=null,p=!1;try{const u=s.poolFor(l);u&&(m=F(a).uniformBuffersCreated);const h=performance.now();for(let c=0;c<r;c+=8){const d=Math.min(c+8,r),b=c/8%2;let M=!1;const B=[];try{u&&(u.begin(b),M=!0);const f=a.createCommandEncoder({label:`autotune ${c}..${d}`}),v=f.beginComputePass();for(let w=c;w<d;w++)B.push(...z(e,t,n,l,w,v).scratch);v.end(),u&&(u.flush(),M=!1),a.queue.submit([f.finish()]),u&&u.release(b)}catch(f){throw M&&u.abort(),f}finally{for(const f of B)f.destroy()}}return await a.queue.onSubmittedWorkDone(),p=!0,Number(((performance.now()-h)*1e3/r).toFixed(1))}finally{try{if(m!==null){const u=F(a).uniformBuffersCreated;s.recordDecodeUniformDelta(u-m)}}finally{try{p&&s.invalidateBindings()}finally{l.destroy()}}}}function le(e,t,n=.15){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0?Math.abs(t/e-1)<=n+Number.EPSILON:!1}function de(e,t){return!e||!t?!1:t.forceSg?e.sg==="on"&&e.sgForced===!0:t.sgOk?!0:e.sg!=="on"}async function ge(e,t,{B:n=64,S:o=96,steps:r=24,rounds:i=3,immediates:s="auto",uniformPool:a=!1}={}){const l=K(n,o),m=await L(e,t,l,{retainEncOut:!1});await e.device.queue.onSubmittedWorkDone();const p=N(e,a);try{await U(e,t,m,n,r,{immediates:s},p);const u=[];for(let h=0;h<i;h++)u.push(await U(e,t,m,n,r,{immediates:s},p));return{medianUs:A(u),runs:u,poolStats:p.snapshot()}}finally{try{p.destroy()}finally{m.arena.destroy()}}}async function ee(e){const r=`
2
  @group(0) @binding(0) var<storage, read_write> out: array<f32>;
3
  const D: u32 = 448u;
4
  const WG: u32 = 256u;
@@ -41,4 +41,4 @@ fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid
41
  }
42
  if (tid % TK == 0u) { out[g * ${a}u + tid / TK] = vr; }
43
  }`,m=e.createShaderModule({code:l}),p=e.createComputePipeline({layout:"auto",compute:{module:m,entryPoint:"main"}}),u=e.createBuffer({size:4*a*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),h=e.createBuffer({size:4*a*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),c=e.createBindGroup({layout:p.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:u}}]}),d=e.createCommandEncoder(),b=d.beginComputePass();b.setPipeline(p),b.setBindGroup(0,c),b.dispatchWorkgroups(4),b.end(),d.copyBufferToBuffer(u,0,h,0,4*a*4),e.queue.submit([d.finish()]),await h.mapAsync(GPUMapMode.READ);const M=new Float32Array(h.getMappedRange().slice(0));h.unmap(),u.destroy(),h.destroy();for(let B=0;B<4;B++)for(let f=0;f<a;f++){let v=0;for(let w=0;w<s;w++)v+=i(f*s+w,B);if(!(Math.abs(M[B*a+f]-v)<=.01))return!0}}return!1}catch{return null}}async function re(e,{treeProbe:t=ee,sgProbe:n=te}={}){const o=!!e.hasSubgroups&&(e.subgroupMinSize??0)>=16,r=async()=>{const a=await t(e.device),l=o?await n(e.device,e.subgroupMinSize):!0;return{treeBug:a,sgMismap:l}};let i=await r(),s=$({...i,sgFeature:o});if(s.retry&&(await e.device.queue.onSubmittedWorkDone(),i=await r(),s=$({...i,sgFeature:o})),s.status==="unsafe"||s.status==="unresolved")throw new X(`webMT: no proven-safe GPU reduction route (treeBug=${i.treeBug}, sgMismap=${i.sgMismap}, subgroups=${o})`,{...i,sgFeature:o});return{...s,verdicts:{...i,sgFeature:o}}}async function me(e,t,n={}){const{reductionSafety:o=null,uniformPool:r=!1,...i}=n,s=o??await re(e),a=N(e,r);try{try{return{...await oe(e,t,i,s,a),poolStats:a.snapshot()}}catch(l){const m={...D,projTiledKinds:[...D.projTiledKinds]};return s.forceSg&&(m.sg="on",m.sgForced=!0),{tuned:m,timings:{},partial:String(l?.message??l),poolStats:a.snapshot()}}}finally{a.destroy()}}async function oe(e,t,{S:n=96,steps:o=24,rounds:r=3,extraRounds:i=4,immediates:s="auto"},{sgOk:a,forceSg:l},m){const p=[{B:1,arms:{def:{},lnOff:{decodeMega:"off",fuseLn:"off"},lnOn:{decodeMega:"off",fuseLn:"on"},...a?{defSg:{sg:"on"},lnOffSg:{decodeMega:"off",fuseLn:"off",sg:"on"},lnOnSg:{decodeMega:"off",fuseLn:"on",sg:"on"}}:{}},comparisons:[["lnOff","def"],["lnOn","def"],...a?[["lnOffSg","defSg"],["lnOnSg","defSg"]]:[]]},{B:16,arms:{def:{},gemv:{lmHead:"gemv"}},comparisons:[["gemv","def"]]},{B:32,arms:{def:{},all5:{tiledProj:R}},comparisons:[["all5","def"]]},{B:64,arms:{def:{},all5:{tiledProj:R},fuseOff:{lmHeadFuse:"off"}},comparisons:[["all5","def"],["fuseOff","def"]]}];a&&p.push({B:8,arms:{def:{},sgOn:{sg:"on"}},comparisons:[["sgOn","def"]],minRounds:r+i}),p.sort((y,S)=>S.B-y.B);const u={};for(const y of p){const S=K(y.B,n),G=await L(e,t,S,{retainEncOut:!1});await e.device.queue.onSubmittedWorkDone();try{const O=Object.keys(y.arms);for(const g of O)await U(e,t,G,y.B,o,{...y.arms[g],immediates:s},m);const P=Object.fromEntries(O.map(g=>[g,[]])),E=async g=>{const _=Z(O,g);for(const W of _)P[W].push(await U(e,t,G,y.B,o,{...y.arms[W],immediates:s},m))},j=y.minRounds??r;for(let g=0;g<j;g++)await E(g);if(y.comparisons.some(([g,_])=>C(P,g,_)==="more")&&j===r)for(let g=j;g<r+i;g++)await E(g);u[`b${y.B}`]=Object.fromEntries(O.map(g=>[g,{medianUs:A(P[g]),runs:P[g]}]))}finally{G.arena.destroy()}}const h=(y,S,G="def")=>{const O=Object.fromEntries(Object.entries(u[`b${y}`]).map(([P,E])=>[P,E.runs]));return C(O,S,G)==="win"},c={...D,projTiledKinds:[...D.projTiledKinds]};if(l)c.sg="on",c.sgForced=!0;else if(u.b8){const y=Object.fromEntries(Object.entries(u.b8).map(([S,G])=>[S,G.runs]));x(y)&&(c.sg="on")}const d=c.sg==="on"?"Sg":"",b=u.b1,M=Object.fromEntries(Object.entries(b).map(([y,S])=>[y,S.runs])),B=`def${d}`,f=`lnOff${d}`,v=`lnOn${d}`,w=A(T(M,f,B)),H=A(T(M,v,B)),k=w<=H?f:v;return h(1,k,`def${d}`)&&(c.decodeMega="off",c.fuseLnMaxB=k.startsWith("lnOff")?0:D.fuseLnMaxB),h(16,"gemv")&&(c.lmHeadMinB=32),h(64,"fuseOff")&&(c.lmHeadFuse="off"),h(32,"all5")?(c.projTiledMinB=32,c.projTiledKinds=[...R]):h(64,"all5")&&(c.projTiledMinB=64,c.projTiledKinds=[...R]),{tuned:c,timings:u}}function pe(e,t){return e?{fuseLn:t<=e.fuseLnMaxB?"on":"off",lmHead:t>=e.lmHeadMinB?"auto":"gemv",lmHeadFuse:e.lmHeadFuse==="off"?"off":"auto",tiledProj:t>=e.projTiledMinB&&e.projTiledMinB<D.projTiledMinB?[...e.projTiledKinds]:"auto",decodeMega:e.sgForced||e.decodeMega==="off"?"off":"auto",sg:e.sg==="on"?"on":"off",encAttnSafe:!!e.sgForced}:{}}export{D as DEFAULT_ROUTING,ce as KERNEL_REV,X as ReductionSafetyError,me as autotuneRouting,le as cachedAutotuneMatches,de as cachedPolicyMatchesSafety,te as detectSgShuffleMismap,ee as detectTreeReductionBug,ge as measureAutotuneReference,C as pairedPerfVerdict,T as pairedRatios,x as pairedStableSgWin,re as probeReductionSafety,$ as resolveReductionSafety,Z as rotatedArmOrder,pe as tunedOptions};
44
- //# sourceMappingURL=autotune-DywP5DSc.js.map
 
1
+ import{r as L}from"./encoder-CZXKGzzg.js";import{c as q,e as z}from"./decoder-BUiaGDqb.js";import{m as F,n as I,o as V}from"./pipelines-BbLc75sB.js";import{V as Y,e as J}from"./constants-CSVWRdrh.js";import"./device-BotbBNoe.js";const R=["fc1","fc2","self_out","cross_q","cross_out"],D=Object.freeze({fuseLnMaxB:4,lmHeadMinB:16,lmHeadFuse:"auto",projTiledMinB:128,projTiledKinds:["fc1","fc2"],decodeMega:"auto",sg:"off"}),Q=.95,ce=12,A=e=>{const t=[...e].sort((o,r)=>o-r),n=t.length>>1;return t.length%2?t[n]:(t[n-1]+t[n])/2};class X extends Error{constructor(t,n){super(t),this.name="ReductionSafetyError",this.code="WEBMT_NO_SAFE_REDUCTION",this.verdicts=n}}function $({treeBug:e,sgMismap:t,sgFeature:n}){const o=a=>a===!0||a===!1||a===null;if(!o(e)||!o(t))throw new Error(`invalid reduction verdicts: treeBug=${e}, sgMismap=${t}`);const r=e===!1,i=!!n&&t===!1;if(r&&i)return{status:"both-safe",retry:!1,sgOk:!0,forceSg:!1};if(r)return{status:"tree-safe",retry:!1,sgOk:!1,forceSg:!1};if(i)return{status:"subgroup-safe",retry:!1,sgOk:!0,forceSg:!0};const s=e===null||!!n&&t===null;return{status:s?"unresolved":"unsafe",retry:s,sgOk:!1,forceSg:!1}}function Z(e,t){if(!e.length)return[];const n=(t%e.length+e.length)%e.length;return[...e.slice(n),...e.slice(0,n)]}function T(e,t,n="def"){const o=e[t],r=e[n];if(!Array.isArray(o)||!Array.isArray(r)||o.length!==r.length||!o.length)throw new Error(`pairedRatios: ${t}/${n} need equal non-empty run arrays`);return o.map((i,s)=>i/r[s])}function C(e,t,n="def"){const o=T(e,t,n),r=A(o),i=o.filter(a=>a<1).length;if(o.length<=3)return r<=.9&&i===o.length?"win":r>=.98&&Math.min(...o)>=.95?"keep":"more";const s=Math.ceil(o.length*(2/3));return r<Q&&i>=s?"win":"keep"}function x(e,t="sgOn",n="def"){const o=T(e,t,n);if(o.length<7)return!1;const r=o.filter(i=>i<1).length;return A(o)<=.9&&r===o.length}function K(e,t){const n=new Uint32Array(e*t);let o=2654435769;for(let r=0;r<n.length;r++)o=Math.imul(o,1664525)+1013904223>>>0,n[r]=100+o%(Y-200);for(let r=0;r<e;r++)n[r*t+t-1]=J;return{ids:n,lens:new Uint32Array(e).fill(t),B:e,S:t}}function N(e,t){let n=null,o=!1,r=0;return{poolFor(i){if(o)throw new Error("autotune uniform-pool session is destroyed");return I(t,i)?(n??=V(e.device,{banks:2}),n):null},recordDecodeUniformDelta(i){r+=Math.max(0,i)},invalidateBindings(){return n?.invalidateBindings()??0},snapshot(){return{decodeTransientUniforms:r}},destroy(){o||(n?.destroy(),n=null,o=!0)}}}async function U(e,t,n,o,r,i,s){const{device:a}=e,l=q(e,t,{B:o,S:n.S,maxSteps:r,...i});let m=null,p=!1;try{const u=s.poolFor(l);u&&(m=F(a).uniformBuffersCreated);const h=performance.now();for(let c=0;c<r;c+=8){const d=Math.min(c+8,r),b=c/8%2;let M=!1;const B=[];try{u&&(u.begin(b),M=!0);const f=a.createCommandEncoder({label:`autotune ${c}..${d}`}),v=f.beginComputePass();for(let w=c;w<d;w++)B.push(...z(e,t,n,l,w,v).scratch);v.end(),u&&(u.flush(),M=!1),a.queue.submit([f.finish()]),u&&u.release(b)}catch(f){throw M&&u.abort(),f}finally{for(const f of B)f.destroy()}}return await a.queue.onSubmittedWorkDone(),p=!0,Number(((performance.now()-h)*1e3/r).toFixed(1))}finally{try{if(m!==null){const u=F(a).uniformBuffersCreated;s.recordDecodeUniformDelta(u-m)}}finally{try{p&&s.invalidateBindings()}finally{l.destroy()}}}}function le(e,t,n=.15){return Number.isFinite(e)&&e>0&&Number.isFinite(t)&&t>0?Math.abs(t/e-1)<=n+Number.EPSILON:!1}function de(e,t){return!e||!t?!1:t.forceSg?e.sg==="on"&&e.sgForced===!0:t.sgOk?!0:e.sg!=="on"}async function ge(e,t,{B:n=64,S:o=96,steps:r=24,rounds:i=3,immediates:s="auto",uniformPool:a=!1}={}){const l=K(n,o),m=await L(e,t,l,{retainEncOut:!1});await e.device.queue.onSubmittedWorkDone();const p=N(e,a);try{await U(e,t,m,n,r,{immediates:s},p);const u=[];for(let h=0;h<i;h++)u.push(await U(e,t,m,n,r,{immediates:s},p));return{medianUs:A(u),runs:u,poolStats:p.snapshot()}}finally{try{p.destroy()}finally{m.arena.destroy()}}}async function ee(e){const r=`
2
  @group(0) @binding(0) var<storage, read_write> out: array<f32>;
3
  const D: u32 = 448u;
4
  const WG: u32 = 256u;
 
41
  }
42
  if (tid % TK == 0u) { out[g * ${a}u + tid / TK] = vr; }
43
  }`,m=e.createShaderModule({code:l}),p=e.createComputePipeline({layout:"auto",compute:{module:m,entryPoint:"main"}}),u=e.createBuffer({size:4*a*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),h=e.createBuffer({size:4*a*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),c=e.createBindGroup({layout:p.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:u}}]}),d=e.createCommandEncoder(),b=d.beginComputePass();b.setPipeline(p),b.setBindGroup(0,c),b.dispatchWorkgroups(4),b.end(),d.copyBufferToBuffer(u,0,h,0,4*a*4),e.queue.submit([d.finish()]),await h.mapAsync(GPUMapMode.READ);const M=new Float32Array(h.getMappedRange().slice(0));h.unmap(),u.destroy(),h.destroy();for(let B=0;B<4;B++)for(let f=0;f<a;f++){let v=0;for(let w=0;w<s;w++)v+=i(f*s+w,B);if(!(Math.abs(M[B*a+f]-v)<=.01))return!0}}return!1}catch{return null}}async function re(e,{treeProbe:t=ee,sgProbe:n=te}={}){const o=!!e.hasSubgroups&&(e.subgroupMinSize??0)>=16,r=async()=>{const a=await t(e.device),l=o?await n(e.device,e.subgroupMinSize):!0;return{treeBug:a,sgMismap:l}};let i=await r(),s=$({...i,sgFeature:o});if(s.retry&&(await e.device.queue.onSubmittedWorkDone(),i=await r(),s=$({...i,sgFeature:o})),s.status==="unsafe"||s.status==="unresolved")throw new X(`webMT: no proven-safe GPU reduction route (treeBug=${i.treeBug}, sgMismap=${i.sgMismap}, subgroups=${o})`,{...i,sgFeature:o});return{...s,verdicts:{...i,sgFeature:o}}}async function me(e,t,n={}){const{reductionSafety:o=null,uniformPool:r=!1,...i}=n,s=o??await re(e),a=N(e,r);try{try{return{...await oe(e,t,i,s,a),poolStats:a.snapshot()}}catch(l){const m={...D,projTiledKinds:[...D.projTiledKinds]};return s.forceSg&&(m.sg="on",m.sgForced=!0),{tuned:m,timings:{},partial:String(l?.message??l),poolStats:a.snapshot()}}}finally{a.destroy()}}async function oe(e,t,{S:n=96,steps:o=24,rounds:r=3,extraRounds:i=4,immediates:s="auto"},{sgOk:a,forceSg:l},m){const p=[{B:1,arms:{def:{},lnOff:{decodeMega:"off",fuseLn:"off"},lnOn:{decodeMega:"off",fuseLn:"on"},...a?{defSg:{sg:"on"},lnOffSg:{decodeMega:"off",fuseLn:"off",sg:"on"},lnOnSg:{decodeMega:"off",fuseLn:"on",sg:"on"}}:{}},comparisons:[["lnOff","def"],["lnOn","def"],...a?[["lnOffSg","defSg"],["lnOnSg","defSg"]]:[]]},{B:16,arms:{def:{},gemv:{lmHead:"gemv"}},comparisons:[["gemv","def"]]},{B:32,arms:{def:{},all5:{tiledProj:R}},comparisons:[["all5","def"]]},{B:64,arms:{def:{},all5:{tiledProj:R},fuseOff:{lmHeadFuse:"off"}},comparisons:[["all5","def"],["fuseOff","def"]]}];a&&p.push({B:8,arms:{def:{},sgOn:{sg:"on"}},comparisons:[["sgOn","def"]],minRounds:r+i}),p.sort((y,S)=>S.B-y.B);const u={};for(const y of p){const S=K(y.B,n),G=await L(e,t,S,{retainEncOut:!1});await e.device.queue.onSubmittedWorkDone();try{const O=Object.keys(y.arms);for(const g of O)await U(e,t,G,y.B,o,{...y.arms[g],immediates:s},m);const P=Object.fromEntries(O.map(g=>[g,[]])),E=async g=>{const _=Z(O,g);for(const W of _)P[W].push(await U(e,t,G,y.B,o,{...y.arms[W],immediates:s},m))},j=y.minRounds??r;for(let g=0;g<j;g++)await E(g);if(y.comparisons.some(([g,_])=>C(P,g,_)==="more")&&j===r)for(let g=j;g<r+i;g++)await E(g);u[`b${y.B}`]=Object.fromEntries(O.map(g=>[g,{medianUs:A(P[g]),runs:P[g]}]))}finally{G.arena.destroy()}}const h=(y,S,G="def")=>{const O=Object.fromEntries(Object.entries(u[`b${y}`]).map(([P,E])=>[P,E.runs]));return C(O,S,G)==="win"},c={...D,projTiledKinds:[...D.projTiledKinds]};if(l)c.sg="on",c.sgForced=!0;else if(u.b8){const y=Object.fromEntries(Object.entries(u.b8).map(([S,G])=>[S,G.runs]));x(y)&&(c.sg="on")}const d=c.sg==="on"?"Sg":"",b=u.b1,M=Object.fromEntries(Object.entries(b).map(([y,S])=>[y,S.runs])),B=`def${d}`,f=`lnOff${d}`,v=`lnOn${d}`,w=A(T(M,f,B)),H=A(T(M,v,B)),k=w<=H?f:v;return h(1,k,`def${d}`)&&(c.decodeMega="off",c.fuseLnMaxB=k.startsWith("lnOff")?0:D.fuseLnMaxB),h(16,"gemv")&&(c.lmHeadMinB=32),h(64,"fuseOff")&&(c.lmHeadFuse="off"),h(32,"all5")?(c.projTiledMinB=32,c.projTiledKinds=[...R]):h(64,"all5")&&(c.projTiledMinB=64,c.projTiledKinds=[...R]),{tuned:c,timings:u}}function pe(e,t){return e?{fuseLn:t<=e.fuseLnMaxB?"on":"off",lmHead:t>=e.lmHeadMinB?"auto":"gemv",lmHeadFuse:e.lmHeadFuse==="off"?"off":"auto",tiledProj:t>=e.projTiledMinB&&e.projTiledMinB<D.projTiledMinB?[...e.projTiledKinds]:"auto",decodeMega:e.sgForced||e.decodeMega==="off"?"off":"auto",sg:e.sg==="on"?"on":"off",encAttnSafe:!!e.sgForced}:{}}export{D as DEFAULT_ROUTING,ce as KERNEL_REV,X as ReductionSafetyError,me as autotuneRouting,le as cachedAutotuneMatches,de as cachedPolicyMatchesSafety,te as detectSgShuffleMismap,ee as detectTreeReductionBug,ge as measureAutotuneReference,C as pairedPerfVerdict,T as pairedRatios,x as pairedStableSgWin,re as probeReductionSafety,$ as resolveReductionSafety,Z as rotatedArmOrder,pe as tunedOptions};
44
+ //# sourceMappingURL=autotune-Bwt_lWMv.js.map
assets/autotune-Bwt_lWMv.js.map ADDED
@@ -0,0 +1 @@
 
 
1
+ {"version":3,"file":"autotune-Bwt_lWMv.js","sources":["../../src/engine/autotune.js"],"sourcesContent":["// Adapter-aware routing autotune.\r\n//\r\n// The 'auto' thresholds in decoder.js encode sweeps from ONE device (RTX\r\n// 5070 Ti laptop). Re-running the sweep suite on the Intel xe-lpg iGPU\r\n// (2026-07-06) flipped four of them outright: fuse_ln LOSES 51% at b1 (its\r\n// dGPU home turf), all-5 tiled projections WIN from B≥32 (the dGPU starves\r\n// below 128), the fused lm_head argmax loses ~5%, and the lm_head\r\n// gemv→tiled crossover moves 16 → 32. Apple/Mali/Adreno have never been\r\n// measured at all. Rather than grow a vendor table, this measures the four\r\n// decisions on THE device at hand (~1s dGPU / ~8s iGPU, once per load) and\r\n// returns a threshold table; callers resolve it per batch with\r\n// tunedOptions(tuned, B) and pass the result through translateBatch.\r\n//\r\n// The tuned space is VALUE-PRESERVING routing only — every arm is a kernel/\r\n// layout choice already quality-gated on its own (proj_sweep divergence\r\n// gate, fuse_ln_equiv, argmax_fuse_equiv, q8 goldens; near-tie argmax flips\r\n// between arms are the known, accepted f16 reality). ffn 'q8' is NOT in the\r\n// space: it fails the golden bar (27/30) no matter how fast it is.\r\n//\r\n// Ties keep the shipped default (a candidate must beat it by WIN_MARGIN),\r\n// so on the 5070 Ti the policy resolves to exactly today's behavior.\r\n\r\nimport { runEncoder } from './encoder.js';\r\nimport { createDecodeState, encodeDecodeStep } from './decoder.js';\r\nimport {\r\n createUniformParamPool, getDispatchStats, shouldUseUniformParamPool,\r\n} from './pipelines.js';\r\nimport { EOS, VOCAB } from './constants.js';\r\n\r\nconst ALL5 = ['fc1', 'fc2', 'self_out', 'cross_q', 'cross_out'];\r\n\r\n// decoder.js 'auto' behavior, expressed as thresholds (see the consts there).\r\nexport const DEFAULT_ROUTING = Object.freeze({\r\n fuseLnMaxB: 4,\r\n lmHeadMinB: 16,\r\n lmHeadFuse: 'auto',\r\n projTiledMinB: 128,\r\n projTiledKinds: ['fc1', 'fc2'],\r\n // 'auto' = megakernel at B ≤ DECODE_MEGA_MAX_B; 'off' disables it. Won\r\n // −12–16% b1 e2e on the NVIDIA it was tuned on, but LOSES on Metal (Mac\r\n // mega_sweep 2026-07-06: +7% b1, and mega+fusedLn 'auto' is 3.1× off the\r\n // lean unfused path) — so it is a measured decision like the others.\r\n decodeMega: 'auto',\r\n // Subgroup reductions at the WT-GEMV + LN sites. Default OFF: a wash on\r\n // the NVIDIA reference (sg_sweep b8 −3.3%, e2e noise), but −12.7% b8 /\r\n // −7.4% b16 steady-state on M5 Max Metal (barriers are what a\r\n // one-workgroup-per-row kernel pays there) — measured per device below.\r\n sg: 'off',\r\n});\r\n\r\n// A candidate wins only if it beats the default by >5%. The defaults come\r\n// from 7-round × 50-step sweeps on the reference GPU; this quick 3-round ×\r\n// 24-step probe must not overturn them on noise (measured: ±4% b1 arm drift\r\n// on a busy dGPU flipped fuseLn between two back-to-back runs at a 2%\r\n// margin, while every real iGPU win measures ≥5.5%).\r\nconst WIN_MARGIN = 0.95;\r\n\r\n// Part of the app's autotune cache key (autotuneCacheKey): bump whenever\r\n// WGSL kernel code, the tuned space, or routing semantics change, so tables\r\n// measured against old kernels re-tune instead of steering new ones.\r\nexport const KERNEL_REV = 12;\n\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\n\r\nexport class ReductionSafetyError extends Error {\r\n constructor(message, verdicts) {\r\n super(message);\r\n this.name = 'ReductionSafetyError';\r\n this.code = 'WEBMT_NO_SAFE_REDUCTION';\r\n this.verdicts = verdicts;\r\n }\r\n}\r\n\r\n// Turn the two tri-state probes into one explicit safety policy. `false`\r\n// means a route was measured clean, `true` means it was measured broken,\r\n// and `null` means the probe itself could not produce a verdict. Performance\r\n// tuning is allowed to choose between routes only when BOTH are proven safe.\r\nexport function resolveReductionSafety({ treeBug, sgMismap, sgFeature }) {\r\n const valid = (v) => v === true || v === false || v === null;\r\n if (!valid(treeBug) || !valid(sgMismap)) {\r\n throw new Error(`invalid reduction verdicts: treeBug=${treeBug}, sgMismap=${sgMismap}`);\r\n }\r\n const treeSafe = treeBug === false;\r\n const sgSafe = !!sgFeature && sgMismap === false;\r\n if (treeSafe && sgSafe) {\r\n return { status: 'both-safe', retry: false, sgOk: true, forceSg: false };\r\n }\r\n if (treeSafe) {\r\n return { status: 'tree-safe', retry: false, sgOk: false, forceSg: false };\r\n }\r\n if (sgSafe) {\r\n return { status: 'subgroup-safe', retry: false, sgOk: true, forceSg: true };\r\n }\r\n const retry = treeBug === null || (!!sgFeature && sgMismap === null);\r\n return { status: retry ? 'unresolved' : 'unsafe', retry, sgOk: false, forceSg: false };\r\n}\r\n\r\n// Rotate rather than merely reverse: with three or more arms, each one gets\r\n// every position in the thermal ramp before the sequence repeats.\r\nexport function rotatedArmOrder(names, round) {\r\n if (!names.length) return [];\r\n const offset = ((round % names.length) + names.length) % names.length;\r\n return [...names.slice(offset), ...names.slice(0, offset)];\r\n}\r\n\r\nexport function pairedRatios(runs, alt, base = 'def') {\r\n const a = runs[alt];\r\n const b = runs[base];\r\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length || !a.length) {\r\n throw new Error(`pairedRatios: ${alt}/${base} need equal non-empty run arrays`);\r\n }\r\n return a.map((v, i) => v / b[i]);\r\n}\r\n\r\n// Three rounds are a screening pass. Only a strong, consistent >=10% win\r\n// settles early; a clean non-win keeps the shipped default; noisy or near-\r\n// threshold results ask for four more paired rounds. At seven rounds the\r\n// candidate needs both a >5% paired-median win and >=5 favorable pairs.\r\nexport function pairedPerfVerdict(runs, alt, base = 'def') {\r\n const ratios = pairedRatios(runs, alt, base);\r\n const med = median(ratios);\r\n const favorable = ratios.filter((r) => r < 1).length;\r\n if (ratios.length <= 3) {\r\n // A three-round early win must be unanimous. Two fast pairs plus one\r\n // loss is exactly the noisy pattern that flipped sg on the reference GPU.\r\n if (med <= 0.90 && favorable === ratios.length) return 'win';\r\n if (med >= 0.98 && Math.min(...ratios) >= 0.95) return 'keep';\r\n return 'more';\r\n }\r\n const need = Math.ceil(ratios.length * (2 / 3));\r\n return med < WIN_MARGIN && favorable >= need ? 'win' : 'keep';\r\n}\r\n\r\n// Performance-only subgroup routing changes reduction order and can flip a\r\n// near-tie token even when both routes are numerically valid. Demand stronger\r\n// and longer evidence than ordinary routing knobs: at least seven paired\r\n// rounds, >=10% median gain, and every round favorable.\r\nexport function pairedStableSgWin(runs, alt = 'sgOn', base = 'def') {\r\n const ratios = pairedRatios(runs, alt, base);\r\n if (ratios.length < 7) return false;\r\n const favorable = ratios.filter((ratio) => ratio < 1).length;\r\n return median(ratios) <= 0.90 && favorable === ratios.length;\r\n}\r\n\r\n// Deterministic filler tokens (LCG) — timing only depends on shapes, but\r\n// keep runs reproducible and inside the vocab (clear of the specials).\r\nfunction syntheticBatch(B, S) {\r\n const ids = new Uint32Array(B * S);\r\n let x = 0x9e3779b9;\r\n for (let i = 0; i < ids.length; i++) {\r\n x = (Math.imul(x, 1664525) + 1013904223) >>> 0;\r\n ids[i] = 100 + (x % (VOCAB - 200));\r\n }\r\n for (let b = 0; b < B; b++) ids[b * S + S - 1] = EOS;\r\n return { ids, lens: new Uint32Array(B).fill(S), B, S };\r\n}\r\n\r\n// One lazy parameter pool per canary/full-tune session. The session owns the\r\n// pool explicitly so cleanup stays in this module instead of hiding mutable\r\n// state on ctx (callers often pass a shallow ctx copy).\r\nfunction createAutotuneParamPoolSession(ctx, enabled) {\r\n let pool = null;\r\n let destroyed = false;\r\n let decodeTransientUniforms = 0;\r\n return {\r\n poolFor(state) {\r\n if (destroyed) throw new Error('autotune uniform-pool session is destroyed');\r\n if (!shouldUseUniformParamPool(enabled, state)) return null;\r\n pool ??= createUniformParamPool(ctx.device, { banks: 2 });\r\n return pool;\r\n },\r\n recordDecodeUniformDelta(delta) {\r\n decodeTransientUniforms += Math.max(0, delta);\r\n },\r\n invalidateBindings() {\r\n return pool?.invalidateBindings() ?? 0;\r\n },\r\n snapshot() {\r\n return { decodeTransientUniforms };\r\n },\r\n destroy() {\r\n if (destroyed) return;\r\n pool?.destroy();\r\n pool = null;\r\n destroyed = true;\r\n },\r\n };\r\n}\r\n\r\n// Wall-clock µs per decode step for one routing arm — same grouped\r\n// record/submit shape as translateBatch (GROUP_STEPS=8), fresh state per\r\n// call so KV growth is identical across arms.\r\nasync function timeArm(ctx, weights, encRun, B, steps, opts, paramPoolSession) {\r\n const { device } = ctx;\r\n const state = createDecodeState(ctx, weights, {\r\n B, S: encRun.S, maxSteps: steps, ...opts,\r\n });\r\n let uniformsBefore = null;\r\n let armDrained = false;\r\n try {\r\n // Match translateBatch's WebKit path while timing routing decisions. Queue\r\n // ordering makes a bank reusable after submit: the next writeBuffer is\r\n // ordered after that submit even though autotune has no readback to await.\r\n const paramPool = paramPoolSession.poolFor(state);\r\n if (paramPool) uniformsBefore = getDispatchStats(device).uniformBuffersCreated;\r\n const t0 = performance.now();\r\n for (let g = 0; g < steps; g += 8) {\r\n const tEnd = Math.min(g + 8, steps);\r\n const bank = (g / 8) % 2;\r\n let poolFrameActive = false;\r\n const scratch = [];\r\n try {\r\n if (paramPool) {\r\n paramPool.begin(bank);\r\n poolFrameActive = true;\r\n }\r\n const encoder = device.createCommandEncoder({ label: `autotune ${g}..${tEnd}` });\r\n const pass = encoder.beginComputePass();\r\n for (let t = g; t < tEnd; t++) {\r\n scratch.push(...encodeDecodeStep(ctx, weights, encRun, state, t, pass).scratch);\r\n }\r\n pass.end();\r\n if (paramPool) {\r\n paramPool.flush();\r\n poolFrameActive = false;\r\n }\r\n device.queue.submit([encoder.finish()]);\r\n if (paramPool) paramPool.release(bank);\r\n } catch (err) {\r\n if (poolFrameActive) paramPool.abort();\r\n throw err;\r\n } finally {\r\n for (const b of scratch) b.destroy();\r\n }\r\n }\r\n await device.queue.onSubmittedWorkDone();\r\n armDrained = true;\r\n return Number((((performance.now() - t0) * 1000) / steps).toFixed(1));\r\n } finally {\r\n try {\r\n if (uniformsBefore !== null) {\r\n const uniformsAfter = getDispatchStats(device).uniformBuffersCreated;\r\n paramPoolSession.recordDecodeUniformDelta(uniformsAfter - uniformsBefore);\r\n }\r\n } finally {\r\n try {\r\n // A session intentionally keeps its bank buffers across arms, but a\r\n // fresh decode state gives every arm a new resource generation.\r\n // Retire the old bind groups before destroying that state so WebKit\r\n // can release its backing buffers immediately.\r\n if (armDrained) paramPoolSession.invalidateBindings();\r\n } finally {\r\n state.destroy();\r\n }\r\n }\r\n }\r\n}\r\n\r\nexport function cachedAutotuneMatches(cachedUs, currentUs, tolerance = 0.15) {\r\n if (!(Number.isFinite(cachedUs) && cachedUs > 0 && Number.isFinite(currentUs) && currentUs > 0)) {\r\n return false;\r\n }\r\n return Math.abs((currentUs / cachedUs) - 1) <= tolerance + Number.EPSILON;\r\n}\r\n\r\nexport function cachedPolicyMatchesSafety(tuned, safety) {\r\n if (!tuned || !safety) return false;\r\n if (safety.forceSg) return tuned.sg === 'on' && tuned.sgForced === true;\r\n if (!safety.sgOk) return tuned.sg !== 'on';\r\n return true;\r\n}\r\n\r\n// A cache can outlive the GPU's current power/thermal regime. The RTX\r\n// reference has two repeatable states whose B64 default step differs by\r\n// ~25%; the b1 mega-vs-lean winner flips with that state. One warmed B64\r\n// canary is much cheaper than a full retune and prevents a 30-day cache from\r\n// steering today's low-clock session with a high-clock policy (or vice versa).\r\nexport async function measureAutotuneReference(\r\n ctx,\r\n weights,\r\n {\r\n B = 64, S = 96, steps = 24, rounds = 3,\r\n immediates = 'auto', uniformPool = false,\r\n } = {},\r\n) {\r\n const batch = syntheticBatch(B, S);\r\n const encRun = await runEncoder(ctx, weights, batch, { retainEncOut: false });\r\n await ctx.device.queue.onSubmittedWorkDone();\r\n const paramPoolSession = createAutotuneParamPoolSession(ctx, uniformPool);\r\n try {\r\n await timeArm(ctx, weights, encRun, B, steps, { immediates }, paramPoolSession);\r\n const runs = [];\r\n for (let r = 0; r < rounds; r++) {\r\n runs.push(await timeArm(ctx, weights, encRun, B, steps, { immediates }, paramPoolSession));\r\n }\r\n return { medianUs: median(runs), runs, poolStats: paramPoolSession.snapshot() };\r\n } finally {\r\n try {\r\n paramPoolSession.destroy();\r\n } finally {\r\n encRun.arena.destroy();\r\n }\r\n }\r\n}\r\n\r\n// Measure the routing decisions on this device and return {tuned, timings}.\r\n// tuned is a threshold table (DEFAULT_ROUTING shape); timings carries the\r\n// per-arm medians for reporting. Weights should be the production load\r\n// (lmHeadQ8/ffnWT/projWT) so 'auto' resolves to what the app will run.\r\n\r\n// GPU correctness self-test for the Adreno 7xx tree-reduction miscompile\r\n// (2026-07 Android round). The driver compiles the guarded-RMW shared-memory\r\n// tree (`if (tid < s) { red[tid] = op(red[tid], red[tid+s]) }` + barrier)\r\n// WRONG inside the real add_ln/attention kernels — deterministically — while\r\n// the same idiom in a minimal shader passes; the trigger is contextual, so\r\n// this probe replicates the smallest KNOWN-FAILING structure verbatim (the\r\n// add_layernorm shape: strided load loop -> shared vbuf + register partials\r\n// -> sum tree -> broadcast mean). ~5ms, no features required. Returns true\r\n// when the device computes it wrong -> callers must force sg reductions;\r\n// false = computes it right; null = the probe itself couldn't run.\r\nexport async function detectTreeReductionBug(device) {\r\n const D = 448;\r\n const WG = 256;\r\n const G = 8;\r\n const code = `\r\n@group(0) @binding(0) var<storage, read_write> out: array<f32>;\r\nconst D: u32 = ${D}u;\r\nconst WG: u32 = ${WG}u;\r\nfn vhash(i: u32, g: u32) -> f32 {\r\n return f32((((i + 1u) * 2654435761u) ^ ((g + 1u) * 40503u)) & 1023u);\r\n}\r\nvar<workgroup> vbuf: array<f32, D>;\r\nvar<workgroup> scratch: array<f32, WG>;\r\n@compute @workgroup_size(${WG})\r\nfn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\r\n let g = wid.x; let tid = lid.x;\r\n var sum: f32 = 0.0;\r\n for (var i = tid; i < D; i = i + WG) {\r\n let v = (vhash(i, g) - 512.0) / 256.0 + (vhash(i + 7777u, g) - 512.0) / 256.0;\r\n vbuf[i] = v;\r\n sum = sum + v;\r\n }\r\n scratch[tid] = sum;\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { scratch[tid] = scratch[tid] + scratch[tid + s]; }\r\n workgroupBarrier();\r\n }\r\n let mu = scratch[0] / f32(D);\r\n workgroupBarrier();\r\n for (var i = tid; i < D; i = i + WG) { out[g * D + i] = vbuf[i] - mu; }\r\n}`;\r\n try {\r\n const module = device.createShaderModule({ code });\r\n const pipeline = device.createComputePipeline({\r\n layout: 'auto', compute: { module, entryPoint: 'main' },\r\n });\r\n const outBuf = device.createBuffer({\r\n size: G * D * 4, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n });\r\n const staging = device.createBuffer({\r\n size: G * D * 4, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,\r\n });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [{ binding: 0, resource: { buffer: outBuf } }],\r\n });\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.dispatchWorkgroups(G);\r\n pass.end();\r\n encoder.copyBufferToBuffer(outBuf, 0, staging, 0, G * D * 4);\r\n device.queue.submit([encoder.finish()]);\r\n await staging.mapAsync(GPUMapMode.READ);\r\n const got = new Float32Array(staging.getMappedRange().slice(0));\r\n staging.unmap();\r\n outBuf.destroy();\r\n staging.destroy();\r\n const hash = (i, g) => ((Math.imul(i + 1, 2654435761) ^ Math.imul(g + 1, 40503)) >>> 0) & 1023;\r\n for (let g = 0; g < G; g++) {\r\n const v = new Float64Array(D);\r\n let sum = 0;\r\n for (let i = 0; i < D; i++) {\r\n v[i] = (hash(i, g) - 512) / 256 + (hash(i + 7777, g) - 512) / 256;\r\n sum += v[i];\r\n }\r\n const mu = sum / D;\r\n for (let i = 0; i < D; i++) {\r\n if (!(Math.abs(got[g * D + i] - (v[i] - mu)) <= 1e-3)) return true;\r\n }\r\n }\r\n return false;\r\n } catch {\r\n // A probe failure must never block engine init — but a dead probe is not\r\n // a clean verdict either: on a tree-bug device a transient crash here\r\n // (memory pressure at load) used to cache a no-forced-sg table FOREVER.\r\n // null = inconclusive: the policy layer retries, then chooses another\r\n // proven-safe route or blocks initialization.\r\n return null;\r\n }\r\n}\r\n\r\n// GPU correctness self-test for the OTHER reduction route. The sg kernels\r\n// (gemm_gemv IF_SG et al.) fold each TK-slice with a subgroupShuffleDown\r\n// butterfly and assume consecutive local invocations occupy consecutive\r\n// lanes of one subgroup. That layout is implementation-defined in WGSL —\r\n// every shipping driver maps linearly, but nothing guarantees it (Codex\r\n// audit 2026-07-10) — so measure it: replicate the kernel's exact butterfly\r\n// at every power-of-two TK the dispatch gate can pick (TK ≤ subgroupMinSize)\r\n// and check the lane-0 slice sums against CPU. Returns true = mismapped (sg\r\n// routes are UNSAFE here), false = clean, null = probe couldn't run.\r\nexport async function detectSgShuffleMismap(device, maxTk) {\r\n const WG = 64;\r\n const G = 4;\r\n const tks = [4, 8, 16, 32].filter((tk) => tk <= Math.min(maxTk ?? 0, WG));\r\n if (!tks.length) return null;\r\n const hash = (i, g) => (((Math.imul(i + 1, 2654435761) ^ Math.imul(g + 1, 40503)) >>> 0) & 1023) / 64;\r\n try {\r\n for (const TK of tks) {\r\n const slices = WG / TK;\r\n const code = `\r\nenable subgroups;\r\n@group(0) @binding(0) var<storage, read_write> out: array<f32>;\r\nconst TK: u32 = ${TK}u;\r\nfn vhash(i: u32, g: u32) -> f32 {\r\n return f32((((i + 1u) * 2654435761u) ^ ((g + 1u) * 40503u)) & 1023u) / 64.0;\r\n}\r\n@compute @workgroup_size(${WG})\r\nfn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\r\n let g = wid.x; let tid = lid.x;\r\n var vr = vhash(tid, g);\r\n for (var s = TK / 2u; s > 0u; s = s >> 1u) {\r\n vr = vr + subgroupShuffleDown(vr, s);\r\n }\r\n if (tid % TK == 0u) { out[g * ${slices}u + tid / TK] = vr; }\r\n}`;\r\n const module = device.createShaderModule({ code });\r\n const pipeline = device.createComputePipeline({\r\n layout: 'auto', compute: { module, entryPoint: 'main' },\r\n });\r\n const outBuf = device.createBuffer({\r\n size: G * slices * 4, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n });\r\n const staging = device.createBuffer({\r\n size: G * slices * 4, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,\r\n });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [{ binding: 0, resource: { buffer: outBuf } }],\r\n });\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.dispatchWorkgroups(G);\r\n pass.end();\r\n encoder.copyBufferToBuffer(outBuf, 0, staging, 0, G * slices * 4);\r\n device.queue.submit([encoder.finish()]);\r\n await staging.mapAsync(GPUMapMode.READ);\r\n const got = new Float32Array(staging.getMappedRange().slice(0));\r\n staging.unmap();\r\n outBuf.destroy();\r\n staging.destroy();\r\n for (let g = 0; g < G; g++) {\r\n for (let sl = 0; sl < slices; sl++) {\r\n let want = 0;\r\n for (let i = 0; i < TK; i++) want += hash(sl * TK + i, g);\r\n if (!(Math.abs(got[g * slices + sl] - want) <= 1e-2)) return true;\r\n }\r\n }\r\n }\r\n return false;\r\n } catch {\r\n // Same contract as detectTreeReductionBug: a dead probe is inconclusive,\r\n // not a verdict. The policy layer may use tree only if tree was proven\r\n // safe; otherwise it retries and then blocks rather than guessing.\r\n return null;\r\n }\r\n}\r\n\r\nexport async function probeReductionSafety(\r\n ctx,\r\n { treeProbe = detectTreeReductionBug, sgProbe = detectSgShuffleMismap } = {},\r\n) {\r\n const sgFeature = !!ctx.hasSubgroups && (ctx.subgroupMinSize ?? 0) >= 16;\r\n // Correctness gates BEFORE any perf decision — one probe per reduction\r\n // route. treeBug: a device with the tree-reduce miscompile must run the sg\r\n // variants at every reduction site (attention, add_ln, row_ln, gemv-WT,\r\n // decoder_mega) - sg is forced on and the b8 perf probe cannot override\r\n // it. sgMismap: a device whose subgroup lane layout breaks the shuffle\r\n // butterfly must never probe/force sg. A null verdict is retried once; after\r\n // that at least one route must be explicitly proven safe.\r\n const probe = async () => {\r\n const treeBug = await treeProbe(ctx.device);\r\n // `true` represents unavailable/unsafe when the feature itself is absent.\r\n const sgMismap = sgFeature\r\n ? await sgProbe(ctx.device, ctx.subgroupMinSize)\r\n : true;\r\n return { treeBug, sgMismap };\r\n };\r\n let verdicts = await probe();\r\n let safety = resolveReductionSafety({ ...verdicts, sgFeature });\r\n if (safety.retry) {\r\n await ctx.device.queue.onSubmittedWorkDone();\r\n verdicts = await probe();\r\n safety = resolveReductionSafety({ ...verdicts, sgFeature });\r\n }\r\n if (safety.status === 'unsafe' || safety.status === 'unresolved') {\r\n throw new ReductionSafetyError(\r\n `webMT: no proven-safe GPU reduction route ` +\r\n `(treeBug=${verdicts.treeBug}, sgMismap=${verdicts.sgMismap}, subgroups=${sgFeature})`,\r\n { ...verdicts, sgFeature },\r\n );\r\n }\r\n return { ...safety, verdicts: { ...verdicts, sgFeature } };\r\n}\r\n\r\nexport async function autotuneRouting(ctx, weights, opts = {}) {\r\n const { reductionSafety = null, uniformPool = false, ...perfOpts } = opts;\r\n const safety = reductionSafety ?? await probeReductionSafety(ctx);\r\n const paramPoolSession = createAutotuneParamPoolSession(ctx, uniformPool);\r\n try {\r\n try {\r\n const result = await probeAndDecide(ctx, weights, perfOpts, safety, paramPoolSession);\r\n return { ...result, poolStats: paramPoolSession.snapshot() };\r\n } catch (err) {\r\n // The perf probe died mid-flight (device pressure, transient loss). The\r\n // correctness verdict above must NOT die with it: on a tree-bug device,\r\n // falling back to plain 'auto' routing (sg off) silently translates\r\n // garbage. Return defaults + the forced-sg bits; `partial` tells callers\r\n // this table is failure-derived and should not be cached.\r\n const tuned = { ...DEFAULT_ROUTING, projTiledKinds: [...DEFAULT_ROUTING.projTiledKinds] };\r\n if (safety.forceSg) {\r\n tuned.sg = 'on';\r\n tuned.sgForced = true;\r\n }\r\n return {\r\n tuned,\r\n timings: {},\r\n partial: String(err?.message ?? err),\r\n poolStats: paramPoolSession.snapshot(),\r\n };\r\n }\r\n } finally {\r\n paramPoolSession.destroy();\r\n }\r\n}\r\n\r\nasync function probeAndDecide(\r\n ctx,\r\n weights,\r\n {\r\n S = 96, steps = 24, rounds = 3, extraRounds = 4,\r\n immediates = 'auto',\r\n },\r\n { sgOk, forceSg },\r\n paramPoolSession,\r\n) {\r\n // One entry per batch point; arms at the same B share one encoder run.\r\n // 'def' is decoder.js 'auto' at that B; every alt is compared against it.\r\n // b1 steps are so short that per-round jitter dominates — give it extra\r\n // rounds (cheap: its arms run in tens of ms). At B ≤ 4 'auto' means the\r\n // megakernel (when eligible), so the b1 alts probe the two lean paths:\r\n // mega with the LN fusion question mooted, and the fully split pipeline.\r\n // Where sg is probeable, every b1 arm also runs WITH sg — the mega-vs-lean\r\n // verdict flips with it (mega's ~400 tree barriers/layer are exactly what\r\n // Metal pays; sg removes ~80% of them), so the b1 decision below is read\r\n // in whichever sg mode the b8 probe picks.\r\n const points = [\r\n {\r\n B: 1,\r\n arms: {\r\n def: {},\r\n lnOff: { decodeMega: 'off', fuseLn: 'off' },\r\n lnOn: { decodeMega: 'off', fuseLn: 'on' },\r\n ...(sgOk ? {\r\n defSg: { sg: 'on' },\r\n lnOffSg: { decodeMega: 'off', fuseLn: 'off', sg: 'on' },\r\n lnOnSg: { decodeMega: 'off', fuseLn: 'on', sg: 'on' },\r\n } : {}),\r\n },\r\n comparisons: [\r\n ['lnOff', 'def'], ['lnOn', 'def'],\r\n ...(sgOk ? [['lnOffSg', 'defSg'], ['lnOnSg', 'defSg']] : []),\r\n ],\r\n },\r\n { B: 16, arms: { def: {}, gemv: { lmHead: 'gemv' } }, comparisons: [['gemv', 'def']] },\r\n { B: 32, arms: { def: {}, all5: { tiledProj: ALL5 } }, comparisons: [['all5', 'def']] },\r\n {\r\n B: 64,\r\n arms: { def: {}, all5: { tiledProj: ALL5 }, fuseOff: { lmHeadFuse: 'off' } },\r\n comparisons: [['all5', 'def'], ['fuseOff', 'def']],\r\n },\r\n ];\r\n // Subgroup arm at b8 — the batch point where the sg signal peaks (all\r\n // GEMV + add_ln sites active, mega/fused-LN out of the picture). Only\r\n // probed where the decode state accepts sg 'on' (feature + slice fit).\r\n // rounds+2 like b1: the sg arms are short and the margin on the NVIDIA\r\n // reference is only ~3% — a hot 3-round probe was seen flipping it on a\r\n // 973µs outlier run. Extra rounds keep the median honest.\r\n if (sgOk) {\r\n points.push({\r\n B: 8,\r\n arms: { def: {}, sgOn: { sg: 'on' } },\r\n comparisons: [['sgOn', 'def']],\r\n minRounds: rounds + extraRounds,\r\n });\r\n }\r\n\r\n // Warm the adapter with the heaviest probe first. Starting at B=1 leaves\r\n // an NVIDIA laptop GPU in P8/low-clock territory and makes dispatch-bound\r\n // mega-vs-lean routing depend on whichever clock ramp this browser launch\r\n // happened to get. Heavy-to-light gives every latency probe a comparable\r\n // post-boost state without adding another synthetic warmup workload.\r\n points.sort((a, b) => b.B - a.B);\r\n\r\n const timings = {};\r\n for (const point of points) {\r\n const batch = syntheticBatch(point.B, S);\r\n const encRun = await runEncoder(ctx, weights, batch, { retainEncOut: false });\r\n await ctx.device.queue.onSubmittedWorkDone();\r\n try {\r\n const names = Object.keys(point.arms);\r\n for (const name of names) {\r\n await timeArm(ctx, weights, encRun, point.B, steps, {\r\n ...point.arms[name], immediates,\r\n }, paramPoolSession);\r\n }\r\n const runs = Object.fromEntries(names.map((n) => [n, []]));\r\n const measureRound = async (r) => {\r\n const order = rotatedArmOrder(names, r);\r\n for (const name of order) {\r\n runs[name].push(await timeArm(ctx, weights, encRun, point.B, steps, {\r\n ...point.arms[name], immediates,\r\n }, paramPoolSession));\r\n }\r\n };\r\n const screeningRounds = point.minRounds ?? rounds;\r\n for (let r = 0; r < screeningRounds; r++) await measureRound(r);\r\n const needsMore = point.comparisons.some(([alt, base]) =>\r\n pairedPerfVerdict(runs, alt, base) === 'more');\r\n if (needsMore && screeningRounds === rounds) {\r\n for (let r = screeningRounds; r < rounds + extraRounds; r++) await measureRound(r);\r\n }\r\n timings[`b${point.B}`] = Object.fromEntries(\r\n names.map((n) => [n, { medianUs: median(runs[n]), runs: runs[n] }]),\r\n );\r\n } finally {\r\n encRun.arena.destroy();\r\n }\r\n }\r\n\r\n const wins = (B, alt, base = 'def') => {\r\n const runs = Object.fromEntries(\r\n Object.entries(timings[`b${B}`]).map(([name, entry]) => [name, entry.runs]),\r\n );\r\n return pairedPerfVerdict(runs, alt, base) === 'win';\r\n };\r\n\r\n const tuned = { ...DEFAULT_ROUTING, projTiledKinds: [...DEFAULT_ROUTING.projTiledKinds] };\r\n // sg is decided FIRST (b8 probe) — the b1 mega-vs-lean question is then\r\n // answered under the sg mode the device will actually run.\r\n if (forceSg) {\r\n tuned.sg = 'on';\r\n tuned.sgForced = true; // correctness, not perf - survives any probe verdict\r\n } else if (timings.b8) {\r\n const b8Runs = Object.fromEntries(\r\n Object.entries(timings.b8).map(([name, entry]) => [name, entry.runs]),\r\n );\r\n if (pairedStableSgWin(b8Runs)) tuned.sg = 'on';\r\n }\r\n const sfx = tuned.sg === 'on' ? 'Sg' : '';\r\n // b1: 'def' is the megakernel (when eligible); a lean-arm win turns it off\r\n // and settles the LN-fusion question for the split pipeline at the same\r\n // time (lowest median of the two winning lean arms decides).\r\n const b1 = timings.b1;\r\n const b1Runs = Object.fromEntries(Object.entries(b1).map(([name, entry]) => [name, entry.runs]));\r\n const baseName = `def${sfx}`;\r\n const offName = `lnOff${sfx}`;\r\n const onName = `lnOn${sfx}`;\r\n const offRatio = median(pairedRatios(b1Runs, offName, baseName));\r\n const onRatio = median(pairedRatios(b1Runs, onName, baseName));\r\n const leanBest = offRatio <= onRatio ? offName : onName;\r\n if (wins(1, leanBest, `def${sfx}`)) {\r\n tuned.decodeMega = 'off';\r\n tuned.fuseLnMaxB = leanBest.startsWith('lnOff') ? 0 : DEFAULT_ROUTING.fuseLnMaxB;\r\n }\r\n if (wins(16, 'gemv')) tuned.lmHeadMinB = 32;\r\n if (wins(64, 'fuseOff')) tuned.lmHeadFuse = 'off';\r\n if (wins(32, 'all5')) {\r\n tuned.projTiledMinB = 32;\r\n tuned.projTiledKinds = [...ALL5];\r\n } else if (wins(64, 'all5')) {\r\n tuned.projTiledMinB = 64;\r\n tuned.projTiledKinds = [...ALL5];\r\n }\r\n return { tuned, timings };\r\n}\r\n\r\n// Resolve a tuned threshold table to concrete createDecodeState/translateBatch\r\n// options for one batch size. tuned == null falls back to plain 'auto'.\r\nexport function tunedOptions(tuned, B) {\r\n if (!tuned) return {};\r\n return {\r\n fuseLn: B <= tuned.fuseLnMaxB ? 'on' : 'off',\r\n lmHead: B >= tuned.lmHeadMinB ? 'auto' : 'gemv',\r\n lmHeadFuse: tuned.lmHeadFuse === 'off' ? 'off' : 'auto',\r\n tiledProj: B >= tuned.projTiledMinB && tuned.projTiledMinB < DEFAULT_ROUTING.projTiledMinB\r\n ? [...tuned.projTiledKinds]\r\n : 'auto',\r\n // Tree-bug devices: mega+sg is VERIFIED broken at hachimi dims on the\r\n // affected Adreno (sg golden 0/30 via mega vs 30/30 lean, 2026-07-07;\r\n // moxhi dims pass — likely its near-16KB shared budget). Until that\r\n // miscompile is bisected, correctness beats mega's small-B win there.\r\n decodeMega: tuned.sgForced ? 'off' : (tuned.decodeMega === 'off' ? 'off' : 'auto'),\r\n // Learned only where supported — 'on' would throw on a device without\r\n // the feature, but tuned tables are per-device (cache keyed on adapter).\r\n sg: tuned.sg === 'on' ? 'on' : 'off',\r\n // Tree-bug devices also miscompile attention_block at non-multiple-of-16\r\n // workgroup sizes — cap the encoder QB there (no-op where QB is already\r\n // a multiple of 8, e.g. every D<=64 model).\r\n encAttnSafe: !!tuned.sgForced,\r\n };\r\n}\r\n"],"names":["ALL5","DEFAULT_ROUTING","WIN_MARGIN","KERNEL_REV","median","xs","s","a","b","m","ReductionSafetyError","message","verdicts","resolveReductionSafety","treeBug","sgMismap","sgFeature","valid","v","treeSafe","sgSafe","retry","rotatedArmOrder","names","round","offset","pairedRatios","runs","alt","base","i","pairedPerfVerdict","ratios","med","favorable","r","need","pairedStableSgWin","ratio","syntheticBatch","B","S","ids","x","VOCAB","EOS","createAutotuneParamPoolSession","ctx","enabled","pool","destroyed","decodeTransientUniforms","state","shouldUseUniformParamPool","createUniformParamPool","delta","timeArm","weights","encRun","steps","opts","paramPoolSession","device","createDecodeState","uniformsBefore","armDrained","paramPool","getDispatchStats","t0","g","tEnd","bank","poolFrameActive","scratch","encoder","pass","t","encodeDecodeStep","err","uniformsAfter","cachedAutotuneMatches","cachedUs","currentUs","tolerance","cachedPolicyMatchesSafety","tuned","safety","measureAutotuneReference","rounds","immediates","uniformPool","batch","runEncoder","detectTreeReductionBug","code","module","pipeline","outBuf","staging","bindGroup","got","hash","sum","mu","detectSgShuffleMismap","maxTk","tks","tk","TK","slices","sl","want","probeReductionSafety","treeProbe","sgProbe","probe","autotuneRouting","reductionSafety","perfOpts","probeAndDecide","extraRounds","sgOk","forceSg","points","timings","point","name","n","measureRound","order","screeningRounds","wins","entry","b8Runs","sfx","b1","b1Runs","baseName","offName","onName","offRatio","onRatio","leanBest","tunedOptions"],"mappings":"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"}
assets/autotune-CVn9SF1X.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import{r as S}from"./debug-CPpXXfWA.js";import{l as D}from"./weights-DxIJF1EY.js";import{e as U}from"./shortlist-C151mR5c.js";import{l as z}from"./tokenizer-BmI7pHmp.js";import{autotuneRouting as h,DEFAULT_ROUTING as O,measureAutotuneReference as k,tunedOptions as N}from"./autotune-Bwt_lWMv.js";import{r as A}from"./encoder-CZXKGzzg.js";import{c as E,e as G}from"./decoder-BUiaGDqb.js";import{V as H,e as I}from"./constants-CSVWRdrh.js";import{h as B,m as P}from"./pipelines-BbLc75sB.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./safe_storage-BYkOahew.js";import"./shapes-ClGtK-ia.js";import"./f16-wKKZr58e.js";import"./device-BotbBNoe.js";const v=e=>{const n=[...e].sort((t,o)=>t-o),r=n.length>>1;return n.length%2?n[r]:(n[r-1]+n[r])/2};function M(e,n){const r={twoBuffersCreated:e.uniformPoolBuffersCreated===2,twoBuffersDestroyed:e.uniformPoolBuffersDestroyed===2,framesBalanced:e.uniformPoolFramesBegun>0&&e.uniformPoolFramesBegun===e.uniformPoolFramesFlushed,zeroTransientUniforms:n.decodeTransientUniforms===0,generationsInvalidated:e.uniformPoolGenerationInvalidations>0,cacheReleased:e.bindGroupCacheSize===0};return{pass:Object.values(r).every(Boolean),checks:r,counters:{poolBuffers:[e.uniformPoolBuffersCreated,e.uniformPoolBuffersDestroyed],frames:[e.uniformPoolFramesBegun,e.uniformPoolFramesFlushed],decodeTransientUniforms:n.decodeTransientUniforms,allUniformBuffers:e.uniformBuffersCreated,generationInvalidations:e.uniformPoolGenerationInvalidations,bindGroupsPurged:e.uniformPoolCachePurges,bindGroupCacheSize:e.bindGroupCacheSize}}}async function w(e,n){const r=await z(),t=await D(e.device,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0,projWT:!0,lmHeadIds:U(r.idToToken)});try{return await n(t)}finally{t.buffer.destroy()}}S("autotune_policy",async e=>e.hasF16?w(e,async n=>{const r={device:e.device,dtype:"f16",limits:e.limits,hasSubgroups:e.hasSubgroups,subgroupMinSize:e.subgroupMinSize},t=performance.now(),{tuned:o,timings:d}=await h(r,n),s=Number((performance.now()-t).toFixed(0)),c=[0,4].includes(o.fuseLnMaxB)&&[16,32].includes(o.lmHeadMinB)&&["auto","off"].includes(o.lmHeadFuse)&&[32,64,128].includes(o.projTiledMinB)&&["auto","off"].includes(o.decodeMega)&&["on","off"].includes(o.sg),l=JSON.stringify(o)===JSON.stringify(O);return{pass:c,detail:{tuned:o,isDefault:l,tuneMs:s,timings:d}}}):{skip:!0,reason:"no shader-f16"});S("autotune_pool_policy",async e=>e.hasF16?w(e,async n=>{const r={device:e.device,dtype:"f16",limits:e.limits,hasSubgroups:e.hasSubgroups,subgroupMinSize:e.subgroupMinSize};B(e.device,{clearCache:!0});const t=performance.now(),{tuned:o,timings:d,partial:s,poolStats:c}=await h(r,n,{immediates:"off",uniformPool:!0}),l=Number((performance.now()-t).toFixed(0)),a=M(P(e.device),c);B(e.device,{clearCache:!0});const u=await k(r,n,{immediates:"off",uniformPool:!0}),m=M(P(e.device),u.poolStats),f=a.pass&&m.pass;return{pass:[0,4].includes(o.fuseLnMaxB)&&[16,32].includes(o.lmHeadMinB)&&["auto","off"].includes(o.lmHeadFuse)&&[32,64,128].includes(o.projTiledMinB)&&["auto","off"].includes(o.decodeMega)&&["on","off"].includes(o.sg)&&!s&&f,detail:{tuned:o,tuneMs:l,partial:s??null,countersPass:f,counters:{full:a,reference:m},timings:d}}}):{skip:!0,reason:"no shader-f16"});function j(e,n){const r=new Uint32Array(e*n);let t=625341585;for(let o=0;o<r.length;o++)t=Math.imul(t,1664525)+1013904223>>>0,r[o]=100+t%(H-200);for(let o=0;o<e;o++)r[o*n+n-1]=I;return{ids:r,lens:new Uint32Array(e).fill(n),B:e,S:n}}async function C(e,n,r,t,o,d){const{device:s}=e,c=E(e,n,{B:t,S:r.S,maxSteps:o,...d});try{const l=performance.now();for(let a=0;a<o;a+=8){const u=Math.min(a+8,o),m=s.createCommandEncoder(),f=m.beginComputePass(),p=[];for(let i=a;i<u;i++)p.push(...G(e,n,r,c,i,f).scratch);f.end(),s.queue.submit([m.finish()]);for(const i of p)i.destroy()}return await s.queue.onSubmittedWorkDone(),Number(((performance.now()-l)*1e3/o).toFixed(1))}finally{c.destroy()}}S("autotune_gate",async e=>e.hasF16?w(e,async n=>{const r={device:e.device,dtype:"f16",limits:e.limits,hasSubgroups:e.hasSubgroups,subgroupMinSize:e.subgroupMinSize},{tuned:t}=await h(r,n),o=[1,16,64],d=5,s=24,c=96,l=[];let a=!0;for(const u of o){const m=j(u,c),f=await A(r,n,m);await r.device.queue.onSubmittedWorkDone();try{const p={auto:{},tuned:N(t,u)};for(const b of Object.values(p))await C(r,n,f,u,s,b);const i={auto:[],tuned:[]};for(let b=0;b<d;b++)for(const[F,T]of Object.entries(p))i[F].push(await C(r,n,f,u,s,T));const g=v(i.auto),y=v(i.tuned);y>g*1.07&&(a=!1),l.push({B:u,autoUs:g,tunedUs:y,deltaPct:Number(((y-g)/g*100).toFixed(1)),runs:i})}finally{f.arena.destroy()}}return{pass:a,detail:{tuned:t,table:l}}}):{skip:!0,reason:"no shader-f16"},{slow:!0});
2
+ //# sourceMappingURL=autotune-CVn9SF1X.js.map
assets/autotune-CVn9SF1X.js.map ADDED
@@ -0,0 +1 @@
 
 
1
+ {"version":3,"file":"autotune-CVn9SF1X.js","sources":["../../src/debug/tests/autotune.js"],"sourcesContent":["// Routing autotune: measure-then-pin the routing decisions whose winners\r\n// flip between adapters (see engine/autotune.js header).\r\n//\r\n// autotune_policy (fast, ~1s dGPU / ~10s iGPU): run autotuneRouting on THIS\r\n// adapter with the production weights and report the chosen thresholds plus\r\n// the raw arm medians. pass = the thresholds come from their allowed sets —\r\n// the point of the test is the printed policy per adapter.\r\n//\r\n// autotune_gate (SLOW): interleaved A/B of decoder.js 'auto' vs the tuned\r\n// policy at B ∈ {1, 16, 64} — asserts tuned is never worse than 'auto'\r\n// beyond noise (7%) at any measured batch, and reports what it buys. On the\r\n// 5070 Ti the policy should resolve to the defaults and read ~0%.\r\nimport { registerTest } from '../registry.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { emittableIds } from '../../engine/shortlist.js';\r\nimport { loadTokenizer } from '../../engine/tokenizer.js';\r\nimport {\r\n autotuneRouting, measureAutotuneReference, tunedOptions, DEFAULT_ROUTING,\r\n} from '../../engine/autotune.js';\r\nimport { runEncoder } from '../../engine/encoder.js';\r\nimport { createDecodeState, encodeDecodeStep } from '../../engine/decoder.js';\r\nimport { EOS, VOCAB } from '../../engine/constants.js';\r\nimport { getDispatchStats, resetDispatchStats } from '../../engine/pipelines.js';\r\n\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\n\r\nfunction poolCounterReport(dispatch, poolStats) {\r\n const checks = {\r\n twoBuffersCreated: dispatch.uniformPoolBuffersCreated === 2,\r\n twoBuffersDestroyed: dispatch.uniformPoolBuffersDestroyed === 2,\r\n framesBalanced: dispatch.uniformPoolFramesBegun > 0\r\n && dispatch.uniformPoolFramesBegun === dispatch.uniformPoolFramesFlushed,\r\n zeroTransientUniforms: poolStats.decodeTransientUniforms === 0,\r\n generationsInvalidated: dispatch.uniformPoolGenerationInvalidations > 0,\r\n cacheReleased: dispatch.bindGroupCacheSize === 0,\r\n };\r\n return {\r\n pass: Object.values(checks).every(Boolean),\r\n checks,\r\n counters: {\r\n poolBuffers: [\r\n dispatch.uniformPoolBuffersCreated,\r\n dispatch.uniformPoolBuffersDestroyed,\r\n ],\r\n frames: [dispatch.uniformPoolFramesBegun, dispatch.uniformPoolFramesFlushed],\r\n decodeTransientUniforms: poolStats.decodeTransientUniforms,\r\n allUniformBuffers: dispatch.uniformBuffersCreated,\r\n generationInvalidations: dispatch.uniformPoolGenerationInvalidations,\r\n bindGroupsPurged: dispatch.uniformPoolCachePurges,\r\n bindGroupCacheSize: dispatch.bindGroupCacheSize,\r\n },\r\n };\r\n}\r\n\r\nasync function withProdWeights(ctx, fn) {\r\n // Mirror the production loader (app engine.js): the q8 lm_head ships the\r\n // emittable-ids shortlist, so routing verdicts are measured on the stack\r\n // the app actually runs. Full-vocab is ~4× heavier at every lm_head site —\r\n // wrong stack for the verdict, and enough sustained GPU load to push a\r\n // phone into WebKit's kill-and-reload zone.\r\n const tok = await loadTokenizer();\r\n const weights = await loadWeights(ctx.device, '/weights', {\r\n targetDtype: 'f16', lmHeadQ8: true, ffnWT: true, projWT: true,\r\n lmHeadIds: emittableIds(tok.idToToken),\r\n });\r\n try {\r\n return await fn(weights);\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n}\r\n\r\nregisterTest('autotune_policy', async (ctx) => {\r\n if (!ctx.hasF16) return { skip: true, reason: 'no shader-f16' };\r\n return withProdWeights(ctx, async (weights) => {\r\n const gctx = {\r\n device: ctx.device, dtype: 'f16', limits: ctx.limits,\r\n hasSubgroups: ctx.hasSubgroups, subgroupMinSize: ctx.subgroupMinSize,\r\n };\r\n const t0 = performance.now();\r\n const { tuned, timings } = await autotuneRouting(gctx, weights);\r\n const tuneMs = Number((performance.now() - t0).toFixed(0));\r\n const sane =\r\n [0, 4].includes(tuned.fuseLnMaxB) &&\r\n [16, 32].includes(tuned.lmHeadMinB) &&\r\n ['auto', 'off'].includes(tuned.lmHeadFuse) &&\r\n [32, 64, 128].includes(tuned.projTiledMinB) &&\r\n ['auto', 'off'].includes(tuned.decodeMega) &&\r\n ['on', 'off'].includes(tuned.sg);\r\n const isDefault = JSON.stringify(tuned) === JSON.stringify(DEFAULT_ROUTING);\r\n return { pass: sane, detail: { tuned, isDefault, tuneMs, timings } };\r\n });\r\n});\r\n\r\n// Force the production WebKit parameter path even on an immediate-capable\r\n// desktop adapter. This catches drift between routing probes and translateBatch\r\n// without needing an iPhone for every autotune change.\r\nregisterTest('autotune_pool_policy', async (ctx) => {\r\n if (!ctx.hasF16) return { skip: true, reason: 'no shader-f16' };\r\n return withProdWeights(ctx, async (weights) => {\r\n const gctx = {\r\n device: ctx.device, dtype: 'f16', limits: ctx.limits,\r\n hasSubgroups: ctx.hasSubgroups, subgroupMinSize: ctx.subgroupMinSize,\r\n };\r\n resetDispatchStats(ctx.device, { clearCache: true });\r\n const t0 = performance.now();\r\n const { tuned, timings, partial, poolStats } = await autotuneRouting(gctx, weights, {\r\n immediates: 'off', uniformPool: true,\r\n });\r\n const tuneMs = Number((performance.now() - t0).toFixed(0));\r\n const fullCounters = poolCounterReport(getDispatchStats(ctx.device), poolStats);\r\n\r\n // The cache-hit canary owns a separate session. Exercise it explicitly so\r\n // both cleanup sites stay covered rather than only the full routing tune.\r\n resetDispatchStats(ctx.device, { clearCache: true });\r\n const reference = await measureAutotuneReference(gctx, weights, {\r\n immediates: 'off', uniformPool: true,\r\n });\r\n const referenceCounters = poolCounterReport(\r\n getDispatchStats(ctx.device), reference.poolStats,\r\n );\r\n const countersPass = fullCounters.pass && referenceCounters.pass;\r\n const sane =\r\n [0, 4].includes(tuned.fuseLnMaxB) &&\r\n [16, 32].includes(tuned.lmHeadMinB) &&\r\n ['auto', 'off'].includes(tuned.lmHeadFuse) &&\r\n [32, 64, 128].includes(tuned.projTiledMinB) &&\r\n ['auto', 'off'].includes(tuned.decodeMega) &&\r\n ['on', 'off'].includes(tuned.sg);\r\n return {\r\n pass: sane && !partial && countersPass,\r\n detail: {\r\n tuned, tuneMs, partial: partial ?? null, countersPass,\r\n counters: { full: fullCounters, reference: referenceCounters },\r\n timings,\r\n },\r\n };\r\n });\r\n});\r\n\r\n// Same synthetic-batch step timing as autotuneRouting, reused for the gate's\r\n// independent A/B (fresh state per arm, grouped submits of 8).\r\nfunction syntheticBatch(B, S) {\r\n const ids = new Uint32Array(B * S);\r\n let x = 0x2545f491;\r\n for (let i = 0; i < ids.length; i++) {\r\n x = (Math.imul(x, 1664525) + 1013904223) >>> 0;\r\n ids[i] = 100 + (x % (VOCAB - 200));\r\n }\r\n for (let b = 0; b < B; b++) ids[b * S + S - 1] = EOS;\r\n return { ids, lens: new Uint32Array(B).fill(S), B, S };\r\n}\r\n\r\nasync function timeArm(ctx, weights, encRun, B, steps, opts) {\r\n const { device } = ctx;\r\n const state = createDecodeState(ctx, weights, { B, S: encRun.S, maxSteps: steps, ...opts });\r\n try {\r\n const t0 = performance.now();\r\n for (let g = 0; g < steps; g += 8) {\r\n const tEnd = Math.min(g + 8, steps);\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n const scratch = [];\r\n for (let t = g; t < tEnd; t++) {\r\n scratch.push(...encodeDecodeStep(ctx, weights, encRun, state, t, pass).scratch);\r\n }\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n for (const b of scratch) b.destroy();\r\n }\r\n await device.queue.onSubmittedWorkDone();\r\n return Number((((performance.now() - t0) * 1000) / steps).toFixed(1));\r\n } finally {\r\n state.destroy();\r\n }\r\n}\r\n\r\nregisterTest(\r\n 'autotune_gate',\r\n async (ctx) => {\r\n if (!ctx.hasF16) return { skip: true, reason: 'no shader-f16' };\r\n return withProdWeights(ctx, async (weights) => {\r\n const gctx = {\r\n device: ctx.device, dtype: 'f16', limits: ctx.limits,\r\n hasSubgroups: ctx.hasSubgroups, subgroupMinSize: ctx.subgroupMinSize,\r\n };\r\n const { tuned } = await autotuneRouting(gctx, weights);\r\n\r\n const BATCHES = [1, 16, 64];\r\n const ROUNDS = 5;\r\n const STEPS = 24;\r\n const S = 96;\r\n const table = [];\r\n let pass = true;\r\n for (const B of BATCHES) {\r\n const batch = syntheticBatch(B, S);\r\n const encRun = await runEncoder(gctx, weights, batch);\r\n await gctx.device.queue.onSubmittedWorkDone();\r\n try {\r\n const arms = { auto: {}, tuned: tunedOptions(tuned, B) };\r\n for (const opts of Object.values(arms)) await timeArm(gctx, weights, encRun, B, STEPS, opts);\r\n const runs = { auto: [], tuned: [] };\r\n for (let r = 0; r < ROUNDS; r++) {\r\n for (const [name, opts] of Object.entries(arms)) {\r\n runs[name].push(await timeArm(gctx, weights, encRun, B, STEPS, opts));\r\n }\r\n }\r\n const autoUs = median(runs.auto);\r\n const tunedUs = median(runs.tuned);\r\n if (tunedUs > autoUs * 1.07) pass = false;\r\n table.push({\r\n B, autoUs, tunedUs,\r\n deltaPct: Number((((tunedUs - autoUs) / autoUs) * 100).toFixed(1)),\r\n runs,\r\n });\r\n } finally {\r\n encRun.arena.destroy();\r\n }\r\n }\r\n return { pass, detail: { tuned, table } };\r\n });\r\n },\r\n { slow: true },\r\n);\r\n"],"names":["median","xs","s","a","b","m","poolCounterReport","dispatch","poolStats","checks","withProdWeights","ctx","fn","tok","loadTokenizer","weights","loadWeights","emittableIds","registerTest","gctx","t0","tuned","timings","autotuneRouting","tuneMs","sane","isDefault","DEFAULT_ROUTING","resetDispatchStats","partial","fullCounters","getDispatchStats","reference","measureAutotuneReference","referenceCounters","countersPass","syntheticBatch","B","S","ids","x","i","VOCAB","EOS","timeArm","encRun","steps","opts","device","state","createDecodeState","g","tEnd","encoder","pass","scratch","t","encodeDecodeStep","BATCHES","ROUNDS","STEPS","table","batch","runEncoder","arms","tunedOptions","runs","r","name","autoUs","tunedUs"],"mappings":"krBAwBA,MAAMA,EAAUC,GAAO,CACrB,MAAMC,EAAI,CAAC,GAAGD,CAAE,EAAE,KAAK,CAACE,EAAGC,IAAMD,EAAIC,CAAC,EAChCC,EAAIH,EAAE,QAAU,EACtB,OAAOA,EAAE,OAAS,EAAIA,EAAEG,CAAC,GAAKH,EAAEG,EAAI,CAAC,EAAIH,EAAEG,CAAC,GAAK,CACnD,EAEA,SAASC,EAAkBC,EAAUC,EAAW,CAC9C,MAAMC,EAAS,CACb,kBAAmBF,EAAS,4BAA8B,EAC1D,oBAAqBA,EAAS,8BAAgC,EAC9D,eAAgBA,EAAS,uBAAyB,GAC7CA,EAAS,yBAA2BA,EAAS,yBAClD,sBAAuBC,EAAU,0BAA4B,EAC7D,uBAAwBD,EAAS,mCAAqC,EACtE,cAAeA,EAAS,qBAAuB,CACnD,EACE,MAAO,CACL,KAAM,OAAO,OAAOE,CAAM,EAAE,MAAM,OAAO,EACzC,OAAAA,EACA,SAAU,CACR,YAAa,CACXF,EAAS,0BACTA,EAAS,2BACjB,EACM,OAAQ,CAACA,EAAS,uBAAwBA,EAAS,wBAAwB,EAC3E,wBAAyBC,EAAU,wBACnC,kBAAmBD,EAAS,sBAC5B,wBAAyBA,EAAS,mCAClC,iBAAkBA,EAAS,uBAC3B,mBAAoBA,EAAS,kBACnC,CACA,CACA,CAEA,eAAeG,EAAgBC,EAAKC,EAAI,CAMtC,MAAMC,EAAM,MAAMC,IACZC,EAAU,MAAMC,EAAYL,EAAI,OAAQ,WAAY,CACxD,YAAa,MAAO,SAAU,GAAM,MAAO,GAAM,OAAQ,GACzD,UAAWM,EAAaJ,EAAI,SAAS,CACzC,CAAG,EACD,GAAI,CACF,OAAO,MAAMD,EAAGG,CAAO,CACzB,QAAC,CACCA,EAAQ,OAAO,SACjB,CACF,CAEAG,EAAa,kBAAmB,MAAOP,GAChCA,EAAI,OACFD,EAAgBC,EAAK,MAAOI,GAAY,CAC7C,MAAMI,EAAO,CACX,OAAQR,EAAI,OAAQ,MAAO,MAAO,OAAQA,EAAI,OAC9C,aAAcA,EAAI,aAAc,gBAAiBA,EAAI,eAC3D,EACUS,EAAK,YAAY,MACjB,CAAE,MAAAC,EAAO,QAAAC,CAAO,EAAK,MAAMC,EAAgBJ,EAAMJ,CAAO,EACxDS,EAAS,QAAQ,YAAY,IAAG,EAAKJ,GAAI,QAAQ,CAAC,CAAC,EACnDK,EACJ,CAAC,EAAG,CAAC,EAAE,SAASJ,EAAM,UAAU,GAChC,CAAC,GAAI,EAAE,EAAE,SAASA,EAAM,UAAU,GAClC,CAAC,OAAQ,KAAK,EAAE,SAASA,EAAM,UAAU,GACzC,CAAC,GAAI,GAAI,GAAG,EAAE,SAASA,EAAM,aAAa,GAC1C,CAAC,OAAQ,KAAK,EAAE,SAASA,EAAM,UAAU,GACzC,CAAC,KAAM,KAAK,EAAE,SAASA,EAAM,EAAE,EAC3BK,EAAY,KAAK,UAAUL,CAAK,IAAM,KAAK,UAAUM,CAAe,EAC1E,MAAO,CAAE,KAAMF,EAAM,OAAQ,CAAE,MAAAJ,EAAO,UAAAK,EAAW,OAAAF,EAAQ,QAAAF,CAAO,EAClE,CAAC,EAlBuB,CAAE,KAAM,GAAM,OAAQ,gBAmB/C,EAKDJ,EAAa,uBAAwB,MAAOP,GACrCA,EAAI,OACFD,EAAgBC,EAAK,MAAOI,GAAY,CAC7C,MAAMI,EAAO,CACX,OAAQR,EAAI,OAAQ,MAAO,MAAO,OAAQA,EAAI,OAC9C,aAAcA,EAAI,aAAc,gBAAiBA,EAAI,eAC3D,EACIiB,EAAmBjB,EAAI,OAAQ,CAAE,WAAY,EAAI,CAAE,EACnD,MAAMS,EAAK,YAAY,MACjB,CAAE,MAAAC,EAAO,QAAAC,EAAS,QAAAO,EAAS,UAAArB,CAAS,EAAK,MAAMe,EAAgBJ,EAAMJ,EAAS,CAClF,WAAY,MAAO,YAAa,EACtC,CAAK,EACKS,EAAS,QAAQ,YAAY,IAAG,EAAKJ,GAAI,QAAQ,CAAC,CAAC,EACnDU,EAAexB,EAAkByB,EAAiBpB,EAAI,MAAM,EAAGH,CAAS,EAI9EoB,EAAmBjB,EAAI,OAAQ,CAAE,WAAY,EAAI,CAAE,EACnD,MAAMqB,EAAY,MAAMC,EAAyBd,EAAMJ,EAAS,CAC9D,WAAY,MAAO,YAAa,EACtC,CAAK,EACKmB,EAAoB5B,EACxByB,EAAiBpB,EAAI,MAAM,EAAGqB,EAAU,SAC9C,EACUG,EAAeL,EAAa,MAAQI,EAAkB,KAQ5D,MAAO,CACL,KAPA,CAAC,EAAG,CAAC,EAAE,SAASb,EAAM,UAAU,GAChC,CAAC,GAAI,EAAE,EAAE,SAASA,EAAM,UAAU,GAClC,CAAC,OAAQ,KAAK,EAAE,SAASA,EAAM,UAAU,GACzC,CAAC,GAAI,GAAI,GAAG,EAAE,SAASA,EAAM,aAAa,GAC1C,CAAC,OAAQ,KAAK,EAAE,SAASA,EAAM,UAAU,GACzC,CAAC,KAAM,KAAK,EAAE,SAASA,EAAM,EAAE,GAEjB,CAACQ,GAAWM,EAC1B,OAAQ,CACN,MAAAd,EAAO,OAAAG,EAAQ,QAASK,GAAW,KAAM,aAAAM,EACzC,SAAU,CAAE,KAAML,EAAc,UAAWI,CAAiB,EAC5D,QAAAZ,CACR,CACA,CACE,CAAC,EAvCuB,CAAE,KAAM,GAAM,OAAQ,gBAwC/C,EAID,SAASc,EAAeC,EAAGC,EAAG,CAC5B,MAAMC,EAAM,IAAI,YAAYF,EAAIC,CAAC,EACjC,IAAIE,EAAI,UACR,QAASC,EAAI,EAAGA,EAAIF,EAAI,OAAQE,IAC9BD,EAAK,KAAK,KAAKA,EAAG,OAAO,EAAI,aAAgB,EAC7CD,EAAIE,CAAC,EAAI,IAAOD,GAAKE,EAAQ,KAE/B,QAAStC,EAAI,EAAGA,EAAIiC,EAAGjC,IAAKmC,EAAInC,EAAIkC,EAAIA,EAAI,CAAC,EAAIK,EACjD,MAAO,CAAE,IAAAJ,EAAK,KAAM,IAAI,YAAYF,CAAC,EAAE,KAAKC,CAAC,EAAG,EAAAD,EAAG,EAAAC,CAAC,CACtD,CAEA,eAAeM,EAAQjC,EAAKI,EAAS8B,EAAQR,EAAGS,EAAOC,EAAM,CAC3D,KAAM,CAAE,OAAAC,CAAM,EAAKrC,EACbsC,EAAQC,EAAkBvC,EAAKI,EAAS,CAAE,EAAAsB,EAAG,EAAGQ,EAAO,EAAG,SAAUC,EAAO,GAAGC,CAAI,CAAE,EAC1F,GAAI,CACF,MAAM3B,EAAK,YAAY,MACvB,QAAS+B,EAAI,EAAGA,EAAIL,EAAOK,GAAK,EAAG,CACjC,MAAMC,EAAO,KAAK,IAAID,EAAI,EAAGL,CAAK,EAC5BO,EAAUL,EAAO,uBACjBM,EAAOD,EAAQ,mBACfE,EAAU,CAAA,EAChB,QAASC,EAAIL,EAAGK,EAAIJ,EAAMI,IACxBD,EAAQ,KAAK,GAAGE,EAAiB9C,EAAKI,EAAS8B,EAAQI,EAAOO,EAAGF,CAAI,EAAE,OAAO,EAEhFA,EAAK,IAAG,EACRN,EAAO,MAAM,OAAO,CAACK,EAAQ,OAAM,CAAE,CAAC,EACtC,UAAWjD,KAAKmD,EAASnD,EAAE,QAAO,CACpC,CACA,aAAM4C,EAAO,MAAM,sBACZ,SAAU,YAAY,IAAG,EAAK5B,GAAM,IAAQ0B,GAAO,QAAQ,CAAC,CAAC,CACtE,QAAC,CACCG,EAAM,QAAO,CACf,CACF,CAEA/B,EACE,gBACA,MAAOP,GACAA,EAAI,OACFD,EAAgBC,EAAK,MAAOI,GAAY,CAC7C,MAAMI,EAAO,CACb,OAAQR,EAAI,OAAQ,MAAO,MAAO,OAAQA,EAAI,OAC9C,aAAcA,EAAI,aAAc,gBAAiBA,EAAI,eAC3D,EACY,CAAE,MAAAU,CAAK,EAAK,MAAME,EAAgBJ,EAAMJ,CAAO,EAE/C2C,EAAU,CAAC,EAAG,GAAI,EAAE,EACpBC,EAAS,EACTC,EAAQ,GACRtB,EAAI,GACJuB,EAAQ,CAAA,EACd,IAAIP,EAAO,GACX,UAAWjB,KAAKqB,EAAS,CACvB,MAAMI,EAAQ1B,EAAeC,EAAGC,CAAC,EAC3BO,EAAS,MAAMkB,EAAW5C,EAAMJ,EAAS+C,CAAK,EACpD,MAAM3C,EAAK,OAAO,MAAM,oBAAmB,EAC3C,GAAI,CACF,MAAM6C,EAAO,CAAE,KAAM,CAAA,EAAI,MAAOC,EAAa5C,EAAOgB,CAAC,GACrD,UAAWU,KAAQ,OAAO,OAAOiB,CAAI,EAAG,MAAMpB,EAAQzB,EAAMJ,EAAS8B,EAAQR,EAAGuB,EAAOb,CAAI,EAC3F,MAAMmB,EAAO,CAAE,KAAM,CAAA,EAAI,MAAO,CAAA,CAAE,EAClC,QAASC,EAAI,EAAGA,EAAIR,EAAQQ,IAC1B,SAAW,CAACC,EAAMrB,CAAI,IAAK,OAAO,QAAQiB,CAAI,EAC5CE,EAAKE,CAAI,EAAE,KAAK,MAAMxB,EAAQzB,EAAMJ,EAAS8B,EAAQR,EAAGuB,EAAOb,CAAI,CAAC,EAGxE,MAAMsB,EAASrE,EAAOkE,EAAK,IAAI,EACzBI,EAAUtE,EAAOkE,EAAK,KAAK,EAC7BI,EAAUD,EAAS,OAAMf,EAAO,IACpCO,EAAM,KAAK,CACT,EAAAxB,EAAG,OAAAgC,EAAQ,QAAAC,EACX,SAAU,SAAUA,EAAUD,GAAUA,EAAU,KAAK,QAAQ,CAAC,CAAC,EACjE,KAAAH,CACZ,CAAW,CACH,QAAC,CACCrB,EAAO,MAAM,SACf,CACF,CACA,MAAO,CAAE,KAAAS,EAAM,OAAQ,CAAE,MAAAjC,EAAO,MAAAwC,CAAK,CAAE,CACzC,CAAC,EAxCuB,CAAE,KAAM,GAAM,OAAQ,iBA0ChD,CAAE,KAAM,EAAI,CACd"}
assets/autotune-CgosBVvF.js DELETED
@@ -1,2 +0,0 @@
1
- import{r as S}from"./debug-C_LNzFrK.js";import{l as D}from"./weights-D8qtuKag.js";import{e as U}from"./shortlist-C151mR5c.js";import{l as z}from"./tokenizer-Ex1u7wXD.js";import{autotuneRouting as h,DEFAULT_ROUTING as O,measureAutotuneReference as k,tunedOptions as A}from"./autotune-DywP5DSc.js";import{r as N}from"./encoder-I9sHImnR.js";import{c as E,e as G}from"./decoder-CI9o-EVx.js";import{V as H,e as I}from"./constants-C8VbFpic.js";import{A as B,l as P}from"./pipelines-DJ7cc1m-.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./shapes-BCQ9D81L.js";import"./f16-wKKZr58e.js";import"./device-BotbBNoe.js";const v=e=>{const n=[...e].sort((t,o)=>t-o),r=n.length>>1;return n.length%2?n[r]:(n[r-1]+n[r])/2};function M(e,n){const r={twoBuffersCreated:e.uniformPoolBuffersCreated===2,twoBuffersDestroyed:e.uniformPoolBuffersDestroyed===2,framesBalanced:e.uniformPoolFramesBegun>0&&e.uniformPoolFramesBegun===e.uniformPoolFramesFlushed,zeroTransientUniforms:n.decodeTransientUniforms===0,generationsInvalidated:e.uniformPoolGenerationInvalidations>0,cacheReleased:e.bindGroupCacheSize===0};return{pass:Object.values(r).every(Boolean),checks:r,counters:{poolBuffers:[e.uniformPoolBuffersCreated,e.uniformPoolBuffersDestroyed],frames:[e.uniformPoolFramesBegun,e.uniformPoolFramesFlushed],decodeTransientUniforms:n.decodeTransientUniforms,allUniformBuffers:e.uniformBuffersCreated,generationInvalidations:e.uniformPoolGenerationInvalidations,bindGroupsPurged:e.uniformPoolCachePurges,bindGroupCacheSize:e.bindGroupCacheSize}}}async function w(e,n){const r=await z(),t=await D(e.device,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0,projWT:!0,lmHeadIds:U(r.idToToken)});try{return await n(t)}finally{t.buffer.destroy()}}S("autotune_policy",async e=>e.hasF16?w(e,async n=>{const r={device:e.device,dtype:"f16",limits:e.limits,hasSubgroups:e.hasSubgroups,subgroupMinSize:e.subgroupMinSize},t=performance.now(),{tuned:o,timings:d}=await h(r,n),s=Number((performance.now()-t).toFixed(0)),c=[0,4].includes(o.fuseLnMaxB)&&[16,32].includes(o.lmHeadMinB)&&["auto","off"].includes(o.lmHeadFuse)&&[32,64,128].includes(o.projTiledMinB)&&["auto","off"].includes(o.decodeMega)&&["on","off"].includes(o.sg),l=JSON.stringify(o)===JSON.stringify(O);return{pass:c,detail:{tuned:o,isDefault:l,tuneMs:s,timings:d}}}):{skip:!0,reason:"no shader-f16"});S("autotune_pool_policy",async e=>e.hasF16?w(e,async n=>{const r={device:e.device,dtype:"f16",limits:e.limits,hasSubgroups:e.hasSubgroups,subgroupMinSize:e.subgroupMinSize};B(e.device,{clearCache:!0});const t=performance.now(),{tuned:o,timings:d,partial:s,poolStats:c}=await h(r,n,{immediates:"off",uniformPool:!0}),l=Number((performance.now()-t).toFixed(0)),a=M(P(e.device),c);B(e.device,{clearCache:!0});const u=await k(r,n,{immediates:"off",uniformPool:!0}),m=M(P(e.device),u.poolStats),f=a.pass&&m.pass;return{pass:[0,4].includes(o.fuseLnMaxB)&&[16,32].includes(o.lmHeadMinB)&&["auto","off"].includes(o.lmHeadFuse)&&[32,64,128].includes(o.projTiledMinB)&&["auto","off"].includes(o.decodeMega)&&["on","off"].includes(o.sg)&&!s&&f,detail:{tuned:o,tuneMs:l,partial:s??null,countersPass:f,counters:{full:a,reference:m},timings:d}}}):{skip:!0,reason:"no shader-f16"});function j(e,n){const r=new Uint32Array(e*n);let t=625341585;for(let o=0;o<r.length;o++)t=Math.imul(t,1664525)+1013904223>>>0,r[o]=100+t%(H-200);for(let o=0;o<e;o++)r[o*n+n-1]=I;return{ids:r,lens:new Uint32Array(e).fill(n),B:e,S:n}}async function C(e,n,r,t,o,d){const{device:s}=e,c=E(e,n,{B:t,S:r.S,maxSteps:o,...d});try{const l=performance.now();for(let a=0;a<o;a+=8){const u=Math.min(a+8,o),m=s.createCommandEncoder(),f=m.beginComputePass(),p=[];for(let i=a;i<u;i++)p.push(...G(e,n,r,c,i,f).scratch);f.end(),s.queue.submit([m.finish()]);for(const i of p)i.destroy()}return await s.queue.onSubmittedWorkDone(),Number(((performance.now()-l)*1e3/o).toFixed(1))}finally{c.destroy()}}S("autotune_gate",async e=>e.hasF16?w(e,async n=>{const r={device:e.device,dtype:"f16",limits:e.limits,hasSubgroups:e.hasSubgroups,subgroupMinSize:e.subgroupMinSize},{tuned:t}=await h(r,n),o=[1,16,64],d=5,s=24,c=96,l=[];let a=!0;for(const u of o){const m=j(u,c),f=await N(r,n,m);await r.device.queue.onSubmittedWorkDone();try{const p={auto:{},tuned:A(t,u)};for(const b of Object.values(p))await C(r,n,f,u,s,b);const i={auto:[],tuned:[]};for(let b=0;b<d;b++)for(const[F,T]of Object.entries(p))i[F].push(await C(r,n,f,u,s,T));const g=v(i.auto),y=v(i.tuned);y>g*1.07&&(a=!1),l.push({B:u,autoUs:g,tunedUs:y,deltaPct:Number(((y-g)/g*100).toFixed(1)),runs:i})}finally{f.arena.destroy()}}return{pass:a,detail:{tuned:t,table:l}}}):{skip:!0,reason:"no shader-f16"},{slow:!0});
2
- //# sourceMappingURL=autotune-CgosBVvF.js.map
 
 
 
assets/autotune-CgosBVvF.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"autotune-CgosBVvF.js","sources":["../../src/debug/tests/autotune.js"],"sourcesContent":["// Routing autotune: measure-then-pin the routing decisions whose winners\r\n// flip between adapters (see engine/autotune.js header).\r\n//\r\n// autotune_policy (fast, ~1s dGPU / ~10s iGPU): run autotuneRouting on THIS\r\n// adapter with the production weights and report the chosen thresholds plus\r\n// the raw arm medians. pass = the thresholds come from their allowed sets —\r\n// the point of the test is the printed policy per adapter.\r\n//\r\n// autotune_gate (SLOW): interleaved A/B of decoder.js 'auto' vs the tuned\r\n// policy at B ∈ {1, 16, 64} — asserts tuned is never worse than 'auto'\r\n// beyond noise (7%) at any measured batch, and reports what it buys. On the\r\n// 5070 Ti the policy should resolve to the defaults and read ~0%.\r\nimport { registerTest } from '../registry.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { emittableIds } from '../../engine/shortlist.js';\r\nimport { loadTokenizer } from '../../engine/tokenizer.js';\r\nimport {\n autotuneRouting, measureAutotuneReference, tunedOptions, DEFAULT_ROUTING,\n} from '../../engine/autotune.js';\nimport { runEncoder } from '../../engine/encoder.js';\r\nimport { createDecodeState, encodeDecodeStep } from '../../engine/decoder.js';\nimport { EOS, VOCAB } from '../../engine/constants.js';\nimport { getDispatchStats, resetDispatchStats } from '../../engine/pipelines.js';\n\r\nconst median = (xs) => {\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\n\nfunction poolCounterReport(dispatch, poolStats) {\n const checks = {\n twoBuffersCreated: dispatch.uniformPoolBuffersCreated === 2,\n twoBuffersDestroyed: dispatch.uniformPoolBuffersDestroyed === 2,\n framesBalanced: dispatch.uniformPoolFramesBegun > 0\n && dispatch.uniformPoolFramesBegun === dispatch.uniformPoolFramesFlushed,\n zeroTransientUniforms: poolStats.decodeTransientUniforms === 0,\n generationsInvalidated: dispatch.uniformPoolGenerationInvalidations > 0,\n cacheReleased: dispatch.bindGroupCacheSize === 0,\n };\n return {\n pass: Object.values(checks).every(Boolean),\n checks,\n counters: {\n poolBuffers: [\n dispatch.uniformPoolBuffersCreated,\n dispatch.uniformPoolBuffersDestroyed,\n ],\n frames: [dispatch.uniformPoolFramesBegun, dispatch.uniformPoolFramesFlushed],\n decodeTransientUniforms: poolStats.decodeTransientUniforms,\n allUniformBuffers: dispatch.uniformBuffersCreated,\n generationInvalidations: dispatch.uniformPoolGenerationInvalidations,\n bindGroupsPurged: dispatch.uniformPoolCachePurges,\n bindGroupCacheSize: dispatch.bindGroupCacheSize,\n },\n };\n}\n\r\nasync function withProdWeights(ctx, fn) {\r\n // Mirror the production loader (app engine.js): the q8 lm_head ships the\r\n // emittable-ids shortlist, so routing verdicts are measured on the stack\r\n // the app actually runs. Full-vocab is ~4× heavier at every lm_head site —\r\n // wrong stack for the verdict, and enough sustained GPU load to push a\r\n // phone into WebKit's kill-and-reload zone.\r\n const tok = await loadTokenizer();\r\n const weights = await loadWeights(ctx.device, '/weights', {\r\n targetDtype: 'f16', lmHeadQ8: true, ffnWT: true, projWT: true,\r\n lmHeadIds: emittableIds(tok.idToToken),\r\n });\r\n try {\r\n return await fn(weights);\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n}\r\n\r\nregisterTest('autotune_policy', async (ctx) => {\r\n if (!ctx.hasF16) return { skip: true, reason: 'no shader-f16' };\r\n return withProdWeights(ctx, async (weights) => {\r\n const gctx = {\r\n device: ctx.device, dtype: 'f16', limits: ctx.limits,\r\n hasSubgroups: ctx.hasSubgroups, subgroupMinSize: ctx.subgroupMinSize,\r\n };\r\n const t0 = performance.now();\r\n const { tuned, timings } = await autotuneRouting(gctx, weights);\r\n const tuneMs = Number((performance.now() - t0).toFixed(0));\r\n const sane =\r\n [0, 4].includes(tuned.fuseLnMaxB) &&\r\n [16, 32].includes(tuned.lmHeadMinB) &&\r\n ['auto', 'off'].includes(tuned.lmHeadFuse) &&\r\n [32, 64, 128].includes(tuned.projTiledMinB) &&\r\n ['auto', 'off'].includes(tuned.decodeMega) &&\r\n ['on', 'off'].includes(tuned.sg);\r\n const isDefault = JSON.stringify(tuned) === JSON.stringify(DEFAULT_ROUTING);\r\n return { pass: sane, detail: { tuned, isDefault, tuneMs, timings } };\r\n });\r\n});\r\n\r\n// Force the production WebKit parameter path even on an immediate-capable\r\n// desktop adapter. This catches drift between routing probes and translateBatch\r\n// without needing an iPhone for every autotune change.\r\nregisterTest('autotune_pool_policy', async (ctx) => {\r\n if (!ctx.hasF16) return { skip: true, reason: 'no shader-f16' };\r\n return withProdWeights(ctx, async (weights) => {\r\n const gctx = {\n device: ctx.device, dtype: 'f16', limits: ctx.limits,\n hasSubgroups: ctx.hasSubgroups, subgroupMinSize: ctx.subgroupMinSize,\n };\n resetDispatchStats(ctx.device, { clearCache: true });\n const t0 = performance.now();\n const { tuned, timings, partial, poolStats } = await autotuneRouting(gctx, weights, {\n immediates: 'off', uniformPool: true,\n });\n const tuneMs = Number((performance.now() - t0).toFixed(0));\n const fullCounters = poolCounterReport(getDispatchStats(ctx.device), poolStats);\n\n // The cache-hit canary owns a separate session. Exercise it explicitly so\n // both cleanup sites stay covered rather than only the full routing tune.\n resetDispatchStats(ctx.device, { clearCache: true });\n const reference = await measureAutotuneReference(gctx, weights, {\n immediates: 'off', uniformPool: true,\n });\n const referenceCounters = poolCounterReport(\n getDispatchStats(ctx.device), reference.poolStats,\n );\n const countersPass = fullCounters.pass && referenceCounters.pass;\n const sane =\n [0, 4].includes(tuned.fuseLnMaxB) &&\r\n [16, 32].includes(tuned.lmHeadMinB) &&\r\n ['auto', 'off'].includes(tuned.lmHeadFuse) &&\r\n [32, 64, 128].includes(tuned.projTiledMinB) &&\r\n ['auto', 'off'].includes(tuned.decodeMega) &&\r\n ['on', 'off'].includes(tuned.sg);\r\n return {\n pass: sane && !partial && countersPass,\n detail: {\n tuned, tuneMs, partial: partial ?? null, countersPass,\n counters: { full: fullCounters, reference: referenceCounters },\n timings,\n },\n };\n });\r\n});\r\n\r\n// Same synthetic-batch step timing as autotuneRouting, reused for the gate's\r\n// independent A/B (fresh state per arm, grouped submits of 8).\r\nfunction syntheticBatch(B, S) {\r\n const ids = new Uint32Array(B * S);\r\n let x = 0x2545f491;\r\n for (let i = 0; i < ids.length; i++) {\r\n x = (Math.imul(x, 1664525) + 1013904223) >>> 0;\r\n ids[i] = 100 + (x % (VOCAB - 200));\r\n }\r\n for (let b = 0; b < B; b++) ids[b * S + S - 1] = EOS;\r\n return { ids, lens: new Uint32Array(B).fill(S), B, S };\r\n}\r\n\r\nasync function timeArm(ctx, weights, encRun, B, steps, opts) {\r\n const { device } = ctx;\r\n const state = createDecodeState(ctx, weights, { B, S: encRun.S, maxSteps: steps, ...opts });\r\n try {\r\n const t0 = performance.now();\r\n for (let g = 0; g < steps; g += 8) {\r\n const tEnd = Math.min(g + 8, steps);\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n const scratch = [];\r\n for (let t = g; t < tEnd; t++) {\r\n scratch.push(...encodeDecodeStep(ctx, weights, encRun, state, t, pass).scratch);\r\n }\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n for (const b of scratch) b.destroy();\r\n }\r\n await device.queue.onSubmittedWorkDone();\r\n return Number((((performance.now() - t0) * 1000) / steps).toFixed(1));\r\n } finally {\r\n state.destroy();\r\n }\r\n}\r\n\r\nregisterTest(\r\n 'autotune_gate',\r\n async (ctx) => {\r\n if (!ctx.hasF16) return { skip: true, reason: 'no shader-f16' };\r\n return withProdWeights(ctx, async (weights) => {\r\n const gctx = {\r\n device: ctx.device, dtype: 'f16', limits: ctx.limits,\r\n hasSubgroups: ctx.hasSubgroups, subgroupMinSize: ctx.subgroupMinSize,\r\n };\r\n const { tuned } = await autotuneRouting(gctx, weights);\r\n\r\n const BATCHES = [1, 16, 64];\r\n const ROUNDS = 5;\r\n const STEPS = 24;\r\n const S = 96;\r\n const table = [];\r\n let pass = true;\r\n for (const B of BATCHES) {\r\n const batch = syntheticBatch(B, S);\r\n const encRun = await runEncoder(gctx, weights, batch);\r\n await gctx.device.queue.onSubmittedWorkDone();\r\n try {\r\n const arms = { auto: {}, tuned: tunedOptions(tuned, B) };\r\n for (const opts of Object.values(arms)) await timeArm(gctx, weights, encRun, B, STEPS, opts);\r\n const runs = { auto: [], tuned: [] };\r\n for (let r = 0; r < ROUNDS; r++) {\r\n for (const [name, opts] of Object.entries(arms)) {\r\n runs[name].push(await timeArm(gctx, weights, encRun, B, STEPS, opts));\r\n }\r\n }\r\n const autoUs = median(runs.auto);\r\n const tunedUs = median(runs.tuned);\r\n if (tunedUs > autoUs * 1.07) pass = false;\r\n table.push({\r\n B, autoUs, tunedUs,\r\n deltaPct: Number((((tunedUs - autoUs) / autoUs) * 100).toFixed(1)),\r\n runs,\r\n });\r\n } finally {\r\n encRun.arena.destroy();\r\n }\r\n }\r\n return { pass, detail: { tuned, table } };\r\n });\r\n },\r\n { slow: true },\r\n);\r\n"],"names":["median","xs","s","a","b","m","poolCounterReport","dispatch","poolStats","checks","withProdWeights","ctx","fn","tok","loadTokenizer","weights","loadWeights","emittableIds","registerTest","gctx","t0","tuned","timings","autotuneRouting","tuneMs","sane","isDefault","DEFAULT_ROUTING","resetDispatchStats","partial","fullCounters","getDispatchStats","reference","measureAutotuneReference","referenceCounters","countersPass","syntheticBatch","B","S","ids","x","i","VOCAB","EOS","timeArm","encRun","steps","opts","device","state","createDecodeState","g","tEnd","encoder","pass","scratch","t","encodeDecodeStep","BATCHES","ROUNDS","STEPS","table","batch","runEncoder","arms","tunedOptions","runs","r","name","autoUs","tunedUs"],"mappings":"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"}
 
 
assets/autotune-DywP5DSc.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"autotune-DywP5DSc.js","sources":["../../src/engine/autotune.js"],"sourcesContent":["// Adapter-aware routing autotune.\r\n//\r\n// The 'auto' thresholds in decoder.js encode sweeps from ONE device (RTX\r\n// 5070 Ti laptop). Re-running the sweep suite on the Intel xe-lpg iGPU\r\n// (2026-07-06) flipped four of them outright: fuse_ln LOSES 51% at b1 (its\r\n// dGPU home turf), all-5 tiled projections WIN from B≥32 (the dGPU starves\r\n// below 128), the fused lm_head argmax loses ~5%, and the lm_head\r\n// gemv→tiled crossover moves 16 → 32. Apple/Mali/Adreno have never been\r\n// measured at all. Rather than grow a vendor table, this measures the four\r\n// decisions on THE device at hand (~1s dGPU / ~8s iGPU, once per load) and\r\n// returns a threshold table; callers resolve it per batch with\r\n// tunedOptions(tuned, B) and pass the result through translateBatch.\r\n//\r\n// The tuned space is VALUE-PRESERVING routing only — every arm is a kernel/\r\n// layout choice already quality-gated on its own (proj_sweep divergence\r\n// gate, fuse_ln_equiv, argmax_fuse_equiv, q8 goldens; near-tie argmax flips\r\n// between arms are the known, accepted f16 reality). ffn 'q8' is NOT in the\r\n// space: it fails the golden bar (27/30) no matter how fast it is.\r\n//\r\n// Ties keep the shipped default (a candidate must beat it by WIN_MARGIN),\r\n// so on the 5070 Ti the policy resolves to exactly today's behavior.\r\n\r\nimport { runEncoder } from './encoder.js';\r\nimport { createDecodeState, encodeDecodeStep } from './decoder.js';\r\nimport {\n createUniformParamPool, getDispatchStats, shouldUseUniformParamPool,\n} from './pipelines.js';\nimport { EOS, VOCAB } from './constants.js';\r\n\r\nconst ALL5 = ['fc1', 'fc2', 'self_out', 'cross_q', 'cross_out'];\r\n\r\n// decoder.js 'auto' behavior, expressed as thresholds (see the consts there).\r\nexport const DEFAULT_ROUTING = Object.freeze({\r\n fuseLnMaxB: 4,\r\n lmHeadMinB: 16,\r\n lmHeadFuse: 'auto',\r\n projTiledMinB: 128,\r\n projTiledKinds: ['fc1', 'fc2'],\r\n // 'auto' = megakernel at B ≤ DECODE_MEGA_MAX_B; 'off' disables it. Won\r\n // −12–16% b1 e2e on the NVIDIA it was tuned on, but LOSES on Metal (Mac\r\n // mega_sweep 2026-07-06: +7% b1, and mega+fusedLn 'auto' is 3.1× off the\r\n // lean unfused path) — so it is a measured decision like the others.\r\n decodeMega: 'auto',\r\n // Subgroup reductions at the WT-GEMV + LN sites. Default OFF: a wash on\r\n // the NVIDIA reference (sg_sweep b8 −3.3%, e2e noise), but −12.7% b8 /\r\n // −7.4% b16 steady-state on M5 Max Metal (barriers are what a\r\n // one-workgroup-per-row kernel pays there) — measured per device below.\r\n sg: 'off',\r\n});\r\n\r\n// A candidate wins only if it beats the default by >5%. The defaults come\r\n// from 7-round × 50-step sweeps on the reference GPU; this quick 3-round ×\r\n// 24-step probe must not overturn them on noise (measured: ±4% b1 arm drift\r\n// on a busy dGPU flipped fuseLn between two back-to-back runs at a 2%\r\n// margin, while every real iGPU win measures ≥5.5%).\r\nconst WIN_MARGIN = 0.95;\r\n\r\n// Part of the app's autotune cache key (autotuneCacheKey): bump whenever\r\n// WGSL kernel code, the tuned space, or routing semantics change, so tables\r\n// measured against old kernels re-tune instead of steering new ones.\r\nexport const KERNEL_REV = 12;\n\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\n\r\nexport class ReductionSafetyError extends Error {\r\n constructor(message, verdicts) {\r\n super(message);\r\n this.name = 'ReductionSafetyError';\r\n this.code = 'WEBMT_NO_SAFE_REDUCTION';\r\n this.verdicts = verdicts;\r\n }\r\n}\r\n\r\n// Turn the two tri-state probes into one explicit safety policy. `false`\r\n// means a route was measured clean, `true` means it was measured broken,\r\n// and `null` means the probe itself could not produce a verdict. Performance\r\n// tuning is allowed to choose between routes only when BOTH are proven safe.\r\nexport function resolveReductionSafety({ treeBug, sgMismap, sgFeature }) {\r\n const valid = (v) => v === true || v === false || v === null;\r\n if (!valid(treeBug) || !valid(sgMismap)) {\r\n throw new Error(`invalid reduction verdicts: treeBug=${treeBug}, sgMismap=${sgMismap}`);\r\n }\r\n const treeSafe = treeBug === false;\r\n const sgSafe = !!sgFeature && sgMismap === false;\r\n if (treeSafe && sgSafe) {\r\n return { status: 'both-safe', retry: false, sgOk: true, forceSg: false };\r\n }\r\n if (treeSafe) {\r\n return { status: 'tree-safe', retry: false, sgOk: false, forceSg: false };\r\n }\r\n if (sgSafe) {\r\n return { status: 'subgroup-safe', retry: false, sgOk: true, forceSg: true };\r\n }\r\n const retry = treeBug === null || (!!sgFeature && sgMismap === null);\r\n return { status: retry ? 'unresolved' : 'unsafe', retry, sgOk: false, forceSg: false };\r\n}\r\n\r\n// Rotate rather than merely reverse: with three or more arms, each one gets\r\n// every position in the thermal ramp before the sequence repeats.\r\nexport function rotatedArmOrder(names, round) {\r\n if (!names.length) return [];\r\n const offset = ((round % names.length) + names.length) % names.length;\r\n return [...names.slice(offset), ...names.slice(0, offset)];\r\n}\r\n\r\nexport function pairedRatios(runs, alt, base = 'def') {\r\n const a = runs[alt];\r\n const b = runs[base];\r\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length || !a.length) {\r\n throw new Error(`pairedRatios: ${alt}/${base} need equal non-empty run arrays`);\r\n }\r\n return a.map((v, i) => v / b[i]);\r\n}\r\n\r\n// Three rounds are a screening pass. Only a strong, consistent >=10% win\r\n// settles early; a clean non-win keeps the shipped default; noisy or near-\r\n// threshold results ask for four more paired rounds. At seven rounds the\r\n// candidate needs both a >5% paired-median win and >=5 favorable pairs.\r\nexport function pairedPerfVerdict(runs, alt, base = 'def') {\r\n const ratios = pairedRatios(runs, alt, base);\r\n const med = median(ratios);\r\n const favorable = ratios.filter((r) => r < 1).length;\r\n if (ratios.length <= 3) {\r\n // A three-round early win must be unanimous. Two fast pairs plus one\r\n // loss is exactly the noisy pattern that flipped sg on the reference GPU.\r\n if (med <= 0.90 && favorable === ratios.length) return 'win';\r\n if (med >= 0.98 && Math.min(...ratios) >= 0.95) return 'keep';\r\n return 'more';\r\n }\r\n const need = Math.ceil(ratios.length * (2 / 3));\r\n return med < WIN_MARGIN && favorable >= need ? 'win' : 'keep';\r\n}\r\n\r\n// Performance-only subgroup routing changes reduction order and can flip a\r\n// near-tie token even when both routes are numerically valid. Demand stronger\r\n// and longer evidence than ordinary routing knobs: at least seven paired\r\n// rounds, >=10% median gain, and every round favorable.\r\nexport function pairedStableSgWin(runs, alt = 'sgOn', base = 'def') {\r\n const ratios = pairedRatios(runs, alt, base);\r\n if (ratios.length < 7) return false;\r\n const favorable = ratios.filter((ratio) => ratio < 1).length;\r\n return median(ratios) <= 0.90 && favorable === ratios.length;\r\n}\r\n\r\n// Deterministic filler tokens (LCG) — timing only depends on shapes, but\r\n// keep runs reproducible and inside the vocab (clear of the specials).\r\nfunction syntheticBatch(B, S) {\r\n const ids = new Uint32Array(B * S);\r\n let x = 0x9e3779b9;\r\n for (let i = 0; i < ids.length; i++) {\r\n x = (Math.imul(x, 1664525) + 1013904223) >>> 0;\r\n ids[i] = 100 + (x % (VOCAB - 200));\r\n }\r\n for (let b = 0; b < B; b++) ids[b * S + S - 1] = EOS;\r\n return { ids, lens: new Uint32Array(B).fill(S), B, S };\r\n}\r\n\r\n// One lazy parameter pool per canary/full-tune session. The session owns the\n// pool explicitly so cleanup stays in this module instead of hiding mutable\n// state on ctx (callers often pass a shallow ctx copy).\nfunction createAutotuneParamPoolSession(ctx, enabled) {\n let pool = null;\n let destroyed = false;\n let decodeTransientUniforms = 0;\n return {\n poolFor(state) {\n if (destroyed) throw new Error('autotune uniform-pool session is destroyed');\n if (!shouldUseUniformParamPool(enabled, state)) return null;\n pool ??= createUniformParamPool(ctx.device, { banks: 2 });\n return pool;\n },\n recordDecodeUniformDelta(delta) {\n decodeTransientUniforms += Math.max(0, delta);\n },\n invalidateBindings() {\n return pool?.invalidateBindings() ?? 0;\n },\n snapshot() {\n return { decodeTransientUniforms };\n },\n destroy() {\n if (destroyed) return;\n pool?.destroy();\n pool = null;\n destroyed = true;\n },\n };\n}\n\n// Wall-clock µs per decode step for one routing arm — same grouped\n// record/submit shape as translateBatch (GROUP_STEPS=8), fresh state per\n// call so KV growth is identical across arms.\nasync function timeArm(ctx, weights, encRun, B, steps, opts, paramPoolSession) {\n const { device } = ctx;\n const state = createDecodeState(ctx, weights, {\n B, S: encRun.S, maxSteps: steps, ...opts,\n });\n let uniformsBefore = null;\n let armDrained = false;\n try {\n // Match translateBatch's WebKit path while timing routing decisions. Queue\n // ordering makes a bank reusable after submit: the next writeBuffer is\n // ordered after that submit even though autotune has no readback to await.\n const paramPool = paramPoolSession.poolFor(state);\n if (paramPool) uniformsBefore = getDispatchStats(device).uniformBuffersCreated;\n const t0 = performance.now();\n for (let g = 0; g < steps; g += 8) {\n const tEnd = Math.min(g + 8, steps);\n const bank = (g / 8) % 2;\n let poolFrameActive = false;\n const scratch = [];\n try {\n if (paramPool) {\n paramPool.begin(bank);\n poolFrameActive = true;\n }\n const encoder = device.createCommandEncoder({ label: `autotune ${g}..${tEnd}` });\n const pass = encoder.beginComputePass();\n for (let t = g; t < tEnd; t++) {\n scratch.push(...encodeDecodeStep(ctx, weights, encRun, state, t, pass).scratch);\n }\r\n pass.end();\r\n if (paramPool) {\r\n paramPool.flush();\r\n poolFrameActive = false;\r\n }\r\n device.queue.submit([encoder.finish()]);\r\n if (paramPool) paramPool.release(bank);\r\n } catch (err) {\r\n if (poolFrameActive) paramPool.abort();\r\n throw err;\r\n } finally {\r\n for (const b of scratch) b.destroy();\r\n }\r\n }\n await device.queue.onSubmittedWorkDone();\n armDrained = true;\n return Number((((performance.now() - t0) * 1000) / steps).toFixed(1));\n } finally {\n try {\n if (uniformsBefore !== null) {\n const uniformsAfter = getDispatchStats(device).uniformBuffersCreated;\n paramPoolSession.recordDecodeUniformDelta(uniformsAfter - uniformsBefore);\n }\n } finally {\n try {\n // A session intentionally keeps its bank buffers across arms, but a\n // fresh decode state gives every arm a new resource generation.\n // Retire the old bind groups before destroying that state so WebKit\n // can release its backing buffers immediately.\n if (armDrained) paramPoolSession.invalidateBindings();\n } finally {\n state.destroy();\n }\n }\n }\n}\r\n\r\nexport function cachedAutotuneMatches(cachedUs, currentUs, tolerance = 0.15) {\r\n if (!(Number.isFinite(cachedUs) && cachedUs > 0 && Number.isFinite(currentUs) && currentUs > 0)) {\r\n return false;\r\n }\r\n return Math.abs((currentUs / cachedUs) - 1) <= tolerance + Number.EPSILON;\r\n}\r\n\r\nexport function cachedPolicyMatchesSafety(tuned, safety) {\r\n if (!tuned || !safety) return false;\r\n if (safety.forceSg) return tuned.sg === 'on' && tuned.sgForced === true;\r\n if (!safety.sgOk) return tuned.sg !== 'on';\r\n return true;\r\n}\r\n\r\n// A cache can outlive the GPU's current power/thermal regime. The RTX\r\n// reference has two repeatable states whose B64 default step differs by\r\n// ~25%; the b1 mega-vs-lean winner flips with that state. One warmed B64\r\n// canary is much cheaper than a full retune and prevents a 30-day cache from\r\n// steering today's low-clock session with a high-clock policy (or vice versa).\r\nexport async function measureAutotuneReference(\r\n ctx,\r\n weights,\r\n {\r\n B = 64, S = 96, steps = 24, rounds = 3,\r\n immediates = 'auto', uniformPool = false,\r\n } = {},\r\n) {\r\n const batch = syntheticBatch(B, S);\n const encRun = await runEncoder(ctx, weights, batch, { retainEncOut: false });\n await ctx.device.queue.onSubmittedWorkDone();\n const paramPoolSession = createAutotuneParamPoolSession(ctx, uniformPool);\n try {\n await timeArm(ctx, weights, encRun, B, steps, { immediates }, paramPoolSession);\n const runs = [];\n for (let r = 0; r < rounds; r++) {\n runs.push(await timeArm(ctx, weights, encRun, B, steps, { immediates }, paramPoolSession));\n }\n return { medianUs: median(runs), runs, poolStats: paramPoolSession.snapshot() };\n } finally {\n try {\n paramPoolSession.destroy();\n } finally {\n encRun.arena.destroy();\n }\n }\r\n}\r\n\r\n// Measure the routing decisions on this device and return {tuned, timings}.\r\n// tuned is a threshold table (DEFAULT_ROUTING shape); timings carries the\r\n// per-arm medians for reporting. Weights should be the production load\r\n// (lmHeadQ8/ffnWT/projWT) so 'auto' resolves to what the app will run.\r\n\r\n// GPU correctness self-test for the Adreno 7xx tree-reduction miscompile\r\n// (2026-07 Android round). The driver compiles the guarded-RMW shared-memory\r\n// tree (`if (tid < s) { red[tid] = op(red[tid], red[tid+s]) }` + barrier)\r\n// WRONG inside the real add_ln/attention kernels — deterministically — while\r\n// the same idiom in a minimal shader passes; the trigger is contextual, so\r\n// this probe replicates the smallest KNOWN-FAILING structure verbatim (the\r\n// add_layernorm shape: strided load loop -> shared vbuf + register partials\r\n// -> sum tree -> broadcast mean). ~5ms, no features required. Returns true\r\n// when the device computes it wrong -> callers must force sg reductions;\r\n// false = computes it right; null = the probe itself couldn't run.\r\nexport async function detectTreeReductionBug(device) {\r\n const D = 448;\r\n const WG = 256;\r\n const G = 8;\r\n const code = `\r\n@group(0) @binding(0) var<storage, read_write> out: array<f32>;\r\nconst D: u32 = ${D}u;\r\nconst WG: u32 = ${WG}u;\r\nfn vhash(i: u32, g: u32) -> f32 {\r\n return f32((((i + 1u) * 2654435761u) ^ ((g + 1u) * 40503u)) & 1023u);\r\n}\r\nvar<workgroup> vbuf: array<f32, D>;\r\nvar<workgroup> scratch: array<f32, WG>;\r\n@compute @workgroup_size(${WG})\r\nfn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\r\n let g = wid.x; let tid = lid.x;\r\n var sum: f32 = 0.0;\r\n for (var i = tid; i < D; i = i + WG) {\r\n let v = (vhash(i, g) - 512.0) / 256.0 + (vhash(i + 7777u, g) - 512.0) / 256.0;\r\n vbuf[i] = v;\r\n sum = sum + v;\r\n }\r\n scratch[tid] = sum;\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { scratch[tid] = scratch[tid] + scratch[tid + s]; }\r\n workgroupBarrier();\r\n }\r\n let mu = scratch[0] / f32(D);\r\n workgroupBarrier();\r\n for (var i = tid; i < D; i = i + WG) { out[g * D + i] = vbuf[i] - mu; }\r\n}`;\r\n try {\r\n const module = device.createShaderModule({ code });\r\n const pipeline = device.createComputePipeline({\r\n layout: 'auto', compute: { module, entryPoint: 'main' },\r\n });\r\n const outBuf = device.createBuffer({\r\n size: G * D * 4, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n });\r\n const staging = device.createBuffer({\r\n size: G * D * 4, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,\r\n });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [{ binding: 0, resource: { buffer: outBuf } }],\r\n });\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.dispatchWorkgroups(G);\r\n pass.end();\r\n encoder.copyBufferToBuffer(outBuf, 0, staging, 0, G * D * 4);\r\n device.queue.submit([encoder.finish()]);\r\n await staging.mapAsync(GPUMapMode.READ);\r\n const got = new Float32Array(staging.getMappedRange().slice(0));\r\n staging.unmap();\r\n outBuf.destroy();\r\n staging.destroy();\r\n const hash = (i, g) => ((Math.imul(i + 1, 2654435761) ^ Math.imul(g + 1, 40503)) >>> 0) & 1023;\r\n for (let g = 0; g < G; g++) {\r\n const v = new Float64Array(D);\r\n let sum = 0;\r\n for (let i = 0; i < D; i++) {\r\n v[i] = (hash(i, g) - 512) / 256 + (hash(i + 7777, g) - 512) / 256;\r\n sum += v[i];\r\n }\r\n const mu = sum / D;\r\n for (let i = 0; i < D; i++) {\r\n if (!(Math.abs(got[g * D + i] - (v[i] - mu)) <= 1e-3)) return true;\r\n }\r\n }\r\n return false;\r\n } catch {\r\n // A probe failure must never block engine init — but a dead probe is not\r\n // a clean verdict either: on a tree-bug device a transient crash here\r\n // (memory pressure at load) used to cache a no-forced-sg table FOREVER.\r\n // null = inconclusive: the policy layer retries, then chooses another\r\n // proven-safe route or blocks initialization.\r\n return null;\r\n }\r\n}\r\n\r\n// GPU correctness self-test for the OTHER reduction route. The sg kernels\r\n// (gemm_gemv IF_SG et al.) fold each TK-slice with a subgroupShuffleDown\r\n// butterfly and assume consecutive local invocations occupy consecutive\r\n// lanes of one subgroup. That layout is implementation-defined in WGSL —\r\n// every shipping driver maps linearly, but nothing guarantees it (Codex\r\n// audit 2026-07-10) — so measure it: replicate the kernel's exact butterfly\r\n// at every power-of-two TK the dispatch gate can pick (TK ≤ subgroupMinSize)\r\n// and check the lane-0 slice sums against CPU. Returns true = mismapped (sg\r\n// routes are UNSAFE here), false = clean, null = probe couldn't run.\r\nexport async function detectSgShuffleMismap(device, maxTk) {\r\n const WG = 64;\r\n const G = 4;\r\n const tks = [4, 8, 16, 32].filter((tk) => tk <= Math.min(maxTk ?? 0, WG));\r\n if (!tks.length) return null;\r\n const hash = (i, g) => (((Math.imul(i + 1, 2654435761) ^ Math.imul(g + 1, 40503)) >>> 0) & 1023) / 64;\r\n try {\r\n for (const TK of tks) {\r\n const slices = WG / TK;\r\n const code = `\r\nenable subgroups;\r\n@group(0) @binding(0) var<storage, read_write> out: array<f32>;\r\nconst TK: u32 = ${TK}u;\r\nfn vhash(i: u32, g: u32) -> f32 {\r\n return f32((((i + 1u) * 2654435761u) ^ ((g + 1u) * 40503u)) & 1023u) / 64.0;\r\n}\r\n@compute @workgroup_size(${WG})\r\nfn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\r\n let g = wid.x; let tid = lid.x;\r\n var vr = vhash(tid, g);\r\n for (var s = TK / 2u; s > 0u; s = s >> 1u) {\r\n vr = vr + subgroupShuffleDown(vr, s);\r\n }\r\n if (tid % TK == 0u) { out[g * ${slices}u + tid / TK] = vr; }\r\n}`;\r\n const module = device.createShaderModule({ code });\r\n const pipeline = device.createComputePipeline({\r\n layout: 'auto', compute: { module, entryPoint: 'main' },\r\n });\r\n const outBuf = device.createBuffer({\r\n size: G * slices * 4, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\r\n });\r\n const staging = device.createBuffer({\r\n size: G * slices * 4, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,\r\n });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [{ binding: 0, resource: { buffer: outBuf } }],\r\n });\r\n const encoder = device.createCommandEncoder();\r\n const pass = encoder.beginComputePass();\r\n pass.setPipeline(pipeline);\r\n pass.setBindGroup(0, bindGroup);\r\n pass.dispatchWorkgroups(G);\r\n pass.end();\r\n encoder.copyBufferToBuffer(outBuf, 0, staging, 0, G * slices * 4);\r\n device.queue.submit([encoder.finish()]);\r\n await staging.mapAsync(GPUMapMode.READ);\r\n const got = new Float32Array(staging.getMappedRange().slice(0));\r\n staging.unmap();\r\n outBuf.destroy();\r\n staging.destroy();\r\n for (let g = 0; g < G; g++) {\r\n for (let sl = 0; sl < slices; sl++) {\r\n let want = 0;\r\n for (let i = 0; i < TK; i++) want += hash(sl * TK + i, g);\r\n if (!(Math.abs(got[g * slices + sl] - want) <= 1e-2)) return true;\r\n }\r\n }\r\n }\r\n return false;\r\n } catch {\r\n // Same contract as detectTreeReductionBug: a dead probe is inconclusive,\r\n // not a verdict. The policy layer may use tree only if tree was proven\r\n // safe; otherwise it retries and then blocks rather than guessing.\r\n return null;\r\n }\r\n}\r\n\r\nexport async function probeReductionSafety(\r\n ctx,\r\n { treeProbe = detectTreeReductionBug, sgProbe = detectSgShuffleMismap } = {},\r\n) {\r\n const sgFeature = !!ctx.hasSubgroups && (ctx.subgroupMinSize ?? 0) >= 16;\r\n // Correctness gates BEFORE any perf decision — one probe per reduction\r\n // route. treeBug: a device with the tree-reduce miscompile must run the sg\r\n // variants at every reduction site (attention, add_ln, row_ln, gemv-WT,\r\n // decoder_mega) - sg is forced on and the b8 perf probe cannot override\r\n // it. sgMismap: a device whose subgroup lane layout breaks the shuffle\r\n // butterfly must never probe/force sg. A null verdict is retried once; after\r\n // that at least one route must be explicitly proven safe.\r\n const probe = async () => {\r\n const treeBug = await treeProbe(ctx.device);\r\n // `true` represents unavailable/unsafe when the feature itself is absent.\r\n const sgMismap = sgFeature\r\n ? await sgProbe(ctx.device, ctx.subgroupMinSize)\r\n : true;\r\n return { treeBug, sgMismap };\r\n };\r\n let verdicts = await probe();\r\n let safety = resolveReductionSafety({ ...verdicts, sgFeature });\r\n if (safety.retry) {\r\n await ctx.device.queue.onSubmittedWorkDone();\r\n verdicts = await probe();\r\n safety = resolveReductionSafety({ ...verdicts, sgFeature });\r\n }\r\n if (safety.status === 'unsafe' || safety.status === 'unresolved') {\r\n throw new ReductionSafetyError(\r\n `webMT: no proven-safe GPU reduction route ` +\r\n `(treeBug=${verdicts.treeBug}, sgMismap=${verdicts.sgMismap}, subgroups=${sgFeature})`,\r\n { ...verdicts, sgFeature },\r\n );\r\n }\r\n return { ...safety, verdicts: { ...verdicts, sgFeature } };\r\n}\r\n\r\nexport async function autotuneRouting(ctx, weights, opts = {}) {\n const { reductionSafety = null, uniformPool = false, ...perfOpts } = opts;\n const safety = reductionSafety ?? await probeReductionSafety(ctx);\n const paramPoolSession = createAutotuneParamPoolSession(ctx, uniformPool);\n try {\n try {\n const result = await probeAndDecide(ctx, weights, perfOpts, safety, paramPoolSession);\n return { ...result, poolStats: paramPoolSession.snapshot() };\n } catch (err) {\n // The perf probe died mid-flight (device pressure, transient loss). The\n // correctness verdict above must NOT die with it: on a tree-bug device,\n // falling back to plain 'auto' routing (sg off) silently translates\n // garbage. Return defaults + the forced-sg bits; `partial` tells callers\n // this table is failure-derived and should not be cached.\n const tuned = { ...DEFAULT_ROUTING, projTiledKinds: [...DEFAULT_ROUTING.projTiledKinds] };\n if (safety.forceSg) {\n tuned.sg = 'on';\n tuned.sgForced = true;\n }\n return {\n tuned,\n timings: {},\n partial: String(err?.message ?? err),\n poolStats: paramPoolSession.snapshot(),\n };\n }\n } finally {\n paramPoolSession.destroy();\n }\n}\n\r\nasync function probeAndDecide(\r\n ctx,\r\n weights,\r\n {\r\n S = 96, steps = 24, rounds = 3, extraRounds = 4,\r\n immediates = 'auto',\n },\n { sgOk, forceSg },\n paramPoolSession,\n) {\n // One entry per batch point; arms at the same B share one encoder run.\r\n // 'def' is decoder.js 'auto' at that B; every alt is compared against it.\r\n // b1 steps are so short that per-round jitter dominates — give it extra\r\n // rounds (cheap: its arms run in tens of ms). At B ≤ 4 'auto' means the\r\n // megakernel (when eligible), so the b1 alts probe the two lean paths:\r\n // mega with the LN fusion question mooted, and the fully split pipeline.\r\n // Where sg is probeable, every b1 arm also runs WITH sg — the mega-vs-lean\r\n // verdict flips with it (mega's ~400 tree barriers/layer are exactly what\r\n // Metal pays; sg removes ~80% of them), so the b1 decision below is read\r\n // in whichever sg mode the b8 probe picks.\r\n const points = [\r\n {\r\n B: 1,\r\n arms: {\r\n def: {},\r\n lnOff: { decodeMega: 'off', fuseLn: 'off' },\r\n lnOn: { decodeMega: 'off', fuseLn: 'on' },\r\n ...(sgOk ? {\r\n defSg: { sg: 'on' },\r\n lnOffSg: { decodeMega: 'off', fuseLn: 'off', sg: 'on' },\r\n lnOnSg: { decodeMega: 'off', fuseLn: 'on', sg: 'on' },\r\n } : {}),\r\n },\r\n comparisons: [\r\n ['lnOff', 'def'], ['lnOn', 'def'],\r\n ...(sgOk ? [['lnOffSg', 'defSg'], ['lnOnSg', 'defSg']] : []),\r\n ],\r\n },\r\n { B: 16, arms: { def: {}, gemv: { lmHead: 'gemv' } }, comparisons: [['gemv', 'def']] },\r\n { B: 32, arms: { def: {}, all5: { tiledProj: ALL5 } }, comparisons: [['all5', 'def']] },\r\n {\r\n B: 64,\r\n arms: { def: {}, all5: { tiledProj: ALL5 }, fuseOff: { lmHeadFuse: 'off' } },\r\n comparisons: [['all5', 'def'], ['fuseOff', 'def']],\r\n },\r\n ];\r\n // Subgroup arm at b8 — the batch point where the sg signal peaks (all\r\n // GEMV + add_ln sites active, mega/fused-LN out of the picture). Only\r\n // probed where the decode state accepts sg 'on' (feature + slice fit).\r\n // rounds+2 like b1: the sg arms are short and the margin on the NVIDIA\r\n // reference is only ~3% — a hot 3-round probe was seen flipping it on a\r\n // 973µs outlier run. Extra rounds keep the median honest.\r\n if (sgOk) {\r\n points.push({\r\n B: 8,\r\n arms: { def: {}, sgOn: { sg: 'on' } },\r\n comparisons: [['sgOn', 'def']],\r\n minRounds: rounds + extraRounds,\r\n });\r\n }\r\n\r\n // Warm the adapter with the heaviest probe first. Starting at B=1 leaves\r\n // an NVIDIA laptop GPU in P8/low-clock territory and makes dispatch-bound\r\n // mega-vs-lean routing depend on whichever clock ramp this browser launch\r\n // happened to get. Heavy-to-light gives every latency probe a comparable\r\n // post-boost state without adding another synthetic warmup workload.\r\n points.sort((a, b) => b.B - a.B);\r\n\r\n const timings = {};\r\n for (const point of points) {\r\n const batch = syntheticBatch(point.B, S);\r\n const encRun = await runEncoder(ctx, weights, batch, { retainEncOut: false });\n await ctx.device.queue.onSubmittedWorkDone();\r\n try {\r\n const names = Object.keys(point.arms);\r\n for (const name of names) {\r\n await timeArm(ctx, weights, encRun, point.B, steps, {\n ...point.arms[name], immediates,\n }, paramPoolSession);\n }\r\n const runs = Object.fromEntries(names.map((n) => [n, []]));\r\n const measureRound = async (r) => {\r\n const order = rotatedArmOrder(names, r);\r\n for (const name of order) {\r\n runs[name].push(await timeArm(ctx, weights, encRun, point.B, steps, {\n ...point.arms[name], immediates,\n }, paramPoolSession));\n }\r\n };\r\n const screeningRounds = point.minRounds ?? rounds;\r\n for (let r = 0; r < screeningRounds; r++) await measureRound(r);\r\n const needsMore = point.comparisons.some(([alt, base]) =>\r\n pairedPerfVerdict(runs, alt, base) === 'more');\r\n if (needsMore && screeningRounds === rounds) {\r\n for (let r = screeningRounds; r < rounds + extraRounds; r++) await measureRound(r);\r\n }\r\n timings[`b${point.B}`] = Object.fromEntries(\r\n names.map((n) => [n, { medianUs: median(runs[n]), runs: runs[n] }]),\r\n );\r\n } finally {\r\n encRun.arena.destroy();\r\n }\r\n }\r\n\r\n const wins = (B, alt, base = 'def') => {\r\n const runs = Object.fromEntries(\r\n Object.entries(timings[`b${B}`]).map(([name, entry]) => [name, entry.runs]),\r\n );\r\n return pairedPerfVerdict(runs, alt, base) === 'win';\r\n };\r\n\r\n const tuned = { ...DEFAULT_ROUTING, projTiledKinds: [...DEFAULT_ROUTING.projTiledKinds] };\r\n // sg is decided FIRST (b8 probe) — the b1 mega-vs-lean question is then\r\n // answered under the sg mode the device will actually run.\r\n if (forceSg) {\r\n tuned.sg = 'on';\r\n tuned.sgForced = true; // correctness, not perf - survives any probe verdict\r\n } else if (timings.b8) {\r\n const b8Runs = Object.fromEntries(\r\n Object.entries(timings.b8).map(([name, entry]) => [name, entry.runs]),\r\n );\r\n if (pairedStableSgWin(b8Runs)) tuned.sg = 'on';\r\n }\r\n const sfx = tuned.sg === 'on' ? 'Sg' : '';\r\n // b1: 'def' is the megakernel (when eligible); a lean-arm win turns it off\r\n // and settles the LN-fusion question for the split pipeline at the same\r\n // time (lowest median of the two winning lean arms decides).\r\n const b1 = timings.b1;\r\n const b1Runs = Object.fromEntries(Object.entries(b1).map(([name, entry]) => [name, entry.runs]));\r\n const baseName = `def${sfx}`;\r\n const offName = `lnOff${sfx}`;\r\n const onName = `lnOn${sfx}`;\r\n const offRatio = median(pairedRatios(b1Runs, offName, baseName));\r\n const onRatio = median(pairedRatios(b1Runs, onName, baseName));\r\n const leanBest = offRatio <= onRatio ? offName : onName;\r\n if (wins(1, leanBest, `def${sfx}`)) {\r\n tuned.decodeMega = 'off';\r\n tuned.fuseLnMaxB = leanBest.startsWith('lnOff') ? 0 : DEFAULT_ROUTING.fuseLnMaxB;\r\n }\r\n if (wins(16, 'gemv')) tuned.lmHeadMinB = 32;\r\n if (wins(64, 'fuseOff')) tuned.lmHeadFuse = 'off';\r\n if (wins(32, 'all5')) {\r\n tuned.projTiledMinB = 32;\r\n tuned.projTiledKinds = [...ALL5];\r\n } else if (wins(64, 'all5')) {\r\n tuned.projTiledMinB = 64;\r\n tuned.projTiledKinds = [...ALL5];\r\n }\r\n return { tuned, timings };\r\n}\r\n\r\n// Resolve a tuned threshold table to concrete createDecodeState/translateBatch\r\n// options for one batch size. tuned == null falls back to plain 'auto'.\r\nexport function tunedOptions(tuned, B) {\r\n if (!tuned) return {};\r\n return {\r\n fuseLn: B <= tuned.fuseLnMaxB ? 'on' : 'off',\r\n lmHead: B >= tuned.lmHeadMinB ? 'auto' : 'gemv',\r\n lmHeadFuse: tuned.lmHeadFuse === 'off' ? 'off' : 'auto',\r\n tiledProj: B >= tuned.projTiledMinB && tuned.projTiledMinB < DEFAULT_ROUTING.projTiledMinB\r\n ? [...tuned.projTiledKinds]\r\n : 'auto',\r\n // Tree-bug devices: mega+sg is VERIFIED broken at hachimi dims on the\r\n // affected Adreno (sg golden 0/30 via mega vs 30/30 lean, 2026-07-07;\r\n // moxhi dims pass — likely its near-16KB shared budget). Until that\r\n // miscompile is bisected, correctness beats mega's small-B win there.\r\n decodeMega: tuned.sgForced ? 'off' : (tuned.decodeMega === 'off' ? 'off' : 'auto'),\r\n // Learned only where supported — 'on' would throw on a device without\r\n // the feature, but tuned tables are per-device (cache keyed on adapter).\r\n sg: tuned.sg === 'on' ? 'on' : 'off',\r\n // Tree-bug devices also miscompile attention_block at non-multiple-of-16\r\n // workgroup sizes — cap the encoder QB there (no-op where QB is already\r\n // a multiple of 8, e.g. every D<=64 model).\r\n encAttnSafe: !!tuned.sgForced,\r\n };\r\n}\r\n"],"names":["ALL5","DEFAULT_ROUTING","WIN_MARGIN","KERNEL_REV","median","xs","s","a","b","m","ReductionSafetyError","message","verdicts","resolveReductionSafety","treeBug","sgMismap","sgFeature","valid","v","treeSafe","sgSafe","retry","rotatedArmOrder","names","round","offset","pairedRatios","runs","alt","base","i","pairedPerfVerdict","ratios","med","favorable","r","need","pairedStableSgWin","ratio","syntheticBatch","B","S","ids","x","VOCAB","EOS","createAutotuneParamPoolSession","ctx","enabled","pool","destroyed","decodeTransientUniforms","state","shouldUseUniformParamPool","createUniformParamPool","delta","timeArm","weights","encRun","steps","opts","paramPoolSession","device","createDecodeState","uniformsBefore","armDrained","paramPool","getDispatchStats","t0","g","tEnd","bank","poolFrameActive","scratch","encoder","pass","t","encodeDecodeStep","err","uniformsAfter","cachedAutotuneMatches","cachedUs","currentUs","tolerance","cachedPolicyMatchesSafety","tuned","safety","measureAutotuneReference","rounds","immediates","uniformPool","batch","runEncoder","detectTreeReductionBug","code","module","pipeline","outBuf","staging","bindGroup","got","hash","sum","mu","detectSgShuffleMismap","maxTk","tks","tk","TK","slices","sl","want","probeReductionSafety","treeProbe","sgProbe","probe","autotuneRouting","reductionSafety","perfOpts","probeAndDecide","extraRounds","sgOk","forceSg","points","timings","point","name","n","measureRound","order","screeningRounds","wins","entry","b8Runs","sfx","b1","b1Runs","baseName","offName","onName","offRatio","onRatio","leanBest","tunedOptions"],"mappings":"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"}
 
 
assets/baseline-DFLF_Mw1.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import{r as u}from"./debug-CPpXXfWA.js";import{runReference as l}from"./reference-BRIi7m-O.js";import{g as h}from"./golden-D7gAaNSE.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./safe_storage-BYkOahew.js";import"./shapes-ClGtK-ia.js";import"./constants-CSVWRdrh.js";const b=8;u("baseline_reference",async()=>{const a=h.items.slice(0,b),i=a.map(e=>e.source),m=a.map(e=>e.text),p=[{device:"wasm",dtype:"q8",batch:1},{device:"wasm",dtype:"q8",batch:4},{device:"webgpu",dtype:"fp16",batch:1},{device:"webgpu",dtype:"fp16",batch:4}],r=[];for(const{device:e,dtype:o,batch:s}of p)try{const t=await l({device:e,dtype:o,sources:i,batchSize:s,onStatus:c=>console.log(`[baseline ${e}/${o} b${s}] ${c}`)}),n={runtime:e,dtype:o,batch:s,loadMs:Math.round(t.loadMs),translateMs:Math.round(t.translateMs),tokens:t.tokens,tokPerSec:Number(t.tokPerSec.toFixed(1)),charsPerSec:Number(t.charsPerSec.toFixed(1))};e==="wasm"&&s===1&&(n.exactVsGolden=t.texts.filter((c,d)=>c===m[d]).length),r.push(n)}catch(t){r.push({runtime:e,dtype:o,batch:s,error:String(t?.message??t)})}return{pass:r.some(e=>!e.error),detail:{runs:r}}},{slow:!0});
2
+ //# sourceMappingURL=baseline-DFLF_Mw1.js.map
assets/{baseline-DK6w1rGg.js.map → baseline-DFLF_Mw1.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"file":"baseline-DK6w1rGg.js","sources":["../../src/debug/tests/baseline.js"],"sourcesContent":["// Early reference baseline (slow): Transformers.js wasm/q8 and webgpu/fp16\r\n// translation speed on the first 8 golden sources. Results are hand-copied\r\n// into docs/bench/baseline.json — they are the denominators for the spike's\r\n// success criteria.\r\nimport { registerTest } from '../registry.js';\r\nimport { runReference } from '../../bench/reference.js';\r\nimport golden from '../../../fixtures/golden.json';\r\n\r\nconst N_ITEMS = 8;\r\n\r\nregisterTest(\r\n 'baseline_reference',\r\n async () => {\r\n const items = golden.items.slice(0, N_ITEMS);\r\n const sources = items.map((it) => it.source);\r\n const goldenTexts = items.map((it) => it.text);\r\n\r\n const configs = [\r\n { device: 'wasm', dtype: 'q8', batch: 1 },\r\n { device: 'wasm', dtype: 'q8', batch: 4 },\r\n { device: 'webgpu', dtype: 'fp16', batch: 1 },\r\n { device: 'webgpu', dtype: 'fp16', batch: 4 },\r\n ];\r\n\r\n const runs = [];\r\n for (const { device, dtype, batch } of configs) {\r\n try {\r\n const res = await runReference({\r\n device,\r\n dtype,\r\n sources,\r\n batchSize: batch,\r\n onStatus: (msg) => console.log(`[baseline ${device}/${dtype} b${batch}] ${msg}`),\r\n });\r\n const run = {\r\n runtime: device,\r\n dtype,\r\n batch,\r\n loadMs: Math.round(res.loadMs),\r\n translateMs: Math.round(res.translateMs),\r\n tokens: res.tokens,\r\n tokPerSec: Number(res.tokPerSec.toFixed(1)),\r\n charsPerSec: Number(res.charsPerSec.toFixed(1)),\r\n };\r\n if (device === 'wasm' && batch === 1) {\r\n // Report-only: q8 vs fp32 golden will differ some; expect >=6/8.\r\n run.exactVsGolden = res.texts.filter((t, i) => t === goldenTexts[i]).length;\r\n }\r\n runs.push(run);\r\n } catch (err) {\r\n runs.push({ runtime: device, dtype, batch, error: String(err?.message ?? err) });\r\n }\r\n }\r\n\r\n const pass = runs.some((r) => !r.error); // fail only if ALL four runs errored\r\n return { pass, detail: { runs } };\r\n },\r\n { slow: true },\r\n);\r\n"],"names":["N_ITEMS","registerTest","items","golden","sources","it","goldenTexts","configs","runs","device","dtype","batch","res","runReference","msg","run","t","i","err","r"],"mappings":"uRAQA,MAAMA,EAAU,EAEhBC,EACE,qBACA,SAAY,CACV,MAAMC,EAAQC,EAAO,MAAM,MAAM,EAAGH,CAAO,EACrCI,EAAUF,EAAM,IAAKG,GAAOA,EAAG,MAAM,EACrCC,EAAcJ,EAAM,IAAKG,GAAOA,EAAG,IAAI,EAEvCE,EAAU,CACd,CAAE,OAAQ,OAAQ,MAAO,KAAM,MAAO,CAAC,EACvC,CAAE,OAAQ,OAAQ,MAAO,KAAM,MAAO,CAAC,EACvC,CAAE,OAAQ,SAAU,MAAO,OAAQ,MAAO,CAAC,EAC3C,CAAE,OAAQ,SAAU,MAAO,OAAQ,MAAO,CAAC,CACjD,EAEUC,EAAO,CAAA,EACb,SAAW,CAAE,OAAAC,EAAQ,MAAAC,EAAO,MAAAC,CAAK,IAAMJ,EACrC,GAAI,CACF,MAAMK,EAAM,MAAMC,EAAa,CAC7B,OAAAJ,EACA,MAAAC,EACA,QAAAN,EACA,UAAWO,EACX,SAAWG,GAAQ,QAAQ,IAAI,aAAaL,CAAM,IAAIC,CAAK,KAAKC,CAAK,KAAKG,CAAG,EAAE,CACzF,CAAS,EACKC,EAAM,CACV,QAASN,EACT,MAAAC,EACA,MAAAC,EACA,OAAQ,KAAK,MAAMC,EAAI,MAAM,EAC7B,YAAa,KAAK,MAAMA,EAAI,WAAW,EACvC,OAAQA,EAAI,OACZ,UAAW,OAAOA,EAAI,UAAU,QAAQ,CAAC,CAAC,EAC1C,YAAa,OAAOA,EAAI,YAAY,QAAQ,CAAC,CAAC,CACxD,EACYH,IAAW,QAAUE,IAAU,IAEjCI,EAAI,cAAgBH,EAAI,MAAM,OAAO,CAACI,EAAGC,IAAMD,IAAMV,EAAYW,CAAC,CAAC,EAAE,QAEvET,EAAK,KAAKO,CAAG,CACf,OAASG,EAAK,CACZV,EAAK,KAAK,CAAE,QAASC,EAAQ,MAAAC,EAAO,MAAAC,EAAO,MAAO,OAAOO,GAAK,SAAWA,CAAG,CAAC,CAAE,CACjF,CAIF,MAAO,CAAE,KADIV,EAAK,KAAMW,GAAM,CAACA,EAAE,KAAK,EACvB,OAAQ,CAAE,KAAAX,CAAI,CAAE,CACjC,EACA,CAAE,KAAM,EAAI,CACd"}
 
1
+ {"version":3,"file":"baseline-DFLF_Mw1.js","sources":["../../src/debug/tests/baseline.js"],"sourcesContent":["// Early reference baseline (slow): Transformers.js wasm/q8 and webgpu/fp16\r\n// translation speed on the first 8 golden sources. Results are hand-copied\r\n// into docs/bench/baseline.json — they are the denominators for the spike's\r\n// success criteria.\r\nimport { registerTest } from '../registry.js';\r\nimport { runReference } from '../../bench/reference.js';\r\nimport golden from '../../../fixtures/golden.json';\r\n\r\nconst N_ITEMS = 8;\r\n\r\nregisterTest(\r\n 'baseline_reference',\r\n async () => {\r\n const items = golden.items.slice(0, N_ITEMS);\r\n const sources = items.map((it) => it.source);\r\n const goldenTexts = items.map((it) => it.text);\r\n\r\n const configs = [\r\n { device: 'wasm', dtype: 'q8', batch: 1 },\r\n { device: 'wasm', dtype: 'q8', batch: 4 },\r\n { device: 'webgpu', dtype: 'fp16', batch: 1 },\r\n { device: 'webgpu', dtype: 'fp16', batch: 4 },\r\n ];\r\n\r\n const runs = [];\r\n for (const { device, dtype, batch } of configs) {\r\n try {\r\n const res = await runReference({\r\n device,\r\n dtype,\r\n sources,\r\n batchSize: batch,\r\n onStatus: (msg) => console.log(`[baseline ${device}/${dtype} b${batch}] ${msg}`),\r\n });\r\n const run = {\r\n runtime: device,\r\n dtype,\r\n batch,\r\n loadMs: Math.round(res.loadMs),\r\n translateMs: Math.round(res.translateMs),\r\n tokens: res.tokens,\r\n tokPerSec: Number(res.tokPerSec.toFixed(1)),\r\n charsPerSec: Number(res.charsPerSec.toFixed(1)),\r\n };\r\n if (device === 'wasm' && batch === 1) {\r\n // Report-only: q8 vs fp32 golden will differ some; expect >=6/8.\r\n run.exactVsGolden = res.texts.filter((t, i) => t === goldenTexts[i]).length;\r\n }\r\n runs.push(run);\r\n } catch (err) {\r\n runs.push({ runtime: device, dtype, batch, error: String(err?.message ?? err) });\r\n }\r\n }\r\n\r\n const pass = runs.some((r) => !r.error); // fail only if ALL four runs errored\r\n return { pass, detail: { runs } };\r\n },\r\n { slow: true },\r\n);\r\n"],"names":["N_ITEMS","registerTest","items","golden","sources","it","goldenTexts","configs","runs","device","dtype","batch","res","runReference","msg","run","t","i","err","r"],"mappings":"0TAQA,MAAMA,EAAU,EAEhBC,EACE,qBACA,SAAY,CACV,MAAMC,EAAQC,EAAO,MAAM,MAAM,EAAGH,CAAO,EACrCI,EAAUF,EAAM,IAAKG,GAAOA,EAAG,MAAM,EACrCC,EAAcJ,EAAM,IAAKG,GAAOA,EAAG,IAAI,EAEvCE,EAAU,CACd,CAAE,OAAQ,OAAQ,MAAO,KAAM,MAAO,CAAC,EACvC,CAAE,OAAQ,OAAQ,MAAO,KAAM,MAAO,CAAC,EACvC,CAAE,OAAQ,SAAU,MAAO,OAAQ,MAAO,CAAC,EAC3C,CAAE,OAAQ,SAAU,MAAO,OAAQ,MAAO,CAAC,CACjD,EAEUC,EAAO,CAAA,EACb,SAAW,CAAE,OAAAC,EAAQ,MAAAC,EAAO,MAAAC,CAAK,IAAMJ,EACrC,GAAI,CACF,MAAMK,EAAM,MAAMC,EAAa,CAC7B,OAAAJ,EACA,MAAAC,EACA,QAAAN,EACA,UAAWO,EACX,SAAWG,GAAQ,QAAQ,IAAI,aAAaL,CAAM,IAAIC,CAAK,KAAKC,CAAK,KAAKG,CAAG,EAAE,CACzF,CAAS,EACKC,EAAM,CACV,QAASN,EACT,MAAAC,EACA,MAAAC,EACA,OAAQ,KAAK,MAAMC,EAAI,MAAM,EAC7B,YAAa,KAAK,MAAMA,EAAI,WAAW,EACvC,OAAQA,EAAI,OACZ,UAAW,OAAOA,EAAI,UAAU,QAAQ,CAAC,CAAC,EAC1C,YAAa,OAAOA,EAAI,YAAY,QAAQ,CAAC,CAAC,CACxD,EACYH,IAAW,QAAUE,IAAU,IAEjCI,EAAI,cAAgBH,EAAI,MAAM,OAAO,CAACI,EAAGC,IAAMD,IAAMV,EAAYW,CAAC,CAAC,EAAE,QAEvET,EAAK,KAAKO,CAAG,CACf,OAASG,EAAK,CACZV,EAAK,KAAK,CAAE,QAASC,EAAQ,MAAAC,EAAO,MAAAC,EAAO,MAAO,OAAOO,GAAK,SAAWA,CAAG,CAAC,CAAE,CACjF,CAIF,MAAO,CAAE,KADIV,EAAK,KAAMW,GAAM,CAACA,EAAE,KAAK,EACvB,OAAQ,CAAE,KAAAX,CAAI,CAAE,CACjC,EACA,CAAE,KAAM,EAAI,CACd"}
assets/baseline-DK6w1rGg.js DELETED
@@ -1,2 +0,0 @@
1
- import{r as u}from"./debug-C_LNzFrK.js";import{runReference as l}from"./reference-Dj87VRUN.js";import{g as h}from"./golden-D7gAaNSE.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./shapes-BCQ9D81L.js";import"./constants-C8VbFpic.js";const b=8;u("baseline_reference",async()=>{const a=h.items.slice(0,b),i=a.map(e=>e.source),m=a.map(e=>e.text),p=[{device:"wasm",dtype:"q8",batch:1},{device:"wasm",dtype:"q8",batch:4},{device:"webgpu",dtype:"fp16",batch:1},{device:"webgpu",dtype:"fp16",batch:4}],r=[];for(const{device:e,dtype:o,batch:s}of p)try{const t=await l({device:e,dtype:o,sources:i,batchSize:s,onStatus:c=>console.log(`[baseline ${e}/${o} b${s}] ${c}`)}),n={runtime:e,dtype:o,batch:s,loadMs:Math.round(t.loadMs),translateMs:Math.round(t.translateMs),tokens:t.tokens,tokPerSec:Number(t.tokPerSec.toFixed(1)),charsPerSec:Number(t.charsPerSec.toFixed(1))};e==="wasm"&&s===1&&(n.exactVsGolden=t.texts.filter((c,d)=>c===m[d]).length),r.push(n)}catch(t){r.push({runtime:e,dtype:o,batch:s,error:String(t?.message??t)})}return{pass:r.some(e=>!e.error),detail:{runs:r}}},{slow:!0});
2
- //# sourceMappingURL=baseline-DK6w1rGg.js.map
 
 
 
assets/batch_cap_ab-67ewcIZi.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import{r as T}from"./debug-CPpXXfWA.js";import{l as B}from"./weights-DxIJF1EY.js";import{l as M}from"./tokenizer-BmI7pHmp.js";import{t as S}from"./generate-Ca3ORHiA.js";import{f as D}from"./constants-CSVWRdrh.js";import{s as A,p as C}from"./t2s-DjPa3Hpi.js";import{p as E}from"./engine-C4r8fF2d.js";import{c as O}from"./chapter3k-DSdzHZt5.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./safe_storage-BYkOahew.js";import"./shapes-ClGtK-ia.js";import"./f16-wKKZr58e.js";import"./encoder-CZXKGzzg.js";import"./pipelines-BbLc75sB.js";import"./decoder-BUiaGDqb.js";import"./device-BotbBNoe.js";import"./autotune-Bwt_lWMv.js";import"./shortlist-C151mR5c.js";const P=n=>{const s=[...n].sort((m,a)=>m-a),o=s.length>>1;return s.length%2?s[o]:(s[o-1]+s[o])/2},l=[128,192,256],w=5;T("batch_cap_ab",async n=>{const{device:s}=n;if(!n.hasF16)return{skip:!0,reason:"production stack needs shader-f16"};const o=await B(s,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0,projWT:!0});try{const m=await M(),a={device:s,dtype:"f16",limits:n.limits},c=O.repeat(16),u=A(c),{rows:i}=C(u.sentences,u.paras,200),k=i.map(t=>t.length),b=async t=>{const r=E(k,a,2,t),e=performance.now();let g=0;for(const[h,f]of r){const{metrics:x}=await S(a,o,m,i.slice(h,f),{maxNewTokens:D});g+=x.tokensGenerated}return{ms:performance.now()-e,tokens:g,batches:r.length,maxB:Math.max(...r.map(([h,f])=>f-h))}},p=Object.fromEntries(l.map(t=>[t,[]]));let d={};for(let t=0;t<w;t++)for(const r of l){const e=await b(r);p[r].push(e.ms),d[r]={batches:e.batches,maxB:e.maxB,tokens:e.tokens}}const y=l.map(t=>{const r=P(p[t]);return{cap:t,medianMs:Math.round(r*10)/10,charsPerSec:Math.round(c.length/r*1e3),...d[t],runs:p[t].map(e=>Math.round(e))}});return{pass:!0,detail:{chars:c.length,rows:i.length,rounds:w,table:y}}}finally{o.buffer.destroy()}},{slow:!0});
2
+ //# sourceMappingURL=batch_cap_ab-67ewcIZi.js.map
assets/{batch_cap_ab-Dd5N_5qo.js.map → batch_cap_ab-67ewcIZi.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"file":"batch_cap_ab-Dd5N_5qo.js","sources":["../../src/debug/tests/batch_cap_ab.js"],"sourcesContent":["// batch_cap_ab: e2e A/B for the app's planBatches hardCap at pack200 —\r\n// decode step scaling is sublinear in B (b64→b128 = 1.6× step for 2× rows),\r\n// so a bigger cap may buy throughput if VRAM/binding limits allow. Arms\r\n// share one source (chapter3k ×16 so the biggest cap still fills ≥2 batches).\r\n//\r\n// HISTORICAL: this test tuned the original flat hardCap 192 on UNSORTED\r\n// pack200 rows. The shipped planner has moved on — length sort + S-aware cap\r\n// (hardCapForS, B·S ≈ 192·224, desktop up to 576) validated on the production\r\n// path via app_stage. Results here don't transfer to the sorted planner.\r\nimport { registerTest } from '../registry.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { loadTokenizer } from '../../engine/tokenizer.js';\r\nimport { translateBatch } from '../../engine/generate.js';\r\nimport { DECODE_CAP } from '../../engine/constants.js';\r\nimport { segmentSource, packSentences } from '../../app/split.js';\r\nimport { planBatches } from '../../app/engine.js';\r\nimport chapterText from '../../../fixtures/chapter3k.txt?raw';\r\n\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\n\r\nconst CAPS = [128, 192, 256];\r\nconst ROUNDS = 5;\r\n\r\nregisterTest('batch_cap_ab', async (ctx) => {\r\n const { device } = ctx;\r\n if (!ctx.hasF16) return { skip: true, reason: 'production stack needs shader-f16' };\r\n const weights = await loadWeights(device, '/weights', {\r\n targetDtype: 'f16', lmHeadQ8: true, ffnWT: true, projWT: true,\r\n });\r\n try {\r\n const tok = await loadTokenizer();\r\n const gctx = { device, dtype: 'f16', limits: ctx.limits };\r\n const text = chapterText.repeat(16);\r\n const seg = segmentSource(text);\r\n const { rows } = packSentences(seg.sentences, seg.paras, 200);\r\n const charLens = rows.map((r) => r.length);\r\n\r\n const runArm = async (cap) => {\r\n const ranges = planBatches(charLens, gctx, 2, cap);\r\n const t0 = performance.now();\r\n let tokens = 0;\r\n for (const [s, e] of ranges) {\r\n const { metrics } = await translateBatch(\r\n gctx, weights, tok, rows.slice(s, e), { maxNewTokens: DECODE_CAP });\r\n tokens += metrics.tokensGenerated;\r\n }\r\n return { ms: performance.now() - t0, tokens, batches: ranges.length, maxB: Math.max(...ranges.map(([s, e]) => e - s)) };\r\n };\r\n\r\n const runs = Object.fromEntries(CAPS.map((c) => [c, []]));\r\n let shape = {};\r\n for (let round = 0; round < ROUNDS; round++) {\r\n for (const cap of CAPS) {\r\n const r = await runArm(cap);\r\n runs[cap].push(r.ms);\r\n shape[cap] = { batches: r.batches, maxB: r.maxB, tokens: r.tokens };\r\n }\r\n }\r\n const table = CAPS.map((cap) => {\r\n const ms = median(runs[cap]);\r\n return {\r\n cap,\r\n medianMs: Math.round(ms * 10) / 10,\r\n charsPerSec: Math.round((text.length / ms) * 1000),\r\n ...shape[cap],\r\n runs: runs[cap].map((x) => Math.round(x)),\r\n };\r\n });\r\n return { pass: true, detail: { chars: text.length, rows: rows.length, rounds: ROUNDS, table } };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n}, { slow: true });\r\n"],"names":["median","xs","s","a","b","m","CAPS","ROUNDS","registerTest","ctx","device","weights","loadWeights","tok","loadTokenizer","gctx","text","chapterText","seg","segmentSource","rows","packSentences","charLens","r","runArm","cap","ranges","planBatches","t0","tokens","e","metrics","translateBatch","DECODE_CAP","runs","c","shape","round","table","ms","x"],"mappings":"wpBAkBA,MAAMA,EAAUC,GAAO,CACrB,MAAMC,EAAI,CAAC,GAAGD,CAAE,EAAE,KAAK,CAACE,EAAGC,IAAMD,EAAIC,CAAC,EAChCC,EAAIH,EAAE,QAAU,EACtB,OAAOA,EAAE,OAAS,EAAIA,EAAEG,CAAC,GAAKH,EAAEG,EAAI,CAAC,EAAIH,EAAEG,CAAC,GAAK,CACnD,EAEMC,EAAO,CAAC,IAAK,IAAK,GAAG,EACrBC,EAAS,EAEfC,EAAa,eAAgB,MAAOC,GAAQ,CAC1C,KAAM,CAAE,OAAAC,CAAM,EAAKD,EACnB,GAAI,CAACA,EAAI,OAAQ,MAAO,CAAE,KAAM,GAAM,OAAQ,qCAC9C,MAAME,EAAU,MAAMC,EAAYF,EAAQ,WAAY,CACpD,YAAa,MAAO,SAAU,GAAM,MAAO,GAAM,OAAQ,EAC7D,CAAG,EACD,GAAI,CACF,MAAMG,EAAM,MAAMC,IACZC,EAAO,CAAE,OAAAL,EAAQ,MAAO,MAAO,OAAQD,EAAI,QAC3CO,EAAOC,EAAY,OAAO,EAAE,EAC5BC,EAAMC,EAAcH,CAAI,EACxB,CAAE,KAAAI,CAAI,EAAKC,EAAcH,EAAI,UAAWA,EAAI,MAAO,GAAG,EACtDI,EAAWF,EAAK,IAAKG,GAAMA,EAAE,MAAM,EAEnCC,EAAS,MAAOC,GAAQ,CAC5B,MAAMC,EAASC,EAAYL,EAAUP,EAAM,EAAGU,CAAG,EAC3CG,EAAK,YAAY,MACvB,IAAIC,EAAS,EACb,SAAW,CAAC3B,EAAG4B,CAAC,IAAKJ,EAAQ,CAC3B,KAAM,CAAE,QAAAK,CAAO,EAAK,MAAMC,EACxBjB,EAAMJ,EAASE,EAAKO,EAAK,MAAMlB,EAAG4B,CAAC,EAAG,CAAE,aAAcG,CAAU,CAAE,EACpEJ,GAAUE,EAAQ,eACpB,CACA,MAAO,CAAE,GAAI,YAAY,IAAG,EAAKH,EAAI,OAAAC,EAAQ,QAASH,EAAO,OAAQ,KAAM,KAAK,IAAI,GAAGA,EAAO,IAAI,CAAC,CAACxB,EAAG4B,CAAC,IAAMA,EAAI5B,CAAC,CAAC,EACtH,EAEMgC,EAAO,OAAO,YAAY5B,EAAK,IAAK6B,GAAM,CAACA,EAAG,CAAA,CAAE,CAAC,CAAC,EACxD,IAAIC,EAAQ,CAAA,EACZ,QAASC,EAAQ,EAAGA,EAAQ9B,EAAQ8B,IAClC,UAAWZ,KAAOnB,EAAM,CACtB,MAAM,EAAI,MAAMkB,EAAOC,CAAG,EAC1BS,EAAKT,CAAG,EAAE,KAAK,EAAE,EAAE,EACnBW,EAAMX,CAAG,EAAI,CAAE,QAAS,EAAE,QAAS,KAAM,EAAE,KAAM,OAAQ,EAAE,MAAM,CACnE,CAEF,MAAMa,EAAQhC,EAAK,IAAKmB,GAAQ,CAC9B,MAAMc,EAAKvC,EAAOkC,EAAKT,CAAG,CAAC,EAC3B,MAAO,CACL,IAAAA,EACA,SAAU,KAAK,MAAMc,EAAK,EAAE,EAAI,GAChC,YAAa,KAAK,MAAOvB,EAAK,OAASuB,EAAM,GAAI,EACjD,GAAGH,EAAMX,CAAG,EACZ,KAAMS,EAAKT,CAAG,EAAE,IAAKe,GAAM,KAAK,MAAMA,CAAC,CAAC,CAChD,CACI,CAAC,EACD,MAAO,CAAE,KAAM,GAAM,OAAQ,CAAE,MAAOxB,EAAK,OAAQ,KAAMI,EAAK,OAAQ,OAAQb,EAAQ,MAAA+B,CAAK,CAAE,CAC/F,QAAC,CACC3B,EAAQ,OAAO,SACjB,CACF,EAAG,CAAE,KAAM,GAAM"}
 
1
+ {"version":3,"file":"batch_cap_ab-67ewcIZi.js","sources":["../../src/debug/tests/batch_cap_ab.js"],"sourcesContent":["// batch_cap_ab: e2e A/B for the app's planBatches hardCap at pack200 —\r\n// decode step scaling is sublinear in B (b64→b128 = 1.6× step for 2× rows),\r\n// so a bigger cap may buy throughput if VRAM/binding limits allow. Arms\r\n// share one source (chapter3k ×16 so the biggest cap still fills ≥2 batches).\r\n//\r\n// HISTORICAL: this test tuned the original flat hardCap 192 on UNSORTED\r\n// pack200 rows. The shipped planner has moved on — length sort + S-aware cap\r\n// (hardCapForS, B·S ≈ 192·224, desktop up to 576) validated on the production\r\n// path via app_stage. Results here don't transfer to the sorted planner.\r\nimport { registerTest } from '../registry.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { loadTokenizer } from '../../engine/tokenizer.js';\r\nimport { translateBatch } from '../../engine/generate.js';\r\nimport { DECODE_CAP } from '../../engine/constants.js';\r\nimport { segmentSource, packSentences } from '../../app/split.js';\r\nimport { planBatches } from '../../app/engine.js';\r\nimport chapterText from '../../../fixtures/chapter3k.txt?raw';\r\n\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\n\r\nconst CAPS = [128, 192, 256];\r\nconst ROUNDS = 5;\r\n\r\nregisterTest('batch_cap_ab', async (ctx) => {\r\n const { device } = ctx;\r\n if (!ctx.hasF16) return { skip: true, reason: 'production stack needs shader-f16' };\r\n const weights = await loadWeights(device, '/weights', {\r\n targetDtype: 'f16', lmHeadQ8: true, ffnWT: true, projWT: true,\r\n });\r\n try {\r\n const tok = await loadTokenizer();\r\n const gctx = { device, dtype: 'f16', limits: ctx.limits };\r\n const text = chapterText.repeat(16);\r\n const seg = segmentSource(text);\r\n const { rows } = packSentences(seg.sentences, seg.paras, 200);\r\n const charLens = rows.map((r) => r.length);\r\n\r\n const runArm = async (cap) => {\r\n const ranges = planBatches(charLens, gctx, 2, cap);\r\n const t0 = performance.now();\r\n let tokens = 0;\r\n for (const [s, e] of ranges) {\r\n const { metrics } = await translateBatch(\r\n gctx, weights, tok, rows.slice(s, e), { maxNewTokens: DECODE_CAP });\r\n tokens += metrics.tokensGenerated;\r\n }\r\n return { ms: performance.now() - t0, tokens, batches: ranges.length, maxB: Math.max(...ranges.map(([s, e]) => e - s)) };\r\n };\r\n\r\n const runs = Object.fromEntries(CAPS.map((c) => [c, []]));\r\n let shape = {};\r\n for (let round = 0; round < ROUNDS; round++) {\r\n for (const cap of CAPS) {\r\n const r = await runArm(cap);\r\n runs[cap].push(r.ms);\r\n shape[cap] = { batches: r.batches, maxB: r.maxB, tokens: r.tokens };\r\n }\r\n }\r\n const table = CAPS.map((cap) => {\r\n const ms = median(runs[cap]);\r\n return {\r\n cap,\r\n medianMs: Math.round(ms * 10) / 10,\r\n charsPerSec: Math.round((text.length / ms) * 1000),\r\n ...shape[cap],\r\n runs: runs[cap].map((x) => Math.round(x)),\r\n };\r\n });\r\n return { pass: true, detail: { chars: text.length, rows: rows.length, rounds: ROUNDS, table } };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n}, { slow: true });\r\n"],"names":["median","xs","a","b","m","CAPS","ROUNDS","registerTest","ctx","device","weights","loadWeights","tok","loadTokenizer","gctx","text","chapterText","seg","segmentSource","rows","packSentences","charLens","r","runArm","cap","ranges","planBatches","t0","tokens","s","e","metrics","translateBatch","DECODE_CAP","runs","c","shape","round","table","ms","x"],"mappings":"2rBAkBA,MAAMA,EAAUC,GAAO,CACrB,MAAM,EAAI,CAAC,GAAGA,CAAE,EAAE,KAAK,CAACC,EAAGC,IAAMD,EAAIC,CAAC,EAChCC,EAAI,EAAE,QAAU,EACtB,OAAO,EAAE,OAAS,EAAI,EAAEA,CAAC,GAAK,EAAEA,EAAI,CAAC,EAAI,EAAEA,CAAC,GAAK,CACnD,EAEMC,EAAO,CAAC,IAAK,IAAK,GAAG,EACrBC,EAAS,EAEfC,EAAa,eAAgB,MAAOC,GAAQ,CAC1C,KAAM,CAAE,OAAAC,CAAM,EAAKD,EACnB,GAAI,CAACA,EAAI,OAAQ,MAAO,CAAE,KAAM,GAAM,OAAQ,qCAC9C,MAAME,EAAU,MAAMC,EAAYF,EAAQ,WAAY,CACpD,YAAa,MAAO,SAAU,GAAM,MAAO,GAAM,OAAQ,EAC7D,CAAG,EACD,GAAI,CACF,MAAMG,EAAM,MAAMC,IACZC,EAAO,CAAE,OAAAL,EAAQ,MAAO,MAAO,OAAQD,EAAI,QAC3CO,EAAOC,EAAY,OAAO,EAAE,EAC5BC,EAAMC,EAAcH,CAAI,EACxB,CAAE,KAAAI,CAAI,EAAKC,EAAcH,EAAI,UAAWA,EAAI,MAAO,GAAG,EACtDI,EAAWF,EAAK,IAAKG,GAAMA,EAAE,MAAM,EAEnCC,EAAS,MAAOC,GAAQ,CAC5B,MAAMC,EAASC,EAAYL,EAAUP,EAAM,EAAGU,CAAG,EAC3CG,EAAK,YAAY,MACvB,IAAIC,EAAS,EACb,SAAW,CAACC,EAAGC,CAAC,IAAKL,EAAQ,CAC3B,KAAM,CAAE,QAAAM,CAAO,EAAK,MAAMC,EACxBlB,EAAMJ,EAASE,EAAKO,EAAK,MAAMU,EAAGC,CAAC,EAAG,CAAE,aAAcG,CAAU,CAAE,EACpEL,GAAUG,EAAQ,eACpB,CACA,MAAO,CAAE,GAAI,YAAY,IAAG,EAAKJ,EAAI,OAAAC,EAAQ,QAASH,EAAO,OAAQ,KAAM,KAAK,IAAI,GAAGA,EAAO,IAAI,CAAC,CAACI,EAAGC,CAAC,IAAMA,EAAID,CAAC,CAAC,EACtH,EAEMK,EAAO,OAAO,YAAY7B,EAAK,IAAK8B,GAAM,CAACA,EAAG,CAAA,CAAE,CAAC,CAAC,EACxD,IAAIC,EAAQ,CAAA,EACZ,QAASC,EAAQ,EAAGA,EAAQ/B,EAAQ+B,IAClC,UAAWb,KAAOnB,EAAM,CACtB,MAAMiB,EAAI,MAAMC,EAAOC,CAAG,EAC1BU,EAAKV,CAAG,EAAE,KAAKF,EAAE,EAAE,EACnBc,EAAMZ,CAAG,EAAI,CAAE,QAASF,EAAE,QAAS,KAAMA,EAAE,KAAM,OAAQA,EAAE,MAAM,CACnE,CAEF,MAAMgB,EAAQjC,EAAK,IAAKmB,GAAQ,CAC9B,MAAMe,EAAKvC,EAAOkC,EAAKV,CAAG,CAAC,EAC3B,MAAO,CACL,IAAAA,EACA,SAAU,KAAK,MAAMe,EAAK,EAAE,EAAI,GAChC,YAAa,KAAK,MAAOxB,EAAK,OAASwB,EAAM,GAAI,EACjD,GAAGH,EAAMZ,CAAG,EACZ,KAAMU,EAAKV,CAAG,EAAE,IAAKgB,GAAM,KAAK,MAAMA,CAAC,CAAC,CAChD,CACI,CAAC,EACD,MAAO,CAAE,KAAM,GAAM,OAAQ,CAAE,MAAOzB,EAAK,OAAQ,KAAMI,EAAK,OAAQ,OAAQb,EAAQ,MAAAgC,CAAK,CAAE,CAC/F,QAAC,CACC5B,EAAQ,OAAO,SACjB,CACF,EAAG,CAAE,KAAM,GAAM"}
assets/batch_cap_ab-Dd5N_5qo.js DELETED
@@ -1,2 +0,0 @@
1
- import{r as T}from"./debug-C_LNzFrK.js";import{l as B}from"./weights-D8qtuKag.js";import{l as M}from"./tokenizer-Ex1u7wXD.js";import{t as S}from"./generate-BIP3NpbY.js";import{g as D}from"./constants-C8VbFpic.js";import{s as A,p as C}from"./t2s-DjPa3Hpi.js";import{p as E}from"./engine-D57xjIIN.js";import{c as O}from"./chapter3k-DSdzHZt5.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./shapes-BCQ9D81L.js";import"./f16-wKKZr58e.js";import"./encoder-I9sHImnR.js";import"./pipelines-DJ7cc1m-.js";import"./decoder-CI9o-EVx.js";import"./device-BotbBNoe.js";import"./autotune-DywP5DSc.js";import"./shortlist-C151mR5c.js";const P=n=>{const e=[...n].sort((m,a)=>m-a),o=e.length>>1;return e.length%2?e[o]:(e[o-1]+e[o])/2},l=[128,192,256],w=5;T("batch_cap_ab",async n=>{const{device:e}=n;if(!n.hasF16)return{skip:!0,reason:"production stack needs shader-f16"};const o=await B(e,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0,projWT:!0});try{const m=await M(),a={device:e,dtype:"f16",limits:n.limits},c=O.repeat(16),u=A(c),{rows:i}=C(u.sentences,u.paras,200),k=i.map(t=>t.length),b=async t=>{const s=E(k,a,2,t),r=performance.now();let g=0;for(const[h,f]of s){const{metrics:x}=await S(a,o,m,i.slice(h,f),{maxNewTokens:D});g+=x.tokensGenerated}return{ms:performance.now()-r,tokens:g,batches:s.length,maxB:Math.max(...s.map(([h,f])=>f-h))}},p=Object.fromEntries(l.map(t=>[t,[]]));let d={};for(let t=0;t<w;t++)for(const s of l){const r=await b(s);p[s].push(r.ms),d[s]={batches:r.batches,maxB:r.maxB,tokens:r.tokens}}const y=l.map(t=>{const s=P(p[t]);return{cap:t,medianMs:Math.round(s*10)/10,charsPerSec:Math.round(c.length/s*1e3),...d[t],runs:p[t].map(r=>Math.round(r))}});return{pass:!0,detail:{chars:c.length,rows:i.length,rounds:w,table:y}}}finally{o.buffer.destroy()}},{slow:!0});
2
- //# sourceMappingURL=batch_cap_ab-Dd5N_5qo.js.map
 
 
 
assets/{bench-CEDJ-mff.js → bench-BarR4Zp5.js} RENAMED
@@ -1,5 +1,5 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/reference-Dj87VRUN.js","assets/shapes-BCQ9D81L.js","assets/constants-C8VbFpic.js"])))=>i.map(i=>d[i]);
2
- import{_ as O}from"./preload-helper-BXl3LOEh.js";import{t as A}from"./generate-BIP3NpbY.js";import{tunedOptions as T}from"./autotune-DywP5DSc.js";import{c as L,b as q}from"./shapes-BCQ9D81L.js";import{c as _}from"./chapter3k-DSdzHZt5.js";function B(t,r=220){const i=String(t).replace(/\r\n/g,`
3
  `).split(`
4
- `),n=[],o=[],l=Math.max(80,Number(r)||220),$=/[^。!?!?;;]+[。!?!?;;]*/g;for(const w of i){const d=w.trim();if(!d){o.push(null);continue}const k=d.match($)||[d];let m="";const b=[],f=()=>{m&&(b.push(n.length),n.push(m),m="")};for(const s of k){if(s.length>l){f();for(let a=0;a<s.length;a+=l)b.push(n.length),n.push(s.slice(a,a+l));continue}m&&(m+s).length>l&&f(),m+=s}f(),o.push(b)}return{chunks:n,plan:o}}const G=["他缓缓拔出长剑,目光冷得像冰。","夜色渐深,客栈里只剩下几盏残灯。","“你到底是什么人?”她低声问道。","山风呼啸,卷起满地的落叶。","老者捋了捋胡须,微微一笑。","这一掌的力道,足以开碑裂石!","“师父,弟子知错了。”少年跪在地上。","江湖上的恩怨,从来没有那么简单。","她转身离去,再也没有回头。","剑光一闪,血溅三尺。","大殿之内,众人鸦雀无声。","他喝了口酒,眼中闪过一丝痛楚。","“今晚三更,后山竹林见。”","马蹄声由远及近,尘土飞扬。","这门功夫,他练了整整二十年。","暮色四合之际,一行人马终于抵达了山脚下的小镇,镇口的酒旗在风中猎猎作响;为首的中年汉子翻身下马,环顾四周,见街道两旁的店铺早已关门闭户,只有远处一家客栈还透出昏黄的灯光,他皱了皱眉,低声吩咐众人收起兵刃,不要惊扰了镇上的百姓。","传闻中的藏剑山庄坐落在群山环抱之中,庄内古木参天,流水潺潺,青石铺就的小径蜿蜒曲折;每逢三月桃花盛开,四方豪杰便会齐聚于此,或论剑,或品茶,或只是远远地望一眼那位传说中的庄主,据说他已经三十年没有拔过剑了,可江湖上没有人敢小看他。","那一夜大雨倾盆,雷声滚滚,破庙里的火堆忽明忽暗;少年抱着怀中的剑谱,听着庙外杂乱的脚步声越来越近,心跳如鼓,他知道,追兵一旦破门而入,自己便再无生路,可师父临终前的嘱托犹在耳边,这本剑谱无论如何都不能落入奸人之手。","掌门之位悬空已有三年,门中各脉明争暗斗从未停歇;大师兄稳重却优柔寡断,二师姐剑法超群却性情孤傲,三师弟聪明伶俐却资历尚浅,长老们各怀心思,谁也不肯先开口,直到那个雪夜,山门外传来一声长啸,所有人都放下了手中的茶盏。","集市上人声鼎沸,卖艺的汉子赤膊耍着一杆铁枪,围观的人群不时爆发出阵阵喝彩声;忽然人群一阵骚动,几名黑衣人分开众人径直走向那名枪手,为首之人冷冷地丢下一块乌黑的令牌,喧闹的集市霎时安静了下来,连风都仿佛停了。","信使跪在堂下,双手呈上一封火漆密函,堂上众人面面相觑;老庄主拆开信笺,只看了一眼,脸色便骤然大变,他缓缓起身,望着窗外沉沉的夜色,半晌才道:传令下去,即刻封山,任何人不得进出,违令者一律逐出师门,永不再录。","三十年前的那场大火烧毁了半座城池,也烧断了两大世家百年的情谊;如今旧事重提,当年的幸存者死的死,散的散,唯有城南那口枯井旁的老槐树还记得一切,树下埋着的,不只是一坛陈年的女儿红,还有一个再也无人敢提起的名字。","渡口的老船夫眯着眼打量来客,见那书生衣衫褴褛却腰悬长剑,不由得多问了一句;书生笑而不答,只将一锭碎银放在船头,转身望向对岸茫茫的芦苇荡,江风吹起他的衣角,露出内衬上暗绣的金线纹样,老船夫握着船桨的手,忽然抖了一下。","林昭推门而入,林昭的剑还在滴着血,可林昭的声音却平静得可怕。","沈青山望着窗外,沈青山知道,今夜之后江湖上再无沈青山这个名字。","“林昭!林昭你给我站住!”她追出门外,可林昭的身影早已消失在夜色之中。","众人都说沈青山败了,可沈青山不这么认为,沈青山收剑入鞘,转身走下擂台。","林昭救过他一次,林昭也骗过他一次��所以当林昭再次出现时,他不知该拔剑还是敬酒。","沈青山的刀快,沈青山的心更狠,凡是见过沈青山出手的人,都不愿再与他为敌。","有人说林昭死在了雁门关外,有人说林昭隐居山林,还有人说,林昭根本就没有存在过。"],I=["刀出如龙,寒气逼人。","他在桥头站了一夜。","“放下剑,我饶你不死。”","钟声响起,山门缓缓开启。","她的暗器从不落空。","灯火摇曳,人影散乱。","一杯酒,敬当年的兄弟。","掌风过处,烛火尽灭。","他背上的伤疤又开始疼了。","“来者何人,报上名来!”","雪落无声,剑亦无声。","这条路,他走了半生。","密道尽头透出一线微光。","恩人一诺,死生不忘。","毒发之时,他咬碎了牙关。","旗帜倒下,城头易主。","江水东流,带不走旧恨。"];function R(t){if(t==="short32")return[...G.slice(0,15),...I];if(t==="chapter3k")return B(_).chunks;if(t==="file23k"){const r=B(_).chunks;return Array.from({length:8},()=>r).flat()}throw new Error(`unknown preset: ${t}`)}const v=t=>[...t].sort((r,i)=>i.length-r.length),y=t=>Number(t.toFixed(1));function N(t){const r=[...t].sort((n,o)=>n-o),i=r.length>>1;return r.length%2?r[i]:(r[i-1]+r[i])/2}async function j(t,r,i,n,o,l=null,$={}){let w=0,d=0,k=0,m=0;const b={uniformBuffersCreated:0,dummyBuffersCreated:0,bindGroupsCreated:0,bindGroupCacheHits:0,bindGroupEvictions:0,immediateSets:0};for(let s=0;s<n.length;s+=o){const a=n.slice(s,s+o),{metrics:M}=await A(t,r,i,a,{...T(l,a.length),...$});w+=M.encoderMs,d+=M.decodeMs,k+=M.tokensGenerated,m+=M.submits;for(const E of Object.keys(b))b[E]+=M.dispatch?.[E]??0}const f=n.reduce((s,a)=>s+a.length,0);return{encoderMs:y(w),decodeMs:y(d),tokens:k,submits:m,dispatch:b,tokPerSec:y(k/d*1e3),e2eCharsPerSec:y(f/(w+d)*1e3)}}const H=["encoderMs","decodeMs","tokens","tokPerSec","e2eCharsPerSec"],D={"tfjs-wasm-q8":{device:"wasm",dtype:"q8"},"tfjs-webgpu-fp16":{device:"webgpu",dtype:"fp16"}};async function J(t,r,i,{presets:n=["short32","chapter3k"],batches:o=[1,4,8,16],repeats:l=3,includeReference:$=!1,referencePresets:w=n,referenceBatches:d=[1,4],referenceCells:k=Object.keys(D).flatMap(s=>w.flatMap(a=>d.map(M=>({runtime:s,preset:a,batch:M})))),tuned:m=null,engineOptions:b={},onStatus:f=()=>{}}={}){const s=[],a=Object.fromEntries(n.map(u=>[u,v(R(u))])),M=u=>Array.isArray(o)?o:o[u],E=r.dtype==="f16"?2:4,C=async u=>{const h=i.encode(a[u][0]),p=L(t,q(h.length),E),c=[];for(const g of M(u)){const e=Math.min(g,p);e!==g&&f(`${u}: batch ${g} clamped to device max ${e}`),c.some(P=>P.batch===e)||c.push({batch:e,...e!==g?{requestedBatch:g}:{}})}return c};f("warmup…"),await j(t,r,i,a[n[0]],(await C(n[0]))[0].batch,m,b);for(const u of n)for(const{batch:h,requestedBatch:p}of await C(u)){const c=[];for(let e=0;e<l;e++)f(`webmt ${u} b${h} repeat ${e+1}/${l}…`),c.push(await j(t,r,i,a[u],h,m,b));const g=Object.fromEntries(H.map(e=>[e,y(N(c.map(P=>P[e])))]));s.push({runtime:"webmt",preset:u,batch:h,...p?{requestedBatch:p}:{},repeats:c,median:g,min:{tokPerSec:Math.min(...c.map(e=>e.tokPerSec)),e2eCharsPerSec:Math.min(...c.map(e=>e.e2eCharsPerSec))},max:{tokPerSec:Math.max(...c.map(e=>e.tokPerSec)),e2eCharsPerSec:Math.max(...c.map(e=>e.e2eCharsPerSec))}})}if($){const{runReference:u}=await O(async()=>{const{runReference:h}=await import("./reference-Dj87VRUN.js");return{runReference:h}},__vite__mapDeps([0,1,2]));for(const{runtime:h,preset:p,batch:c}of k){const{device:g,dtype:e}=D[h]??{};if(!g)throw new Error(`unknown reference runtime: ${h}`);const P=a[p]??v(R(p));f(`${h} ${p} b${c} (single run)…`);try{const S=await u({device:g,dtype:e,sources:P,batchSize:c,onStatus:F=>f(`${h} ${p} b${c}: ${F}`)}),x={loadMs:Math.round(S.loadMs),translateMs:Math.round(S.translateMs),tokens:S.tokens,tokPerSec:y(S.tokPerSec),e2eCharsPerSec:y(S.charsPerSec)};s.push({runtime:h,preset:p,batch:c,repeats:[x],median:x})}catch(S){s.push({runtime:h,preset:p,batch:c,error:String(S?.message??S)})}}}return s}function K(t,r,{date:i,stack:n}={}){const o=new Date,l=`${o.getFullYear()}-${String(o.getMonth()+1).padStart(2,"0")}-${String(o.getDate()).padStart(2,"0")}`;return{schema:"webmt-bench-v1",date:i??l,adapterInfo:r,...n?{stack:n}:{},baselineRef:"docs/bench/baseline.json",runs:t}}export{K as b,R as p,J as r};
5
- //# sourceMappingURL=bench-CEDJ-mff.js.map
 
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/reference-BRIi7m-O.js","assets/shapes-ClGtK-ia.js","assets/constants-CSVWRdrh.js"])))=>i.map(i=>d[i]);
2
+ import{_ as O}from"./preload-helper-BXl3LOEh.js";import{t as A}from"./generate-Ca3ORHiA.js";import{tunedOptions as T}from"./autotune-Bwt_lWMv.js";import{c as L,b as q}from"./shapes-ClGtK-ia.js";import{c as _}from"./chapter3k-DSdzHZt5.js";function B(t,r=220){const i=String(t).replace(/\r\n/g,`
3
  `).split(`
4
+ `),n=[],o=[],l=Math.max(80,Number(r)||220),$=/[^。!?!?;;]+[。!?!?;;]*/g;for(const w of i){const d=w.trim();if(!d){o.push(null);continue}const k=d.match($)||[d];let m="";const b=[],f=()=>{m&&(b.push(n.length),n.push(m),m="")};for(const s of k){if(s.length>l){f();for(let a=0;a<s.length;a+=l)b.push(n.length),n.push(s.slice(a,a+l));continue}m&&(m+s).length>l&&f(),m+=s}f(),o.push(b)}return{chunks:n,plan:o}}const G=["他缓缓拔出长剑,目光冷得像冰。","夜色渐深,客栈里只剩下几盏残灯。","“你到底是什么人?”她低声问道。","山风呼啸,卷起满地的落叶。","老者捋了捋胡须,微微一笑。","这一掌的力道,足以开碑裂石!","“师父,弟子知错了。”少年跪在地上。","江湖上的恩怨,从来没有那么简单。","她转身离去,再也没有回头。","剑光一闪,血溅三尺。","大殿之内,众人鸦雀无声。","他喝了口酒,眼中闪过一丝痛楚。","“今晚三更,后山竹林见。”","马蹄声由远及近,尘土飞扬。","这门功夫,他练了整整二十年。","暮色四合之际,一行人马终于抵达了山脚下的小镇,镇口的酒旗在风中猎猎作响;为首的中年汉子翻身下马,环顾四周,见街道两旁的店铺早已关门闭户,只有远处一家客栈还透出昏黄的灯光,他皱了皱眉,低声吩咐众人收起兵刃,不要惊扰了镇上的百姓。","传闻中的藏剑山庄坐落在群山环抱之中,庄内古木参天,流水潺潺,青石铺就的小径蜿蜒曲折;每逢三月桃花盛开,四方豪杰便会齐聚于此,或论剑,或品茶,或只是远远地望一眼那位传说中的庄主,据说他已经三十年没有拔过剑了,可江湖上没有人敢小看他。","那一夜大雨倾盆,雷声滚滚,破庙里的火堆忽明忽暗;少年抱着怀中的剑谱,听着庙外杂乱的脚步声越来越近,心跳如鼓,他知道,追兵一旦破门而入,自己便再无生路,可师父临终前的嘱托犹在耳边,这本剑谱无论如何都不能落入奸人之手。","掌门之位悬空已有三年,门中各脉明争暗斗从未停歇;大师兄稳重却优柔寡断,二师姐剑法超群却性情孤傲,三师弟聪明伶俐却资历尚浅,长老们各怀心思,谁也不肯先开口,直到那个雪夜,山门外传来一声长啸,所有人都放下了手中的茶盏。","集市上人声鼎沸,卖艺的汉子赤膊耍着一杆铁枪,围观的人群不时爆发出阵阵喝彩声;忽然人群一阵骚动,几名黑衣人分开众人径直走向那名枪手,为首之人冷冷地丢下一块乌黑的令牌,喧闹的集市霎时安静了下来,连风都仿佛停了。","信使跪在堂下,双手呈上一封火漆密函,堂上众人面面相觑;老庄主拆开信笺,只看了一眼,脸色便骤然大变,他缓缓起身,望着窗外沉沉的夜色,半晌才道:传令下去,即刻封山,任何人不得进出,违令者一律逐出师门,永不再录。","三十年前的那场大火烧毁了半座城池,也烧断了两大世家百年的情谊;如今旧事重提,当年的幸存者死的死,散的散,唯有城南那口枯井旁的老槐树还记得一切,树下埋着的,不只是一坛陈年的女儿红,还有一个再也无人敢提起的名字。","渡口的老船夫眯着眼打量来客,见那书生衣衫褴褛却腰悬长剑,不由得多问了一句;书生笑而不答,只将一锭碎银放在船头,转身望向对岸茫茫的芦苇荡,江风吹起他的衣角,露出内衬上暗绣的金线纹样,老船夫握着船桨的手,忽然抖了一下。","林昭推门而入,林昭的剑还在滴着血,可林昭的声音却平静得可怕。","沈青山望着窗外,沈青山知道,今夜之后江湖上再无沈青山这个名字。","“林昭!林昭你给我站住!”她追出门外,可林昭的身影早已消失在夜色之中。","众人都说沈青山败了,可沈青山不这么认为,沈青山收剑入鞘,转身走下擂台。","林昭救过他一次,林昭也骗过他一次所以当林昭再次出现时,他不知该拔剑还是敬酒。","沈青山的刀快,沈青山的心更狠,凡是见过沈青山出手的人,都不愿再与他为敌。","有人说林昭死在了雁门关外,有人说林昭隐居山林,还有人说,林昭根本就没有存在过。"],I=["刀出如龙,寒气逼人。","他在桥头站了一夜。","“放下剑,我饶你不死。”","钟声响起,山门缓缓开启。","她的暗器从不落空。","灯火摇曳,人影散乱。","一杯酒,敬当年的兄弟。","掌风过处,烛火尽灭。","他背上的伤疤又开始疼了。","“来者何人,报上名来!”","雪落无声,剑亦无声。","这条路,他走了半生。","密道尽头透出一线微光。","恩人一诺,死生不忘。","毒发之时,他咬碎了牙关。","旗帜倒下,城头易主。","江水东流,带不走旧恨。"];function R(t){if(t==="short32")return[...G.slice(0,15),...I];if(t==="chapter3k")return B(_).chunks;if(t==="file23k"){const r=B(_).chunks;return Array.from({length:8},()=>r).flat()}throw new Error(`unknown preset: ${t}`)}const v=t=>[...t].sort((r,i)=>i.length-r.length),y=t=>Number(t.toFixed(1));function N(t){const r=[...t].sort((n,o)=>n-o),i=r.length>>1;return r.length%2?r[i]:(r[i-1]+r[i])/2}async function j(t,r,i,n,o,l=null,$={}){let w=0,d=0,k=0,m=0;const b={uniformBuffersCreated:0,dummyBuffersCreated:0,bindGroupsCreated:0,bindGroupCacheHits:0,bindGroupEvictions:0,immediateSets:0};for(let s=0;s<n.length;s+=o){const a=n.slice(s,s+o),{metrics:M}=await A(t,r,i,a,{...T(l,a.length),...$});w+=M.encoderMs,d+=M.decodeMs,k+=M.tokensGenerated,m+=M.submits;for(const E of Object.keys(b))b[E]+=M.dispatch?.[E]??0}const f=n.reduce((s,a)=>s+a.length,0);return{encoderMs:y(w),decodeMs:y(d),tokens:k,submits:m,dispatch:b,tokPerSec:y(k/d*1e3),e2eCharsPerSec:y(f/(w+d)*1e3)}}const H=["encoderMs","decodeMs","tokens","tokPerSec","e2eCharsPerSec"],D={"tfjs-wasm-q8":{device:"wasm",dtype:"q8"},"tfjs-webgpu-fp16":{device:"webgpu",dtype:"fp16"}};async function J(t,r,i,{presets:n=["short32","chapter3k"],batches:o=[1,4,8,16],repeats:l=3,includeReference:$=!1,referencePresets:w=n,referenceBatches:d=[1,4],referenceCells:k=Object.keys(D).flatMap(s=>w.flatMap(a=>d.map(M=>({runtime:s,preset:a,batch:M})))),tuned:m=null,engineOptions:b={},onStatus:f=()=>{}}={}){const s=[],a=Object.fromEntries(n.map(u=>[u,v(R(u))])),M=u=>Array.isArray(o)?o:o[u],E=r.dtype==="f16"?2:4,C=async u=>{const h=i.encode(a[u][0]),p=L(t,q(h.length),E),c=[];for(const g of M(u)){const e=Math.min(g,p);e!==g&&f(`${u}: batch ${g} clamped to device max ${e}`),c.some(P=>P.batch===e)||c.push({batch:e,...e!==g?{requestedBatch:g}:{}})}return c};f("warmup…"),await j(t,r,i,a[n[0]],(await C(n[0]))[0].batch,m,b);for(const u of n)for(const{batch:h,requestedBatch:p}of await C(u)){const c=[];for(let e=0;e<l;e++)f(`webmt ${u} b${h} repeat ${e+1}/${l}…`),c.push(await j(t,r,i,a[u],h,m,b));const g=Object.fromEntries(H.map(e=>[e,y(N(c.map(P=>P[e])))]));s.push({runtime:"webmt",preset:u,batch:h,...p?{requestedBatch:p}:{},repeats:c,median:g,min:{tokPerSec:Math.min(...c.map(e=>e.tokPerSec)),e2eCharsPerSec:Math.min(...c.map(e=>e.e2eCharsPerSec))},max:{tokPerSec:Math.max(...c.map(e=>e.tokPerSec)),e2eCharsPerSec:Math.max(...c.map(e=>e.e2eCharsPerSec))}})}if($){const{runReference:u}=await O(async()=>{const{runReference:h}=await import("./reference-BRIi7m-O.js");return{runReference:h}},__vite__mapDeps([0,1,2]));for(const{runtime:h,preset:p,batch:c}of k){const{device:g,dtype:e}=D[h]??{};if(!g)throw new Error(`unknown reference runtime: ${h}`);const P=a[p]??v(R(p));f(`${h} ${p} b${c} (single run)…`);try{const S=await u({device:g,dtype:e,sources:P,batchSize:c,onStatus:F=>f(`${h} ${p} b${c}: ${F}`)}),x={loadMs:Math.round(S.loadMs),translateMs:Math.round(S.translateMs),tokens:S.tokens,tokPerSec:y(S.tokPerSec),e2eCharsPerSec:y(S.charsPerSec)};s.push({runtime:h,preset:p,batch:c,repeats:[x],median:x})}catch(S){s.push({runtime:h,preset:p,batch:c,error:String(S?.message??S)})}}}return s}function K(t,r,{date:i,stack:n}={}){const o=new Date,l=`${o.getFullYear()}-${String(o.getMonth()+1).padStart(2,"0")}-${String(o.getDate()).padStart(2,"0")}`;return{schema:"webmt-bench-v1",date:i??l,adapterInfo:r,...n?{stack:n}:{},baselineRef:"docs/bench/baseline.json",runs:t}}export{K as b,R as p,J as r};
5
+ //# sourceMappingURL=bench-BarR4Zp5.js.map
assets/{bench-CEDJ-mff.js.map → bench-BarR4Zp5.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"mappings":"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","names":["splitText","text","maxChars","lines","chunks","plan","limit","sentenceRe","rawLine","line","pieces","current","indexes","pushCurrent","piece","i","EXTRA_SHORT","presetChunks","name","goldenSources","chapterText","base","byLengthDesc","a","b","round1","x","median","values","s","mid","runEngineOnce","ctx","weights","tok","orderedChunks","batch","tuned","engineOptions","encoderMs","decodeMs","tokens","submits","dispatch","group","metrics","translateBatch","tunedOptions","field","srcChars","n","c","MEDIAN_FIELDS","REF_RUNTIMES","runBenchMatrix","presets","batches","repeats","includeReference","referencePresets","referenceBatches","referenceCells","runtime","preset","onStatus","rows","ordered","p","batchesFor","dtypeBytes","clampedBatches","ids","maxBatch","maxBatchForLimits","bucketFor","list","clamped","requestedBatch","reps","r","med","f","runReference","__vitePreload","device","dtype","res","msg","entry","err","buildReport","adapterInfo","date","stack","d","localDate"],"ignoreList":[],"sources":["../../src/bench/chunk.js","../../src/bench/bench.js"],"sourcesContent":["// Text chunker, ported EXACTLY from the old app's worker\r\n// (moxhimt30-browser/src/worker/translator.worker.js) so the chapter benchmark\r\n// exercises the same chunk-size distribution the shipped app produces.\r\n//\r\n// splitText: newline → lines; each line split by the CJK/latin sentence regex,\r\n// sentences accumulated up to `maxChars` (clamped to ≥80, default 220);\r\n// oversized single sentences hard-split at the limit. Empty lines become a\r\n// null plan entry. Returns {chunks, plan} where plan[i] is the list of chunk\r\n// indexes for line i (null for blank lines).\r\nexport function splitText(text, maxChars = 220) {\r\n const lines = String(text || '').replace(/\\r\\n/g, '\\n').split('\\n');\r\n const chunks = [];\r\n const plan = [];\r\n const limit = Math.max(80, Number(maxChars) || 220);\r\n const sentenceRe = /[^。!?!?;;]+[。!?!?;;]*/g;\r\n\r\n for (const rawLine of lines) {\r\n const line = rawLine.trim();\r\n if (!line) {\r\n plan.push(null);\r\n continue;\r\n }\r\n const pieces = line.match(sentenceRe) || [line];\r\n let current = '';\r\n const indexes = [];\r\n const pushCurrent = () => {\r\n if (!current) return;\r\n indexes.push(chunks.length);\r\n chunks.push(current);\r\n current = '';\r\n };\r\n\r\n for (const piece of pieces) {\r\n if (piece.length > limit) {\r\n pushCurrent();\r\n for (let i = 0; i < piece.length; i += limit) {\r\n indexes.push(chunks.length);\r\n chunks.push(piece.slice(i, i + limit));\r\n }\r\n continue;\r\n }\r\n if (current && (current + piece).length > limit) {\r\n pushCurrent();\r\n }\r\n current += piece;\r\n }\r\n pushCurrent();\r\n plan.push(indexes);\r\n }\r\n return { chunks, plan };\r\n}\r\n\r\n// Reassemble translated chunks per the plan: chunks of one source line join\r\n// with ' ', lines join with '\\n', blank lines come back as ''.\r\nexport function joinChunks(translated, plan) {\r\n return plan.map((indexes) => {\r\n if (indexes === null) return '';\r\n return indexes.map((idx) => translated[idx]).filter(Boolean).join(' ');\r\n }).join('\\n');\r\n}\r\n","// M5 benchmark matrix: engine (webmt) across preset × batch, plus optional\r\n// Transformers.js reference rows, exported as a webmt-bench-v1 report.\r\n//\r\n// Metric semantics (documented, deliberate):\r\n// tokPerSec tokens / Σ decodeMs — DECODE-ONLY throughput, the kernel\r\n// story; comparable with m3/m4 numbers and baseline tok/s.\r\n// e2eCharsPerSec source chars / Σ(encoderMs + decodeMs) — the honest\r\n// end-user number: encoder + full decode loop including all\r\n// per-group readbacks (decodeMs contains mapAsync waits).\r\n// Excludes tokenize/detokenize JS (sub-ms per chunk).\r\n//\r\n// Batching hygiene: chunks are ordered LONGEST-FIRST before grouping into\r\n// translateBatch calls (mirrors the old worker's sortedChunkJobs) so a group\r\n// holds similar-length rows — padding and per-group decode caps are set by\r\n// the longest row, so mixing lengths wastes steps on the short rows.\r\nimport { translateBatch } from '../engine/generate.js';\r\nimport { tunedOptions } from '../engine/autotune.js';\r\nimport { maxBatchForLimits, bucketFor } from '../engine/shapes.js';\r\n// reference.js pulls in transformers.js + ORT (~24MB with the wasm) — loaded\r\n// on demand so plain engine benches never fetch it.\r\nimport { splitText } from './chunk.js';\r\nimport goldenSources from '../../fixtures/golden_sources.json';\r\nimport chapterText from '../../fixtures/chapter3k.txt?raw';\r\n\r\n// 17 extra short sentences (same wuxia register as golden_sources' first 15)\r\n// to bring the short preset to 32.\r\nconst EXTRA_SHORT = [\r\n '刀出如龙,寒气逼人。',\r\n '他在桥头站了一夜。',\r\n '“放下剑,我饶你不死。”',\r\n '钟声响起,山门缓缓开启。',\r\n '她的暗器从不落空。',\r\n '灯火摇曳,人影散乱。',\r\n '一杯酒,敬当年的兄弟。',\r\n '掌风过处,烛火尽灭。',\r\n '他背上的伤疤又开始疼了。',\r\n '“来者何人,报上名来!”',\r\n '雪落无声,剑亦无声。',\r\n '这条路,他走了半生。',\r\n '密道尽头透出一线微光。',\r\n '恩人一诺,死生不忘。',\r\n '毒发之时,他咬碎了牙关。',\r\n '旗帜倒下,城头易主。',\r\n '江水东流,带不走旧恨。',\r\n];\r\n\r\n// Preset name → chunk list. short32 = first 15 golden short sources + 17\r\n// extras; chapter3k = the fixture chapter through the ported app chunker;\r\n// file23k = the chapter3k chunk list repeated 8× (152 chunks, ~23k chars) —\r\n// simulates translating a real .txt file, where large batches actually fill.\r\nexport function presetChunks(name) {\r\n if (name === 'short32') return [...goldenSources.slice(0, 15), ...EXTRA_SHORT];\r\n if (name === 'chapter3k') return splitText(chapterText).chunks;\r\n if (name === 'file23k') {\r\n const base = splitText(chapterText).chunks;\r\n return Array.from({ length: 8 }, () => base).flat();\r\n }\r\n throw new Error(`unknown preset: ${name}`);\r\n}\r\n\r\nconst byLengthDesc = (chunks) => [...chunks].sort((a, b) => b.length - a.length);\r\nconst round1 = (x) => Number(x.toFixed(1));\r\n\r\nfunction median(values) {\r\n const s = [...values].sort((a, b) => a - b);\r\n const mid = s.length >> 1;\r\n return s.length % 2 ? s[mid] : (s[mid - 1] + s[mid]) / 2;\r\n}\r\n\r\n// One engine measurement of a preset at a batch size: sequential\r\n// translateBatch calls over longest-first groups of `batch` chunks.\r\n// `tuned` (a routing table from autotuneRouting) resolves per group like the\r\n// app's translateText does; null keeps decoder.js 'auto' — the kernel floor.\r\nasync function runEngineOnce(ctx, weights, tok, orderedChunks, batch, tuned = null, engineOptions = {}) {\r\n let encoderMs = 0;\r\n let decodeMs = 0;\r\n let tokens = 0;\r\n let submits = 0;\r\n const dispatch = {\r\n uniformBuffersCreated: 0, dummyBuffersCreated: 0, bindGroupsCreated: 0,\r\n bindGroupCacheHits: 0, bindGroupEvictions: 0, immediateSets: 0,\r\n };\r\n for (let i = 0; i < orderedChunks.length; i += batch) {\r\n const group = orderedChunks.slice(i, i + batch);\r\n const { metrics } = await translateBatch(ctx, weights, tok, group,\r\n { ...tunedOptions(tuned, group.length), ...engineOptions });\r\n encoderMs += metrics.encoderMs;\r\n decodeMs += metrics.decodeMs;\r\n tokens += metrics.tokensGenerated;\r\n submits += metrics.submits;\r\n for (const field of Object.keys(dispatch)) dispatch[field] += metrics.dispatch?.[field] ?? 0;\r\n }\r\n const srcChars = orderedChunks.reduce((n, c) => n + c.length, 0);\r\n return {\r\n encoderMs: round1(encoderMs),\r\n decodeMs: round1(decodeMs),\r\n tokens,\r\n submits,\r\n dispatch,\r\n tokPerSec: round1((tokens / decodeMs) * 1000),\r\n e2eCharsPerSec: round1((srcChars / (encoderMs + decodeMs)) * 1000),\r\n };\r\n}\r\n\r\nconst MEDIAN_FIELDS = ['encoderMs', 'decodeMs', 'tokens', 'tokPerSec', 'e2eCharsPerSec'];\r\n\r\nconst REF_RUNTIMES = {\r\n 'tfjs-wasm-q8': { device: 'wasm', dtype: 'q8' },\r\n 'tfjs-webgpu-fp16': { device: 'webgpu', dtype: 'fp16' },\r\n};\r\n\r\n// Runs the full matrix. Returns rows:\r\n// {runtime:'webmt', preset, batch, repeats:[{encoderMs, decodeMs, tokens,\r\n// submits, tokPerSec, e2eCharsPerSec}...], median:{...}, min:{tokPerSec,\r\n// e2eCharsPerSec}, max:{...}}\r\n// `batches` is either one array (all presets) or a per-preset map\r\n// {preset: [sizes]}. Sizes above the device binding limit (maxBatchForLimits\r\n// at the preset's longest-chunk bucket) are clamped to the max usable batch —\r\n// clamped rows carry `requestedBatch`.\r\n// Reference rows (includeReference) run ONCE each (they are slow):\r\n// {runtime:'tfjs-wasm-q8'|'tfjs-webgpu-fp16', preset, batch, repeats:[one],\r\n// median:{...}} or {..., error} if the runtime failed to load/run.\r\n// referenceCells [{runtime, preset, batch}...] picks exact cells; the default\r\n// preserves the old behavior (both runtimes × referencePresets × b1/b4).\r\nexport async function runBenchMatrix(ctx, weights, tok, {\r\n presets = ['short32', 'chapter3k'],\r\n batches = [1, 4, 8, 16],\r\n repeats = 3,\r\n includeReference = false,\r\n referencePresets = presets,\r\n referenceBatches = [1, 4],\r\n referenceCells = Object.keys(REF_RUNTIMES).flatMap((runtime) =>\r\n referencePresets.flatMap((preset) =>\r\n referenceBatches.map((batch) => ({ runtime, preset, batch })))),\r\n tuned = null,\r\n engineOptions = {},\r\n onStatus = () => {},\r\n} = {}) {\r\n const rows = [];\r\n const ordered = Object.fromEntries(\r\n presets.map((p) => [p, byLengthDesc(presetChunks(p))]),\r\n );\r\n const batchesFor = (preset) => (Array.isArray(batches) ? batches : batches[preset]);\r\n\r\n // Clamp a preset's batch list to what the device binding limit allows. S for\r\n // the guard = the bucket of the preset's LONGEST chunk (chunks are grouped\r\n // longest-first, so the first group is the worst case).\r\n const dtypeBytes = weights.dtype === 'f16' ? 2 : 4;\r\n const clampedBatches = async (preset) => {\r\n const ids = tok.encode(ordered[preset][0]);\r\n const maxBatch = maxBatchForLimits(ctx, bucketFor(ids.length), dtypeBytes);\r\n const list = [];\r\n for (const b of batchesFor(preset)) {\r\n const clamped = Math.min(b, maxBatch);\r\n if (clamped !== b) onStatus(`${preset}: batch ${b} clamped to device max ${clamped}`);\r\n if (!list.some((x) => x.batch === clamped)) {\r\n list.push({ batch: clamped, ...(clamped !== b ? { requestedBatch: b } : {}) });\r\n }\r\n }\r\n return list;\r\n };\r\n\r\n // One warmup before the first cell only: primes pipeline caches / GPU\r\n // clocks so repeat 1 of cell 1 is not an outlier. Uses the CLAMPED batch so\r\n // the warmup itself cannot exceed the device limit on smaller GPUs.\r\n onStatus('warmup…');\r\n await runEngineOnce(ctx, weights, tok, ordered[presets[0]],\r\n (await clampedBatches(presets[0]))[0].batch, tuned, engineOptions);\r\n\r\n for (const preset of presets) {\r\n for (const { batch, requestedBatch } of await clampedBatches(preset)) {\r\n const reps = [];\r\n for (let r = 0; r < repeats; r++) {\r\n onStatus(`webmt ${preset} b${batch} repeat ${r + 1}/${repeats}…`);\r\n reps.push(await runEngineOnce(\r\n ctx, weights, tok, ordered[preset], batch, tuned, engineOptions,\r\n ));\r\n }\r\n const med = Object.fromEntries(\r\n MEDIAN_FIELDS.map((f) => [f, round1(median(reps.map((x) => x[f])))]),\r\n );\r\n rows.push({\r\n runtime: 'webmt',\r\n preset,\r\n batch,\r\n ...(requestedBatch ? { requestedBatch } : {}),\r\n repeats: reps,\r\n median: med,\r\n min: {\r\n tokPerSec: Math.min(...reps.map((x) => x.tokPerSec)),\r\n e2eCharsPerSec: Math.min(...reps.map((x) => x.e2eCharsPerSec)),\r\n },\r\n max: {\r\n tokPerSec: Math.max(...reps.map((x) => x.tokPerSec)),\r\n e2eCharsPerSec: Math.max(...reps.map((x) => x.e2eCharsPerSec)),\r\n },\r\n });\r\n }\r\n }\r\n\r\n if (includeReference) {\r\n const { runReference } = await import('./reference.js');\r\n for (const { runtime, preset, batch } of referenceCells) {\r\n const { device, dtype } = REF_RUNTIMES[runtime] ?? {};\r\n if (!device) throw new Error(`unknown reference runtime: ${runtime}`);\r\n const chunks = ordered[preset] ?? byLengthDesc(presetChunks(preset));\r\n onStatus(`${runtime} ${preset} b${batch} (single run)…`);\r\n try {\r\n const res = await runReference({\r\n device, dtype, sources: chunks, batchSize: batch,\r\n onStatus: (msg) => onStatus(`${runtime} ${preset} b${batch}: ${msg}`),\r\n });\r\n const entry = {\r\n loadMs: Math.round(res.loadMs),\r\n translateMs: Math.round(res.translateMs),\r\n tokens: res.tokens,\r\n tokPerSec: round1(res.tokPerSec),\r\n // ORT's generate() interleaves encoder+decoder inside\r\n // translateMs, so its chars/s is already end-to-end.\r\n e2eCharsPerSec: round1(res.charsPerSec),\r\n };\r\n rows.push({ runtime, preset, batch, repeats: [entry], median: entry });\r\n } catch (err) {\r\n rows.push({ runtime, preset, batch, error: String(err?.message ?? err) });\r\n }\r\n }\r\n }\r\n\r\n return rows;\r\n}\r\n\r\nexport function buildReport(rows, adapterInfo, { date, stack } = {}) {\r\n // Local calendar date, not UTC — a run before 07:00 Asia/Bangkok would\r\n // otherwise be stamped with yesterday's date.\r\n const d = new Date();\r\n const localDate = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;\r\n return {\r\n schema: 'webmt-bench-v1',\r\n date: date ?? localDate,\r\n adapterInfo,\r\n // stack: what was actually measured — {shortlist: n|0, autotune:\r\n // 'measured'|'partial'|'off', tuned} — so a report is self-describing\r\n // (pre-2026-07-10 reports without it ran full-vocab + plain 'auto').\r\n ...(stack ? { stack } : {}),\r\n baselineRef: 'docs/bench/baseline.json',\r\n runs: rows,\r\n };\r\n}\r\n"],"file":"bench-CEDJ-mff.js"}
 
1
+ {"version":3,"mappings":"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","names":["splitText","text","maxChars","lines","chunks","plan","limit","sentenceRe","rawLine","line","pieces","current","indexes","pushCurrent","piece","i","EXTRA_SHORT","presetChunks","name","goldenSources","chapterText","base","byLengthDesc","a","b","round1","x","median","values","s","mid","runEngineOnce","ctx","weights","tok","orderedChunks","batch","tuned","engineOptions","encoderMs","decodeMs","tokens","submits","dispatch","group","metrics","translateBatch","tunedOptions","field","srcChars","n","c","MEDIAN_FIELDS","REF_RUNTIMES","runBenchMatrix","presets","batches","repeats","includeReference","referencePresets","referenceBatches","referenceCells","runtime","preset","onStatus","rows","ordered","p","batchesFor","dtypeBytes","clampedBatches","ids","maxBatch","maxBatchForLimits","bucketFor","list","clamped","requestedBatch","reps","r","med","f","runReference","__vitePreload","device","dtype","res","msg","entry","err","buildReport","adapterInfo","date","stack","d","localDate"],"ignoreList":[],"sources":["../../src/bench/chunk.js","../../src/bench/bench.js"],"sourcesContent":["// Text chunker, ported EXACTLY from the old app's worker\r\n// (moxhimt30-browser/src/worker/translator.worker.js) so the chapter benchmark\r\n// exercises the same chunk-size distribution the shipped app produces.\r\n//\r\n// splitText: newline → lines; each line split by the CJK/latin sentence regex,\r\n// sentences accumulated up to `maxChars` (clamped to ≥80, default 220);\r\n// oversized single sentences hard-split at the limit. Empty lines become a\r\n// null plan entry. Returns {chunks, plan} where plan[i] is the list of chunk\r\n// indexes for line i (null for blank lines).\r\nexport function splitText(text, maxChars = 220) {\r\n const lines = String(text || '').replace(/\\r\\n/g, '\\n').split('\\n');\r\n const chunks = [];\r\n const plan = [];\r\n const limit = Math.max(80, Number(maxChars) || 220);\r\n const sentenceRe = /[^。!?!?;;]+[。!?!?;;]*/g;\r\n\r\n for (const rawLine of lines) {\r\n const line = rawLine.trim();\r\n if (!line) {\r\n plan.push(null);\r\n continue;\r\n }\r\n const pieces = line.match(sentenceRe) || [line];\r\n let current = '';\r\n const indexes = [];\r\n const pushCurrent = () => {\r\n if (!current) return;\r\n indexes.push(chunks.length);\r\n chunks.push(current);\r\n current = '';\r\n };\r\n\r\n for (const piece of pieces) {\r\n if (piece.length > limit) {\r\n pushCurrent();\r\n for (let i = 0; i < piece.length; i += limit) {\r\n indexes.push(chunks.length);\r\n chunks.push(piece.slice(i, i + limit));\r\n }\r\n continue;\r\n }\r\n if (current && (current + piece).length > limit) {\r\n pushCurrent();\r\n }\r\n current += piece;\r\n }\r\n pushCurrent();\r\n plan.push(indexes);\r\n }\r\n return { chunks, plan };\r\n}\r\n\r\n// Reassemble translated chunks per the plan: chunks of one source line join\r\n// with ' ', lines join with '\\n', blank lines come back as ''.\r\nexport function joinChunks(translated, plan) {\r\n return plan.map((indexes) => {\r\n if (indexes === null) return '';\r\n return indexes.map((idx) => translated[idx]).filter(Boolean).join(' ');\r\n }).join('\\n');\r\n}\r\n","// M5 benchmark matrix: engine (webmt) across preset × batch, plus optional\r\n// Transformers.js reference rows, exported as a webmt-bench-v1 report.\r\n//\r\n// Metric semantics (documented, deliberate):\r\n// tokPerSec tokens / Σ decodeMs — DECODE-ONLY throughput, the kernel\r\n// story; comparable with m3/m4 numbers and baseline tok/s.\r\n// e2eCharsPerSec source chars / Σ(encoderMs + decodeMs) — the honest\r\n// end-user number: encoder + full decode loop including all\r\n// per-group readbacks (decodeMs contains mapAsync waits).\r\n// Excludes tokenize/detokenize JS (sub-ms per chunk).\r\n//\r\n// Batching hygiene: chunks are ordered LONGEST-FIRST before grouping into\r\n// translateBatch calls (mirrors the old worker's sortedChunkJobs) so a group\r\n// holds similar-length rows — padding and per-group decode caps are set by\r\n// the longest row, so mixing lengths wastes steps on the short rows.\r\nimport { translateBatch } from '../engine/generate.js';\r\nimport { tunedOptions } from '../engine/autotune.js';\r\nimport { maxBatchForLimits, bucketFor } from '../engine/shapes.js';\r\n// reference.js pulls in transformers.js + ORT (~24MB with the wasm) — loaded\r\n// on demand so plain engine benches never fetch it.\r\nimport { splitText } from './chunk.js';\r\nimport goldenSources from '../../fixtures/golden_sources.json';\r\nimport chapterText from '../../fixtures/chapter3k.txt?raw';\r\n\r\n// 17 extra short sentences (same wuxia register as golden_sources' first 15)\r\n// to bring the short preset to 32.\r\nconst EXTRA_SHORT = [\r\n '刀出如龙,寒气逼人。',\r\n '他在桥头站了一夜。',\r\n '“放下剑,我饶你不死。”',\r\n '钟声响起,山门缓缓开启。',\r\n '她的暗器从不落空。',\r\n '灯火摇曳,人影散乱。',\r\n '一杯酒,敬当年的兄弟。',\r\n '掌风过处,烛火尽灭。',\r\n '他背上的伤疤又开始疼了。',\r\n '“来者何人,报上名来!”',\r\n '雪落无声,剑亦无声。',\r\n '这条路,他走了半生。',\r\n '密道尽头透出一线微光。',\r\n '恩人一诺,死生不忘。',\r\n '毒发之时,他咬碎了牙关。',\r\n '旗帜倒下,城头易主。',\r\n '江水东流,带不走旧恨。',\r\n];\r\n\r\n// Preset name → chunk list. short32 = first 15 golden short sources + 17\r\n// extras; chapter3k = the fixture chapter through the ported app chunker;\r\n// file23k = the chapter3k chunk list repeated 8× (152 chunks, ~23k chars) —\r\n// simulates translating a real .txt file, where large batches actually fill.\r\nexport function presetChunks(name) {\r\n if (name === 'short32') return [...goldenSources.slice(0, 15), ...EXTRA_SHORT];\r\n if (name === 'chapter3k') return splitText(chapterText).chunks;\r\n if (name === 'file23k') {\r\n const base = splitText(chapterText).chunks;\r\n return Array.from({ length: 8 }, () => base).flat();\r\n }\r\n throw new Error(`unknown preset: ${name}`);\r\n}\r\n\r\nconst byLengthDesc = (chunks) => [...chunks].sort((a, b) => b.length - a.length);\r\nconst round1 = (x) => Number(x.toFixed(1));\r\n\r\nfunction median(values) {\r\n const s = [...values].sort((a, b) => a - b);\r\n const mid = s.length >> 1;\r\n return s.length % 2 ? s[mid] : (s[mid - 1] + s[mid]) / 2;\r\n}\r\n\r\n// One engine measurement of a preset at a batch size: sequential\r\n// translateBatch calls over longest-first groups of `batch` chunks.\r\n// `tuned` (a routing table from autotuneRouting) resolves per group like the\r\n// app's translateText does; null keeps decoder.js 'auto' — the kernel floor.\r\nasync function runEngineOnce(ctx, weights, tok, orderedChunks, batch, tuned = null, engineOptions = {}) {\r\n let encoderMs = 0;\r\n let decodeMs = 0;\r\n let tokens = 0;\r\n let submits = 0;\r\n const dispatch = {\r\n uniformBuffersCreated: 0, dummyBuffersCreated: 0, bindGroupsCreated: 0,\r\n bindGroupCacheHits: 0, bindGroupEvictions: 0, immediateSets: 0,\r\n };\r\n for (let i = 0; i < orderedChunks.length; i += batch) {\r\n const group = orderedChunks.slice(i, i + batch);\r\n const { metrics } = await translateBatch(ctx, weights, tok, group,\r\n { ...tunedOptions(tuned, group.length), ...engineOptions });\r\n encoderMs += metrics.encoderMs;\r\n decodeMs += metrics.decodeMs;\r\n tokens += metrics.tokensGenerated;\r\n submits += metrics.submits;\r\n for (const field of Object.keys(dispatch)) dispatch[field] += metrics.dispatch?.[field] ?? 0;\r\n }\r\n const srcChars = orderedChunks.reduce((n, c) => n + c.length, 0);\r\n return {\r\n encoderMs: round1(encoderMs),\r\n decodeMs: round1(decodeMs),\r\n tokens,\r\n submits,\r\n dispatch,\r\n tokPerSec: round1((tokens / decodeMs) * 1000),\r\n e2eCharsPerSec: round1((srcChars / (encoderMs + decodeMs)) * 1000),\r\n };\r\n}\r\n\r\nconst MEDIAN_FIELDS = ['encoderMs', 'decodeMs', 'tokens', 'tokPerSec', 'e2eCharsPerSec'];\r\n\r\nconst REF_RUNTIMES = {\r\n 'tfjs-wasm-q8': { device: 'wasm', dtype: 'q8' },\r\n 'tfjs-webgpu-fp16': { device: 'webgpu', dtype: 'fp16' },\r\n};\r\n\r\n// Runs the full matrix. Returns rows:\r\n// {runtime:'webmt', preset, batch, repeats:[{encoderMs, decodeMs, tokens,\r\n// submits, tokPerSec, e2eCharsPerSec}...], median:{...}, min:{tokPerSec,\r\n// e2eCharsPerSec}, max:{...}}\r\n// `batches` is either one array (all presets) or a per-preset map\r\n// {preset: [sizes]}. Sizes above the device binding limit (maxBatchForLimits\r\n// at the preset's longest-chunk bucket) are clamped to the max usable batch —\r\n// clamped rows carry `requestedBatch`.\r\n// Reference rows (includeReference) run ONCE each (they are slow):\r\n// {runtime:'tfjs-wasm-q8'|'tfjs-webgpu-fp16', preset, batch, repeats:[one],\r\n// median:{...}} or {..., error} if the runtime failed to load/run.\r\n// referenceCells [{runtime, preset, batch}...] picks exact cells; the default\r\n// preserves the old behavior (both runtimes × referencePresets × b1/b4).\r\nexport async function runBenchMatrix(ctx, weights, tok, {\r\n presets = ['short32', 'chapter3k'],\r\n batches = [1, 4, 8, 16],\r\n repeats = 3,\r\n includeReference = false,\r\n referencePresets = presets,\r\n referenceBatches = [1, 4],\r\n referenceCells = Object.keys(REF_RUNTIMES).flatMap((runtime) =>\r\n referencePresets.flatMap((preset) =>\r\n referenceBatches.map((batch) => ({ runtime, preset, batch })))),\r\n tuned = null,\r\n engineOptions = {},\r\n onStatus = () => {},\r\n} = {}) {\r\n const rows = [];\r\n const ordered = Object.fromEntries(\r\n presets.map((p) => [p, byLengthDesc(presetChunks(p))]),\r\n );\r\n const batchesFor = (preset) => (Array.isArray(batches) ? batches : batches[preset]);\r\n\r\n // Clamp a preset's batch list to what the device binding limit allows. S for\r\n // the guard = the bucket of the preset's LONGEST chunk (chunks are grouped\r\n // longest-first, so the first group is the worst case).\r\n const dtypeBytes = weights.dtype === 'f16' ? 2 : 4;\r\n const clampedBatches = async (preset) => {\r\n const ids = tok.encode(ordered[preset][0]);\r\n const maxBatch = maxBatchForLimits(ctx, bucketFor(ids.length), dtypeBytes);\r\n const list = [];\r\n for (const b of batchesFor(preset)) {\r\n const clamped = Math.min(b, maxBatch);\r\n if (clamped !== b) onStatus(`${preset}: batch ${b} clamped to device max ${clamped}`);\r\n if (!list.some((x) => x.batch === clamped)) {\r\n list.push({ batch: clamped, ...(clamped !== b ? { requestedBatch: b } : {}) });\r\n }\r\n }\r\n return list;\r\n };\r\n\r\n // One warmup before the first cell only: primes pipeline caches / GPU\r\n // clocks so repeat 1 of cell 1 is not an outlier. Uses the CLAMPED batch so\r\n // the warmup itself cannot exceed the device limit on smaller GPUs.\r\n onStatus('warmup…');\r\n await runEngineOnce(ctx, weights, tok, ordered[presets[0]],\r\n (await clampedBatches(presets[0]))[0].batch, tuned, engineOptions);\r\n\r\n for (const preset of presets) {\r\n for (const { batch, requestedBatch } of await clampedBatches(preset)) {\r\n const reps = [];\r\n for (let r = 0; r < repeats; r++) {\r\n onStatus(`webmt ${preset} b${batch} repeat ${r + 1}/${repeats}…`);\r\n reps.push(await runEngineOnce(\r\n ctx, weights, tok, ordered[preset], batch, tuned, engineOptions,\r\n ));\r\n }\r\n const med = Object.fromEntries(\r\n MEDIAN_FIELDS.map((f) => [f, round1(median(reps.map((x) => x[f])))]),\r\n );\r\n rows.push({\r\n runtime: 'webmt',\r\n preset,\r\n batch,\r\n ...(requestedBatch ? { requestedBatch } : {}),\r\n repeats: reps,\r\n median: med,\r\n min: {\r\n tokPerSec: Math.min(...reps.map((x) => x.tokPerSec)),\r\n e2eCharsPerSec: Math.min(...reps.map((x) => x.e2eCharsPerSec)),\r\n },\r\n max: {\r\n tokPerSec: Math.max(...reps.map((x) => x.tokPerSec)),\r\n e2eCharsPerSec: Math.max(...reps.map((x) => x.e2eCharsPerSec)),\r\n },\r\n });\r\n }\r\n }\r\n\r\n if (includeReference) {\r\n const { runReference } = await import('./reference.js');\r\n for (const { runtime, preset, batch } of referenceCells) {\r\n const { device, dtype } = REF_RUNTIMES[runtime] ?? {};\r\n if (!device) throw new Error(`unknown reference runtime: ${runtime}`);\r\n const chunks = ordered[preset] ?? byLengthDesc(presetChunks(preset));\r\n onStatus(`${runtime} ${preset} b${batch} (single run)…`);\r\n try {\r\n const res = await runReference({\r\n device, dtype, sources: chunks, batchSize: batch,\r\n onStatus: (msg) => onStatus(`${runtime} ${preset} b${batch}: ${msg}`),\r\n });\r\n const entry = {\r\n loadMs: Math.round(res.loadMs),\r\n translateMs: Math.round(res.translateMs),\r\n tokens: res.tokens,\r\n tokPerSec: round1(res.tokPerSec),\r\n // ORT's generate() interleaves encoder+decoder inside\r\n // translateMs, so its chars/s is already end-to-end.\r\n e2eCharsPerSec: round1(res.charsPerSec),\r\n };\r\n rows.push({ runtime, preset, batch, repeats: [entry], median: entry });\r\n } catch (err) {\r\n rows.push({ runtime, preset, batch, error: String(err?.message ?? err) });\r\n }\r\n }\r\n }\r\n\r\n return rows;\r\n}\r\n\r\nexport function buildReport(rows, adapterInfo, { date, stack } = {}) {\r\n // Local calendar date, not UTC — a run before 07:00 Asia/Bangkok would\r\n // otherwise be stamped with yesterday's date.\r\n const d = new Date();\r\n const localDate = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;\r\n return {\r\n schema: 'webmt-bench-v1',\r\n date: date ?? localDate,\r\n adapterInfo,\r\n // stack: what was actually measured — {shortlist: n|0, autotune:\r\n // 'measured'|'partial'|'off', tuned} — so a report is self-describing\r\n // (pre-2026-07-10 reports without it ran full-vocab + plain 'auto').\r\n ...(stack ? { stack } : {}),\r\n baselineRef: 'docs/bench/baseline.json',\r\n runs: rows,\r\n };\r\n}\r\n"],"file":"bench-BarR4Zp5.js"}
assets/{bench-D8r1wO6A.js → bench-D3sid5uF.js} RENAMED
@@ -1,4 +1,4 @@
1
- import"./modulepreload-polyfill-B5Qt9EMX.js";import{initDevice as v}from"./device-BotbBNoe.js";import{l as L}from"./weights-D8qtuKag.js";import{l as R}from"./tokenizer-Ex1u7wXD.js";import{t as T}from"./generate-BIP3NpbY.js";import{e as E}from"./shortlist-C151mR5c.js";import{autotuneRouting as q,tunedOptions as I}from"./autotune-DywP5DSc.js";import{c as B}from"./verify-HJ8NImMM.js";import{r as P,b as O}from"./bench-CEDJ-mff.js";import{g}from"./golden-D7gAaNSE.js";import"./shapes-BCQ9D81L.js";import"./constants-C8VbFpic.js";import"./f16-wKKZr58e.js";import"./encoder-I9sHImnR.js";import"./pipelines-DJ7cc1m-.js";import"./decoder-CI9o-EVx.js";import"./preload-helper-BXl3LOEh.js";import"./chapter3k-DSdzHZt5.js";const C=document.querySelector("#app");C.innerHTML=`
2
  <h1>webMT bench</h1>
3
  <p>
4
  <button id="load">Load engine</button>
@@ -26,4 +26,4 @@ ${s?.stack??""}`)}finally{b.disabled=!1}});let f=null;function A(e){const n=e.ru
26
  ${o}
27
  </table>`}$.addEventListener("click",async()=>{$.disabled=!0;const{ctx:e,weights:n,tok:i}=l;try{const o=await P(e,n,i,{includeReference:F.checked,referencePresets:["short32"],tuned:l.tuned,engineOptions:{immediates:l.immediates},onStatus:t=>{y.textContent=t}});f=O(o,e.adapterInfo,{stack:l.stack}),A(f),y.textContent="benchmark complete",w.disabled=!1}catch(o){y.textContent="",a(`BENCH FAILED: ${o?.message??o}
28
  ${o?.stack??""}`)}finally{$.disabled=!1}});w.addEventListener("click",()=>{if(!f)return;const e=new Blob([JSON.stringify(f,null,2)],{type:"application/json"}),n=document.createElement("a");n.href=URL.createObjectURL(e),n.download=`webmt-bench-${f.date}.json`,n.click(),URL.revokeObjectURL(n.href)});
29
- //# sourceMappingURL=bench-D8r1wO6A.js.map
 
1
+ import"./modulepreload-polyfill-B5Qt9EMX.js";import{initDevice as v}from"./device-BotbBNoe.js";import{l as L}from"./weights-DxIJF1EY.js";import{l as R}from"./tokenizer-BmI7pHmp.js";import{t as T}from"./generate-Ca3ORHiA.js";import{e as E}from"./shortlist-C151mR5c.js";import{autotuneRouting as q,tunedOptions as I}from"./autotune-Bwt_lWMv.js";import{c as B}from"./verify-6VYYmR5k.js";import{r as P,b as O}from"./bench-BarR4Zp5.js";import{g}from"./golden-D7gAaNSE.js";import"./shapes-ClGtK-ia.js";import"./constants-CSVWRdrh.js";import"./f16-wKKZr58e.js";import"./encoder-CZXKGzzg.js";import"./pipelines-BbLc75sB.js";import"./decoder-BUiaGDqb.js";import"./preload-helper-BXl3LOEh.js";import"./chapter3k-DSdzHZt5.js";const C=document.querySelector("#app");C.innerHTML=`
2
  <h1>webMT bench</h1>
3
  <p>
4
  <button id="load">Load engine</button>
 
26
  ${o}
27
  </table>`}$.addEventListener("click",async()=>{$.disabled=!0;const{ctx:e,weights:n,tok:i}=l;try{const o=await P(e,n,i,{includeReference:F.checked,referencePresets:["short32"],tuned:l.tuned,engineOptions:{immediates:l.immediates},onStatus:t=>{y.textContent=t}});f=O(o,e.adapterInfo,{stack:l.stack}),A(f),y.textContent="benchmark complete",w.disabled=!1}catch(o){y.textContent="",a(`BENCH FAILED: ${o?.message??o}
28
  ${o?.stack??""}`)}finally{$.disabled=!1}});w.addEventListener("click",()=>{if(!f)return;const e=new Blob([JSON.stringify(f,null,2)],{type:"application/json"}),n=document.createElement("a");n.href=URL.createObjectURL(e),n.download=`webmt-bench-${f.date}.json`,n.click(),URL.revokeObjectURL(n.href)});
29
+ //# sourceMappingURL=bench-D3sid5uF.js.map
assets/{bench-D8r1wO6A.js.map → bench-D3sid5uF.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"file":"bench-D8r1wO6A.js","sources":["../../src/bench-main.js"],"sourcesContent":["// Minimal Verify + Benchmark UI: load the engine, run the 30 golden sentences\r\n// through the SAME translateBatch/compareToGolden path the M3 gate uses, and\r\n// run the M5 benchmark matrix (optionally with Transformers.js reference\r\n// rows) with JSON export.\r\nimport { initDevice } from './engine/device.js';\r\nimport { loadWeights } from './engine/weights.js';\r\nimport { loadTokenizer } from './engine/tokenizer.js';\r\nimport { translateBatch } from './engine/generate.js';\r\nimport { emittableIds } from './engine/shortlist.js';\r\nimport { autotuneRouting, tunedOptions } from './engine/autotune.js';\r\nimport { compareToGolden } from './bench/verify.js';\r\nimport { runBenchMatrix, buildReport } from './bench/bench.js';\r\nimport golden from '../fixtures/golden.json';\r\n\r\nconst app = document.querySelector('#app');\r\napp.innerHTML = `\r\n <h1>webMT bench</h1>\r\n <p>\r\n <button id=\"load\">Load engine</button>\r\n <button id=\"verify\" disabled>Verify vs golden (30)</button>\r\n <button id=\"bench\" disabled>Benchmark</button>\r\n <label><input type=\"checkbox\" id=\"includeRef\"> Include reference runtimes</label>\r\n <button id=\"export\" disabled>Export JSON</button>\r\n </p>\r\n <p id=\"status\" style=\"color:#8bc\"></p>\r\n <div id=\"benchTable\"></div>\r\n <pre id=\"out\" style=\"white-space:pre-wrap\"></pre>\r\n`;\r\nconst loadBtn = document.querySelector('#load');\r\nconst verifyBtn = document.querySelector('#verify');\r\nconst benchBtn = document.querySelector('#bench');\r\nconst includeRef = document.querySelector('#includeRef');\r\nconst exportBtn = document.querySelector('#export');\r\nconst statusEl = document.querySelector('#status');\r\nconst benchTable = document.querySelector('#benchTable');\r\nconst out = document.querySelector('#out');\r\nconst log = (line) => { out.textContent += `${line}\\n`; };\r\n\r\nlet engine = null; // {ctx, weights, tok, tuned, stack}\r\n\r\nloadBtn.addEventListener('click', async () => {\r\n loadBtn.disabled = true;\r\n try {\r\n log('loading engine…');\r\n const ctx = await initDevice();\r\n const dtype = ctx.hasF16 ? 'f16' : 'f32';\r\n const params = new URLSearchParams(location.search);\r\n const immediates = params.get('immediates') === '0' ? 'off' : 'auto';\r\n // Mirror the production loader (app engine.js): tokenizer FIRST so the\r\n // q8 lm_head ships the emittable-ids shortlist. Same escape hatch as the\r\n // app: ?shortlist=0 measures the full-vocab kernel floor (what every\r\n // pre-2026-07-10 bench report measured).\r\n const tok = await loadTokenizer();\r\n const wantShort = params.get('shortlist') !== '0';\r\n const lmHeadIds = dtype === 'f16' && wantShort ? emittableIds(tok.idToToken) : null;\r\n // lmHeadQ8: int8 lm_head (W8A16) — the perf default for real use; quality\r\n // gated at 29/30 golden (q8_lmhead_golden), same bar as f16's m3 gate.\r\n const weights = await loadWeights(ctx.device, '/weights', {\r\n targetDtype: dtype, lmHeadQ8: dtype === 'f16', ffnWT: dtype === 'f16', projWT: dtype === 'f16',\r\n directQ8: params.get('directq8') !== '0',\r\n ...(lmHeadIds ? { lmHeadIds } : {}),\r\n });\r\n // Mirror production routing: measure this device instead of running the\r\n // NVIDIA-tuned 'auto' thresholds (~1s dGPU, ~4-8s iGPU/phone, fresh each\r\n // load — the bench never reads the app's localStorage cache). ?tune=0\r\n // keeps plain 'auto' for kernel-floor comparisons.\r\n let tuned = null;\r\n let autotune = 'off';\r\n if (params.get('tune') !== '0') {\r\n log('autotuning routing on this device…');\r\n const r = await autotuneRouting({ ...ctx, dtype }, weights, { immediates });\r\n tuned = r.tuned;\r\n autotune = r.partial ? 'partial' : 'measured';\r\n if (r.partial) log(`autotune partial (${r.partial}) — defaults + correctness verdicts only`);\r\n }\r\n const stack = {\r\n shortlist: lmHeadIds ? lmHeadIds.length : 0,\r\n autotune,\r\n tuned,\r\n directQ8: weights.q8Stats.directTensors > 0,\r\n q8Stats: weights.q8Stats,\r\n immediates: immediates === 'auto' && ctx.hasImmediates ? 'on' : 'off',\r\n };\r\n engine = { ctx: { ...ctx, dtype }, weights, tok, tuned, stack, immediates };\r\n log(`engine ready: ${ctx.adapterInfo.description || ctx.adapterInfo.vendor} (${dtype}, `\r\n + `${lmHeadIds ? `shortlist ${lmHeadIds.length}` : 'full vocab'}, autotune ${autotune})`);\r\n if (tuned) log(`tuned: ${JSON.stringify(tuned)}`);\r\n verifyBtn.disabled = false;\r\n benchBtn.disabled = false;\r\n } catch (err) {\r\n log(`LOAD FAILED: ${err?.message ?? err}`);\r\n loadBtn.disabled = false;\r\n }\r\n});\r\n\r\nverifyBtn.addEventListener('click', async () => {\r\n verifyBtn.disabled = true;\r\n const { ctx, weights, tok } = engine;\r\n let exact = 0;\r\n let forcedEos = 0;\r\n let mismatches = 0;\r\n let tokPerSecSum = 0;\r\n try {\r\n for (let i = 0; i < golden.items.length; i++) {\r\n const item = golden.items[i];\r\n const { rows, metrics } = await translateBatch(ctx, weights, tok, [item.source],\r\n {\r\n maxNewTokens: item.maxNewTokens,\r\n ...tunedOptions(engine.tuned, 1),\r\n immediates: engine.immediates,\r\n });\r\n tokPerSecSum += metrics.tokPerSec;\r\n const cmp = compareToGolden(rows[0].ids, item.ids);\r\n if (cmp.verdict === 'exact') exact++;\r\n else if (cmp.verdict === 'forced-eos') forcedEos++;\r\n else mismatches++;\r\n log(`[${String(i).padStart(2)}] ${cmp.verdict.toUpperCase().padEnd(10)} ` +\r\n `${metrics.tokPerSec.toFixed(0)} tok/s ${item.source}`);\r\n if (cmp.verdict === 'mismatch') {\r\n log(` step ${cmp.step}`);\r\n log(` engine: ${rows[0].text}`);\r\n log(` golden: ${item.text}`);\r\n }\r\n }\r\n const total = golden.items.length;\r\n const need = Math.ceil(0.95 * total);\r\n const ok = exact + forcedEos >= need;\r\n log(`\\n${ok ? 'PASS' : 'FAIL'}: exact=${exact} forced-eos=${forcedEos} ` +\r\n `mismatch=${mismatches} (need ${need}/${total}) ` +\r\n `avg ${(tokPerSecSum / total).toFixed(1)} tok/s @ batch=1`);\r\n } catch (err) {\r\n log(`VERIFY FAILED: ${err?.message ?? err}\\n${err?.stack ?? ''}`);\r\n } finally {\r\n verifyBtn.disabled = false;\r\n }\r\n});\r\n\r\n// --- Benchmark matrix (M5) ---\r\nlet lastReport = null;\r\n\r\nfunction renderBenchTable(report) {\r\n const rows = report.runs;\r\n const range = (r, f) => (r.min ? ` (${r.min[f]}–${r.max[f]})` : '');\r\n const cells = rows.map((r) => r.error\r\n ? `<tr><td>${r.runtime}</td><td>${r.preset}</td><td>${r.batch}</td>\r\n <td colspan=\"4\" style=\"color:#f55\">ERROR: ${r.error}</td></tr>`\r\n : `<tr><td>${r.runtime}</td><td>${r.preset}</td><td>${r.batch}</td>\r\n <td>${r.median.tokPerSec}${range(r, 'tokPerSec')}</td>\r\n <td>${r.median.e2eCharsPerSec}${range(r, 'e2eCharsPerSec')}</td>\r\n <td>${r.median.tokens}</td>\r\n <td>${r.median.decodeMs ?? r.median.translateMs}</td></tr>`).join('');\r\n benchTable.innerHTML = `\r\n <table border=\"1\" cellpadding=\"4\" style=\"border-collapse:collapse\">\r\n <tr><th>runtime</th><th>preset</th><th>batch</th>\r\n <th>tok/s median (min–max)</th><th>chars/s median (min–max)</th>\r\n <th>tokens</th><th>decode ms</th></tr>\r\n ${cells}\r\n </table>`;\r\n}\r\n\r\nbenchBtn.addEventListener('click', async () => {\r\n benchBtn.disabled = true;\r\n const { ctx, weights, tok } = engine;\r\n try {\r\n const rows = await runBenchMatrix(ctx, weights, tok, {\r\n includeReference: includeRef.checked,\r\n referencePresets: ['short32'], // reference runtimes are minutes-slow on chapter3k\r\n tuned: engine.tuned,\r\n engineOptions: { immediates: engine.immediates },\r\n onStatus: (msg) => { statusEl.textContent = msg; },\r\n });\r\n lastReport = buildReport(rows, ctx.adapterInfo, { stack: engine.stack });\r\n renderBenchTable(lastReport);\r\n statusEl.textContent = 'benchmark complete';\r\n exportBtn.disabled = false;\r\n } catch (err) {\r\n statusEl.textContent = '';\r\n log(`BENCH FAILED: ${err?.message ?? err}\\n${err?.stack ?? ''}`);\r\n } finally {\r\n benchBtn.disabled = false;\r\n }\r\n});\r\n\r\nexportBtn.addEventListener('click', () => {\r\n if (!lastReport) return;\r\n const blob = new Blob([JSON.stringify(lastReport, null, 2)], { type: 'application/json' });\r\n const a = document.createElement('a');\r\n a.href = URL.createObjectURL(blob);\r\n a.download = `webmt-bench-${lastReport.date}.json`;\r\n a.click();\r\n URL.revokeObjectURL(a.href);\r\n});\r\n"],"names":["app","loadBtn","verifyBtn","benchBtn","includeRef","exportBtn","statusEl","benchTable","out","log","line","engine","ctx","initDevice","dtype","params","immediates","tok","loadTokenizer","wantShort","lmHeadIds","emittableIds","weights","loadWeights","tuned","autotune","autotuneRouting","stack","err","exact","forcedEos","mismatches","tokPerSecSum","i","golden","item","rows","metrics","translateBatch","tunedOptions","cmp","compareToGolden","total","need","ok","lastReport","renderBenchTable","report","range","r","f","cells","runBenchMatrix","msg","buildReport","blob","a"],"mappings":"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"}
 
1
+ {"version":3,"file":"bench-D3sid5uF.js","sources":["../../src/bench-main.js"],"sourcesContent":["// Minimal Verify + Benchmark UI: load the engine, run the 30 golden sentences\r\n// through the SAME translateBatch/compareToGolden path the M3 gate uses, and\r\n// run the M5 benchmark matrix (optionally with Transformers.js reference\r\n// rows) with JSON export.\r\nimport { initDevice } from './engine/device.js';\r\nimport { loadWeights } from './engine/weights.js';\r\nimport { loadTokenizer } from './engine/tokenizer.js';\r\nimport { translateBatch } from './engine/generate.js';\r\nimport { emittableIds } from './engine/shortlist.js';\r\nimport { autotuneRouting, tunedOptions } from './engine/autotune.js';\r\nimport { compareToGolden } from './bench/verify.js';\r\nimport { runBenchMatrix, buildReport } from './bench/bench.js';\r\nimport golden from '../fixtures/golden.json';\r\n\r\nconst app = document.querySelector('#app');\r\napp.innerHTML = `\r\n <h1>webMT bench</h1>\r\n <p>\r\n <button id=\"load\">Load engine</button>\r\n <button id=\"verify\" disabled>Verify vs golden (30)</button>\r\n <button id=\"bench\" disabled>Benchmark</button>\r\n <label><input type=\"checkbox\" id=\"includeRef\"> Include reference runtimes</label>\r\n <button id=\"export\" disabled>Export JSON</button>\r\n </p>\r\n <p id=\"status\" style=\"color:#8bc\"></p>\r\n <div id=\"benchTable\"></div>\r\n <pre id=\"out\" style=\"white-space:pre-wrap\"></pre>\r\n`;\r\nconst loadBtn = document.querySelector('#load');\r\nconst verifyBtn = document.querySelector('#verify');\r\nconst benchBtn = document.querySelector('#bench');\r\nconst includeRef = document.querySelector('#includeRef');\r\nconst exportBtn = document.querySelector('#export');\r\nconst statusEl = document.querySelector('#status');\r\nconst benchTable = document.querySelector('#benchTable');\r\nconst out = document.querySelector('#out');\r\nconst log = (line) => { out.textContent += `${line}\\n`; };\r\n\r\nlet engine = null; // {ctx, weights, tok, tuned, stack}\r\n\r\nloadBtn.addEventListener('click', async () => {\r\n loadBtn.disabled = true;\r\n try {\r\n log('loading engine…');\r\n const ctx = await initDevice();\r\n const dtype = ctx.hasF16 ? 'f16' : 'f32';\r\n const params = new URLSearchParams(location.search);\r\n const immediates = params.get('immediates') === '0' ? 'off' : 'auto';\r\n // Mirror the production loader (app engine.js): tokenizer FIRST so the\r\n // q8 lm_head ships the emittable-ids shortlist. Same escape hatch as the\r\n // app: ?shortlist=0 measures the full-vocab kernel floor (what every\r\n // pre-2026-07-10 bench report measured).\r\n const tok = await loadTokenizer();\r\n const wantShort = params.get('shortlist') !== '0';\r\n const lmHeadIds = dtype === 'f16' && wantShort ? emittableIds(tok.idToToken) : null;\r\n // lmHeadQ8: int8 lm_head (W8A16) — the perf default for real use; quality\r\n // gated at 29/30 golden (q8_lmhead_golden), same bar as f16's m3 gate.\r\n const weights = await loadWeights(ctx.device, '/weights', {\r\n targetDtype: dtype, lmHeadQ8: dtype === 'f16', ffnWT: dtype === 'f16', projWT: dtype === 'f16',\r\n directQ8: params.get('directq8') !== '0',\r\n ...(lmHeadIds ? { lmHeadIds } : {}),\r\n });\r\n // Mirror production routing: measure this device instead of running the\r\n // NVIDIA-tuned 'auto' thresholds (~1s dGPU, ~4-8s iGPU/phone, fresh each\r\n // load — the bench never reads the app's localStorage cache). ?tune=0\r\n // keeps plain 'auto' for kernel-floor comparisons.\r\n let tuned = null;\r\n let autotune = 'off';\r\n if (params.get('tune') !== '0') {\r\n log('autotuning routing on this device…');\r\n const r = await autotuneRouting({ ...ctx, dtype }, weights, { immediates });\r\n tuned = r.tuned;\r\n autotune = r.partial ? 'partial' : 'measured';\r\n if (r.partial) log(`autotune partial (${r.partial}) — defaults + correctness verdicts only`);\r\n }\r\n const stack = {\r\n shortlist: lmHeadIds ? lmHeadIds.length : 0,\r\n autotune,\r\n tuned,\r\n directQ8: weights.q8Stats.directTensors > 0,\r\n q8Stats: weights.q8Stats,\r\n immediates: immediates === 'auto' && ctx.hasImmediates ? 'on' : 'off',\r\n };\r\n engine = { ctx: { ...ctx, dtype }, weights, tok, tuned, stack, immediates };\r\n log(`engine ready: ${ctx.adapterInfo.description || ctx.adapterInfo.vendor} (${dtype}, `\r\n + `${lmHeadIds ? `shortlist ${lmHeadIds.length}` : 'full vocab'}, autotune ${autotune})`);\r\n if (tuned) log(`tuned: ${JSON.stringify(tuned)}`);\r\n verifyBtn.disabled = false;\r\n benchBtn.disabled = false;\r\n } catch (err) {\r\n log(`LOAD FAILED: ${err?.message ?? err}`);\r\n loadBtn.disabled = false;\r\n }\r\n});\r\n\r\nverifyBtn.addEventListener('click', async () => {\r\n verifyBtn.disabled = true;\r\n const { ctx, weights, tok } = engine;\r\n let exact = 0;\r\n let forcedEos = 0;\r\n let mismatches = 0;\r\n let tokPerSecSum = 0;\r\n try {\r\n for (let i = 0; i < golden.items.length; i++) {\r\n const item = golden.items[i];\r\n const { rows, metrics } = await translateBatch(ctx, weights, tok, [item.source],\r\n {\r\n maxNewTokens: item.maxNewTokens,\r\n ...tunedOptions(engine.tuned, 1),\r\n immediates: engine.immediates,\r\n });\r\n tokPerSecSum += metrics.tokPerSec;\r\n const cmp = compareToGolden(rows[0].ids, item.ids);\r\n if (cmp.verdict === 'exact') exact++;\r\n else if (cmp.verdict === 'forced-eos') forcedEos++;\r\n else mismatches++;\r\n log(`[${String(i).padStart(2)}] ${cmp.verdict.toUpperCase().padEnd(10)} ` +\r\n `${metrics.tokPerSec.toFixed(0)} tok/s ${item.source}`);\r\n if (cmp.verdict === 'mismatch') {\r\n log(` step ${cmp.step}`);\r\n log(` engine: ${rows[0].text}`);\r\n log(` golden: ${item.text}`);\r\n }\r\n }\r\n const total = golden.items.length;\r\n const need = Math.ceil(0.95 * total);\r\n const ok = exact + forcedEos >= need;\r\n log(`\\n${ok ? 'PASS' : 'FAIL'}: exact=${exact} forced-eos=${forcedEos} ` +\r\n `mismatch=${mismatches} (need ${need}/${total}) ` +\r\n `avg ${(tokPerSecSum / total).toFixed(1)} tok/s @ batch=1`);\r\n } catch (err) {\r\n log(`VERIFY FAILED: ${err?.message ?? err}\\n${err?.stack ?? ''}`);\r\n } finally {\r\n verifyBtn.disabled = false;\r\n }\r\n});\r\n\r\n// --- Benchmark matrix (M5) ---\r\nlet lastReport = null;\r\n\r\nfunction renderBenchTable(report) {\r\n const rows = report.runs;\r\n const range = (r, f) => (r.min ? ` (${r.min[f]}–${r.max[f]})` : '');\r\n const cells = rows.map((r) => r.error\r\n ? `<tr><td>${r.runtime}</td><td>${r.preset}</td><td>${r.batch}</td>\r\n <td colspan=\"4\" style=\"color:#f55\">ERROR: ${r.error}</td></tr>`\r\n : `<tr><td>${r.runtime}</td><td>${r.preset}</td><td>${r.batch}</td>\r\n <td>${r.median.tokPerSec}${range(r, 'tokPerSec')}</td>\r\n <td>${r.median.e2eCharsPerSec}${range(r, 'e2eCharsPerSec')}</td>\r\n <td>${r.median.tokens}</td>\r\n <td>${r.median.decodeMs ?? r.median.translateMs}</td></tr>`).join('');\r\n benchTable.innerHTML = `\r\n <table border=\"1\" cellpadding=\"4\" style=\"border-collapse:collapse\">\r\n <tr><th>runtime</th><th>preset</th><th>batch</th>\r\n <th>tok/s median (min–max)</th><th>chars/s median (min–max)</th>\r\n <th>tokens</th><th>decode ms</th></tr>\r\n ${cells}\r\n </table>`;\r\n}\r\n\r\nbenchBtn.addEventListener('click', async () => {\r\n benchBtn.disabled = true;\r\n const { ctx, weights, tok } = engine;\r\n try {\r\n const rows = await runBenchMatrix(ctx, weights, tok, {\r\n includeReference: includeRef.checked,\r\n referencePresets: ['short32'], // reference runtimes are minutes-slow on chapter3k\r\n tuned: engine.tuned,\r\n engineOptions: { immediates: engine.immediates },\r\n onStatus: (msg) => { statusEl.textContent = msg; },\r\n });\r\n lastReport = buildReport(rows, ctx.adapterInfo, { stack: engine.stack });\r\n renderBenchTable(lastReport);\r\n statusEl.textContent = 'benchmark complete';\r\n exportBtn.disabled = false;\r\n } catch (err) {\r\n statusEl.textContent = '';\r\n log(`BENCH FAILED: ${err?.message ?? err}\\n${err?.stack ?? ''}`);\r\n } finally {\r\n benchBtn.disabled = false;\r\n }\r\n});\r\n\r\nexportBtn.addEventListener('click', () => {\r\n if (!lastReport) return;\r\n const blob = new Blob([JSON.stringify(lastReport, null, 2)], { type: 'application/json' });\r\n const a = document.createElement('a');\r\n a.href = URL.createObjectURL(blob);\r\n a.download = `webmt-bench-${lastReport.date}.json`;\r\n a.click();\r\n URL.revokeObjectURL(a.href);\r\n});\r\n"],"names":["app","loadBtn","verifyBtn","benchBtn","includeRef","exportBtn","statusEl","benchTable","out","log","line","engine","ctx","initDevice","dtype","params","immediates","tok","loadTokenizer","wantShort","lmHeadIds","emittableIds","weights","loadWeights","tuned","autotune","autotuneRouting","stack","err","exact","forcedEos","mismatches","tokPerSecSum","i","golden","item","rows","metrics","translateBatch","tunedOptions","cmp","compareToGolden","total","need","ok","lastReport","renderBenchTable","report","range","r","f","cells","runBenchMatrix","msg","buildReport","blob","a"],"mappings":"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"}
assets/compact_equiv-DlvjNh2p.js DELETED
@@ -1,2 +0,0 @@
1
- import{r as w}from"./debug-C_LNzFrK.js";import{l as h}from"./weights-D8qtuKag.js";import{l as u}from"./tokenizer-Ex1u7wXD.js";import{t as d}from"./generate-BIP3NpbY.js";import{p as k}from"./bench-CEDJ-mff.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./shapes-BCQ9D81L.js";import"./constants-C8VbFpic.js";import"./f16-wKKZr58e.js";import"./encoder-I9sHImnR.js";import"./pipelines-DJ7cc1m-.js";import"./decoder-CI9o-EVx.js";import"./device-BotbBNoe.js";import"./autotune-DywP5DSc.js";import"./chapter3k-DSdzHZt5.js";w("compact_equiv",async s=>{const{device:n}=s,i=s.hasF16?"f16":"f32",r=await h(n,"/weights",{targetDtype:i});try{const p=await u(),f={device:n,dtype:i,limits:s.limits},c=k("file23k").slice(0,64),o=await d(f,r,p,c,{compact:!1}),e=await d(f,r,p,c,{compact:!0});let m=0,a=null;for(let t=0;t<o.rows.length;t++)o.rows[t].ids.join(",")!==e.rows[t].ids.join(",")&&(m++,a??={row:t,off:o.rows[t].ids.slice(0,12).join(","),on:e.rows[t].ids.slice(0,12).join(",")});const l=e.metrics.compactions;return{pass:m===0&&l>0,detail:{dtype:i,B:c.length,mismatchRows:m,compactions:l,...a?{firstMismatch:a}:{},offDecodeMs:Number(o.metrics.decodeMs.toFixed(1)),onDecodeMs:Number(e.metrics.decodeMs.toFixed(1)),offTokPerSec:Number(o.metrics.tokPerSec.toFixed(0)),onTokPerSec:Number(e.metrics.tokPerSec.toFixed(0)),steps:{off:o.metrics.steps,on:e.metrics.steps}}}}finally{r.buffer.destroy()}});
2
- //# sourceMappingURL=compact_equiv-DlvjNh2p.js.map
 
 
 
assets/compact_equiv-DlvjNh2p.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"compact_equiv-DlvjNh2p.js","sources":["../../src/debug/tests/compact_equiv.js"],"sourcesContent":["// EOS-compaction equivalence gate: translateBatch({compact: true}) must be\r\n// TOKEN-EXACT identical to {compact: false} on a ragged batch. Exactness is\r\n// by construction — compaction only moves rows (kernel routing is pinned\r\n// across the rebuild, per-row math never mixes rows) — so any diff is an\r\n// indexing bug in compactDecodeState (KV prefix, bitmask, ring seed, lens).\r\n//\r\n// Chunks are deliberately NOT length-sorted (unlike the bench) so rows hit\r\n// eos far apart and several compactions actually fire; the test fails if\r\n// none did (a policy regression would otherwise pass vacuously).\r\nimport { registerTest } from '../registry.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { loadTokenizer } from '../../engine/tokenizer.js';\r\nimport { translateBatch } from '../../engine/generate.js';\r\nimport { presetChunks } from '../../bench/bench.js';\r\n\r\nregisterTest('compact_equiv', async (ctx) => {\r\n const { device } = ctx;\r\n const dtype = ctx.hasF16 ? 'f16' : 'f32';\r\n const weights = await loadWeights(device, '/weights', { targetDtype: dtype });\r\n try {\r\n const tok = await loadTokenizer();\r\n const gctx = { device, dtype, limits: ctx.limits };\r\n const chunks = presetChunks('file23k').slice(0, 64);\r\n\r\n const off = await translateBatch(gctx, weights, tok, chunks, { compact: false });\r\n const on = await translateBatch(gctx, weights, tok, chunks, { compact: true });\r\n\r\n let mismatchRows = 0;\r\n let firstMismatch = null;\r\n for (let i = 0; i < off.rows.length; i++) {\r\n if (off.rows[i].ids.join(',') !== on.rows[i].ids.join(',')) {\r\n mismatchRows++;\r\n firstMismatch ??= {\r\n row: i,\r\n off: off.rows[i].ids.slice(0, 12).join(','),\r\n on: on.rows[i].ids.slice(0, 12).join(','),\r\n };\r\n }\r\n }\r\n const compactions = on.metrics.compactions;\r\n return {\r\n pass: mismatchRows === 0 && compactions > 0,\r\n detail: {\r\n dtype, B: chunks.length, mismatchRows, compactions,\r\n ...(firstMismatch ? { firstMismatch } : {}),\r\n offDecodeMs: Number(off.metrics.decodeMs.toFixed(1)),\r\n onDecodeMs: Number(on.metrics.decodeMs.toFixed(1)),\r\n offTokPerSec: Number(off.metrics.tokPerSec.toFixed(0)),\r\n onTokPerSec: Number(on.metrics.tokPerSec.toFixed(0)),\r\n steps: { off: off.metrics.steps, on: on.metrics.steps },\r\n },\r\n };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n});\r\n"],"names":["registerTest","ctx","device","dtype","weights","loadWeights","tok","loadTokenizer","gctx","chunks","presetChunks","off","translateBatch","on","mismatchRows","firstMismatch","i","compactions"],"mappings":"kjBAeAA,EAAa,gBAAiB,MAAOC,GAAQ,CAC3C,KAAM,CAAE,OAAAC,CAAM,EAAKD,EACbE,EAAQF,EAAI,OAAS,MAAQ,MAC7BG,EAAU,MAAMC,EAAYH,EAAQ,WAAY,CAAE,YAAaC,CAAK,CAAE,EAC5E,GAAI,CACF,MAAMG,EAAM,MAAMC,IACZC,EAAO,CAAE,OAAAN,EAAQ,MAAAC,EAAO,OAAQF,EAAI,QACpCQ,EAASC,EAAa,SAAS,EAAE,MAAM,EAAG,EAAE,EAE5CC,EAAM,MAAMC,EAAeJ,EAAMJ,EAASE,EAAKG,EAAQ,CAAE,QAAS,EAAK,CAAE,EACzEI,EAAK,MAAMD,EAAeJ,EAAMJ,EAASE,EAAKG,EAAQ,CAAE,QAAS,EAAI,CAAE,EAE7E,IAAIK,EAAe,EACfC,EAAgB,KACpB,QAASC,EAAI,EAAGA,EAAIL,EAAI,KAAK,OAAQK,IAC/BL,EAAI,KAAKK,CAAC,EAAE,IAAI,KAAK,GAAG,IAAMH,EAAG,KAAKG,CAAC,EAAE,IAAI,KAAK,GAAG,IACvDF,IACAC,IAAkB,CAChB,IAAKC,EACL,IAAKL,EAAI,KAAKK,CAAC,EAAE,IAAI,MAAM,EAAG,EAAE,EAAE,KAAK,GAAG,EAC1C,GAAIH,EAAG,KAAKG,CAAC,EAAE,IAAI,MAAM,EAAG,EAAE,EAAE,KAAK,GAAG,CAClD,GAGI,MAAMC,EAAcJ,EAAG,QAAQ,YAC/B,MAAO,CACL,KAAMC,IAAiB,GAAKG,EAAc,EAC1C,OAAQ,CACN,MAAAd,EAAO,EAAGM,EAAO,OAAQ,aAAAK,EAAc,YAAAG,EACvC,GAAIF,EAAgB,CAAE,cAAAA,CAAa,EAAK,GACxC,YAAa,OAAOJ,EAAI,QAAQ,SAAS,QAAQ,CAAC,CAAC,EACnD,WAAY,OAAOE,EAAG,QAAQ,SAAS,QAAQ,CAAC,CAAC,EACjD,aAAc,OAAOF,EAAI,QAAQ,UAAU,QAAQ,CAAC,CAAC,EACrD,YAAa,OAAOE,EAAG,QAAQ,UAAU,QAAQ,CAAC,CAAC,EACnD,MAAO,CAAE,IAAKF,EAAI,QAAQ,MAAO,GAAIE,EAAG,QAAQ,KAAK,CAC7D,CACA,CACE,QAAC,CACCT,EAAQ,OAAO,SACjB,CACF,CAAC"}
 
 
assets/compact_equiv-ehtvJC3N.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import{r as b}from"./debug-CPpXXfWA.js";import{l as y}from"./weights-DxIJF1EY.js";import{l as M}from"./tokenizer-BmI7pHmp.js";import{t as f}from"./generate-Ca3ORHiA.js";import{p as P}from"./bench-BarR4Zp5.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./safe_storage-BYkOahew.js";import"./shapes-ClGtK-ia.js";import"./constants-CSVWRdrh.js";import"./f16-wKKZr58e.js";import"./encoder-CZXKGzzg.js";import"./pipelines-BbLc75sB.js";import"./decoder-BUiaGDqb.js";import"./device-BotbBNoe.js";import"./autotune-Bwt_lWMv.js";import"./chapter3k-DSdzHZt5.js";b("compact_equiv",async r=>{const{device:d}=r,c=r.hasF16?"f16":"f32",s=await y(d,"/weights",{targetDtype:c});try{const m=await M(),a={device:d,dtype:c,limits:r.limits},i=P("file23k").slice(0,64),e=await f(a,s,m,i,{compact:!1}),g={realloc:await f(a,s,m,i,{compact:!0,inPlaceCompact:!1}),inplace:await f(a,s,m,i,{compact:!0,inPlaceCompact:!0})},u={};let p=!0;for(const[w,o]of Object.entries(g)){let n=0,l=null;for(let t=0;t<e.rows.length;t++)e.rows[t].ids.join(",")!==o.rows[t].ids.join(",")&&(n++,l??={row:t,off:e.rows[t].ids.slice(0,12).join(","),on:o.rows[t].ids.slice(0,12).join(",")});const{compactions:h,compactMode:k}=o.metrics;p=p&&n===0&&h>0&&k===w,u[w]={mismatchRows:n,compactions:h,compactMode:k,...l?{firstMismatch:l}:{},decodeMs:Number(o.metrics.decodeMs.toFixed(1)),tokPerSec:Number(o.metrics.tokPerSec.toFixed(0)),steps:o.metrics.steps}}return{pass:p,detail:{dtype:c,B:i.length,offDecodeMs:Number(e.metrics.decodeMs.toFixed(1)),offTokPerSec:Number(e.metrics.tokPerSec.toFixed(0)),offSteps:e.metrics.steps,...u}}}finally{s.buffer.destroy()}});
2
+ //# sourceMappingURL=compact_equiv-ehtvJC3N.js.map
assets/compact_equiv-ehtvJC3N.js.map ADDED
@@ -0,0 +1 @@
 
 
1
+ {"version":3,"file":"compact_equiv-ehtvJC3N.js","sources":["../../src/debug/tests/compact_equiv.js"],"sourcesContent":["// EOS-compaction equivalence gate: both rebuild and in-place mechanisms must\n// be TOKEN-EXACT against {compact:false} on a ragged batch. Any diff is an\n// indexing bug in KV prefixes, masks, ring stride/seed or source lenses.\n//\r\n// Chunks are deliberately NOT length-sorted (unlike the bench) so rows hit\r\n// eos far apart and several compactions actually fire; the test fails if\r\n// none did (a policy regression would otherwise pass vacuously).\r\nimport { registerTest } from '../registry.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { loadTokenizer } from '../../engine/tokenizer.js';\r\nimport { translateBatch } from '../../engine/generate.js';\r\nimport { presetChunks } from '../../bench/bench.js';\r\n\r\nregisterTest('compact_equiv', async (ctx) => {\r\n const { device } = ctx;\r\n const dtype = ctx.hasF16 ? 'f16' : 'f32';\r\n const weights = await loadWeights(device, '/weights', { targetDtype: dtype });\r\n try {\r\n const tok = await loadTokenizer();\r\n const gctx = { device, dtype, limits: ctx.limits };\r\n const chunks = presetChunks('file23k').slice(0, 64);\r\n\r\n const off = await translateBatch(gctx, weights, tok, chunks, { compact: false });\n const arms = {\n realloc: await translateBatch(gctx, weights, tok, chunks, {\n compact: true, inPlaceCompact: false,\n }),\n inplace: await translateBatch(gctx, weights, tok, chunks, {\n compact: true, inPlaceCompact: true,\n }),\n };\n\n const details = {};\n let pass = true;\n for (const [name, result] of Object.entries(arms)) {\n let mismatchRows = 0;\n let firstMismatch = null;\n for (let i = 0; i < off.rows.length; i++) {\n if (off.rows[i].ids.join(',') !== result.rows[i].ids.join(',')) {\n mismatchRows++;\n firstMismatch ??= {\n row: i,\n off: off.rows[i].ids.slice(0, 12).join(','),\n on: result.rows[i].ids.slice(0, 12).join(','),\n };\n }\n }\n const { compactions, compactMode } = result.metrics;\n pass = pass && mismatchRows === 0 && compactions > 0 && compactMode === name;\n details[name] = {\n mismatchRows, compactions, compactMode,\n ...(firstMismatch ? { firstMismatch } : {}),\n decodeMs: Number(result.metrics.decodeMs.toFixed(1)),\n tokPerSec: Number(result.metrics.tokPerSec.toFixed(0)),\n steps: result.metrics.steps,\n };\n }\n return {\n pass,\n detail: {\n dtype, B: chunks.length,\n offDecodeMs: Number(off.metrics.decodeMs.toFixed(1)),\n offTokPerSec: Number(off.metrics.tokPerSec.toFixed(0)),\n offSteps: off.metrics.steps,\n ...details,\n },\n };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n});\r\n"],"names":["registerTest","ctx","device","dtype","weights","loadWeights","tok","loadTokenizer","gctx","chunks","presetChunks","off","translateBatch","arms","details","pass","name","result","mismatchRows","firstMismatch","i","compactions","compactMode"],"mappings":"qlBAaAA,EAAa,gBAAiB,MAAOC,GAAQ,CAC3C,KAAM,CAAE,OAAAC,CAAM,EAAKD,EACbE,EAAQF,EAAI,OAAS,MAAQ,MAC7BG,EAAU,MAAMC,EAAYH,EAAQ,WAAY,CAAE,YAAaC,CAAK,CAAE,EAC5E,GAAI,CACF,MAAMG,EAAM,MAAMC,IACZC,EAAO,CAAE,OAAAN,EAAQ,MAAAC,EAAO,OAAQF,EAAI,QACpCQ,EAASC,EAAa,SAAS,EAAE,MAAM,EAAG,EAAE,EAE5CC,EAAM,MAAMC,EAAeJ,EAAMJ,EAASE,EAAKG,EAAQ,CAAE,QAAS,GAAO,EACzEI,EAAO,CACX,QAAS,MAAMD,EAAeJ,EAAMJ,EAASE,EAAKG,EAAQ,CACxD,QAAS,GAAM,eAAgB,EACvC,CAAO,EACD,QAAS,MAAMG,EAAeJ,EAAMJ,EAASE,EAAKG,EAAQ,CACxD,QAAS,GAAM,eAAgB,EACvC,CAAO,CACP,EAEUK,EAAU,CAAA,EAChB,IAAIC,EAAO,GACX,SAAW,CAACC,EAAMC,CAAM,IAAK,OAAO,QAAQJ,CAAI,EAAG,CACjD,IAAIK,EAAe,EACfC,EAAgB,KACpB,QAASC,EAAI,EAAGA,EAAIT,EAAI,KAAK,OAAQS,IAC/BT,EAAI,KAAKS,CAAC,EAAE,IAAI,KAAK,GAAG,IAAMH,EAAO,KAAKG,CAAC,EAAE,IAAI,KAAK,GAAG,IAC3DF,IACAC,IAAkB,CAChB,IAAKC,EACL,IAAKT,EAAI,KAAKS,CAAC,EAAE,IAAI,MAAM,EAAG,EAAE,EAAE,KAAK,GAAG,EAC1C,GAAIH,EAAO,KAAKG,CAAC,EAAE,IAAI,MAAM,EAAG,EAAE,EAAE,KAAK,GAAG,CACxD,GAGM,KAAM,CAAE,YAAAC,EAAa,YAAAC,CAAW,EAAKL,EAAO,QAC5CF,EAAOA,GAAQG,IAAiB,GAAKG,EAAc,GAAKC,IAAgBN,EACxEF,EAAQE,CAAI,EAAI,CACd,aAAAE,EAAc,YAAAG,EAAa,YAAAC,EAC3B,GAAIH,EAAgB,CAAE,cAAAA,CAAa,EAAK,GACxC,SAAU,OAAOF,EAAO,QAAQ,SAAS,QAAQ,CAAC,CAAC,EACnD,UAAW,OAAOA,EAAO,QAAQ,UAAU,QAAQ,CAAC,CAAC,EACrD,MAAOA,EAAO,QAAQ,KAC9B,CACI,CACA,MAAO,CACL,KAAAF,EACA,OAAQ,CACN,MAAAZ,EAAO,EAAGM,EAAO,OACjB,YAAa,OAAOE,EAAI,QAAQ,SAAS,QAAQ,CAAC,CAAC,EACnD,aAAc,OAAOA,EAAI,QAAQ,UAAU,QAAQ,CAAC,CAAC,EACrD,SAAUA,EAAI,QAAQ,MACtB,GAAGG,CACX,CACA,CACE,QAAC,CACCV,EAAQ,OAAO,SACjB,CACF,CAAC"}
assets/{constants-C8VbFpic.js → constants-CSVWRdrh.js} RENAMED
@@ -1,2 +1,2 @@
1
- let t,d,n,c,i,f,l,p,E,m,D,h,C,g,M,S,w,u;const L=1.2,r=["dModel","heads","headDim","ffn","encLayers","decLayers","vocab","maxPos","srcCap","decodeCap","eos","pad","decoderStart"];function A(a){if(!a||typeof a!="object")throw new Error("model config: not an object");const e={};for(const o of r){const s=a[o];if(!Number.isInteger(s)||s<0)throw new Error(`model config: ${o} must be a non-negative integer, got ${s}`);e[o]=s}for(const o of r.slice(0,10))if(e[o]===0)throw new Error(`model config: ${o} must be positive`);if(!(typeof a.lnEps=="number"&&a.lnEps>0&&a.lnEps<.1))throw new Error(`model config: lnEps must be in (0, 0.1), got ${a.lnEps}`);if(e.lnEps=a.lnEps,e.heads*e.headDim!==e.dModel)throw new Error(`model config: heads·headDim = ${e.heads*e.headDim} != dModel ${e.dModel}`);for(const o of["dModel","headDim","ffn"])if(e[o]%4!==0)throw new Error(`model config: ${o} = ${e[o]} must be a multiple of 4 (vec4 kernels)`);if(e.srcCap%32!==0)throw new Error(`model config: srcCap ${e.srcCap} must be a multiple of 32 (bucketFor invariant)`);if(e.srcCap>e.maxPos||e.decodeCap>e.maxPos)throw new Error(`model config: srcCap ${e.srcCap} / decodeCap ${e.decodeCap} must not exceed maxPos ${e.maxPos}`);for(const o of["eos","pad","decoderStart"])if(e[o]>=e.vocab)throw new Error(`model config: ${o} = ${e[o]} out of vocab ${e.vocab}`);return a.scaleEmbedding===!1&&(e.scaleEmbedding=!1),e.embedScale=e.scaleEmbedding===!1?1:Math.sqrt(e.dModel),e}let b=null;function v(){return{...b}}function P(a){const e=A(a);return b=e,t=e.dModel,d=e.heads,n=e.headDim,c=e.ffn,i=e.vocab,f=e.encLayers,l=e.decLayers,p=e.maxPos,E=e.srcCap,m=e.decodeCap,D=Math.ceil(Math.max(e.srcCap,e.decodeCap)/32)*32+32,h=e.eos,C=e.pad,g=e.decoderStart,M=e.lnEps,S=e.embedScale,w=1/Math.sqrt(e.headDim),u=Math.ceil(e.vocab/32),e}function $(a,e="weights"){const o=a??{};if(o.dModel!==t||o.heads!==d||o.headDim!==n||o.ffn!==c||o.vocab!==i||o.encLayers!==f||o.decLayers!==l||o.maxPos!==p||o.srcCap!==E||o.decodeCap!==m||o.eos!==h||o.pad!==C||o.decoderStart!==g)throw new Error(`${e} belong to a different model config than the active one — call applyModelConfig(weights.model) (loadWeights/uploadParsed do it) before dispatching`)}P({dModel:448,heads:8,headDim:56,ffn:1792,encLayers:8,decLayers:2,vocab:24e3,maxPos:512,srcCap:320,decodeCap:224,eos:2,pad:0,decoderStart:0,lnEps:1e-5});export{w as A,u as B,t as D,S as E,c as F,n as H,M as L,C as P,L as R,D as S,i as V,v as a,P as b,g as c,d,h as e,E as f,m as g,$ as h,f as i,l as j,A as p};
2
- //# sourceMappingURL=constants-C8VbFpic.js.map
 
1
+ let t,d,n,c,i,f,l,p,E,m,D,h,C,g,M,S,w,u;const L=1.2,r=["dModel","heads","headDim","ffn","encLayers","decLayers","vocab","maxPos","srcCap","decodeCap","eos","pad","decoderStart"];function A(a){if(!a||typeof a!="object")throw new Error("model config: not an object");const e={};for(const o of r){const s=a[o];if(!Number.isInteger(s)||s<0)throw new Error(`model config: ${o} must be a non-negative integer, got ${s}`);e[o]=s}for(const o of r.slice(0,10))if(e[o]===0)throw new Error(`model config: ${o} must be positive`);if(!(typeof a.lnEps=="number"&&a.lnEps>0&&a.lnEps<.1))throw new Error(`model config: lnEps must be in (0, 0.1), got ${a.lnEps}`);if(e.lnEps=a.lnEps,e.heads*e.headDim!==e.dModel)throw new Error(`model config: heads·headDim = ${e.heads*e.headDim} != dModel ${e.dModel}`);for(const o of["dModel","headDim","ffn"])if(e[o]%4!==0)throw new Error(`model config: ${o} = ${e[o]} must be a multiple of 4 (vec4 kernels)`);if(e.srcCap%32!==0)throw new Error(`model config: srcCap ${e.srcCap} must be a multiple of 32 (bucketFor invariant)`);if(e.srcCap>e.maxPos||e.decodeCap>e.maxPos)throw new Error(`model config: srcCap ${e.srcCap} / decodeCap ${e.decodeCap} must not exceed maxPos ${e.maxPos}`);for(const o of["eos","pad","decoderStart"])if(e[o]>=e.vocab)throw new Error(`model config: ${o} = ${e[o]} out of vocab ${e.vocab}`);return a.scaleEmbedding===!1&&(e.scaleEmbedding=!1),e.embedScale=e.scaleEmbedding===!1?1:Math.sqrt(e.dModel),e}let b=null;function v(){return{...b}}function P(a){const e=A(a);return b=e,t=e.dModel,d=e.heads,n=e.headDim,c=e.ffn,i=e.vocab,f=e.encLayers,l=e.decLayers,p=e.maxPos,E=e.srcCap,m=e.decodeCap,D=Math.ceil(Math.max(e.srcCap,e.decodeCap)/32)*32+32,h=e.eos,C=e.pad,g=e.decoderStart,M=e.lnEps,S=e.embedScale,w=1/Math.sqrt(e.headDim),u=Math.ceil(e.vocab/32),e}function $(a,e="weights"){const o=a??{};if(o.dModel!==t||o.heads!==d||o.headDim!==n||o.ffn!==c||o.vocab!==i||o.encLayers!==f||o.decLayers!==l||o.maxPos!==p||o.srcCap!==E||o.decodeCap!==m||o.eos!==h||o.pad!==C||o.decoderStart!==g)throw new Error(`${e} belong to a different model config than the active one — call applyModelConfig(weights.model) (loadWeights/uploadParsed do it) before dispatching`)}P({dModel:448,heads:8,headDim:56,ffn:1792,encLayers:8,decLayers:2,vocab:24e3,maxPos:512,srcCap:320,decodeCap:224,eos:2,pad:0,decoderStart:0,lnEps:1e-5});export{w as A,u as B,t as D,S as E,c as F,n as H,M as L,C as P,L as R,D as S,i as V,v as a,P as b,g as c,d,h as e,m as f,E as g,$ as h,f as i,l as j,A as p};
2
+ //# sourceMappingURL=constants-CSVWRdrh.js.map
assets/{constants-C8VbFpic.js.map → constants-CSVWRdrh.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"file":"constants-C8VbFpic.js","sources":["../../src/engine/constants.js"],"sourcesContent":["// Single source of numeric truth for the ACTIVE Marian model — shared by JS\r\n// reference math, engine code, and templated into WGSL kernels.\r\n//\r\n// The geometry lives in `let` bindings booted to MoxhiMT-30 and swapped by\r\n// applyModelConfig(manifest.model) when weights load (uploadParsed calls it),\r\n// so ONE build serves the whole MT-30/60 family. Two rules keep that sound:\r\n// 1. Consumers read these at CALL time (function bodies / default params) —\r\n// never snapshot them into module-top-level derived consts.\r\n// 2. Every dim baked into WGSL rides the pipeline-cache key (defines in\r\n// normalizeFlags), so switching models builds fresh pipelines instead of\r\n// reusing stale ones. runEncoder/createDecodeState assert the weights\r\n// they're handed match the active config (assertModelActive) — using two\r\n// models interleaved without re-applying is a caller error, caught loud.\r\n\r\nexport let D_MODEL, HEADS, HEAD_DIM, FFN, VOCAB;\r\nexport let ENC_LAYERS, DEC_LAYERS;\r\nexport let MAX_POS, SRC_CAP, DECODE_CAP;\r\n// Attention kernel shared-memory scores capacity — max valid K/V length any\r\n// dispatch may see (bucketed SRC_CAP and DECODE_CAP both fit), +32 headroom.\r\nexport let SCORES_CAP;\r\nexport let EOS, PAD, DECODER_START;\r\nexport let LN_EPS;\r\nexport let EMBED_SCALE; // √D_MODEL (scale_embedding), 1 when scaleEmbedding: false\r\nexport let ATTN_SCALE; // 1/√HEAD_DIM\r\nexport let BITMASK_WORDS; // ⌈VOCAB/32⌉ u32 words per repetition-bitmask row\r\n\r\n// Decode policy (HF generation config), not model geometry — constant across\r\n// the family so far; move into the manifest if a member ever changes it.\r\nexport const REP_PENALTY = 1.2;\r\n\r\n// Validate a manifest `model` block and return it normalized. Throws on\r\n// missing/ill-typed fields and on anything the kernels cannot serve — the\r\n// engine's portability envelope is Marian with vec4-able dims, fused-QKV\r\n// strides (heads·headDim == dModel), swish FFN, and tied embeddings (the\r\n// lm_head reads shared.weight); those last two are the exporter's to assert.\r\nconst INT_FIELDS = [\r\n 'dModel', 'heads', 'headDim', 'ffn', 'encLayers', 'decLayers',\r\n 'vocab', 'maxPos', 'srcCap', 'decodeCap', 'eos', 'pad', 'decoderStart',\r\n];\r\n\r\nexport function parseModelConfig(model) {\r\n if (!model || typeof model !== 'object') throw new Error('model config: not an object');\r\n const m = {};\r\n for (const f of INT_FIELDS) {\r\n const v = model[f];\r\n if (!Number.isInteger(v) || v < 0) {\r\n throw new Error(`model config: ${f} must be a non-negative integer, got ${v}`);\r\n }\r\n m[f] = v;\r\n }\r\n for (const f of INT_FIELDS.slice(0, 10)) { // all but eos/pad/decoderStart\r\n if (m[f] === 0) throw new Error(`model config: ${f} must be positive`);\r\n }\r\n if (!(typeof model.lnEps === 'number' && model.lnEps > 0 && model.lnEps < 0.1)) {\r\n throw new Error(`model config: lnEps must be in (0, 0.1), got ${model.lnEps}`);\r\n }\r\n m.lnEps = model.lnEps;\r\n if (m.heads * m.headDim !== m.dModel) {\r\n throw new Error(`model config: heads·headDim = ${m.heads * m.headDim} != dModel ${m.dModel}`);\r\n }\r\n for (const f of ['dModel', 'headDim', 'ffn']) {\r\n if (m[f] % 4 !== 0) {\r\n throw new Error(`model config: ${f} = ${m[f]} must be a multiple of 4 (vec4 kernels)`);\r\n }\r\n }\r\n if (m.srcCap % 32 !== 0) {\r\n throw new Error(`model config: srcCap ${m.srcCap} must be a multiple of 32 (bucketFor invariant)`);\r\n }\r\n if (m.srcCap > m.maxPos || m.decodeCap > m.maxPos) {\r\n throw new Error(\r\n `model config: srcCap ${m.srcCap} / decodeCap ${m.decodeCap} must not exceed maxPos ${m.maxPos}`);\r\n }\r\n for (const f of ['eos', 'pad', 'decoderStart']) {\r\n if (m[f] >= m.vocab) throw new Error(`model config: ${f} = ${m[f]} out of vocab ${m.vocab}`);\r\n }\r\n // scale_embedding: false is representable (embed kernel takes EMBED_SCALE).\r\n if (model.scaleEmbedding === false) m.scaleEmbedding = false;\r\n m.embedScale = m.scaleEmbedding === false ? 1 : Math.sqrt(m.dModel);\r\n return m;\r\n}\r\n\r\nlet ACTIVE = null;\r\n\r\n// The currently applied config, as a re-appliable copy — for policy caching\r\n// keys and for tests that switch models and must restore what they found.\r\nexport function activeModelConfig() {\r\n return { ...ACTIVE };\r\n}\r\n\r\n// Make `model` the active config. Idempotent; callers normally never invoke\r\n// this directly — uploadParsed/loadWeights apply the manifest's block.\r\nexport function applyModelConfig(model) {\r\n const m = parseModelConfig(model);\r\n ACTIVE = m;\r\n D_MODEL = m.dModel; HEADS = m.heads; HEAD_DIM = m.headDim; FFN = m.ffn; VOCAB = m.vocab;\r\n ENC_LAYERS = m.encLayers; DEC_LAYERS = m.decLayers;\r\n MAX_POS = m.maxPos; SRC_CAP = m.srcCap; DECODE_CAP = m.decodeCap;\r\n SCORES_CAP = Math.ceil(Math.max(m.srcCap, m.decodeCap) / 32) * 32 + 32;\r\n EOS = m.eos; PAD = m.pad; DECODER_START = m.decoderStart;\r\n LN_EPS = m.lnEps;\r\n EMBED_SCALE = m.embedScale;\r\n ATTN_SCALE = 1 / Math.sqrt(m.headDim);\r\n BITMASK_WORDS = Math.ceil(m.vocab / 32);\r\n return m;\r\n}\r\n\r\n// Guard for engine entry points: the weights being dispatched must have been\r\n// the last applied config (their dims are live in kernel defines right now).\r\nexport function assertModelActive(model, what = 'weights') {\r\n const m = model ?? {};\r\n const stale =\r\n m.dModel !== D_MODEL || m.heads !== HEADS || m.headDim !== HEAD_DIM ||\r\n m.ffn !== FFN || m.vocab !== VOCAB ||\r\n m.encLayers !== ENC_LAYERS || m.decLayers !== DEC_LAYERS ||\r\n m.maxPos !== MAX_POS || m.srcCap !== SRC_CAP || m.decodeCap !== DECODE_CAP ||\r\n m.eos !== EOS || m.pad !== PAD || m.decoderStart !== DECODER_START;\r\n if (stale) {\r\n throw new Error(\r\n `${what} belong to a different model config than the active one — ` +\r\n 'call applyModelConfig(weights.model) (loadWeights/uploadParsed do it) before dispatching');\r\n }\r\n}\r\n\r\n// Boot config: MoxhiMT-30 zh→vi (d_model 448, 8 heads × 56, ffn 1792, enc 8 /\r\n// dec 2, vocab 24k) — kept as the pre-load default so tools and unit tests\r\n// see the shipped numbers (EMBED_SCALE √448, ATTN_SCALE 1/√56, SCORES_CAP 352).\r\napplyModelConfig({\r\n dModel: 448, heads: 8, headDim: 56, ffn: 1792,\r\n encLayers: 8, decLayers: 2,\r\n vocab: 24000, maxPos: 512, srcCap: 320, decodeCap: 224,\r\n eos: 2, pad: 0, decoderStart: 0, lnEps: 1e-5,\r\n});\r\n"],"names":["D_MODEL","HEADS","HEAD_DIM","FFN","VOCAB","ENC_LAYERS","DEC_LAYERS","MAX_POS","SRC_CAP","DECODE_CAP","SCORES_CAP","EOS","PAD","DECODER_START","LN_EPS","EMBED_SCALE","ATTN_SCALE","BITMASK_WORDS","REP_PENALTY","INT_FIELDS","parseModelConfig","model","m","f","v","ACTIVE","activeModelConfig","applyModelConfig","assertModelActive","what"],"mappings":"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"}
 
1
+ {"version":3,"file":"constants-CSVWRdrh.js","sources":["../../src/engine/constants.js"],"sourcesContent":["// Single source of numeric truth for the ACTIVE Marian model — shared by JS\r\n// reference math, engine code, and templated into WGSL kernels.\r\n//\r\n// The geometry lives in `let` bindings booted to MoxhiMT-30 and swapped by\r\n// applyModelConfig(manifest.model) when weights load (uploadParsed calls it),\r\n// so ONE build serves the whole MT-30/60 family. Two rules keep that sound:\r\n// 1. Consumers read these at CALL time (function bodies / default params) —\r\n// never snapshot them into module-top-level derived consts.\r\n// 2. Every dim baked into WGSL rides the pipeline-cache key (defines in\r\n// normalizeFlags), so switching models builds fresh pipelines instead of\r\n// reusing stale ones. runEncoder/createDecodeState assert the weights\r\n// they're handed match the active config (assertModelActive) — using two\r\n// models interleaved without re-applying is a caller error, caught loud.\r\n\r\nexport let D_MODEL, HEADS, HEAD_DIM, FFN, VOCAB;\r\nexport let ENC_LAYERS, DEC_LAYERS;\r\nexport let MAX_POS, SRC_CAP, DECODE_CAP;\r\n// Attention kernel shared-memory scores capacity — max valid K/V length any\r\n// dispatch may see (bucketed SRC_CAP and DECODE_CAP both fit), +32 headroom.\r\nexport let SCORES_CAP;\r\nexport let EOS, PAD, DECODER_START;\r\nexport let LN_EPS;\r\nexport let EMBED_SCALE; // √D_MODEL (scale_embedding), 1 when scaleEmbedding: false\r\nexport let ATTN_SCALE; // 1/√HEAD_DIM\r\nexport let BITMASK_WORDS; // ⌈VOCAB/32⌉ u32 words per repetition-bitmask row\r\n\r\n// Decode policy (HF generation config), not model geometry — constant across\r\n// the family so far; move into the manifest if a member ever changes it.\r\nexport const REP_PENALTY = 1.2;\r\n\r\n// Validate a manifest `model` block and return it normalized. Throws on\r\n// missing/ill-typed fields and on anything the kernels cannot serve — the\r\n// engine's portability envelope is Marian with vec4-able dims, fused-QKV\r\n// strides (heads·headDim == dModel), swish FFN, and tied embeddings (the\r\n// lm_head reads shared.weight); those last two are the exporter's to assert.\r\nconst INT_FIELDS = [\r\n 'dModel', 'heads', 'headDim', 'ffn', 'encLayers', 'decLayers',\r\n 'vocab', 'maxPos', 'srcCap', 'decodeCap', 'eos', 'pad', 'decoderStart',\r\n];\r\n\r\nexport function parseModelConfig(model) {\r\n if (!model || typeof model !== 'object') throw new Error('model config: not an object');\r\n const m = {};\r\n for (const f of INT_FIELDS) {\r\n const v = model[f];\r\n if (!Number.isInteger(v) || v < 0) {\r\n throw new Error(`model config: ${f} must be a non-negative integer, got ${v}`);\r\n }\r\n m[f] = v;\r\n }\r\n for (const f of INT_FIELDS.slice(0, 10)) { // all but eos/pad/decoderStart\r\n if (m[f] === 0) throw new Error(`model config: ${f} must be positive`);\r\n }\r\n if (!(typeof model.lnEps === 'number' && model.lnEps > 0 && model.lnEps < 0.1)) {\r\n throw new Error(`model config: lnEps must be in (0, 0.1), got ${model.lnEps}`);\r\n }\r\n m.lnEps = model.lnEps;\r\n if (m.heads * m.headDim !== m.dModel) {\r\n throw new Error(`model config: heads·headDim = ${m.heads * m.headDim} != dModel ${m.dModel}`);\r\n }\r\n for (const f of ['dModel', 'headDim', 'ffn']) {\r\n if (m[f] % 4 !== 0) {\r\n throw new Error(`model config: ${f} = ${m[f]} must be a multiple of 4 (vec4 kernels)`);\r\n }\r\n }\r\n if (m.srcCap % 32 !== 0) {\r\n throw new Error(`model config: srcCap ${m.srcCap} must be a multiple of 32 (bucketFor invariant)`);\r\n }\r\n if (m.srcCap > m.maxPos || m.decodeCap > m.maxPos) {\r\n throw new Error(\r\n `model config: srcCap ${m.srcCap} / decodeCap ${m.decodeCap} must not exceed maxPos ${m.maxPos}`);\r\n }\r\n for (const f of ['eos', 'pad', 'decoderStart']) {\r\n if (m[f] >= m.vocab) throw new Error(`model config: ${f} = ${m[f]} out of vocab ${m.vocab}`);\r\n }\r\n // scale_embedding: false is representable (embed kernel takes EMBED_SCALE).\r\n if (model.scaleEmbedding === false) m.scaleEmbedding = false;\r\n m.embedScale = m.scaleEmbedding === false ? 1 : Math.sqrt(m.dModel);\r\n return m;\r\n}\r\n\r\nlet ACTIVE = null;\r\n\r\n// The currently applied config, as a re-appliable copy — for policy caching\r\n// keys and for tests that switch models and must restore what they found.\r\nexport function activeModelConfig() {\r\n return { ...ACTIVE };\r\n}\r\n\r\n// Make `model` the active config. Idempotent; callers normally never invoke\r\n// this directly — uploadParsed/loadWeights apply the manifest's block.\r\nexport function applyModelConfig(model) {\r\n const m = parseModelConfig(model);\r\n ACTIVE = m;\r\n D_MODEL = m.dModel; HEADS = m.heads; HEAD_DIM = m.headDim; FFN = m.ffn; VOCAB = m.vocab;\r\n ENC_LAYERS = m.encLayers; DEC_LAYERS = m.decLayers;\r\n MAX_POS = m.maxPos; SRC_CAP = m.srcCap; DECODE_CAP = m.decodeCap;\r\n SCORES_CAP = Math.ceil(Math.max(m.srcCap, m.decodeCap) / 32) * 32 + 32;\r\n EOS = m.eos; PAD = m.pad; DECODER_START = m.decoderStart;\r\n LN_EPS = m.lnEps;\r\n EMBED_SCALE = m.embedScale;\r\n ATTN_SCALE = 1 / Math.sqrt(m.headDim);\r\n BITMASK_WORDS = Math.ceil(m.vocab / 32);\r\n return m;\r\n}\r\n\r\n// Guard for engine entry points: the weights being dispatched must have been\r\n// the last applied config (their dims are live in kernel defines right now).\r\nexport function assertModelActive(model, what = 'weights') {\r\n const m = model ?? {};\r\n const stale =\r\n m.dModel !== D_MODEL || m.heads !== HEADS || m.headDim !== HEAD_DIM ||\r\n m.ffn !== FFN || m.vocab !== VOCAB ||\r\n m.encLayers !== ENC_LAYERS || m.decLayers !== DEC_LAYERS ||\r\n m.maxPos !== MAX_POS || m.srcCap !== SRC_CAP || m.decodeCap !== DECODE_CAP ||\r\n m.eos !== EOS || m.pad !== PAD || m.decoderStart !== DECODER_START;\r\n if (stale) {\r\n throw new Error(\r\n `${what} belong to a different model config than the active one — ` +\r\n 'call applyModelConfig(weights.model) (loadWeights/uploadParsed do it) before dispatching');\r\n }\r\n}\r\n\r\n// Boot config: MoxhiMT-30 zh→vi (d_model 448, 8 heads × 56, ffn 1792, enc 8 /\r\n// dec 2, vocab 24k) — kept as the pre-load default so tools and unit tests\r\n// see the shipped numbers (EMBED_SCALE √448, ATTN_SCALE 1/√56, SCORES_CAP 352).\r\napplyModelConfig({\r\n dModel: 448, heads: 8, headDim: 56, ffn: 1792,\r\n encLayers: 8, decLayers: 2,\r\n vocab: 24000, maxPos: 512, srcCap: 320, decodeCap: 224,\r\n eos: 2, pad: 0, decoderStart: 0, lnEps: 1e-5,\r\n});\r\n"],"names":["D_MODEL","HEADS","HEAD_DIM","FFN","VOCAB","ENC_LAYERS","DEC_LAYERS","MAX_POS","SRC_CAP","DECODE_CAP","SCORES_CAP","EOS","PAD","DECODER_START","LN_EPS","EMBED_SCALE","ATTN_SCALE","BITMASK_WORDS","REP_PENALTY","INT_FIELDS","parseModelConfig","model","m","f","v","ACTIVE","activeModelConfig","applyModelConfig","assertModelActive","what"],"mappings":"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"}
assets/debug-CPpXXfWA.js ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/smoke-K9h6fIty.js","assets/gpu-utils-BTh3AGTJ.js","assets/f16-wKKZr58e.js","assets/modulepreload-polyfill-B5Qt9EMX.js","assets/preload-helper-BXl3LOEh.js","assets/safe_storage-BYkOahew.js","assets/adreno_probe-CqGqVTv4.js","assets/pipelines-BbLc75sB.js","assets/constants-CSVWRdrh.js","assets/baseline-DFLF_Mw1.js","assets/reference-BRIi7m-O.js","assets/shapes-ClGtK-ia.js","assets/golden-D7gAaNSE.js","assets/weights-CjdTbC0j.js","assets/weights-DxIJF1EY.js","assets/gemm-D7s5caz-.js","assets/math-LI6LFmUv.js","assets/addln_embed-DSGHKDTg.js","assets/attention-1v-Zzb1X.js","assets/argmax-DMqT6ikS.js","assets/m1-ChH0PXgP.js","assets/tokenizer-BmI7pHmp.js","assets/encoder-CZXKGzzg.js","assets/ref_encoder_hidden-CUwekASB.js","assets/m2-C6ZI52AZ.js","assets/decoder-BUiaGDqb.js","assets/device-BotbBNoe.js","assets/m3-BB4rtLld.js","assets/generate-Ca3ORHiA.js","assets/verify-6VYYmR5k.js","assets/m4a-Bi3JA7HG.js","assets/bench-BarR4Zp5.js","assets/autotune-Bwt_lWMv.js","assets/chapter3k-DSdzHZt5.js","assets/m4b-DU_HxrT8.js","assets/profile-9RIrShZy.js","assets/enc_profile-Cd2YNhxk.js","assets/tiled_sweep-D69q0Uwl.js","assets/attn_sweep-CxMb0QH-.js","assets/lm_head_sweep-DOnLFBgw.js","assets/proj_sweep-BYYjREkq.js","assets/compact_equiv-ehtvJC3N.js","assets/inplace_compact_ab-C4XMGNaY.js","assets/shortlist-C151mR5c.js","assets/q8_lmhead-DyzB2_Xc.js","assets/argmax_fuse-CKXRwPoI.js","assets/ffn_q8_sweep-mBESY628.js","assets/ffn_mt_sweep-CNL-3O1A.js","assets/fuse_ln-B9IB1iwo.js","assets/prod_profile-BiK4oWxS.js","assets/dec_profile-BiK_GKoQ.js","assets/t2s-DjPa3Hpi.js","assets/dec_lmhead_sweep-BPuLSi-e.js","assets/dec_compact_sweep-DTumwRLm.js","assets/engine-C4r8fF2d.js","assets/dec_group_sweep-CRbQBEBp.js","assets/proj_wt-CHUQOKUK.js","assets/enc_v3_sweep-DEIxXWaH.js","assets/ffn_splitk-Co1rRVPB.js","assets/proj_splitk-DpBAl_HS.js","assets/enc_pack-Ca6dFJ28.js","assets/mega-5caPKJzt.js","assets/mega_compile-CgYbNzWb.js","assets/immediates-Cm07vs0B.js","assets/uniform_pool-D_1kmO8C.js","assets/kv_grow_equiv-BO6Gq23R.js","assets/kv_planner_ab-DYKyirqA.js","assets/autotune-CVn9SF1X.js","assets/dims_generic-WhMSqU9R.js","assets/pack_ab-BcU5qWVN.js","assets/batch_cap_ab-67ewcIZi.js","assets/sg-BOzCd9yH.js","assets/mega_sg-OHQegQaR.js","assets/hachimi60-B79dFqCU.js","assets/m5-D84Up6LQ.js","assets/xdev-SZ1IlM_M.js","assets/app_stage-DrqfcKH2.js","assets/vocab_union-Ct8E25TZ.js","assets/shortlist_probe-vk5f4Ltv.js","assets/shortlist_ab-D2W7sCBf.js","assets/title_probe-C95DyHD4.js","assets/tm_grownfile-BV8tDJ0w.js","assets/tm_store-COfE6euS.js"])))=>i.map(i=>d[i]);
2
+ import"./modulepreload-polyfill-B5Qt9EMX.js";import{_ as t}from"./preload-helper-BXl3LOEh.js";import{s as O}from"./safe_storage-BYkOahew.js";const R=[];function $(e,r,{slow:n=!1}={}){R.push({name:e,fn:r,slow:n})}async function D(e,{includeSlow:r=!1,only:n=null,onResult:_=null,onStart:a=null}={}){const E=[],m=i=>{E.push(i),_?.(i)},o=n?R.filter(({name:i})=>i.includes(n)):R;for(const{name:i,fn:v,slow:p}of o){if(p&&!r&&!n){m({name:i,skip:!0,reason:"slow",ms:0});continue}a?.(i);const c=performance.now();let I;try{const u=await v(e);u&&u.skip?I={name:i,skip:!0,reason:u.reason??"",ms:performance.now()-c}:I={name:i,pass:!!u?.pass,detail:u?.detail??"",ms:performance.now()-c}}catch(u){I={name:i,pass:!1,detail:{error:String(u?.message??u),stack:String(u?.stack??"")},ms:performance.now()-c}}m(I)}return E}const d=document.querySelector("#app"),l=new URLSearchParams(location.search),T=l.get("run"),P=l.get("autorun")==="1",f=l.get("slow")==="1",V=l.get("only");function s(e,r){const n=document.createElement(e);return r!==void 0&&(n.textContent=r),n}async function L(e){if(T)try{await fetch(`/__gpu-results?run=${encodeURIComponent(T)}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})}catch(r){d.append(s("pre",`POST failed: ${r}`))}}function h(e){const r=document.createElement("table");r.border="1";const n=r.insertRow();for(const _ of["test","status","ms","detail"])n.append(s("th",_));for(const _ of e){const a=r.insertRow(),E=_.skip?`SKIP (${_.reason})`:_.pass?"PASS":"FAIL";a.style.color=_.skip?"#aa5":_.pass?"#5d5":"#f55",a.append(s("td",_.name),s("td",E),s("td",_.ms.toFixed(1))),a.append(s("td",typeof _.detail=="string"?_.detail:JSON.stringify(_.detail??"")))}d.append(r)}async function A(e){d.append(s("pre",`FATAL: ${e}`)),await L({fatal:e,results:[]})}async function g(){d.append(s("h1","webMT GPU debug harness"));let e;try{const[{initDevice:o}]=await Promise.all([t(()=>import("./device-BotbBNoe.js"),[]),t(()=>import("./smoke-K9h6fIty.js"),__vite__mapDeps([0,1,2,3,4,5])),t(()=>import("./adreno_probe-CqGqVTv4.js"),__vite__mapDeps([6,4,1,7,8,2,3,5])),t(()=>import("./baseline-DFLF_Mw1.js"),__vite__mapDeps([9,10,11,8,12,3,4,5])),t(()=>import("./weights-CjdTbC0j.js"),__vite__mapDeps([13,14,11,8,2,3,4,5])),t(()=>import("./gemm-D7s5caz-.js"),__vite__mapDeps([15,1,7,8,14,11,2,16,3,4,5])),t(()=>import("./addln_embed-DSGHKDTg.js"),__vite__mapDeps([17,1,7,8,16,2,3,4,5])),t(()=>import("./attention-1v-Zzb1X.js"),__vite__mapDeps([18,1,7,8,16,2,3,4,5])),t(()=>import("./argmax-DMqT6ikS.js"),__vite__mapDeps([19,1,7,8,16,3,4,5])),t(()=>import("./m1-ChH0PXgP.js"),__vite__mapDeps([20,1,14,11,8,2,21,22,7,23,3,4,5])),t(()=>import("./m2-C6ZI52AZ.js"),__vite__mapDeps([24,1,14,11,8,2,21,22,7,25,26,23,3,4,5])),t(()=>import("./m3-BB4rtLld.js"),__vite__mapDeps([27,14,11,8,2,21,28,22,7,25,26,29,12,3,4,5])),t(()=>import("./m4a-Bi3JA7HG.js"),__vite__mapDeps([30,14,11,8,2,21,28,22,7,25,26,31,4,32,33,12,3,5])),t(()=>import("./m4b-DU_HxrT8.js"),__vite__mapDeps([34,14,11,8,2,21,22,7,25,26,35,31,4,28,32,33,12,3,5])),t(()=>import("./enc_profile-Cd2YNhxk.js"),__vite__mapDeps([36,14,11,8,2,21,35,25,22,7,26,31,4,28,32,33,3,5])),t(()=>import("./tiled_sweep-D69q0Uwl.js"),__vite__mapDeps([37,14,11,8,2,21,22,7,31,4,28,25,26,32,33,3,5])),t(()=>import("./attn_sweep-CxMb0QH-.js"),__vite__mapDeps([38,1,14,11,8,2,21,22,7,31,4,28,25,26,32,33,3,5])),t(()=>import("./lm_head_sweep-DOnLFBgw.js"),__vite__mapDeps([39,14,11,8,2,21,22,7,25,26,35,31,4,28,32,33,3,5])),t(()=>import("./proj_sweep-BYYjREkq.js"),__vite__mapDeps([40,1,14,11,8,2,21,22,7,25,26,35,31,4,28,32,33,3,5])),t(()=>import("./compact_equiv-ehtvJC3N.js"),__vite__mapDeps([41,14,11,8,2,21,28,22,7,25,26,31,4,32,33,3,5])),t(()=>import("./inplace_compact_ab-C4XMGNaY.js"),__vite__mapDeps([42,14,11,8,2,21,43,28,22,7,25,26,32,12,3,4,5])),t(()=>import("./q8_lmhead-DyzB2_Xc.js"),__vite__mapDeps([44,14,11,8,2,21,43,28,22,7,25,26,29,12,3,4,5])),t(()=>import("./argmax_fuse-CKXRwPoI.js"),__vite__mapDeps([45,1,7,8,14,11,2,21,28,22,25,26,35,31,4,32,33,3,5])),t(()=>import("./ffn_q8_sweep-mBESY628.js"),__vite__mapDeps([46,14,11,8,2,21,22,7,25,26,35,31,4,28,32,33,3,5])),t(()=>import("./ffn_mt_sweep-CNL-3O1A.js"),__vite__mapDeps([47,14,11,8,2,21,22,7,25,26,35,31,4,28,32,33,3,5])),t(()=>import("./fuse_ln-B9IB1iwo.js"),__vite__mapDeps([48,1,7,8,14,11,2,21,28,22,25,26,35,31,4,32,33,16,3,5])),t(()=>import("./prod_profile-BiK4oWxS.js"),__vite__mapDeps([49,14,11,8,2,43,21,22,7,25,26,35,31,4,28,32,33,3,5])),t(()=>import("./dec_profile-BiK_GKoQ.js"),__vite__mapDeps([50,14,11,8,2,43,21,22,7,25,26,32,35,51,33,3,4,5])),t(()=>import("./dec_lmhead_sweep-BPuLSi-e.js"),__vite__mapDeps([52,14,11,8,2,21,22,7,25,26,32,35,51,50,43,33,3,4,5])),t(()=>import("./dec_compact_sweep-DTumwRLm.js"),__vite__mapDeps([53,14,11,8,2,21,28,22,7,25,26,32,51,54,43,33,3,4,5])),t(()=>import("./dec_group_sweep-CRbQBEBp.js"),__vite__mapDeps([55,14,11,8,2,21,28,22,7,25,26,32,51,54,43,33,3,4,5])),t(()=>import("./proj_wt-CHUQOKUK.js"),__vite__mapDeps([56,1,7,8,14,11,2,21,28,22,25,26,35,31,4,32,33,16,3,5])),t(()=>import("./enc_v3_sweep-DEIxXWaH.js"),__vite__mapDeps([57,14,11,8,2,21,22,7,31,4,28,25,26,32,33,3,5])),t(()=>import("./ffn_splitk-Co1rRVPB.js"),__vite__mapDeps([58,1,7,8,14,11,2,21,28,22,25,26,35,31,4,32,33,16,3,5])),t(()=>import("./proj_splitk-DpBAl_HS.js"),__vite__mapDeps([59,1,7,8,14,11,2,21,28,22,25,26,35,31,4,32,33,16,3,5])),t(()=>import("./enc_pack-Ca6dFJ28.js"),__vite__mapDeps([60,1,14,11,8,2,21,22,7,28,25,26,31,4,32,33,3,5])),t(()=>import("./mega-5caPKJzt.js"),__vite__mapDeps([61,14,11,8,2,21,28,22,7,25,26,35,31,4,32,33,29,12,3,5])),t(()=>import("./mega_compile-CgYbNzWb.js"),__vite__mapDeps([62,7,8,14,11,2,3,4,5])),t(()=>import("./immediates-Cm07vs0B.js"),__vite__mapDeps([63,14,11,8,2,21,43,28,22,7,25,26,32,35,12,3,4,5])),t(()=>import("./uniform_pool-D_1kmO8C.js"),__vite__mapDeps([64,14,11,8,2,21,43,28,22,7,25,26,12,3,4,5])),t(()=>import("./kv_grow_equiv-BO6Gq23R.js"),__vite__mapDeps([65,14,11,8,2,21,43,28,22,7,25,26,31,4,32,33,3,5])),t(()=>import("./kv_planner_ab-DYKyirqA.js"),__vite__mapDeps([66,14,11,8,2,21,43,28,22,7,25,26,54,32,51,12,3,4,5])),t(()=>import("./autotune-CVn9SF1X.js"),__vite__mapDeps([67,14,11,8,2,43,21,32,22,7,25,26,3,4,5])),t(()=>import("./dims_generic-WhMSqU9R.js"),__vite__mapDeps([68,1,14,11,8,2,22,7,25,26,16,3,4,5])),t(()=>import("./pack_ab-BcU5qWVN.js"),__vite__mapDeps([69,14,11,8,2,21,28,22,7,25,26,51,54,32,43,33,3,4,5])),t(()=>import("./batch_cap_ab-67ewcIZi.js"),__vite__mapDeps([70,14,11,8,2,21,28,22,7,25,26,51,54,32,43,33,3,4,5])),t(()=>import("./sg-BOzCd9yH.js"),__vite__mapDeps([71,4,7,8,14,11,2,21,28,22,25,26,35,31,32,33,29,12,3,5])),t(()=>import("./mega_sg-OHQegQaR.js"),__vite__mapDeps([72,7,8,14,11,2,21,28,22,25,26,35,31,4,32,33,29,12,3,5])),t(()=>import("./hachimi60-B79dFqCU.js"),__vite__mapDeps([73,14,11,8,2,21,28,22,7,25,26,32,29,43,3,4,5])),t(()=>import("./m5-D84Up6LQ.js"),__vite__mapDeps([74,14,11,8,2,21,28,22,7,25,26,31,4,32,33,3,5])),t(()=>import("./xdev-SZ1IlM_M.js"),__vite__mapDeps([75,14,11,8,2,21,28,22,7,25,26,31,4,32,33,3,5])),t(()=>import("./app_stage-DrqfcKH2.js"),__vite__mapDeps([76,14,11,8,2,21,28,22,7,25,26,32,43,51,54,33,3,4,5])),t(()=>import("./vocab_union-Ct8E25TZ.js"),__vite__mapDeps([77,14,11,8,2,21,28,22,7,25,26,32,51,54,43,33,3,4,5])),t(()=>import("./shortlist_probe-vk5f4Ltv.js"),__vite__mapDeps([78,14,11,8,2,21,28,22,7,25,26,32,51,54,43,12,33,3,4,5])),t(()=>import("./shortlist_ab-D2W7sCBf.js"),__vite__mapDeps([79,14,11,8,2,21,28,22,7,25,26,32,43,51,54,12,33,3,4,5])),t(()=>import("./title_probe-C95DyHD4.js"),__vite__mapDeps([80,14,11,8,2,21,28,22,7,25,26,3,4,5])),t(()=>import("./tm_grownfile-BV8tDJ0w.js"),__vite__mapDeps([81,54,26,14,11,8,2,21,28,22,7,25,32,43,51,82,33,3,4,5]))]);e=await o()}catch(o){await A(`${o?.message??o}
3
+ ${o?.stack??""}`);return}const r=e.adapterInfo;d.append(s("pre",`adapter: vendor=${r.vendor} arch=${r.architecture} device=${r.device}
4
+ description=${r.description}
5
+ shader-f16=${e.hasF16} timestamp-query=${e.hasTimestamps} subgroups=${e.hasSubgroups} (min ${e.subgroupMinSize}) immediates=${e.hasImmediates}`));const n=async()=>{try{const o=s("pre",""),i=s("pre","");d.append(o,i);const v=await D(e,{includeSlow:f,only:V,onStart:p=>{i.textContent=`RUNNING ${p}…`},onResult:p=>{const c=p.skip?`SKIP(${p.reason})`:p.pass?"PASS":"FAIL";o.append(`${c} ${p.name} ${(p.ms??0).toFixed(0)}ms
6
+ `)}});i.remove(),h(v),await L({adapterInfo:e.adapterInfo,hasF16:e.hasF16,hasTimestamps:e.hasTimestamps,results:v})}catch(o){await A(`${o?.message??o}
7
+ ${o?.stack??""}`)}},_=O("session"),a="moxhi.debug.autorun.inflight",E=async()=>{_.setItem(a,"1");try{await n()}finally{_.removeItem(a)}},m=()=>{const o=s("button","Run tests");o.addEventListener("click",()=>{o.disabled=!0,E()}),d.append(o)};P&&!_.persistent?(d.append(s("pre",`autorun off: the browser blocks sessionStorage, so the crash-rerun guard
8
+ cannot survive a reload (a killed tab would re-run the suite forever).
9
+ Tap the button to run once.`)),m()):P&&!_.getItem(a)?await E():(P&&(_.removeItem(a),d.append(s("pre",`autorun blocked: the previous run never finished — the browser reset the page
10
+ mid-run (mobile WebKit kills tabs under memory/GPU pressure; a full suite is
11
+ heavy for a phone — prefer ?only=<test>). Tap the button to run again.`))),m())}g();export{$ as r};
12
+ //# sourceMappingURL=debug-CPpXXfWA.js.map
assets/debug-CPpXXfWA.js.map ADDED
@@ -0,0 +1 @@
 
 
1
+ {"version":3,"mappings":"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","names":["tests","registerTest","name","fn","slow","runAll","ctx","includeSlow","only","onResult","onStart","results","push","entry","selected","t0","out","err","app","params","runId","autorun","el","tag","text","node","postResults","payload","renderResults","table","head","h","r","row","status","fatal","message","main","initDevice","__vitePreload","info","run","progress","current","storage","safeStorage","RUN_FLAG","guardedRun","offerButton","btn"],"ignoreList":[],"sources":["../../src/debug/registry.js","../../src/debug-main.js"],"sourcesContent":["// Tiny GPU test registry. Test fns receive the ctx object from initDevice()\r\n// and return {pass, detail} or {skip: true, reason} — or throw (throw = fail).\r\n\r\nconst tests = [];\r\n\r\nexport function registerTest(name, fn, { slow = false } = {}) {\r\n tests.push({ name, fn, slow });\r\n}\r\n\r\n// `only` (substring) filters the test list — iteration aid for tuning runs;\r\n// matching tests run even when marked slow (asking for one by name is opting\r\n// into its cost).\r\nexport async function runAll(ctx, { includeSlow = false, only = null, onResult = null, onStart = null } = {}) {\r\n const results = [];\r\n const push = (entry) => {\r\n results.push(entry);\r\n onResult?.(entry); // live-progress hook (manual-mode devices render per test)\r\n };\r\n const selected = only ? tests.filter(({ name }) => name.includes(only)) : tests;\r\n for (const { name, fn, slow } of selected) {\r\n if (slow && !includeSlow && !only) {\r\n push({ name, skip: true, reason: 'slow', ms: 0 });\r\n continue;\r\n }\r\n onStart?.(name); // names the test in flight — what a killed tab died in\r\n const t0 = performance.now();\r\n let entry;\r\n try {\r\n const out = await fn(ctx);\r\n if (out && out.skip) {\r\n entry = { name, skip: true, reason: out.reason ?? '', ms: performance.now() - t0 };\r\n } else {\r\n entry = { name, pass: !!out?.pass, detail: out?.detail ?? '', ms: performance.now() - t0 };\r\n }\r\n } catch (err) {\r\n entry = {\r\n name,\r\n pass: false,\r\n detail: { error: String(err?.message ?? err), stack: String(err?.stack ?? '') },\r\n ms: performance.now() - t0,\r\n };\r\n }\r\n push(entry);\r\n }\r\n return results;\r\n}\r\n","import { runAll } from './debug/registry.js';\nimport { safeStorage } from './app/safe_storage.js';\n\nconst app = document.querySelector('#app');\nconst params = new URLSearchParams(location.search);\nconst runId = params.get('run');\nconst autorun = params.get('autorun') === '1';\nconst includeSlow = params.get('slow') === '1';\nconst only = params.get('only');\n\nfunction el(tag, text) {\n const node = document.createElement(tag);\n if (text !== undefined) node.textContent = text;\n return node;\n}\n\nasync function postResults(payload) {\n if (!runId) return;\n try {\n await fetch(`/__gpu-results?run=${encodeURIComponent(runId)}`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n });\n } catch (err) {\n app.append(el('pre', `POST failed: ${err}`));\n }\n}\n\nfunction renderResults(results) {\n const table = document.createElement('table');\n table.border = '1';\n const head = table.insertRow();\n for (const h of ['test', 'status', 'ms', 'detail']) head.append(el('th', h));\n for (const r of results) {\n const row = table.insertRow();\n const status = r.skip ? `SKIP (${r.reason})` : r.pass ? 'PASS' : 'FAIL';\n row.style.color = r.skip ? '#aa5' : r.pass ? '#5d5' : '#f55';\n row.append(el('td', r.name), el('td', status), el('td', r.ms.toFixed(1)));\n row.append(el('td', typeof r.detail === 'string' ? r.detail : JSON.stringify(r.detail ?? '')));\n }\n app.append(table);\n}\n\nasync function fatal(message) {\n app.append(el('pre', `FATAL: ${message}`));\n await postResults({ fatal: message, results: [] });\n}\n\nasync function main() {\n app.append(el('h1', 'webMT GPU debug harness'));\n let ctx;\n try {\n const [{ initDevice }] = await Promise.all([\n import('./engine/device.js'),\n import('./debug/tests/smoke.js'), // registers tests\n import('./debug/tests/adreno_probe.js'), // early: must run before any device-lost cascade\n import('./debug/tests/baseline.js'),\n import('./debug/tests/weights.js'),\n import('./debug/tests/gemm.js'),\n import('./debug/tests/addln_embed.js'),\n import('./debug/tests/attention.js'),\n import('./debug/tests/argmax.js'),\n import('./debug/tests/m1.js'),\n import('./debug/tests/m2.js'),\n import('./debug/tests/m3.js'),\n import('./debug/tests/m4a.js'),\n import('./debug/tests/m4b.js'),\n import('./debug/tests/enc_profile.js'),\n import('./debug/tests/tiled_sweep.js'),\n import('./debug/tests/attn_sweep.js'),\n import('./debug/tests/lm_head_sweep.js'),\n import('./debug/tests/proj_sweep.js'),\n import('./debug/tests/compact_equiv.js'),\n import('./debug/tests/inplace_compact_ab.js'),\n import('./debug/tests/q8_lmhead.js'),\n import('./debug/tests/argmax_fuse.js'),\n import('./debug/tests/ffn_q8_sweep.js'),\n import('./debug/tests/ffn_mt_sweep.js'),\n import('./debug/tests/fuse_ln.js'),\n import('./debug/tests/prod_profile.js'),\n import('./debug/tests/dec_profile.js'),\n import('./debug/tests/dec_lmhead_sweep.js'),\n import('./debug/tests/dec_compact_sweep.js'),\n import('./debug/tests/dec_group_sweep.js'),\n import('./debug/tests/proj_wt.js'),\n import('./debug/tests/enc_v3_sweep.js'),\n import('./debug/tests/ffn_splitk.js'),\n import('./debug/tests/proj_splitk.js'),\n import('./debug/tests/enc_pack.js'),\n import('./debug/tests/mega.js'),\n import('./debug/tests/mega_compile.js'),\n import('./debug/tests/immediates.js'),\n import('./debug/tests/uniform_pool.js'),\n import('./debug/tests/kv_grow_equiv.js'),\n import('./debug/tests/kv_planner_ab.js'),\n import('./debug/tests/autotune.js'),\n import('./debug/tests/dims_generic.js'),\n import('./debug/tests/pack_ab.js'),\n import('./debug/tests/batch_cap_ab.js'),\n import('./debug/tests/sg.js'),\n import('./debug/tests/mega_sg.js'),\n import('./debug/tests/hachimi60.js'),\n import('./debug/tests/m5.js'),\n import('./debug/tests/xdev.js'),\n import('./debug/tests/app_stage.js'),\n import('./debug/tests/vocab_union.js'),\n import('./debug/tests/shortlist_probe.js'),\n import('./debug/tests/shortlist_ab.js'),\n import('./debug/tests/title_probe.js'),\n import('./debug/tests/tm_grownfile.js'),\n ]);\n ctx = await initDevice();\n } catch (err) {\n await fatal(`${err?.message ?? err}\\n${err?.stack ?? ''}`);\n return;\n }\n\n const info = ctx.adapterInfo;\n app.append(el('pre',\n `adapter: vendor=${info.vendor} arch=${info.architecture} device=${info.device}\\n` +\n `description=${info.description}\\n` +\n `shader-f16=${ctx.hasF16} timestamp-query=${ctx.hasTimestamps} subgroups=${ctx.hasSubgroups} ` +\n `(min ${ctx.subgroupMinSize}) immediates=${ctx.hasImmediates}`));\n\n const run = async () => {\n try {\n // Live progress line per finished test — a phone screen (manual mode)\n // needs to show life long before the final table + POST. The trailing\n // RUNNING line names the test in flight: when WebKit kills the tab\n // mid-suite, it is the only record of where it died.\n const progress = el('pre', '');\n const current = el('pre', '');\n app.append(progress, current);\n const results = await runAll(ctx, {\n includeSlow, only,\n onStart: (name) => { current.textContent = `RUNNING ${name}…`; },\n onResult: (r) => {\n const status = r.skip ? `SKIP(${r.reason})` : r.pass ? 'PASS' : 'FAIL';\n progress.append(`${status} ${r.name} ${(r.ms ?? 0).toFixed(0)}ms\\n`);\n },\n });\n current.remove();\n renderResults(results);\n await postResults({\n adapterInfo: ctx.adapterInfo,\n hasF16: ctx.hasF16,\n hasTimestamps: ctx.hasTimestamps,\n results,\n });\n } catch (err) {\n await fatal(`${err?.message ?? err}\\n${err?.stack ?? ''}`);\n }\n };\n\n // A run that never finishes leaves this flag behind. Mobile WebKit kills\n // the tab under sustained GPU/memory pressure and AUTO-RELOADS the same\n // URL — with ?autorun=1 that is an infinite crash-rerun loop cooking the\n // phone. sessionStorage survives the crash-reload (same tab), so a leftover\n // flag downgrades autorun to a button instead of re-running blind.\n const storage = safeStorage('session');\n const RUN_FLAG = 'moxhi.debug.autorun.inflight';\n const guardedRun = async () => {\n storage.setItem(RUN_FLAG, '1');\n try {\n await run();\n } finally {\n storage.removeItem(RUN_FLAG);\n }\n };\n const offerButton = () => {\n const btn = el('button', 'Run tests');\n btn.addEventListener('click', () => {\n btn.disabled = true;\n guardedRun();\n });\n app.append(btn);\n };\n\n if (autorun && !storage.persistent) {\n // Storage blocked (private mode / policy): the crash-rerun guard cannot\n // work — an in-memory flag dies with the tab, so every crash-reload\n // would re-run the suite blind, forever. Refuse to autorun; hand the\n // user the button instead.\n app.append(el('pre',\n 'autorun off: the browser blocks sessionStorage, so the crash-rerun guard\\n'\n + 'cannot survive a reload (a killed tab would re-run the suite forever).\\n'\n + 'Tap the button to run once.'));\n offerButton();\n } else if (autorun && !storage.getItem(RUN_FLAG)) {\n await guardedRun();\n } else {\n if (autorun) {\n storage.removeItem(RUN_FLAG);\n app.append(el('pre',\n 'autorun blocked: the previous run never finished — the browser reset the page\\n'\n + 'mid-run (mobile WebKit kills tabs under memory/GPU pressure; a full suite is\\n'\n + 'heavy for a phone — prefer ?only=<test>). Tap the button to run again.'));\n }\n offerButton();\n }\n}\n\nmain();\n"],"file":"debug-CPpXXfWA.js"}
assets/debug-C_LNzFrK.js DELETED
@@ -1,10 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/smoke-CdvWPh6h.js","assets/gpu-utils-BTh3AGTJ.js","assets/f16-wKKZr58e.js","assets/modulepreload-polyfill-B5Qt9EMX.js","assets/preload-helper-BXl3LOEh.js","assets/adreno_probe-Cmg7uBSr.js","assets/pipelines-DJ7cc1m-.js","assets/constants-C8VbFpic.js","assets/baseline-DK6w1rGg.js","assets/reference-Dj87VRUN.js","assets/shapes-BCQ9D81L.js","assets/golden-D7gAaNSE.js","assets/weights-DdcFroki.js","assets/weights-D8qtuKag.js","assets/gemm-BevsAh0y.js","assets/math-DNG-wiC0.js","assets/addln_embed-C7q7s0KH.js","assets/attention-D1W9vlkP.js","assets/argmax-CQZtdTcb.js","assets/m1-CblZ7dLr.js","assets/tokenizer-Ex1u7wXD.js","assets/encoder-I9sHImnR.js","assets/ref_encoder_hidden-CUwekASB.js","assets/m2-CEmuKo3t.js","assets/decoder-CI9o-EVx.js","assets/device-BotbBNoe.js","assets/m3-bNC_jVI-.js","assets/generate-BIP3NpbY.js","assets/verify-HJ8NImMM.js","assets/m4a-DwPJ-ykJ.js","assets/bench-CEDJ-mff.js","assets/autotune-DywP5DSc.js","assets/chapter3k-DSdzHZt5.js","assets/m4b-Bbsi2kRa.js","assets/profile-Cs9YyiDl.js","assets/enc_profile-MCfG_UF7.js","assets/tiled_sweep-PDDg0bvL.js","assets/attn_sweep-DYmEfGm0.js","assets/lm_head_sweep-i1HkpnpI.js","assets/proj_sweep-C4hwAPN0.js","assets/compact_equiv-DlvjNh2p.js","assets/q8_lmhead-ShJkGAGH.js","assets/shortlist-C151mR5c.js","assets/argmax_fuse-DghSWREY.js","assets/ffn_q8_sweep-CzjROpKi.js","assets/ffn_mt_sweep-C1Hx90-M.js","assets/fuse_ln-D9lPdjQA.js","assets/prod_profile-DIeKN13f.js","assets/dec_profile-CbyhJ4Uh.js","assets/t2s-DjPa3Hpi.js","assets/dec_lmhead_sweep-CIP2_LVw.js","assets/dec_compact_sweep-D5MD5NcK.js","assets/engine-D57xjIIN.js","assets/dec_group_sweep-BQZHA49R.js","assets/proj_wt-ButVfHbm.js","assets/enc_v3_sweep-KJ7rmxpR.js","assets/ffn_splitk-BcvlYYh7.js","assets/proj_splitk-Cs-73wZv.js","assets/enc_pack-CogML5_V.js","assets/mega-CfbKWn4e.js","assets/mega_compile-DO_qOM0t.js","assets/immediates-DLI-AWcu.js","assets/uniform_pool-B-zI5YI-.js","assets/autotune-CgosBVvF.js","assets/dims_generic-CRcEhL2O.js","assets/pack_ab-Czm6OU7A.js","assets/batch_cap_ab-Dd5N_5qo.js","assets/sg-DQiSU0cG.js","assets/mega_sg-IcwFXnNa.js","assets/hachimi60-CcGFlEcS.js","assets/m5-RMZfcs8d.js","assets/xdev-C-dj6LRx.js","assets/app_stage-BHS27TUf.js","assets/vocab_union-BadZ9veT.js","assets/shortlist_probe-BK39z8xe.js","assets/shortlist_ab-p3WRUgI7.js","assets/title_probe-BC6tvnpl.js","assets/tm_grownfile-GCQ3hGjJ.js","assets/tm_store-COfE6euS.js"])))=>i.map(i=>d[i]);
2
- import"./modulepreload-polyfill-B5Qt9EMX.js";import{_ as t}from"./preload-helper-BXl3LOEh.js";const P=[];function y(e,r,{slow:n=!1}={}){P.push({name:e,fn:r,slow:n})}async function O(e,{includeSlow:r=!1,only:n=null,onResult:_=null,onStart:u=null}={}){const E=[],o=i=>{E.push(i),_?.(i)},m=n?P.filter(({name:i})=>i.includes(n)):P;for(const{name:i,fn:a,slow:v}of m){if(v&&!r&&!n){o({name:i,skip:!0,reason:"slow",ms:0});continue}u?.(i);const l=performance.now();let c;try{const p=await a(e);p&&p.skip?c={name:i,skip:!0,reason:p.reason??"",ms:performance.now()-l}:c={name:i,pass:!!p?.pass,detail:p?.detail??"",ms:performance.now()-l}}catch(p){c={name:i,pass:!1,detail:{error:String(p?.message??p),stack:String(p?.stack??"")},ms:performance.now()-l}}o(c)}return E}const d=document.querySelector("#app"),I=new URLSearchParams(location.search),R=I.get("run"),T=I.get("autorun")==="1",D=I.get("slow")==="1",V=I.get("only");function s(e,r){const n=document.createElement(e);return r!==void 0&&(n.textContent=r),n}async function L(e){if(R)try{await fetch(`/__gpu-results?run=${encodeURIComponent(R)}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})}catch(r){d.append(s("pre",`POST failed: ${r}`))}}function f(e){const r=document.createElement("table");r.border="1";const n=r.insertRow();for(const _ of["test","status","ms","detail"])n.append(s("th",_));for(const _ of e){const u=r.insertRow(),E=_.skip?`SKIP (${_.reason})`:_.pass?"PASS":"FAIL";u.style.color=_.skip?"#aa5":_.pass?"#5d5":"#f55",u.append(s("td",_.name),s("td",E),s("td",_.ms.toFixed(1))),u.append(s("td",typeof _.detail=="string"?_.detail:JSON.stringify(_.detail??"")))}d.append(r)}async function A(e){d.append(s("pre",`FATAL: ${e}`)),await L({fatal:e,results:[]})}async function h(){d.append(s("h1","webMT GPU debug harness"));let e;try{const[{initDevice:o}]=await Promise.all([t(()=>import("./device-BotbBNoe.js"),[]),t(()=>import("./smoke-CdvWPh6h.js"),__vite__mapDeps([0,1,2,3,4])),t(()=>import("./adreno_probe-Cmg7uBSr.js"),__vite__mapDeps([5,4,1,6,7,2,3])),t(()=>import("./baseline-DK6w1rGg.js"),__vite__mapDeps([8,9,10,7,11,3,4])),t(()=>import("./weights-DdcFroki.js"),__vite__mapDeps([12,13,10,7,2,3,4])),t(()=>import("./gemm-BevsAh0y.js"),__vite__mapDeps([14,1,6,7,13,10,2,15,3,4])),t(()=>import("./addln_embed-C7q7s0KH.js"),__vite__mapDeps([16,1,6,7,15,2,3,4])),t(()=>import("./attention-D1W9vlkP.js"),__vite__mapDeps([17,1,6,7,15,2,3,4])),t(()=>import("./argmax-CQZtdTcb.js"),__vite__mapDeps([18,1,6,7,15,3,4])),t(()=>import("./m1-CblZ7dLr.js"),__vite__mapDeps([19,1,13,10,7,2,20,21,6,22,3,4])),t(()=>import("./m2-CEmuKo3t.js"),__vite__mapDeps([23,1,13,10,7,2,20,21,6,24,25,22,3,4])),t(()=>import("./m3-bNC_jVI-.js"),__vite__mapDeps([26,13,10,7,2,20,27,21,6,24,25,28,11,3,4])),t(()=>import("./m4a-DwPJ-ykJ.js"),__vite__mapDeps([29,13,10,7,2,20,27,21,6,24,25,30,4,31,32,11,3])),t(()=>import("./m4b-Bbsi2kRa.js"),__vite__mapDeps([33,13,10,7,2,20,21,6,24,25,34,30,4,27,31,32,11,3])),t(()=>import("./enc_profile-MCfG_UF7.js"),__vite__mapDeps([35,13,10,7,2,20,34,24,21,6,25,30,4,27,31,32,3])),t(()=>import("./tiled_sweep-PDDg0bvL.js"),__vite__mapDeps([36,13,10,7,2,20,21,6,30,4,27,24,25,31,32,3])),t(()=>import("./attn_sweep-DYmEfGm0.js"),__vite__mapDeps([37,1,13,10,7,2,20,21,6,30,4,27,24,25,31,32,3])),t(()=>import("./lm_head_sweep-i1HkpnpI.js"),__vite__mapDeps([38,13,10,7,2,20,21,6,24,25,34,30,4,27,31,32,3])),t(()=>import("./proj_sweep-C4hwAPN0.js"),__vite__mapDeps([39,1,13,10,7,2,20,21,6,24,25,34,30,4,27,31,32,3])),t(()=>import("./compact_equiv-DlvjNh2p.js"),__vite__mapDeps([40,13,10,7,2,20,27,21,6,24,25,30,4,31,32,3])),t(()=>import("./q8_lmhead-ShJkGAGH.js"),__vite__mapDeps([41,13,10,7,2,20,42,27,21,6,24,25,28,11,3,4])),t(()=>import("./argmax_fuse-DghSWREY.js"),__vite__mapDeps([43,1,6,7,13,10,2,20,27,21,24,25,34,30,4,31,32,3])),t(()=>import("./ffn_q8_sweep-CzjROpKi.js"),__vite__mapDeps([44,13,10,7,2,20,21,6,24,25,34,30,4,27,31,32,3])),t(()=>import("./ffn_mt_sweep-C1Hx90-M.js"),__vite__mapDeps([45,13,10,7,2,20,21,6,24,25,34,30,4,27,31,32,3])),t(()=>import("./fuse_ln-D9lPdjQA.js"),__vite__mapDeps([46,1,6,7,13,10,2,20,27,21,24,25,34,30,4,31,32,15,3])),t(()=>import("./prod_profile-DIeKN13f.js"),__vite__mapDeps([47,13,10,7,2,42,20,21,6,24,25,34,30,4,27,31,32,3])),t(()=>import("./dec_profile-CbyhJ4Uh.js"),__vite__mapDeps([48,13,10,7,2,42,20,21,6,24,25,31,34,49,32,3,4])),t(()=>import("./dec_lmhead_sweep-CIP2_LVw.js"),__vite__mapDeps([50,13,10,7,2,20,21,6,24,25,31,34,49,48,42,32,3,4])),t(()=>import("./dec_compact_sweep-D5MD5NcK.js"),__vite__mapDeps([51,13,10,7,2,20,27,21,6,24,25,31,49,52,42,32,3,4])),t(()=>import("./dec_group_sweep-BQZHA49R.js"),__vite__mapDeps([53,13,10,7,2,20,27,21,6,24,25,31,49,52,42,32,3,4])),t(()=>import("./proj_wt-ButVfHbm.js"),__vite__mapDeps([54,1,6,7,13,10,2,20,27,21,24,25,34,30,4,31,32,15,3])),t(()=>import("./enc_v3_sweep-KJ7rmxpR.js"),__vite__mapDeps([55,13,10,7,2,20,21,6,30,4,27,24,25,31,32,3])),t(()=>import("./ffn_splitk-BcvlYYh7.js"),__vite__mapDeps([56,1,6,7,13,10,2,20,27,21,24,25,34,30,4,31,32,15,3])),t(()=>import("./proj_splitk-Cs-73wZv.js"),__vite__mapDeps([57,1,6,7,13,10,2,20,27,21,24,25,34,30,4,31,32,15,3])),t(()=>import("./enc_pack-CogML5_V.js"),__vite__mapDeps([58,1,13,10,7,2,20,21,6,27,24,25,30,4,31,32,3])),t(()=>import("./mega-CfbKWn4e.js"),__vite__mapDeps([59,13,10,7,2,20,27,21,6,24,25,34,30,4,31,32,28,11,3])),t(()=>import("./mega_compile-DO_qOM0t.js"),__vite__mapDeps([60,6,7,13,10,2,3,4])),t(()=>import("./immediates-DLI-AWcu.js"),__vite__mapDeps([61,13,10,7,2,20,42,27,21,6,24,25,31,34,11,3,4])),t(()=>import("./uniform_pool-B-zI5YI-.js"),__vite__mapDeps([62,13,10,7,2,20,42,27,21,6,24,25,11,3,4])),t(()=>import("./autotune-CgosBVvF.js"),__vite__mapDeps([63,13,10,7,2,42,20,31,21,6,24,25,3,4])),t(()=>import("./dims_generic-CRcEhL2O.js"),__vite__mapDeps([64,1,13,10,7,2,21,6,24,25,15,3,4])),t(()=>import("./pack_ab-Czm6OU7A.js"),__vite__mapDeps([65,13,10,7,2,20,27,21,6,24,25,49,52,31,42,32,3,4])),t(()=>import("./batch_cap_ab-Dd5N_5qo.js"),__vite__mapDeps([66,13,10,7,2,20,27,21,6,24,25,49,52,31,42,32,3,4])),t(()=>import("./sg-DQiSU0cG.js"),__vite__mapDeps([67,4,6,7,13,10,2,20,27,21,24,25,34,30,31,32,28,11,3])),t(()=>import("./mega_sg-IcwFXnNa.js"),__vite__mapDeps([68,6,7,13,10,2,20,27,21,24,25,34,30,4,31,32,28,11,3])),t(()=>import("./hachimi60-CcGFlEcS.js"),__vite__mapDeps([69,13,10,7,2,20,27,21,6,24,25,31,28,42,3,4])),t(()=>import("./m5-RMZfcs8d.js"),__vite__mapDeps([70,13,10,7,2,20,27,21,6,24,25,30,4,31,32,3])),t(()=>import("./xdev-C-dj6LRx.js"),__vite__mapDeps([71,13,10,7,2,20,27,21,6,24,25,30,4,31,32,3])),t(()=>import("./app_stage-BHS27TUf.js"),__vite__mapDeps([72,13,10,7,2,20,27,21,6,24,25,31,42,49,52,32,3,4])),t(()=>import("./vocab_union-BadZ9veT.js"),__vite__mapDeps([73,13,10,7,2,20,27,21,6,24,25,31,49,52,42,32,3,4])),t(()=>import("./shortlist_probe-BK39z8xe.js"),__vite__mapDeps([74,13,10,7,2,20,27,21,6,24,25,31,49,52,42,11,32,3,4])),t(()=>import("./shortlist_ab-p3WRUgI7.js"),__vite__mapDeps([75,13,10,7,2,20,27,21,6,24,25,31,42,49,52,11,32,3,4])),t(()=>import("./title_probe-BC6tvnpl.js"),__vite__mapDeps([76,13,10,7,2,20,27,21,6,24,25,3,4])),t(()=>import("./tm_grownfile-GCQ3hGjJ.js"),__vite__mapDeps([77,52,25,13,10,7,2,20,27,21,6,24,31,42,49,78,32,3,4]))]);e=await o()}catch(o){await A(`${o?.message??o}
3
- ${o?.stack??""}`);return}const r=e.adapterInfo;d.append(s("pre",`adapter: vendor=${r.vendor} arch=${r.architecture} device=${r.device}
4
- description=${r.description}
5
- shader-f16=${e.hasF16} timestamp-query=${e.hasTimestamps} subgroups=${e.hasSubgroups} (min ${e.subgroupMinSize}) immediates=${e.hasImmediates}`));const n=async()=>{try{const o=s("pre",""),m=s("pre","");d.append(o,m);const i=await O(e,{includeSlow:D,only:V,onStart:a=>{m.textContent=`RUNNING ${a}…`},onResult:a=>{const v=a.skip?`SKIP(${a.reason})`:a.pass?"PASS":"FAIL";o.append(`${v} ${a.name} ${(a.ms??0).toFixed(0)}ms
6
- `)}});m.remove(),f(i),await L({adapterInfo:e.adapterInfo,hasF16:e.hasF16,hasTimestamps:e.hasTimestamps,results:i})}catch(o){await A(`${o?.message??o}
7
- ${o?.stack??""}`)}},_="moxhi.debug.autorun.inflight",u=async()=>{sessionStorage.setItem(_,"1");try{await n()}finally{sessionStorage.removeItem(_)}},E=()=>{const o=s("button","Run tests");o.addEventListener("click",()=>{o.disabled=!0,u()}),d.append(o)};T&&!sessionStorage.getItem(_)?await u():(T&&(sessionStorage.removeItem(_),d.append(s("pre",`autorun blocked: the previous run never finished — the browser reset the page
8
- mid-run (mobile WebKit kills tabs under memory/GPU pressure; a full suite is
9
- heavy for a phone — prefer ?only=<test>). Tap the button to run again.`))),E())}h();export{y as r};
10
- //# sourceMappingURL=debug-C_LNzFrK.js.map
 
 
 
 
 
 
 
 
 
 
 
assets/debug-C_LNzFrK.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"mappings":"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","names":["tests","registerTest","name","fn","slow","runAll","ctx","includeSlow","only","onResult","onStart","results","push","entry","selected","t0","out","err","app","params","runId","autorun","el","tag","text","node","postResults","payload","renderResults","table","head","h","r","row","status","fatal","message","main","initDevice","__vitePreload","info","run","progress","current","RUN_FLAG","guardedRun","offerButton","btn"],"ignoreList":[],"sources":["../../src/debug/registry.js","../../src/debug-main.js"],"sourcesContent":["// Tiny GPU test registry. Test fns receive the ctx object from initDevice()\r\n// and return {pass, detail} or {skip: true, reason} — or throw (throw = fail).\r\n\r\nconst tests = [];\r\n\r\nexport function registerTest(name, fn, { slow = false } = {}) {\r\n tests.push({ name, fn, slow });\r\n}\r\n\r\n// `only` (substring) filters the test list — iteration aid for tuning runs;\r\n// matching tests run even when marked slow (asking for one by name is opting\r\n// into its cost).\r\nexport async function runAll(ctx, { includeSlow = false, only = null, onResult = null, onStart = null } = {}) {\r\n const results = [];\r\n const push = (entry) => {\r\n results.push(entry);\r\n onResult?.(entry); // live-progress hook (manual-mode devices render per test)\r\n };\r\n const selected = only ? tests.filter(({ name }) => name.includes(only)) : tests;\r\n for (const { name, fn, slow } of selected) {\r\n if (slow && !includeSlow && !only) {\r\n push({ name, skip: true, reason: 'slow', ms: 0 });\r\n continue;\r\n }\r\n onStart?.(name); // names the test in flight — what a killed tab died in\r\n const t0 = performance.now();\r\n let entry;\r\n try {\r\n const out = await fn(ctx);\r\n if (out && out.skip) {\r\n entry = { name, skip: true, reason: out.reason ?? '', ms: performance.now() - t0 };\r\n } else {\r\n entry = { name, pass: !!out?.pass, detail: out?.detail ?? '', ms: performance.now() - t0 };\r\n }\r\n } catch (err) {\r\n entry = {\r\n name,\r\n pass: false,\r\n detail: { error: String(err?.message ?? err), stack: String(err?.stack ?? '') },\r\n ms: performance.now() - t0,\r\n };\r\n }\r\n push(entry);\r\n }\r\n return results;\r\n}\r\n","import { runAll } from './debug/registry.js';\r\n\r\nconst app = document.querySelector('#app');\r\nconst params = new URLSearchParams(location.search);\r\nconst runId = params.get('run');\r\nconst autorun = params.get('autorun') === '1';\r\nconst includeSlow = params.get('slow') === '1';\r\nconst only = params.get('only');\r\n\r\nfunction el(tag, text) {\r\n const node = document.createElement(tag);\r\n if (text !== undefined) node.textContent = text;\r\n return node;\r\n}\r\n\r\nasync function postResults(payload) {\r\n if (!runId) return;\r\n try {\r\n await fetch(`/__gpu-results?run=${encodeURIComponent(runId)}`, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(payload),\r\n });\r\n } catch (err) {\r\n app.append(el('pre', `POST failed: ${err}`));\r\n }\r\n}\r\n\r\nfunction renderResults(results) {\r\n const table = document.createElement('table');\r\n table.border = '1';\r\n const head = table.insertRow();\r\n for (const h of ['test', 'status', 'ms', 'detail']) head.append(el('th', h));\r\n for (const r of results) {\r\n const row = table.insertRow();\r\n const status = r.skip ? `SKIP (${r.reason})` : r.pass ? 'PASS' : 'FAIL';\r\n row.style.color = r.skip ? '#aa5' : r.pass ? '#5d5' : '#f55';\r\n row.append(el('td', r.name), el('td', status), el('td', r.ms.toFixed(1)));\r\n row.append(el('td', typeof r.detail === 'string' ? r.detail : JSON.stringify(r.detail ?? '')));\r\n }\r\n app.append(table);\r\n}\r\n\r\nasync function fatal(message) {\r\n app.append(el('pre', `FATAL: ${message}`));\r\n await postResults({ fatal: message, results: [] });\r\n}\r\n\r\nasync function main() {\r\n app.append(el('h1', 'webMT GPU debug harness'));\r\n let ctx;\r\n try {\r\n const [{ initDevice }] = await Promise.all([\r\n import('./engine/device.js'),\r\n import('./debug/tests/smoke.js'), // registers tests\r\n import('./debug/tests/adreno_probe.js'), // early: must run before any device-lost cascade\r\n import('./debug/tests/baseline.js'),\r\n import('./debug/tests/weights.js'),\r\n import('./debug/tests/gemm.js'),\r\n import('./debug/tests/addln_embed.js'),\r\n import('./debug/tests/attention.js'),\r\n import('./debug/tests/argmax.js'),\r\n import('./debug/tests/m1.js'),\r\n import('./debug/tests/m2.js'),\r\n import('./debug/tests/m3.js'),\r\n import('./debug/tests/m4a.js'),\r\n import('./debug/tests/m4b.js'),\r\n import('./debug/tests/enc_profile.js'),\r\n import('./debug/tests/tiled_sweep.js'),\r\n import('./debug/tests/attn_sweep.js'),\r\n import('./debug/tests/lm_head_sweep.js'),\r\n import('./debug/tests/proj_sweep.js'),\r\n import('./debug/tests/compact_equiv.js'),\r\n import('./debug/tests/q8_lmhead.js'),\r\n import('./debug/tests/argmax_fuse.js'),\r\n import('./debug/tests/ffn_q8_sweep.js'),\r\n import('./debug/tests/ffn_mt_sweep.js'),\r\n import('./debug/tests/fuse_ln.js'),\r\n import('./debug/tests/prod_profile.js'),\r\n import('./debug/tests/dec_profile.js'),\r\n import('./debug/tests/dec_lmhead_sweep.js'),\r\n import('./debug/tests/dec_compact_sweep.js'),\r\n import('./debug/tests/dec_group_sweep.js'),\r\n import('./debug/tests/proj_wt.js'),\r\n import('./debug/tests/enc_v3_sweep.js'),\r\n import('./debug/tests/ffn_splitk.js'),\r\n import('./debug/tests/proj_splitk.js'),\r\n import('./debug/tests/enc_pack.js'),\r\n import('./debug/tests/mega.js'),\r\n import('./debug/tests/mega_compile.js'),\r\n import('./debug/tests/immediates.js'),\r\n import('./debug/tests/uniform_pool.js'),\r\n import('./debug/tests/autotune.js'),\r\n import('./debug/tests/dims_generic.js'),\r\n import('./debug/tests/pack_ab.js'),\r\n import('./debug/tests/batch_cap_ab.js'),\r\n import('./debug/tests/sg.js'),\r\n import('./debug/tests/mega_sg.js'),\r\n import('./debug/tests/hachimi60.js'),\r\n import('./debug/tests/m5.js'),\r\n import('./debug/tests/xdev.js'),\r\n import('./debug/tests/app_stage.js'),\r\n import('./debug/tests/vocab_union.js'),\r\n import('./debug/tests/shortlist_probe.js'),\r\n import('./debug/tests/shortlist_ab.js'),\r\n import('./debug/tests/title_probe.js'),\r\n import('./debug/tests/tm_grownfile.js'),\r\n ]);\r\n ctx = await initDevice();\r\n } catch (err) {\r\n await fatal(`${err?.message ?? err}\\n${err?.stack ?? ''}`);\r\n return;\r\n }\r\n\r\n const info = ctx.adapterInfo;\r\n app.append(el('pre',\r\n `adapter: vendor=${info.vendor} arch=${info.architecture} device=${info.device}\\n` +\r\n `description=${info.description}\\n` +\r\n `shader-f16=${ctx.hasF16} timestamp-query=${ctx.hasTimestamps} subgroups=${ctx.hasSubgroups} ` +\r\n `(min ${ctx.subgroupMinSize}) immediates=${ctx.hasImmediates}`));\r\n\r\n const run = async () => {\r\n try {\r\n // Live progress line per finished test — a phone screen (manual mode)\r\n // needs to show life long before the final table + POST. The trailing\r\n // RUNNING line names the test in flight: when WebKit kills the tab\r\n // mid-suite, it is the only record of where it died.\r\n const progress = el('pre', '');\r\n const current = el('pre', '');\r\n app.append(progress, current);\r\n const results = await runAll(ctx, {\r\n includeSlow, only,\r\n onStart: (name) => { current.textContent = `RUNNING ${name}…`; },\r\n onResult: (r) => {\r\n const status = r.skip ? `SKIP(${r.reason})` : r.pass ? 'PASS' : 'FAIL';\r\n progress.append(`${status} ${r.name} ${(r.ms ?? 0).toFixed(0)}ms\\n`);\r\n },\r\n });\r\n current.remove();\r\n renderResults(results);\r\n await postResults({\r\n adapterInfo: ctx.adapterInfo,\r\n hasF16: ctx.hasF16,\r\n hasTimestamps: ctx.hasTimestamps,\r\n results,\r\n });\r\n } catch (err) {\r\n await fatal(`${err?.message ?? err}\\n${err?.stack ?? ''}`);\r\n }\r\n };\r\n\r\n // A run that never finishes leaves this flag behind. Mobile WebKit kills\r\n // the tab under sustained GPU/memory pressure and AUTO-RELOADS the same\r\n // URL — with ?autorun=1 that is an infinite crash-rerun loop cooking the\r\n // phone. sessionStorage survives the crash-reload (same tab), so a leftover\r\n // flag downgrades autorun to a button instead of re-running blind.\r\n const RUN_FLAG = 'moxhi.debug.autorun.inflight';\r\n const guardedRun = async () => {\r\n sessionStorage.setItem(RUN_FLAG, '1');\r\n try {\r\n await run();\r\n } finally {\r\n sessionStorage.removeItem(RUN_FLAG);\r\n }\r\n };\r\n const offerButton = () => {\r\n const btn = el('button', 'Run tests');\r\n btn.addEventListener('click', () => {\r\n btn.disabled = true;\r\n guardedRun();\r\n });\r\n app.append(btn);\r\n };\r\n\r\n if (autorun && !sessionStorage.getItem(RUN_FLAG)) {\r\n await guardedRun();\r\n } else {\r\n if (autorun) {\r\n sessionStorage.removeItem(RUN_FLAG);\r\n app.append(el('pre',\r\n 'autorun blocked: the previous run never finished — the browser reset the page\\n'\r\n + 'mid-run (mobile WebKit kills tabs under memory/GPU pressure; a full suite is\\n'\r\n + 'heavy for a phone — prefer ?only=<test>). Tap the button to run again.'));\r\n }\r\n offerButton();\r\n }\r\n}\r\n\r\nmain();\r\n"],"file":"debug-C_LNzFrK.js"}
 
 
assets/dec_compact_sweep-D5MD5NcK.js DELETED
@@ -1,2 +0,0 @@
1
- import{r as q}from"./debug-C_LNzFrK.js";import{l as B}from"./weights-D8qtuKag.js";import{l as C}from"./tokenizer-Ex1u7wXD.js";import{t as v}from"./generate-BIP3NpbY.js";import{autotuneRouting as z,tunedOptions as G}from"./autotune-DywP5DSc.js";import{g as H}from"./constants-C8VbFpic.js";import{t as P,s as Q,p as U}from"./t2s-DjPa3Hpi.js";import{l as I,p as J}from"./engine-D57xjIIN.js";import{c as K}from"./chapter3k-DSdzHZt5.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./shapes-BCQ9D81L.js";import"./f16-wKKZr58e.js";import"./encoder-I9sHImnR.js";import"./pipelines-DJ7cc1m-.js";import"./decoder-CI9o-EVx.js";import"./device-BotbBNoe.js";import"./shortlist-C151mR5c.js";const A=5,c=[.25,.125,.0625,.03125],r=n=>`f${String(n).slice(2)}`,L=n=>{const a=[...n].sort((p,m)=>p-m),o=a.length>>1;return a.length%2?a[o]:(a[o-1]+a[o])/2};q("dec_compact_sweep",async n=>{if(!n.hasF16)return{skip:!0,reason:"production stack needs shader-f16"};const{device:a}=n;let o=null,p="chapter3k×8";try{const l=await fetch("/local/qingshan.txt");l.ok&&(o=await l.text(),p="qingshan_local")}catch{}o||(o=K.repeat(8));const m=await B(a,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0,projWT:!0});try{const l=await C(),d={...n,dtype:"f16"},{tuned:D}=await z(d,m),_=P(o),k=Q(_.text),b=U(k.sentences,k.paras,200).rows,x=b.map(t=>t.length),O=I(x),f=J(O.map(t=>x[t]),d,2),y=(f.length>6?[...f.slice(0,4),...f.slice(-2)]:f).map(([t,e])=>O.slice(t,e).map(s=>b[s])),j=async t=>{const e=performance.now();let s=0,T=0,E=0;const F=[];for(const S of y){const{rows:W,metrics:w}=await v(d,m,l,S,{...G(D,S.length),maxNewTokens:H,compactFrac:t});s+=w.steps,T+=w.compactions,E+=w.tokensGenerated,F.push(...W.map($=>$.text))}return{wallMs:performance.now()-e,steps:s,compactions:T,tokens:E,texts:F}};await j(c[0]);const h=Object.fromEntries(c.map(t=>[r(t),[]])),u={};for(let t=0;t<A;t++)for(const e of c){const s=await j(e);h[r(e)].push(Number(s.wallMs.toFixed(1))),u[r(e)]=s}const M=u[r(c[0])];let g=0;for(const t of c.slice(1)){const e=u[r(t)];for(let s=0;s<M.texts.length;s++)M.texts[s]!==e.texts[s]&&g++}const i=Object.fromEntries(c.map(t=>[r(t),Number(L(h[r(t)]).toFixed(1))])),R=i[r(c[0])],N=Object.keys(i).reduce((t,e)=>i[e]<i[t]?e:t);return{pass:g===0,detail:{source:p,batches:y.map(t=>t.length),rounds:A,wallMedMs:i,best:`${N} ${(100*(1-i[N]/R)).toFixed(1)}% vs f25`,perArm:Object.fromEntries(Object.entries(u).map(([t,e])=>[t,{steps:e.steps,compactions:e.compactions,tokens:e.tokens}])),mismatch:g,runs:h}}}finally{m.buffer.destroy()}},{slow:!0});
2
- //# sourceMappingURL=dec_compact_sweep-D5MD5NcK.js.map
 
 
 
assets/dec_compact_sweep-DTumwRLm.js ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import{r as q}from"./debug-CPpXXfWA.js";import{l as B}from"./weights-DxIJF1EY.js";import{l as C}from"./tokenizer-BmI7pHmp.js";import{t as v}from"./generate-Ca3ORHiA.js";import{autotuneRouting as z,tunedOptions as G}from"./autotune-Bwt_lWMv.js";import{f as H}from"./constants-CSVWRdrh.js";import{t as P,s as Q,p as U}from"./t2s-DjPa3Hpi.js";import{b as I,p as J}from"./engine-C4r8fF2d.js";import{c as K}from"./chapter3k-DSdzHZt5.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./safe_storage-BYkOahew.js";import"./shapes-ClGtK-ia.js";import"./f16-wKKZr58e.js";import"./encoder-CZXKGzzg.js";import"./pipelines-BbLc75sB.js";import"./decoder-BUiaGDqb.js";import"./device-BotbBNoe.js";import"./shortlist-C151mR5c.js";const A=5,c=[.25,.125,.0625,.03125],r=n=>`f${String(n).slice(2)}`,L=n=>{const a=[...n].sort((p,m)=>p-m),o=a.length>>1;return a.length%2?a[o]:(a[o-1]+a[o])/2};q("dec_compact_sweep",async n=>{if(!n.hasF16)return{skip:!0,reason:"production stack needs shader-f16"};const{device:a}=n;let o=null,p="chapter3k×8";try{const l=await fetch("/local/qingshan.txt");l.ok&&(o=await l.text(),p="qingshan_local")}catch{}o||(o=K.repeat(8));const m=await B(a,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0,projWT:!0});try{const l=await C(),d={...n,dtype:"f16"},{tuned:D}=await z(d,m),_=P(o),b=Q(_.text),k=U(b.sentences,b.paras,200).rows,x=k.map(t=>t.length),O=I(x),f=J(O.map(t=>x[t]),d,2),y=(f.length>6?[...f.slice(0,4),...f.slice(-2)]:f).map(([t,e])=>O.slice(t,e).map(s=>k[s])),j=async t=>{const e=performance.now();let s=0,T=0,E=0;const F=[];for(const S of y){const{rows:W,metrics:g}=await v(d,m,l,S,{...G(D,S.length),maxNewTokens:H,compactFrac:t});s+=g.steps,T+=g.compactions,E+=g.tokensGenerated,F.push(...W.map($=>$.text))}return{wallMs:performance.now()-e,steps:s,compactions:T,tokens:E,texts:F}};await j(c[0]);const h=Object.fromEntries(c.map(t=>[r(t),[]])),u={};for(let t=0;t<A;t++)for(const e of c){const s=await j(e);h[r(e)].push(Number(s.wallMs.toFixed(1))),u[r(e)]=s}const M=u[r(c[0])];let w=0;for(const t of c.slice(1)){const e=u[r(t)];for(let s=0;s<M.texts.length;s++)M.texts[s]!==e.texts[s]&&w++}const i=Object.fromEntries(c.map(t=>[r(t),Number(L(h[r(t)]).toFixed(1))])),R=i[r(c[0])],N=Object.keys(i).reduce((t,e)=>i[e]<i[t]?e:t);return{pass:w===0,detail:{source:p,batches:y.map(t=>t.length),rounds:A,wallMedMs:i,best:`${N} ${(100*(1-i[N]/R)).toFixed(1)}% vs f25`,perArm:Object.fromEntries(Object.entries(u).map(([t,e])=>[t,{steps:e.steps,compactions:e.compactions,tokens:e.tokens}])),mismatch:w,runs:h}}}finally{m.buffer.destroy()}},{slow:!0});
2
+ //# sourceMappingURL=dec_compact_sweep-DTumwRLm.js.map
assets/{dec_compact_sweep-D5MD5NcK.js.map → dec_compact_sweep-DTumwRLm.js.map} RENAMED
@@ -1 +1 @@
1
- {"version":3,"file":"dec_compact_sweep-D5MD5NcK.js","sources":["../../src/debug/tests/dec_compact_sweep.js"],"sourcesContent":["// compactFrac A/B on REAL file-mode batches — the decode round's utilization\r\n// lever. dec_profile put the per-step kernels at their ceiling (lm_head sweep\r\n// 2026-07-09: every geometry/dtype arm a wash), but app_stage arithmetic says\r\n// ~35% of row-slots compute rows that already emitted EOS: tokens/steps ≈ 346\r\n// productive rows/step vs ~534 average B. The 0.25 dead-fraction compaction\r\n// threshold (plus 8-step readback granularity × in-flight depth) leaves half\r\n// the batches never compacting at all (53 compactions / 113 batches).\r\n//\r\n// Arms sweep compactFrac down from the production 0.25. Compaction is\r\n// token-exact by construction (routing pinned, live rows copied verbatim —\r\n// compact_equiv gate), so arms must produce IDENTICAL texts: any mismatch\r\n// fails the test. Metric = summed translateBatch wall over the batch set,\r\n// arms interleaved per round, medians over ROUNDS.\r\n//\r\n// Batch set: the first 4 ranges of the real sorted plan (576-row short-row\r\n// batches — where the waste and the win live) + the last 2 (long-row 192-cap\r\n// tail). Fixture fallback uses whatever plan chapter3k×8 yields.\r\nimport { registerTest } from '../registry.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { loadTokenizer } from '../../engine/tokenizer.js';\r\nimport { translateBatch } from '../../engine/generate.js';\r\nimport { autotuneRouting, tunedOptions } from '../../engine/autotune.js';\r\nimport { DECODE_CAP } from '../../engine/constants.js';\r\nimport { segmentSource, packSentences } from '../../app/split.js';\r\nimport { planBatches, lengthOrder } from '../../app/engine.js';\r\nimport { t2s } from '../../app/t2s.js';\r\nimport chapterText from '../../../fixtures/chapter3k.txt?raw';\r\n\r\nconst ROUNDS = 5;\r\nconst ARMS = [0.25, 0.125, 0.0625, 0.03125]; // 0.25 = production baseline\r\nconst armName = (f) => `f${String(f).slice(2)}`;\r\n\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\n\r\nregisterTest('dec_compact_sweep', async (ctx) => {\r\n if (!ctx.hasF16) return { skip: true, reason: 'production stack needs shader-f16' };\r\n const { device } = ctx;\r\n\r\n let text = null;\r\n let source = 'chapter3k×8';\r\n try {\r\n const res = await fetch('/local/qingshan.txt');\r\n if (res.ok) {\r\n text = await res.text();\r\n source = 'qingshan_local';\r\n }\r\n } catch { /* fixture fallback */ }\r\n if (!text) text = chapterText.repeat(8);\r\n\r\n const weights = await loadWeights(device, '/weights', {\r\n targetDtype: 'f16', lmHeadQ8: true, ffnWT: true, projWT: true,\r\n });\r\n try {\r\n const tok = await loadTokenizer();\r\n const gctx = { ...ctx, dtype: 'f16' };\r\n const { tuned } = await autotuneRouting(gctx, weights);\r\n\r\n const conv = t2s(text);\r\n const seg = segmentSource(conv.text);\r\n const rows = packSentences(seg.sentences, seg.paras, 200).rows;\r\n const lens = rows.map((r) => r.length);\r\n const order = lengthOrder(lens);\r\n const ranges = planBatches(order.map((i) => lens[i]), gctx, 2);\r\n const picked = ranges.length > 6\r\n ? [...ranges.slice(0, 4), ...ranges.slice(-2)]\r\n : ranges;\r\n const batches = picked.map(([s, e]) => order.slice(s, e).map((i) => rows[i]));\r\n\r\n const runArm = async (frac) => {\r\n const t0 = performance.now();\r\n let steps = 0;\r\n let compactions = 0;\r\n let tokens = 0;\r\n const texts = [];\r\n for (const srcs of batches) {\r\n const { rows: out, metrics } = await translateBatch(gctx, weights, tok, srcs, {\r\n ...tunedOptions(tuned, srcs.length),\r\n maxNewTokens: DECODE_CAP,\r\n compactFrac: frac,\r\n });\r\n steps += metrics.steps;\r\n compactions += metrics.compactions;\r\n tokens += metrics.tokensGenerated;\r\n texts.push(...out.map((r) => r.text));\r\n }\r\n return { wallMs: performance.now() - t0, steps, compactions, tokens, texts };\r\n };\r\n\r\n // Warmup (pipeline compiles + tokenizer LRU fill) outside the timed rounds.\r\n await runArm(ARMS[0]);\r\n const walls = Object.fromEntries(ARMS.map((f) => [armName(f), []]));\r\n const last = {};\r\n for (let r = 0; r < ROUNDS; r++) {\r\n for (const f of ARMS) {\r\n const res = await runArm(f);\r\n walls[armName(f)].push(Number(res.wallMs.toFixed(1)));\r\n last[armName(f)] = res;\r\n }\r\n }\r\n\r\n // Token-exactness across arms — compaction must never change output.\r\n const base = last[armName(ARMS[0])];\r\n let mismatch = 0;\r\n for (const f of ARMS.slice(1)) {\r\n const t = last[armName(f)];\r\n for (let i = 0; i < base.texts.length; i++) {\r\n if (base.texts[i] !== t.texts[i]) mismatch++;\r\n }\r\n }\r\n\r\n const meds = Object.fromEntries(\r\n ARMS.map((f) => [armName(f), Number(median(walls[armName(f)]).toFixed(1))]),\r\n );\r\n const baseMed = meds[armName(ARMS[0])];\r\n const bestName = Object.keys(meds).reduce((x, y) => (meds[y] < meds[x] ? y : x));\r\n return {\r\n pass: mismatch === 0,\r\n detail: {\r\n source,\r\n batches: batches.map((b) => b.length),\r\n rounds: ROUNDS,\r\n wallMedMs: meds,\r\n best: `${bestName} ${(100 * (1 - meds[bestName] / baseMed)).toFixed(1)}% vs f25`,\r\n perArm: Object.fromEntries(Object.entries(last).map(([k, v]) => [k, {\r\n steps: v.steps, compactions: v.compactions, tokens: v.tokens,\r\n }])),\r\n mismatch,\r\n runs: walls,\r\n },\r\n };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n}, { slow: true });\r\n"],"names":["ROUNDS","ARMS","armName","f","median","xs","s","a","b","m","registerTest","ctx","device","text","source","res","chapterText","weights","loadWeights","tok","loadTokenizer","gctx","tuned","autotuneRouting","conv","t2s","seg","segmentSource","rows","packSentences","lens","r","order","lengthOrder","ranges","planBatches","i","batches","runArm","frac","t0","steps","compactions","tokens","texts","srcs","out","metrics","translateBatch","tunedOptions","DECODE_CAP","walls","last","base","mismatch","t","meds","baseMed","bestName","x","y","k","v"],"mappings":"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"}
 
1
+ {"version":3,"file":"dec_compact_sweep-DTumwRLm.js","sources":["../../src/debug/tests/dec_compact_sweep.js"],"sourcesContent":["// compactFrac A/B on REAL file-mode batches — the decode round's utilization\r\n// lever. dec_profile put the per-step kernels at their ceiling (lm_head sweep\r\n// 2026-07-09: every geometry/dtype arm a wash), but app_stage arithmetic says\r\n// ~35% of row-slots compute rows that already emitted EOS: tokens/steps ≈ 346\r\n// productive rows/step vs ~534 average B. The 0.25 dead-fraction compaction\r\n// threshold (plus 8-step readback granularity �� in-flight depth) leaves half\r\n// the batches never compacting at all (53 compactions / 113 batches).\r\n//\r\n// Arms sweep compactFrac down from the production 0.25. Compaction is\r\n// token-exact by construction (routing pinned, live rows copied verbatim —\r\n// compact_equiv gate), so arms must produce IDENTICAL texts: any mismatch\r\n// fails the test. Metric = summed translateBatch wall over the batch set,\r\n// arms interleaved per round, medians over ROUNDS.\r\n//\r\n// Batch set: the first 4 ranges of the real sorted plan (576-row short-row\r\n// batches — where the waste and the win live) + the last 2 (long-row 192-cap\r\n// tail). Fixture fallback uses whatever plan chapter3k×8 yields.\r\nimport { registerTest } from '../registry.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { loadTokenizer } from '../../engine/tokenizer.js';\r\nimport { translateBatch } from '../../engine/generate.js';\r\nimport { autotuneRouting, tunedOptions } from '../../engine/autotune.js';\r\nimport { DECODE_CAP } from '../../engine/constants.js';\r\nimport { segmentSource, packSentences } from '../../app/split.js';\r\nimport { planBatches, lengthOrder } from '../../app/engine.js';\r\nimport { t2s } from '../../app/t2s.js';\r\nimport chapterText from '../../../fixtures/chapter3k.txt?raw';\r\n\r\nconst ROUNDS = 5;\r\nconst ARMS = [0.25, 0.125, 0.0625, 0.03125]; // 0.25 = production baseline\r\nconst armName = (f) => `f${String(f).slice(2)}`;\r\n\r\nconst median = (xs) => {\r\n const s = [...xs].sort((a, b) => a - b);\r\n const m = s.length >> 1;\r\n return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2;\r\n};\r\n\r\nregisterTest('dec_compact_sweep', async (ctx) => {\r\n if (!ctx.hasF16) return { skip: true, reason: 'production stack needs shader-f16' };\r\n const { device } = ctx;\r\n\r\n let text = null;\r\n let source = 'chapter3k×8';\r\n try {\r\n const res = await fetch('/local/qingshan.txt');\r\n if (res.ok) {\r\n text = await res.text();\r\n source = 'qingshan_local';\r\n }\r\n } catch { /* fixture fallback */ }\r\n if (!text) text = chapterText.repeat(8);\r\n\r\n const weights = await loadWeights(device, '/weights', {\r\n targetDtype: 'f16', lmHeadQ8: true, ffnWT: true, projWT: true,\r\n });\r\n try {\r\n const tok = await loadTokenizer();\r\n const gctx = { ...ctx, dtype: 'f16' };\r\n const { tuned } = await autotuneRouting(gctx, weights);\r\n\r\n const conv = t2s(text);\r\n const seg = segmentSource(conv.text);\r\n const rows = packSentences(seg.sentences, seg.paras, 200).rows;\r\n const lens = rows.map((r) => r.length);\r\n const order = lengthOrder(lens);\r\n const ranges = planBatches(order.map((i) => lens[i]), gctx, 2);\r\n const picked = ranges.length > 6\r\n ? [...ranges.slice(0, 4), ...ranges.slice(-2)]\r\n : ranges;\r\n const batches = picked.map(([s, e]) => order.slice(s, e).map((i) => rows[i]));\r\n\r\n const runArm = async (frac) => {\r\n const t0 = performance.now();\r\n let steps = 0;\r\n let compactions = 0;\r\n let tokens = 0;\r\n const texts = [];\r\n for (const srcs of batches) {\r\n const { rows: out, metrics } = await translateBatch(gctx, weights, tok, srcs, {\r\n ...tunedOptions(tuned, srcs.length),\r\n maxNewTokens: DECODE_CAP,\r\n compactFrac: frac,\r\n });\r\n steps += metrics.steps;\r\n compactions += metrics.compactions;\r\n tokens += metrics.tokensGenerated;\r\n texts.push(...out.map((r) => r.text));\r\n }\r\n return { wallMs: performance.now() - t0, steps, compactions, tokens, texts };\r\n };\r\n\r\n // Warmup (pipeline compiles + tokenizer LRU fill) outside the timed rounds.\r\n await runArm(ARMS[0]);\r\n const walls = Object.fromEntries(ARMS.map((f) => [armName(f), []]));\r\n const last = {};\r\n for (let r = 0; r < ROUNDS; r++) {\r\n for (const f of ARMS) {\r\n const res = await runArm(f);\r\n walls[armName(f)].push(Number(res.wallMs.toFixed(1)));\r\n last[armName(f)] = res;\r\n }\r\n }\r\n\r\n // Token-exactness across arms — compaction must never change output.\r\n const base = last[armName(ARMS[0])];\r\n let mismatch = 0;\r\n for (const f of ARMS.slice(1)) {\r\n const t = last[armName(f)];\r\n for (let i = 0; i < base.texts.length; i++) {\r\n if (base.texts[i] !== t.texts[i]) mismatch++;\r\n }\r\n }\r\n\r\n const meds = Object.fromEntries(\r\n ARMS.map((f) => [armName(f), Number(median(walls[armName(f)]).toFixed(1))]),\r\n );\r\n const baseMed = meds[armName(ARMS[0])];\r\n const bestName = Object.keys(meds).reduce((x, y) => (meds[y] < meds[x] ? y : x));\r\n return {\r\n pass: mismatch === 0,\r\n detail: {\r\n source,\r\n batches: batches.map((b) => b.length),\r\n rounds: ROUNDS,\r\n wallMedMs: meds,\r\n best: `${bestName} ${(100 * (1 - meds[bestName] / baseMed)).toFixed(1)}% vs f25`,\r\n perArm: Object.fromEntries(Object.entries(last).map(([k, v]) => [k, {\r\n steps: v.steps, compactions: v.compactions, tokens: v.tokens,\r\n }])),\r\n mismatch,\r\n runs: walls,\r\n },\r\n };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n}, { slow: true });\r\n"],"names":["ROUNDS","ARMS","armName","f","median","xs","s","a","b","m","registerTest","ctx","device","text","source","res","chapterText","weights","loadWeights","tok","loadTokenizer","gctx","tuned","autotuneRouting","conv","t2s","seg","segmentSource","rows","packSentences","lens","r","order","lengthOrder","ranges","planBatches","i","batches","runArm","frac","t0","steps","compactions","tokens","texts","srcs","out","metrics","translateBatch","tunedOptions","DECODE_CAP","walls","last","base","mismatch","t","meds","baseMed","bestName","x","y","k","v"],"mappings":"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"}
assets/dec_group_sweep-BQZHA49R.js DELETED
@@ -1,2 +0,0 @@
1
- import{r as R}from"./debug-C_LNzFrK.js";import{l as W}from"./weights-D8qtuKag.js";import{l as q}from"./tokenizer-Ex1u7wXD.js";import{t as B}from"./generate-BIP3NpbY.js";import{autotuneRouting as C,tunedOptions as v}from"./autotune-DywP5DSc.js";import{g as z}from"./constants-C8VbFpic.js";import{t as H,s as P,p as Q}from"./t2s-DjPa3Hpi.js";import{l as U,p as G}from"./engine-D57xjIIN.js";import{c as I}from"./chapter3k-DSdzHZt5.js";import"./modulepreload-polyfill-B5Qt9EMX.js";import"./preload-helper-BXl3LOEh.js";import"./shapes-BCQ9D81L.js";import"./f16-wKKZr58e.js";import"./encoder-I9sHImnR.js";import"./pipelines-DJ7cc1m-.js";import"./decoder-CI9o-EVx.js";import"./device-BotbBNoe.js";import"./shortlist-C151mR5c.js";const A=5,n=[8,4,16],J=c=>{const r=[...c].sort((m,i)=>m-i),o=r.length>>1;return r.length%2?r[o]:(r[o-1]+r[o])/2};R("dec_group_sweep",async c=>{if(!c.hasF16)return{skip:!0,reason:"production stack needs shader-f16"};const{device:r}=c;let o=null,m="chapter3k×8";try{const p=await fetch("/local/qingshan.txt");p.ok&&(o=await p.text(),m="qingshan_local")}catch{}o||(o=I.repeat(8));const i=await W(r,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0,projWT:!0});try{const p=await q(),u={...c,dtype:"f16"},{tuned:D}=await C(u,i),F=H(o),w=P(F.text),b=Q(w.sentences,w.paras,200).rows,x=b.map(t=>t.length),k=U(x),l=G(k.map(t=>x[t]),u,2),$=(l.length>6?[...l.slice(0,4),...l.slice(-2)]:l).map(([t,s])=>k.slice(t,s).map(e=>b[e])),O=async t=>{const s=performance.now();let e=0,T=0,E=0;const M=[];for(const N of $){const{rows:S,metrics:d}=await B(u,i,p,N,{...v(D,N.length),maxNewTokens:z,groupSteps:t});e+=d.steps,T+=d.compactions,E+=d.submits,M.push(...S.map(_=>_.text))}return{wallMs:performance.now()-s,steps:e,compactions:T,submits:E,texts:M}};await O(n[0]);const g=Object.fromEntries(n.map(t=>[`g${t}`,[]])),f={};for(let t=0;t<A;t++)for(const s of n){const e=await O(s);g[`g${s}`].push(Number(e.wallMs.toFixed(1))),f[`g${s}`]=e}const y=f[`g${n[0]}`];let h=0;for(const t of n.slice(1)){const s=f[`g${t}`];for(let e=0;e<y.texts.length;e++)y.texts[e]!==s.texts[e]&&h++}const a=Object.fromEntries(n.map(t=>[`g${t}`,Number(J(g[`g${t}`]).toFixed(1))])),j=Object.keys(a).reduce((t,s)=>a[s]<a[t]?s:t);return{pass:h===0,detail:{source:m,batches:$.map(t=>t.length),rounds:A,wallMedMs:a,best:`${j} ${(100*(1-a[j]/a[`g${n[0]}`])).toFixed(1)}% vs g8`,perArm:Object.fromEntries(Object.entries(f).map(([t,s])=>[t,{steps:s.steps,compactions:s.compactions,submits:s.submits}])),mismatch:h,runs:g}}}finally{i.buffer.destroy()}},{slow:!0});
2
- //# sourceMappingURL=dec_group_sweep-BQZHA49R.js.map