Humuhumu33 commited on
Commit
bcdc5b6
·
verified ·
1 Parent(s): a24d0c6

profiler: fix read-only binding + dot8 batched-verify proxy + refined verdict

Browse files
Files changed (1) hide show
  1. kernel-profile.html +10 -7
kernel-profile.html CHANGED
@@ -50,7 +50,7 @@ fn main(@builtin(workgroup_id) wg:vec3<u32>, @builtin(local_invocation_id) lid:v
50
  let word=qw[rowW+w]; let v=w<<2u;
51
  ${mode==='read'?'accu=accu^word;':Array.from({length:R},(_,r)=>`acc=acc+dot16(word^${r}u, v);`).join(' ')}
52
  w=w+${T}u; }
53
- ${mode==='read'?'let acc=f32(accu&1u);':''}
54
  red[lid.x]=acc; workgroupBarrier();
55
  var s=${T>>1}u; loop{ if(s==0u){break;} if(t<s){ red[rr*${T}u+t]=red[rr*${T}u+t]+red[rr*${T}u+t+s]; } workgroupBarrier(); s=s/2u; }
56
  if(t==0u && n0<P.y){ o[n0]=red[rr*${T}u]; }
@@ -67,6 +67,7 @@ const VARIANTS=[
67
  {id:"dot1", name:"dot ×1 (the real kernel)", mode:"dot", R:1, T:64, ROWS:4, grp:"alu"},
68
  {id:"dot2", name:"dot ×2 (2× ALU, same reads)", mode:"dot", R:2, T:64, ROWS:4, grp:"alu"},
69
  {id:"dot4", name:"dot ×4 (4× ALU, same reads)", mode:"dot", R:4, T:64, ROWS:4, grp:"alu"},
 
70
  {id:"occ32", name:"dot ×1 · 32 thr/row · 8 rows/wg", mode:"dot", R:1, T:32, ROWS:8, grp:"occ"},
71
  {id:"occ128",name:"dot ×1 · 128 thr/row · 2 rows/wg", mode:"dot", R:1, T:128,ROWS:2, grp:"occ"},
72
  ];
@@ -120,15 +121,17 @@ const VARIANTS=[
120
  }
121
 
122
  say("done · adapter: "+((info.vendor||"?")+" "+(info.architecture||"")+" "+(info.device||"")).trim(),"ok");
123
- const g=id=>rows.find(r=>r.V.id===id&&r.gbps); const rd=g("read"), d1=g("dot1"), d2=g("dot2"), d4=g("dot4"), o32=g("occ32"), o128=g("occ128");
124
  const maxG=Math.max(...rows.filter(r=>r.gbps).map(r=>r.gbps));
125
- const readVsDot = (rd&&d1)? rd.gbps/d1.gbps : 0;
126
- const aluSlope = (d1&&d4)? d1.gbps/d4.gbps : 0; // >~1.5 ⇒ time scales with ALU ⇒ ALU-throughput bound
127
  const occGain = d1? Math.max(o32?o32.gbps/d1.gbps:0, o128?o128.gbps/d1.gbps:0) : 0;
 
 
128
  let verdict, cls;
129
- if(readVsDot>=1.6){ verdict = `ALU-BOUND. read-only reaches ${rd.gbps.toFixed(0)} GB/s but dot ×1 only ${d1.gbps.toFixed(0)} (${readVsDot.toFixed(1)}× gap), and more ALU scales time down (×1→×4 = ${aluSlope.toFixed(1)}×). The f32 unpack is the wall fewer instructions per weight (int8 dot4I8Packed) is the lever. Spec-decode's batch stays expensive until this is fixed.`; cls="warn"; }
130
- else if(occGain>=1.15){ verdict = `OCCUPANCY/LATENCY-BOUND. read-only dot (${readVsDot.toFixed(1)}×) so ALU is hidden, and changing threads/row moved it ${occGain.toFixed(2)}× — the kernel isn't keeping enough memory requests in flight. Lever = restructure parallelism (rows/wg, threads/row, more waves), NOT int8.`; cls="warn"; }
131
- else{ verdict = `MEMORY/LATENCY-BOUND at this access pattern. read-only (${rd?rd.gbps.toFixed(0):"?"} GB/s) dot ×1 (${d1?d1.gbps.toFixed(0):"?"}), ALU adds little (×1→×4 = ${aluSlope.toFixed(1)}×), and occupancy tweaks barely move it (${occGain.toFixed(2)}×). int8 will NOT help the per-row cooperative read pattern is the ceiling; needs a different memory layout. Compare to the 152 GB/s pure-stream roofline: this pattern leaves ${rd?(100*rd.gbps/152).toFixed(0):"?"}% on the table.`; cls="no"; }
132
 
133
  out.innerHTML=`
134
  <div class="card"><span class="k" style="color:var(--dim)">Test matrix</span> &nbsp; ${N.toLocaleString()} × ${K} · ${(wBytes/1073741824).toFixed(2)} GB · pure-stream roofline 152 GB/s (220 tok/s)</div>
 
50
  let word=qw[rowW+w]; let v=w<<2u;
51
  ${mode==='read'?'accu=accu^word;':Array.from({length:R},(_,r)=>`acc=acc+dot16(word^${r}u, v);`).join(' ')}
52
  w=w+${T}u; }
53
+ ${mode==='read'?'var acc=f32(accu&1u); if(accu==0xffffffffu){ acc=acc+x[0].x; }':''}
54
  red[lid.x]=acc; workgroupBarrier();
55
  var s=${T>>1}u; loop{ if(s==0u){break;} if(t<s){ red[rr*${T}u+t]=red[rr*${T}u+t]+red[rr*${T}u+t+s]; } workgroupBarrier(); s=s/2u; }
56
  if(t==0u && n0<P.y){ o[n0]=red[rr*${T}u]; }
 
67
  {id:"dot1", name:"dot ×1 (the real kernel)", mode:"dot", R:1, T:64, ROWS:4, grp:"alu"},
68
  {id:"dot2", name:"dot ×2 (2× ALU, same reads)", mode:"dot", R:2, T:64, ROWS:4, grp:"alu"},
69
  {id:"dot4", name:"dot ×4 (4× ALU, same reads)", mode:"dot", R:4, T:64, ROWS:4, grp:"alu"},
70
+ {id:"dot8", name:"dot ×8 (KX=8 batched-verify proxy)", mode:"dot", R:8, T:64, ROWS:4, grp:"alu"},
71
  {id:"occ32", name:"dot ×1 · 32 thr/row · 8 rows/wg", mode:"dot", R:1, T:32, ROWS:8, grp:"occ"},
72
  {id:"occ128",name:"dot ×1 · 128 thr/row · 2 rows/wg", mode:"dot", R:1, T:128,ROWS:2, grp:"occ"},
73
  ];
 
121
  }
122
 
123
  say("done · adapter: "+((info.vendor||"?")+" "+(info.architecture||"")+" "+(info.device||"")).trim(),"ok");
124
+ const g=id=>rows.find(r=>r.V.id===id&&r.gbps); const rd=g("read"), d1=g("dot1"), d4=g("dot4"), d8=g("dot8"), o32=g("occ32"), o128=g("occ128");
125
  const maxG=Math.max(...rows.filter(r=>r.gbps).map(r=>r.gbps));
126
+ const readVsDot = (rd&&d1)? rd.gbps/d1.gbps : 0; // >~1.5 ⇒ reads themselves fly, ALU is the wall
127
+ const aluSlope = (d1&&d4)? d1.gbps/d4.gbps : 0; // >~1.5 ⇒ time scales with ALU ⇒ ALU-throughput bound
128
  const occGain = d1? Math.max(o32?o32.gbps/d1.gbps:0, o128?o128.gbps/d1.gbps:0) : 0;
129
+ const batchFree = (d1&&d8)? d8.gbps/d1.gbps : 0; // ~1 ⇒ 8-wide batched verify costs ~same as 1 ⇒ spec-decode is ~free
130
+ const readCeil = rd? rd.gbps : 0;
131
  let verdict, cls;
132
+ const specNote = d8 ? ` Batched verify (dot ×8, the KX=8 spec proxy) runs at ${d8.gbps.toFixed(0)} GB/s = ${batchFree.toFixed(2)}× the single kernel so verifying 8 tokens costs 1 token. Spec-decode IS ~free here; its earlier 1.0× was per-window JS/fence OVERHEAD, not GPU cost. Killing that overhead unlocks the ~4× the 93%-acceptance implies.` : "";
133
+ if(aluSlope>=1.6 && readVsDot>=1.6){ verdict = `ALU-BOUND. reads fly (${readCeil.toFixed(0)} GB/s) but dot ×1 only ${d1.gbps.toFixed(0)}, and ×1→×4 scales ${aluSlope.toFixed(1)}×. Fewer instructions per weight (int8 dot4I8Packed) is the lever.` + specNote; cls="warn"; }
134
+ else{ verdict = `MEMORY-LATENCY-BOUND NOT ALU-bound. Quadrupling the ALU (×1→×4) costs only ${aluSlope.toFixed(1)}× → the f32 unpack is hidden; int8 will NOT help. read-only tops ${readCeil.toFixed(0)} GB/s at this pattern vs 152 pure-stream, and dot ×1 sits at ${d1?d1.gbps.toFixed(0):"?"} (${readCeil?(100*d1.gbps/readCeil).toFixed(0):"?"}% of even the read ceiling). Lever = more memory-level parallelism (register-block several output rows per thread so more loads are in flight before the barrier), NOT int8/occupancy.` + specNote; cls=(occGain>=1.15?"warn":"no"); }
135
 
136
  out.innerHTML=`
137
  <div class="card"><span class="k" style="color:var(--dim)">Test matrix</span> &nbsp; ${N.toLocaleString()} × ${K} · ${(wBytes/1073741824).toFixed(2)} GB · pure-stream roofline 152 GB/s (220 tok/s)</div>