Spaces:
Running
Running
moxhi a1e03ec
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- README.md +36 -36
- adreno-repro.html +0 -358
- assets/addln_embed-DSGHKDTg.js +0 -2
- assets/addln_embed-DSGHKDTg.js.map +0 -1
- assets/adreno_probe-CqGqVTv4.js +0 -393
- assets/adreno_probe-CqGqVTv4.js.map +0 -1
- assets/app_stage-DrqfcKH2.js +0 -2
- assets/app_stage-DrqfcKH2.js.map +0 -1
- assets/argmax-DMqT6ikS.js +0 -2
- assets/argmax-DMqT6ikS.js.map +0 -1
- assets/argmax_fuse-CKXRwPoI.js +0 -2
- assets/argmax_fuse-CKXRwPoI.js.map +0 -1
- assets/attention-1v-Zzb1X.js +0 -65
- assets/attention-1v-Zzb1X.js.map +0 -1
- assets/attn_sweep-CxMb0QH-.js +0 -2
- assets/attn_sweep-CxMb0QH-.js.map +0 -1
- assets/autotune-Bwt_lWMv.js +0 -44
- assets/autotune-Bwt_lWMv.js.map +0 -1
- assets/autotune-CVn9SF1X.js +0 -2
- assets/autotune-CVn9SF1X.js.map +0 -1
- assets/autotune-CaFlLr-b.js +0 -0
- assets/baseline-DFLF_Mw1.js +0 -2
- assets/baseline-DFLF_Mw1.js.map +0 -1
- assets/batch_cap_ab-67ewcIZi.js +0 -2
- assets/batch_cap_ab-67ewcIZi.js.map +0 -1
- assets/bench-BarR4Zp5.js +0 -5
- assets/bench-BarR4Zp5.js.map +0 -1
- assets/bench-D3sid5uF.js +0 -29
- assets/bench-D3sid5uF.js.map +0 -1
- assets/bench-DsT6x25S.js +64 -0
- assets/chapter3k-DSdzHZt5.js +0 -35
- assets/chapter3k-DSdzHZt5.js.map +0 -1
- assets/compact_equiv-ehtvJC3N.js +0 -2
- assets/compact_equiv-ehtvJC3N.js.map +0 -1
- assets/constants-CSVWRdrh.js +0 -2
- assets/constants-CSVWRdrh.js.map +0 -1
- assets/debug-CPpXXfWA.js +0 -12
- assets/debug-CPpXXfWA.js.map +0 -1
- assets/dec_compact_sweep-DTumwRLm.js +0 -2
- assets/dec_compact_sweep-DTumwRLm.js.map +0 -1
- assets/dec_group_sweep-CRbQBEBp.js +0 -2
- assets/dec_group_sweep-CRbQBEBp.js.map +0 -1
- assets/dec_lmhead_sweep-BPuLSi-e.js +0 -2
- assets/dec_lmhead_sweep-BPuLSi-e.js.map +0 -1
- assets/dec_profile-BiK_GKoQ.js +0 -2
- assets/dec_profile-BiK_GKoQ.js.map +0 -1
- assets/decoder-BUiaGDqb.js +0 -2
- assets/decoder-BUiaGDqb.js.map +0 -1
- assets/device-BotbBNoe.js +0 -2
- assets/device-BotbBNoe.js.map +0 -1
README.md
CHANGED
|
@@ -1,36 +1,36 @@
|
|
| 1 |
-
---
|
| 2 |
-
title: Mặc Hi — Chinese→Vietnamese WebGPU Kernels
|
| 3 |
-
emoji: 🖌️
|
| 4 |
-
colorFrom: gray
|
| 5 |
-
colorTo: red
|
| 6 |
-
sdk: static
|
| 7 |
-
pinned: false
|
| 8 |
-
short_description: Dịch truyện Trung→Việt với custom WebGPU kernels
|
| 9 |
-
---
|
| 10 |
-
|
| 11 |
-
# Mặc Hi 墨曦 — dịch truyện Trung→Việt trong trình duyệt
|
| 12 |
-
|
| 13 |
-
Marian NMT (zh→vi) chạy **hoàn toàn trong trình duyệt** trên các WebGPU kernel
|
| 14 |
-
viết tay bằng WGSL — không dùng ONNX Runtime / WASM cho phần suy luận.
|
| 15 |
-
|
| 16 |
-
**Custom kernels:** fused encoder/decoder attention, GEMM/GEMV f16,
|
| 17 |
-
int8 LM head (tiled + reduce), RMS/LayerNorm dùng subgroups,
|
| 18 |
-
mega-kernel decode cho batch nhỏ, autotune routing theo từng GPU
|
| 19 |
-
(có phát hiện driver miscompile trên Adreno 7xx và tự chuyển sang
|
| 20 |
-
biến thể subgroup an toàn).
|
| 21 |
-
|
| 22 |
-
**Tính năng:**
|
| 23 |
-
- 2 model zh→vi (Mặc Hi d448/8×56, Hachimi d576/8×72) — chuyển đổi ngay trong app
|
| 24 |
-
- Tự động chuyển phồn thể → giản thể (dữ liệu OpenCC) trước khi dịch
|
| 25 |
-
- Tokenizer SPM-BPE tự viết (không dùng transformers.js) — toàn bộ pipeline tự viết
|
| 26 |
-
- Batch decode + KV cache, chạy được cả trên GPU điện thoại (Adreno)
|
| 27 |
-
- PWA: cài như app, dịch **offline** sau lần tải model đầu tiên
|
| 28 |
-
- Khôi phục sau device-lost, resume giữa chừng, wake lock khi đang dịch
|
| 29 |
-
|
| 30 |
-
**Yêu cầu:** trình duyệt hỗ trợ WebGPU (Chrome/Edge 121+, Chrome Android).
|
| 31 |
-
Bản chính thức: <https://moxhi.pages.dev>
|
| 32 |
-
|
| 33 |
-
Cảm hứng trình bày từ các space
|
| 34 |
-
[gemma-4-webgpu-kernels](https://huggingface.co/spaces/webml-community/gemma-4-webgpu-kernels)
|
| 35 |
-
và [lfm2-webgpu-kernels](https://huggingface.co/spaces/webml-community/lfm2-webgpu-kernels)
|
| 36 |
-
của webml-community.
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Mặc Hi — Chinese→Vietnamese WebGPU Kernels
|
| 3 |
+
emoji: 🖌️
|
| 4 |
+
colorFrom: gray
|
| 5 |
+
colorTo: red
|
| 6 |
+
sdk: static
|
| 7 |
+
pinned: false
|
| 8 |
+
short_description: Dịch truyện Trung→Việt với custom WebGPU kernels
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
# Mặc Hi 墨曦 — dịch truyện Trung→Việt trong trình duyệt
|
| 12 |
+
|
| 13 |
+
Marian NMT (zh→vi) chạy **hoàn toàn trong trình duyệt** trên các WebGPU kernel
|
| 14 |
+
viết tay bằng WGSL — không dùng ONNX Runtime / WASM cho phần suy luận.
|
| 15 |
+
|
| 16 |
+
**Custom kernels:** fused encoder/decoder attention, GEMM/GEMV f16,
|
| 17 |
+
int8 LM head (tiled + reduce), RMS/LayerNorm dùng subgroups,
|
| 18 |
+
mega-kernel decode cho batch nhỏ, autotune routing theo từng GPU
|
| 19 |
+
(có phát hiện driver miscompile trên Adreno 7xx và tự chuyển sang
|
| 20 |
+
biến thể subgroup an toàn).
|
| 21 |
+
|
| 22 |
+
**Tính năng:**
|
| 23 |
+
- 2 model zh→vi (Mặc Hi d448/8×56, Hachimi d576/8×72) — chuyển đổi ngay trong app
|
| 24 |
+
- Tự động chuyển phồn thể → giản thể (dữ liệu OpenCC) trước khi dịch
|
| 25 |
+
- Tokenizer SPM-BPE tự viết (không dùng transformers.js) — toàn bộ pipeline tự viết
|
| 26 |
+
- Batch decode + KV cache, chạy được cả trên GPU điện thoại (Adreno)
|
| 27 |
+
- PWA: cài như app, dịch **offline** sau lần tải model đầu tiên
|
| 28 |
+
- Khôi phục sau device-lost, resume giữa chừng, wake lock khi đang dịch
|
| 29 |
+
|
| 30 |
+
**Yêu cầu:** trình duyệt hỗ trợ WebGPU (Chrome/Edge 121+, Chrome Android).
|
| 31 |
+
Bản chính thức: <https://moxhi.pages.dev>
|
| 32 |
+
|
| 33 |
+
Cảm hứng trình bày từ các space
|
| 34 |
+
[gemma-4-webgpu-kernels](https://huggingface.co/spaces/webml-community/gemma-4-webgpu-kernels)
|
| 35 |
+
và [lfm2-webgpu-kernels](https://huggingface.co/spaces/webml-community/lfm2-webgpu-kernels)
|
| 36 |
+
của webml-community.
|
adreno-repro.html
DELETED
|
@@ -1,358 +0,0 @@
|
|
| 1 |
-
<!doctype html>
|
| 2 |
-
<meta charset="utf-8">
|
| 3 |
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
| 4 |
-
<title>Adreno WGSL workgroup tree-reduction miscompile — self-contained repro</title>
|
| 5 |
-
<style>
|
| 6 |
-
body { background: #111; color: #ddd; font: 14px/1.45 monospace; margin: 12px; }
|
| 7 |
-
.pass { color: #5d5; } .fail { color: #f55; } .info { color: #aa5; }
|
| 8 |
-
pre { white-space: pre-wrap; word-break: break-all; }
|
| 9 |
-
</style>
|
| 10 |
-
<h2>WGSL workgroup tree-reduction miscompile repro (Adreno 7xx)</h2>
|
| 11 |
-
<p>Five compute shaders, deterministic inputs, results checked on the CPU.<br>
|
| 12 |
-
On affected devices (observed: Adreno 710/7xx, Android 14, Chrome 150):
|
| 13 |
-
<b>#2 #3 #4 FAIL deterministically</b> while #1 (same reduction idiom, minimal
|
| 14 |
-
context) and #5 (subgroup-op workaround) PASS. On healthy devices all five PASS.</p>
|
| 15 |
-
<pre id="out">initializing WebGPU…</pre>
|
| 16 |
-
<script type="module">
|
| 17 |
-
const out = document.getElementById('out');
|
| 18 |
-
const log = (line, cls) => {
|
| 19 |
-
const span = document.createElement('span');
|
| 20 |
-
if (cls) span.className = cls;
|
| 21 |
-
span.textContent = line + '\n';
|
| 22 |
-
out.append(span);
|
| 23 |
-
};
|
| 24 |
-
out.textContent = '';
|
| 25 |
-
|
| 26 |
-
// Deterministic payload, exact in f32; Math.imul matches WGSL u32 wraparound.
|
| 27 |
-
const payload = (i, g) => ((Math.imul(i + 1, 2654435761) ^ Math.imul(g + 1, 40503)) >>> 0) & 1023;
|
| 28 |
-
const VHASH = `
|
| 29 |
-
fn vhash(i: u32, g: u32) -> f32 {
|
| 30 |
-
return f32((((i + 1u) * 2654435761u) ^ ((g + 1u) * 40503u)) & 1023u);
|
| 31 |
-
}`;
|
| 32 |
-
const GROUPS = 256;
|
| 33 |
-
const REPS = 2;
|
| 34 |
-
|
| 35 |
-
// ---- #1 control: the naked idiom (guarded-RMW tree + all-thread broadcast).
|
| 36 |
-
const CONTROL = `
|
| 37 |
-
@group(0) @binding(0) var<storage, read_write> out: array<f32>;
|
| 38 |
-
const WG: u32 = 256u;
|
| 39 |
-
${VHASH}
|
| 40 |
-
var<workgroup> red: array<f32, WG>;
|
| 41 |
-
@compute @workgroup_size(256)
|
| 42 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 43 |
-
let g = wid.x; let tid = lid.x;
|
| 44 |
-
red[tid] = vhash(tid, g);
|
| 45 |
-
workgroupBarrier();
|
| 46 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 47 |
-
if (tid < s) { red[tid] = red[tid] + red[tid + s]; }
|
| 48 |
-
workgroupBarrier();
|
| 49 |
-
}
|
| 50 |
-
out[g * WG + tid] = red[0];
|
| 51 |
-
}`;
|
| 52 |
-
const controlWant = (g) => {
|
| 53 |
-
let s = 0;
|
| 54 |
-
for (let t = 0; t < 256; t++) s += payload(t, g);
|
| 55 |
-
return s;
|
| 56 |
-
};
|
| 57 |
-
|
| 58 |
-
// ---- #2 the same idiom inside a LayerNorm-shaped shader (strided load loop
|
| 59 |
-
// into a second shared array + two tree reductions + broadcast mean/inv-std).
|
| 60 |
-
// This is a structural replica of a real inference kernel; data is generated
|
| 61 |
-
// in-shader so there are no storage READS at all — pure shader structure.
|
| 62 |
-
const LN_BODY = (broadcast) => `
|
| 63 |
-
@group(0) @binding(0) var<storage, read_write> out: array<f32>;
|
| 64 |
-
const WG: u32 = 256u;
|
| 65 |
-
const D: u32 = 448u;
|
| 66 |
-
const EPS: f32 = 1e-5;
|
| 67 |
-
${VHASH}
|
| 68 |
-
fn xval(i: u32, g: u32) -> f32 { return (vhash(i, g) - 512.0) / 256.0; }
|
| 69 |
-
fn rval(i: u32, g: u32) -> f32 { return (vhash(i + 7777u, g) - 512.0) / 256.0; }
|
| 70 |
-
fn gval(i: u32) -> f32 { return 1.0 + (vhash(i, 12345u) - 512.0) / 1024.0; }
|
| 71 |
-
fn bval(i: u32) -> f32 { return (vhash(i, 54321u) - 512.0) / 512.0; }
|
| 72 |
-
var<workgroup> vbuf: array<f32, D>;
|
| 73 |
-
var<workgroup> scratch: array<f32, WG>;
|
| 74 |
-
@compute @workgroup_size(256)
|
| 75 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 76 |
-
let g = wid.x; let tid = lid.x;
|
| 77 |
-
var sum: f32 = 0.0;
|
| 78 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 79 |
-
let v = xval(i, g) + rval(i, g);
|
| 80 |
-
vbuf[i] = v;
|
| 81 |
-
sum = sum + v;
|
| 82 |
-
}
|
| 83 |
-
scratch[tid] = sum;
|
| 84 |
-
workgroupBarrier();
|
| 85 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 86 |
-
if (tid < s) { scratch[tid] = scratch[tid] + scratch[tid + s]; }
|
| 87 |
-
workgroupBarrier();
|
| 88 |
-
}
|
| 89 |
-
${broadcast === 'uload'
|
| 90 |
-
? 'let mu = workgroupUniformLoad(&scratch[0]) / f32(D);'
|
| 91 |
-
: 'let mu = scratch[0] / f32(D);\n workgroupBarrier();'}
|
| 92 |
-
var sq: f32 = 0.0;
|
| 93 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 94 |
-
let dev = vbuf[i] - mu;
|
| 95 |
-
sq = sq + dev * dev;
|
| 96 |
-
}
|
| 97 |
-
scratch[tid] = sq;
|
| 98 |
-
workgroupBarrier();
|
| 99 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 100 |
-
if (tid < s) { scratch[tid] = scratch[tid] + scratch[tid + s]; }
|
| 101 |
-
workgroupBarrier();
|
| 102 |
-
}
|
| 103 |
-
${broadcast === 'uload'
|
| 104 |
-
? 'let inv = inverseSqrt(workgroupUniformLoad(&scratch[0]) / f32(D) + EPS);'
|
| 105 |
-
: 'let inv = inverseSqrt(scratch[0] / f32(D) + EPS);'}
|
| 106 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 107 |
-
out[g * D + i] = gval(i) * (vbuf[i] - mu) * inv + bval(i);
|
| 108 |
-
}
|
| 109 |
-
}`;
|
| 110 |
-
const lnWantRows = [];
|
| 111 |
-
const lnWant = (g, i) => {
|
| 112 |
-
if (!lnWantRows[g]) {
|
| 113 |
-
const D = 448;
|
| 114 |
-
const v = new Float64Array(D);
|
| 115 |
-
let sum = 0;
|
| 116 |
-
for (let j = 0; j < D; j++) {
|
| 117 |
-
v[j] = (payload(j, g) - 512) / 256 + (payload(j + 7777, g) - 512) / 256;
|
| 118 |
-
sum += v[j];
|
| 119 |
-
}
|
| 120 |
-
const mu = sum / D;
|
| 121 |
-
let sq = 0;
|
| 122 |
-
for (let j = 0; j < D; j++) sq += (v[j] - mu) * (v[j] - mu);
|
| 123 |
-
const inv = 1 / Math.sqrt(sq / D + 1e-5);
|
| 124 |
-
lnWantRows[g] = v.map((x, j) =>
|
| 125 |
-
(1 + (payload(j, 12345) - 512) / 1024) * (x - mu) * inv + (payload(j, 54321) - 512) / 512);
|
| 126 |
-
}
|
| 127 |
-
return lnWantRows[g][i];
|
| 128 |
-
};
|
| 129 |
-
|
| 130 |
-
// ---- #4 attention-softmax shape: two reductions REUSING one shared array
|
| 131 |
-
// (max, then sum). Most threads skip the scan loop (len=3 « WG=128) and
|
| 132 |
-
// carry the -1e30 neutral. Output = rowMax + denom per thread. On affected
|
| 133 |
-
// devices the failing value is ≈ -6.4e31 = 64 × (-1e30): one entire
|
| 134 |
-
// 64-thread wave's phase-2 re-writes of red[] were read as their stale
|
| 135 |
-
// phase-1 values ACROSS the barrier.
|
| 136 |
-
const ATTN = `
|
| 137 |
-
@group(0) @binding(0) var<storage, read_write> out: array<f32>;
|
| 138 |
-
const WG: u32 = 128u;
|
| 139 |
-
const D4: u32 = 14u;
|
| 140 |
-
const H: u32 = 4u;
|
| 141 |
-
const LEN: u32 = 3u;
|
| 142 |
-
const SCALE: f32 = ${1 / Math.sqrt(56)};
|
| 143 |
-
${VHASH}
|
| 144 |
-
fn elem(id: u32, salt: u32, g: u32) -> f32 { return (vhash(id, salt + 3u * g) - 512.0) / 512.0; }
|
| 145 |
-
fn qvec(g: u32, h: u32, i4: u32) -> vec4<f32> {
|
| 146 |
-
let base = h * 64u + i4 * 4u;
|
| 147 |
-
return vec4<f32>(elem(base, 11u, g), elem(base + 1u, 11u, g), elem(base + 2u, 11u, g), elem(base + 3u, 11u, g));
|
| 148 |
-
}
|
| 149 |
-
fn kvec(g: u32, h: u32, j: u32, i4: u32) -> vec4<f32> {
|
| 150 |
-
let base = (j * H + h) * 64u + i4 * 4u;
|
| 151 |
-
return vec4<f32>(elem(base, 22u, g), elem(base + 1u, 22u, g), elem(base + 2u, 22u, g), elem(base + 3u, 22u, g));
|
| 152 |
-
}
|
| 153 |
-
var<workgroup> qs4: array<vec4<f32>, D4>;
|
| 154 |
-
var<workgroup> scores: array<f32, 352>;
|
| 155 |
-
var<workgroup> red: array<f32, WG>;
|
| 156 |
-
var<workgroup> part: array<vec4<f32>, WG>;
|
| 157 |
-
@compute @workgroup_size(128)
|
| 158 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 159 |
-
let row = wid.x; let h = wid.y; let tid = lid.x;
|
| 160 |
-
let gi = row * H + h;
|
| 161 |
-
for (var i = tid; i < D4; i = i + WG) { qs4[i] = qvec(row, h, i); }
|
| 162 |
-
workgroupBarrier();
|
| 163 |
-
var localMax: f32 = -1e30;
|
| 164 |
-
for (var j = tid; j < LEN; j = j + WG) {
|
| 165 |
-
var dot4 = vec4<f32>(0.0);
|
| 166 |
-
for (var i = 0u; i < D4; i = i + 1u) { dot4 = dot4 + qs4[i] * kvec(row, h, j, i); }
|
| 167 |
-
let sc = (dot4.x + dot4.y + dot4.z + dot4.w) * SCALE;
|
| 168 |
-
scores[j] = sc;
|
| 169 |
-
localMax = max(localMax, sc);
|
| 170 |
-
}
|
| 171 |
-
red[tid] = localMax;
|
| 172 |
-
workgroupBarrier();
|
| 173 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 174 |
-
if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }
|
| 175 |
-
workgroupBarrier();
|
| 176 |
-
}
|
| 177 |
-
let rowMax = red[0];
|
| 178 |
-
workgroupBarrier(); // red[0] reads done before the sum pass reuses red
|
| 179 |
-
var localSum: f32 = 0.0;
|
| 180 |
-
for (var j = tid; j < LEN; j = j + WG) {
|
| 181 |
-
let e = exp(scores[j] - rowMax);
|
| 182 |
-
scores[j] = e;
|
| 183 |
-
localSum = localSum + e;
|
| 184 |
-
}
|
| 185 |
-
red[tid] = localSum;
|
| 186 |
-
workgroupBarrier();
|
| 187 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 188 |
-
if (tid < s) { red[tid] = red[tid] + red[tid + s]; }
|
| 189 |
-
workgroupBarrier();
|
| 190 |
-
}
|
| 191 |
-
out[gi * WG + tid] = rowMax + red[0];
|
| 192 |
-
}`;
|
| 193 |
-
const attnElem = (id, salt, g) => (payload(id, salt + 3 * g) - 512) / 512;
|
| 194 |
-
const attnWantRows = [];
|
| 195 |
-
const attnWant = (gi) => {
|
| 196 |
-
if (attnWantRows[gi] === undefined) {
|
| 197 |
-
const row = Math.floor(gi / 4);
|
| 198 |
-
const h = gi % 4;
|
| 199 |
-
const q = [];
|
| 200 |
-
for (let d = 0; d < 56; d++) q.push(attnElem(h * 64 + d, 11, row));
|
| 201 |
-
const scores = [];
|
| 202 |
-
for (let j = 0; j < 3; j++) {
|
| 203 |
-
let dot = 0;
|
| 204 |
-
for (let d = 0; d < 56; d++) dot += q[d] * attnElem((j * 4 + h) * 64 + d, 22, row);
|
| 205 |
-
scores.push(dot / Math.sqrt(56));
|
| 206 |
-
}
|
| 207 |
-
const m = Math.max(...scores);
|
| 208 |
-
attnWantRows[gi] = m + scores.reduce((a, s) => a + Math.exp(s - m), 0);
|
| 209 |
-
}
|
| 210 |
-
return attnWantRows[gi];
|
| 211 |
-
};
|
| 212 |
-
|
| 213 |
-
// ---- #5 workaround: identical LayerNorm structure, reductions done with
|
| 214 |
-
// subgroupAdd + subgroupElect + serial fold (no guarded-RMW tree). PASSES on
|
| 215 |
-
// the affected devices.
|
| 216 |
-
const LN_SG = `
|
| 217 |
-
enable subgroups;
|
| 218 |
-
@group(0) @binding(0) var<storage, read_write> out: array<f32>;
|
| 219 |
-
const WG: u32 = 256u;
|
| 220 |
-
const D: u32 = 448u;
|
| 221 |
-
const EPS: f32 = 1e-5;
|
| 222 |
-
${VHASH}
|
| 223 |
-
fn xval(i: u32, g: u32) -> f32 { return (vhash(i, g) - 512.0) / 256.0; }
|
| 224 |
-
fn rval(i: u32, g: u32) -> f32 { return (vhash(i + 7777u, g) - 512.0) / 256.0; }
|
| 225 |
-
fn gval(i: u32) -> f32 { return 1.0 + (vhash(i, 12345u) - 512.0) / 1024.0; }
|
| 226 |
-
fn bval(i: u32) -> f32 { return (vhash(i, 54321u) - 512.0) / 512.0; }
|
| 227 |
-
var<workgroup> vbuf: array<f32, D>;
|
| 228 |
-
var<workgroup> sgSum: array<f32, WG / 4u>;
|
| 229 |
-
var<workgroup> sgSq: array<f32, WG / 4u>;
|
| 230 |
-
@compute @workgroup_size(256)
|
| 231 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>,
|
| 232 |
-
@builtin(subgroup_size) sgSize: u32) {
|
| 233 |
-
let g = wid.x; let tid = lid.x;
|
| 234 |
-
let sgId = tid / sgSize;
|
| 235 |
-
let nSg = (WG + sgSize - 1u) / sgSize;
|
| 236 |
-
var sum: f32 = 0.0;
|
| 237 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 238 |
-
let v = xval(i, g) + rval(i, g);
|
| 239 |
-
vbuf[i] = v;
|
| 240 |
-
sum = sum + v;
|
| 241 |
-
}
|
| 242 |
-
let s1 = subgroupAdd(sum);
|
| 243 |
-
if (subgroupElect()) { sgSum[sgId] = s1; }
|
| 244 |
-
workgroupBarrier();
|
| 245 |
-
var total = 0.0;
|
| 246 |
-
for (var i = 0u; i < nSg; i = i + 1u) { total = total + sgSum[i]; }
|
| 247 |
-
let mu = total / f32(D);
|
| 248 |
-
var sq: f32 = 0.0;
|
| 249 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 250 |
-
let dev = vbuf[i] - mu;
|
| 251 |
-
sq = sq + dev * dev;
|
| 252 |
-
}
|
| 253 |
-
let s2 = subgroupAdd(sq);
|
| 254 |
-
if (subgroupElect()) { sgSq[sgId] = s2; }
|
| 255 |
-
workgroupBarrier();
|
| 256 |
-
var total2 = 0.0;
|
| 257 |
-
for (var i = 0u; i < nSg; i = i + 1u) { total2 = total2 + sgSq[i]; }
|
| 258 |
-
let inv = inverseSqrt(total2 / f32(D) + EPS);
|
| 259 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 260 |
-
out[g * D + i] = gval(i) * (vbuf[i] - mu) * inv + bval(i);
|
| 261 |
-
}
|
| 262 |
-
}`;
|
| 263 |
-
|
| 264 |
-
async function runCase(device, { name, code, outPerGroup, want, tol, dispatchY = 1, expectOnAffected }) {
|
| 265 |
-
const module = device.createShaderModule({ code });
|
| 266 |
-
const info = await module.getCompilationInfo();
|
| 267 |
-
const errors = info.messages.filter((m) => m.type === 'error');
|
| 268 |
-
if (errors.length) {
|
| 269 |
-
log(`COMPILE ERROR ${name}: ${errors[0].message}`, 'fail');
|
| 270 |
-
return;
|
| 271 |
-
}
|
| 272 |
-
const pipeline = device.createComputePipeline({ layout: 'auto', compute: { module, entryPoint: 'main' } });
|
| 273 |
-
const total = GROUPS * dispatchY * outPerGroup;
|
| 274 |
-
const outBuf = device.createBuffer({ size: total * 4, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC });
|
| 275 |
-
const staging = device.createBuffer({ size: total * 4, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ });
|
| 276 |
-
const bindGroup = device.createBindGroup({
|
| 277 |
-
layout: pipeline.getBindGroupLayout(0),
|
| 278 |
-
entries: [{ binding: 0, resource: { buffer: outBuf } }],
|
| 279 |
-
});
|
| 280 |
-
let bad = 0;
|
| 281 |
-
let firstBad = null;
|
| 282 |
-
const badPerRep = [];
|
| 283 |
-
for (let rep = 0; rep < REPS; rep++) {
|
| 284 |
-
const enc = device.createCommandEncoder();
|
| 285 |
-
const pass = enc.beginComputePass();
|
| 286 |
-
pass.setPipeline(pipeline);
|
| 287 |
-
pass.setBindGroup(0, bindGroup);
|
| 288 |
-
pass.dispatchWorkgroups(GROUPS, dispatchY);
|
| 289 |
-
pass.end();
|
| 290 |
-
enc.copyBufferToBuffer(outBuf, 0, staging, 0, total * 4);
|
| 291 |
-
device.queue.submit([enc.finish()]);
|
| 292 |
-
await staging.mapAsync(GPUMapMode.READ);
|
| 293 |
-
const got = new Float32Array(staging.getMappedRange().slice(0));
|
| 294 |
-
staging.unmap();
|
| 295 |
-
let repBad = 0;
|
| 296 |
-
for (let g = 0; g < GROUPS * dispatchY; g++) {
|
| 297 |
-
for (let i = 0; i < outPerGroup; i++) {
|
| 298 |
-
const w = want(g, i);
|
| 299 |
-
const v = got[g * outPerGroup + i];
|
| 300 |
-
if (!(Math.abs(v - w) <= tol)) {
|
| 301 |
-
repBad++;
|
| 302 |
-
if (!firstBad) firstBad = { rep, workgroup: g, lane: i, got: v, want: w };
|
| 303 |
-
}
|
| 304 |
-
}
|
| 305 |
-
}
|
| 306 |
-
badPerRep.push(repBad);
|
| 307 |
-
bad += repBad;
|
| 308 |
-
}
|
| 309 |
-
outBuf.destroy();
|
| 310 |
-
staging.destroy();
|
| 311 |
-
const status = bad === 0 ? 'PASS' : 'FAIL';
|
| 312 |
-
log(`${status} ${name} (expected on affected device: ${expectOnAffected})`, bad === 0 ? 'pass' : 'fail');
|
| 313 |
-
log(` badValues/rep=${JSON.stringify(badPerRep)} of ${total}` +
|
| 314 |
-
(firstBad ? ` firstBad=${JSON.stringify(firstBad)}` : ''), 'info');
|
| 315 |
-
}
|
| 316 |
-
|
| 317 |
-
async function main() {
|
| 318 |
-
if (!navigator.gpu) { log('WebGPU unavailable', 'fail'); return; }
|
| 319 |
-
const adapter = await navigator.gpu.requestAdapter();
|
| 320 |
-
if (!adapter) { log('no adapter', 'fail'); return; }
|
| 321 |
-
const hasSg = adapter.features.has('subgroups');
|
| 322 |
-
const device = await adapter.requestDevice({ requiredFeatures: hasSg ? ['subgroups'] : [] });
|
| 323 |
-
const ai = adapter.info ?? {};
|
| 324 |
-
log(`adapter: vendor=${ai.vendor} architecture=${ai.architecture} device=${ai.device} description=${ai.description}`);
|
| 325 |
-
log(`subgroups=${hasSg}${hasSg ? ` (min ${adapter.info?.subgroupMinSize ?? '?'})` : ''}`);
|
| 326 |
-
log(`UA: ${navigator.userAgent}`);
|
| 327 |
-
log('');
|
| 328 |
-
device.addEventListener?.('uncapturederror', (e) => log(`uncaptured error: ${e.error?.message}`, 'fail'));
|
| 329 |
-
|
| 330 |
-
await runCase(device, {
|
| 331 |
-
name: '#1 control — same tree idiom, minimal shader',
|
| 332 |
-
code: CONTROL, outPerGroup: 256, want: controlWant, tol: 0, expectOnAffected: 'PASS',
|
| 333 |
-
});
|
| 334 |
-
await runCase(device, {
|
| 335 |
-
name: '#2 LayerNorm structure — tree reductions',
|
| 336 |
-
code: LN_BODY('plain'), outPerGroup: 448, want: lnWant, tol: 1e-3, expectOnAffected: 'FAIL (deterministic)',
|
| 337 |
-
});
|
| 338 |
-
await runCase(device, {
|
| 339 |
-
name: '#3 LayerNorm structure — workgroupUniformLoad broadcasts',
|
| 340 |
-
code: LN_BODY('uload'), outPerGroup: 448, want: lnWant, tol: 1e-3, expectOnAffected: 'FAIL (uload does not help)',
|
| 341 |
-
});
|
| 342 |
-
await runCase(device, {
|
| 343 |
-
name: '#4 attention-softmax structure — two reductions reusing one array',
|
| 344 |
-
code: ATTN, outPerGroup: 128, want: attnWant, tol: 1e-3, dispatchY: 4,
|
| 345 |
-
expectOnAffected: 'FAIL (stale-wave: got ≈ -6.4e31 = 64 × -1e30)',
|
| 346 |
-
});
|
| 347 |
-
if (hasSg) {
|
| 348 |
-
await runCase(device, {
|
| 349 |
-
name: '#5 LayerNorm structure — subgroup-op reductions (workaround)',
|
| 350 |
-
code: LN_SG, outPerGroup: 448, want: lnWant, tol: 1e-3, expectOnAffected: 'PASS',
|
| 351 |
-
});
|
| 352 |
-
} else {
|
| 353 |
-
log('SKIP #5 subgroup workaround (subgroups feature unavailable)', 'info');
|
| 354 |
-
}
|
| 355 |
-
log('\ndone.');
|
| 356 |
-
}
|
| 357 |
-
main().catch((e) => log(`FATAL: ${e.message}\n${e.stack}`, 'fail'));
|
| 358 |
-
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assets/addln_embed-DSGHKDTg.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 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-DSGHKDTg.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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":"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"}
|
|
|
|
|
|
assets/adreno_probe-CqGqVTv4.js
DELETED
|
@@ -1,393 +0,0 @@
|
|
| 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}
|
| 10 |
-
`;function ve(e){return`${T(e)}
|
| 11 |
-
var<workgroup> red: array<f32, WG>;
|
| 12 |
-
@compute @workgroup_size(${e})
|
| 13 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 14 |
-
let g = wid.x; let tid = lid.x;
|
| 15 |
-
red[tid] = vhash(tid, g);
|
| 16 |
-
workgroupBarrier();
|
| 17 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 18 |
-
if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }
|
| 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>) {
|
| 26 |
-
let g = wid.x; let tid = lid.x;
|
| 27 |
-
red[tid] = vhash(tid, g);
|
| 28 |
-
workgroupBarrier();
|
| 29 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 30 |
-
if (tid < s) { red[tid] = red[tid] + red[tid + s]; }
|
| 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>) {
|
| 38 |
-
let g = wid.x; let tid = lid.x;
|
| 39 |
-
red[tid] = vhash(tid, g);
|
| 40 |
-
workgroupBarrier();
|
| 41 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 42 |
-
if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }
|
| 43 |
-
workgroupBarrier();
|
| 44 |
-
}
|
| 45 |
-
if (tid == 0u) { out[g] = red[0]; }
|
| 46 |
-
}`;return x(e.device,o,{wg:128,outPerGroup:1,want:ne(128)})});S("adreno_probe_tree_twice_wg128",e=>{const o=`${T(128)}
|
| 47 |
-
var<workgroup> red: array<f32, WG>;
|
| 48 |
-
@compute @workgroup_size(128)
|
| 49 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 50 |
-
let g = wid.x; let tid = lid.x;
|
| 51 |
-
red[tid] = vhash(tid, g);
|
| 52 |
-
workgroupBarrier();
|
| 53 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 54 |
-
if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }
|
| 55 |
-
workgroupBarrier();
|
| 56 |
-
}
|
| 57 |
-
let m = red[0];
|
| 58 |
-
workgroupBarrier(); // red[0] reads done before the sum pass reuses red
|
| 59 |
-
red[tid] = vhash(tid, g) * 0.5 + 1.0;
|
| 60 |
-
workgroupBarrier();
|
| 61 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 62 |
-
if (tid < s) { red[tid] = red[tid] + red[tid + s]; }
|
| 63 |
-
workgroupBarrier();
|
| 64 |
-
}
|
| 65 |
-
out[g * WG + tid] = m + red[0];
|
| 66 |
-
}`,r=t=>{let n=-1/0,i=0;for(let l=0;l<128;l++){const _=N(l,t);n=Math.max(n,_),i+=_*.5+1}return n+i};return x(e.device,o,{wg:128,outPerGroup:128,want:r})});S("adreno_probe_skiploop_wg128",e=>{const o=`${T(128)}
|
| 67 |
-
const LEN: u32 = 16u;
|
| 68 |
-
var<workgroup> scores: array<f32, LEN>;
|
| 69 |
-
var<workgroup> red: array<f32, WG>;
|
| 70 |
-
@compute @workgroup_size(128)
|
| 71 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 72 |
-
let g = wid.x; let tid = lid.x;
|
| 73 |
-
var localMax: f32 = -1e30;
|
| 74 |
-
for (var j = tid; j < LEN; j = j + WG) {
|
| 75 |
-
let sc = vhash(j, g);
|
| 76 |
-
scores[j] = sc;
|
| 77 |
-
localMax = max(localMax, sc);
|
| 78 |
-
}
|
| 79 |
-
red[tid] = localMax;
|
| 80 |
-
workgroupBarrier();
|
| 81 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 82 |
-
if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }
|
| 83 |
-
workgroupBarrier();
|
| 84 |
-
}
|
| 85 |
-
// Consume scores too so the compiler cannot drop it: out = rowMax + scores[tid%LEN].
|
| 86 |
-
out[g * WG + tid] = red[0] + scores[tid % LEN];
|
| 87 |
-
}`,r=(t,n)=>{let i=-1/0;for(let l=0;l<16;l++)i=Math.max(i,N(l,t));return i+N(n%16,t)};return x(e.device,o,{wg:128,outPerGroup:128,want:r})});S("adreno_probe_share_wg128",e=>{const o=`${T(128)}
|
| 88 |
-
var<workgroup> sh: array<f32, WG>;
|
| 89 |
-
@compute @workgroup_size(128)
|
| 90 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 91 |
-
let g = wid.x; let tid = lid.x;
|
| 92 |
-
sh[tid] = vhash(tid, g);
|
| 93 |
-
workgroupBarrier();
|
| 94 |
-
out[g * WG + tid] = sh[(tid + 64u) % WG];
|
| 95 |
-
}`;return x(e.device,o,{wg:128,outPerGroup:128,want:(r,t)=>N((t+64)%128,r)})});S("adreno_probe_uload_wg128",e=>{const o=`${T(128)}
|
| 96 |
-
var<workgroup> red: array<f32, WG>;
|
| 97 |
-
@compute @workgroup_size(128)
|
| 98 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 99 |
-
let g = wid.x; let tid = lid.x;
|
| 100 |
-
red[tid] = vhash(tid, g);
|
| 101 |
-
workgroupBarrier();
|
| 102 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 103 |
-
if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }
|
| 104 |
-
workgroupBarrier();
|
| 105 |
-
}
|
| 106 |
-
out[g * WG + tid] = workgroupUniformLoad(&red[0]);
|
| 107 |
-
}`;return x(e.device,o,{wg:128,outPerGroup:128,want:ne(128)})});S("adreno_probe_sg_wg256",e=>{if(!e.hasSubgroups)return{skip:!0,reason:"subgroups feature unavailable"};const o=`enable subgroups;
|
| 108 |
-
${T(256)}
|
| 109 |
-
var<workgroup> sgSum: array<f32, WG / 4u>;
|
| 110 |
-
@compute @workgroup_size(256)
|
| 111 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>,
|
| 112 |
-
@builtin(subgroup_size) sgSize: u32) {
|
| 113 |
-
let g = wid.x; let tid = lid.x;
|
| 114 |
-
let s1 = subgroupAdd(vhash(tid, g));
|
| 115 |
-
let sgId = tid / sgSize;
|
| 116 |
-
if (subgroupElect()) { sgSum[sgId] = s1; }
|
| 117 |
-
workgroupBarrier();
|
| 118 |
-
let nSg = (WG + sgSize - 1u) / sgSize;
|
| 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}
|
| 131 |
-
var<workgroup> vbuf: array<f32, D>;
|
| 132 |
-
var<workgroup> scratch: array<f32, WG>;
|
| 133 |
-
@compute @workgroup_size(256)
|
| 134 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 135 |
-
let g = wid.x; let tid = lid.x;
|
| 136 |
-
var sum: f32 = 0.0;
|
| 137 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 138 |
-
let v = xval(i, g) + rval(i, g);
|
| 139 |
-
vbuf[i] = v;
|
| 140 |
-
sum = sum + v;
|
| 141 |
-
}
|
| 142 |
-
scratch[tid] = sum;
|
| 143 |
-
workgroupBarrier();
|
| 144 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 145 |
-
if (tid < s) { scratch[tid] = scratch[tid] + scratch[tid + s]; }
|
| 146 |
-
workgroupBarrier();
|
| 147 |
-
}
|
| 148 |
-
let mu = scratch[0] / f32(D);
|
| 149 |
-
workgroupBarrier();
|
| 150 |
-
${e?`
|
| 151 |
-
for (var i = tid; i < D; i = i + WG) { out[g * D + i] = vbuf[i] - mu; }
|
| 152 |
-
`:`
|
| 153 |
-
var sq: f32 = 0.0;
|
| 154 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 155 |
-
let dev = vbuf[i] - mu;
|
| 156 |
-
sq = sq + dev * dev;
|
| 157 |
-
}
|
| 158 |
-
scratch[tid] = sq;
|
| 159 |
-
workgroupBarrier();
|
| 160 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 161 |
-
if (tid < s) { scratch[tid] = scratch[tid] + scratch[tid + s]; }
|
| 162 |
-
workgroupBarrier();
|
| 163 |
-
}
|
| 164 |
-
let inv = inverseSqrt(scratch[0] / f32(D) + EPS);
|
| 165 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 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;
|
| 173 |
-
const LEN: u32 = ${U.LEN}u;
|
| 174 |
-
const JT: u32 = WG / D4;
|
| 175 |
-
const SCORES_CAP: u32 = 352u;
|
| 176 |
-
const SCALE: f32 = ${1/Math.sqrt(U.D)};
|
| 177 |
-
fn elem(id: u32, salt: u32, g: u32) -> f32 { return (vhash(id, salt + 3u * g) - 512.0) / 512.0; }
|
| 178 |
-
fn qvec(g: u32, h: u32, i4: u32) -> vec4<f32> {
|
| 179 |
-
let base = h * 64u + i4 * 4u;
|
| 180 |
-
return vec4<f32>(elem(base, 11u, g), elem(base + 1u, 11u, g), elem(base + 2u, 11u, g), elem(base + 3u, 11u, g));
|
| 181 |
-
}
|
| 182 |
-
fn kvvec(g: u32, h: u32, j: u32, i4: u32, salt: u32) -> vec4<f32> {
|
| 183 |
-
let base = (j * H + h) * 64u + i4 * 4u;
|
| 184 |
-
return vec4<f32>(elem(base, salt, g), elem(base + 1u, salt, g), elem(base + 2u, salt, g), elem(base + 3u, salt, g));
|
| 185 |
-
}
|
| 186 |
-
var<workgroup> qs4: array<vec4<f32>, D4>;
|
| 187 |
-
var<workgroup> scores: array<f32, SCORES_CAP>;
|
| 188 |
-
var<workgroup> red: array<f32, WG>;
|
| 189 |
-
var<workgroup> part: array<vec4<f32>, WG>;
|
| 190 |
-
@compute @workgroup_size(${U.WG})
|
| 191 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 192 |
-
let row = wid.x; let h = wid.y; let tid = lid.x;
|
| 193 |
-
let gi = row * H + h;
|
| 194 |
-
for (var i = tid; i < D4; i = i + WG) { qs4[i] = qvec(row, h, i); }
|
| 195 |
-
workgroupBarrier();
|
| 196 |
-
var localMax: f32 = -1e30;
|
| 197 |
-
for (var j = tid; j < LEN; j = j + WG) {
|
| 198 |
-
var dot4 = vec4<f32>(0.0);
|
| 199 |
-
for (var i = 0u; i < D4; i = i + 1u) { dot4 = dot4 + qs4[i] * kvvec(row, h, j, i, 22u); }
|
| 200 |
-
let sc = (dot4.x + dot4.y + dot4.z + dot4.w) * SCALE;
|
| 201 |
-
scores[j] = sc;
|
| 202 |
-
localMax = max(localMax, sc);
|
| 203 |
-
}
|
| 204 |
-
red[tid] = localMax;
|
| 205 |
-
workgroupBarrier();
|
| 206 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 207 |
-
if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }
|
| 208 |
-
workgroupBarrier();
|
| 209 |
-
}
|
| 210 |
-
let rowMax = red[0];
|
| 211 |
-
workgroupBarrier();
|
| 212 |
-
var localSum: f32 = 0.0;
|
| 213 |
-
for (var j = tid; j < LEN; j = j + WG) {
|
| 214 |
-
let e = exp(scores[j] - rowMax);
|
| 215 |
-
scores[j] = e;
|
| 216 |
-
localSum = localSum + e;
|
| 217 |
-
}
|
| 218 |
-
red[tid] = localSum;
|
| 219 |
-
workgroupBarrier();
|
| 220 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 221 |
-
if (tid < s) { red[tid] = red[tid] + red[tid + s]; }
|
| 222 |
-
workgroupBarrier();
|
| 223 |
-
}
|
| 224 |
-
let denom = red[0];
|
| 225 |
-
${e?`
|
| 226 |
-
out[gi * WG + tid] = rowMax + denom;
|
| 227 |
-
`:`
|
| 228 |
-
let dq = tid % D4;
|
| 229 |
-
let jg = tid / D4;
|
| 230 |
-
var acc = vec4<f32>(0.0);
|
| 231 |
-
if (jg < JT) {
|
| 232 |
-
for (var j = jg; j < LEN; j = j + JT) {
|
| 233 |
-
acc = acc + scores[j] * kvvec(row, h, j, dq, 33u);
|
| 234 |
-
}
|
| 235 |
-
}
|
| 236 |
-
part[tid] = acc;
|
| 237 |
-
workgroupBarrier();
|
| 238 |
-
if (tid < D4) {
|
| 239 |
-
var o = vec4<f32>(0.0);
|
| 240 |
-
for (var g2 = 0u; g2 < JT; g2 = g2 + 1u) { o = o + part[g2 * D4 + tid]; }
|
| 241 |
-
o = o / denom;
|
| 242 |
-
let yoff = gi * D + tid * 4u;
|
| 243 |
-
out[yoff] = o.x;
|
| 244 |
-
out[yoff + 1u] = o.y;
|
| 245 |
-
out[yoff + 2u] = o.z;
|
| 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}
|
| 253 |
-
var<workgroup> vbuf: array<f32, D>;
|
| 254 |
-
var<workgroup> scratch: array<f32, WG>;
|
| 255 |
-
@compute @workgroup_size(256)
|
| 256 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 257 |
-
let g = wid.x; let tid = lid.x;
|
| 258 |
-
var sum: f32 = 0.0;
|
| 259 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 260 |
-
let v = xval(i, g) + rval(i, g);
|
| 261 |
-
vbuf[i] = v;
|
| 262 |
-
sum = sum + v;
|
| 263 |
-
}
|
| 264 |
-
scratch[tid] = sum;
|
| 265 |
-
workgroupBarrier();
|
| 266 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 267 |
-
if (tid < s) { scratch[tid] = scratch[tid] + scratch[tid + s]; }
|
| 268 |
-
workgroupBarrier();
|
| 269 |
-
}
|
| 270 |
-
let mu = workgroupUniformLoad(&scratch[0]) / f32(D);
|
| 271 |
-
var sq: f32 = 0.0;
|
| 272 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 273 |
-
let dev = vbuf[i] - mu;
|
| 274 |
-
sq = sq + dev * dev;
|
| 275 |
-
}
|
| 276 |
-
scratch[tid] = sq;
|
| 277 |
-
workgroupBarrier();
|
| 278 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 279 |
-
if (tid < s) { scratch[tid] = scratch[tid] + scratch[tid + s]; }
|
| 280 |
-
workgroupBarrier();
|
| 281 |
-
}
|
| 282 |
-
let inv = inverseSqrt(workgroupUniformLoad(&scratch[0]) / f32(D) + EPS);
|
| 283 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 284 |
-
out[g * D + i] = gval(i) * (vbuf[i] - mu) * inv + bval(i);
|
| 285 |
-
}
|
| 286 |
-
}`;return x(e.device,o,{wg:256,outPerGroup:Y,want:ie(Y,!1),tol:.001})});S("adreno_probe3_attn_gen_sg",e=>{if(!e.hasSubgroups)return{skip:!0,reason:"subgroups feature unavailable"};const o=`enable subgroups;
|
| 287 |
-
${T(U.WG)}
|
| 288 |
-
const D: u32 = ${U.D}u;
|
| 289 |
-
const D4: u32 = ${U.D4}u;
|
| 290 |
-
const H: u32 = ${U.H}u;
|
| 291 |
-
const LEN: u32 = ${U.LEN}u;
|
| 292 |
-
const JT: u32 = WG / D4;
|
| 293 |
-
const SCORES_CAP: u32 = 352u;
|
| 294 |
-
const SCALE: f32 = ${1/Math.sqrt(U.D)};
|
| 295 |
-
fn elem(id: u32, salt: u32, g: u32) -> f32 { return (vhash(id, salt + 3u * g) - 512.0) / 512.0; }
|
| 296 |
-
fn qvec(g: u32, h: u32, i4: u32) -> vec4<f32> {
|
| 297 |
-
let base = h * 64u + i4 * 4u;
|
| 298 |
-
return vec4<f32>(elem(base, 11u, g), elem(base + 1u, 11u, g), elem(base + 2u, 11u, g), elem(base + 3u, 11u, g));
|
| 299 |
-
}
|
| 300 |
-
fn kvvec(g: u32, h: u32, j: u32, i4: u32, salt: u32) -> vec4<f32> {
|
| 301 |
-
let base = (j * H + h) * 64u + i4 * 4u;
|
| 302 |
-
return vec4<f32>(elem(base, salt, g), elem(base + 1u, salt, g), elem(base + 2u, salt, g), elem(base + 3u, salt, g));
|
| 303 |
-
}
|
| 304 |
-
var<workgroup> qs4: array<vec4<f32>, D4>;
|
| 305 |
-
var<workgroup> scores: array<f32, SCORES_CAP>;
|
| 306 |
-
var<workgroup> sgm: array<f32, WG / 4u>;
|
| 307 |
-
var<workgroup> sgs: array<f32, WG / 4u>;
|
| 308 |
-
var<workgroup> part: array<vec4<f32>, WG>;
|
| 309 |
-
@compute @workgroup_size(${U.WG})
|
| 310 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>,
|
| 311 |
-
@builtin(subgroup_size) sgSize: u32) {
|
| 312 |
-
let row = wid.x; let h = wid.y; let tid = lid.x;
|
| 313 |
-
let gi = row * H + h;
|
| 314 |
-
let sgId = tid / sgSize;
|
| 315 |
-
let nSg = (WG + sgSize - 1u) / sgSize;
|
| 316 |
-
for (var i = tid; i < D4; i = i + WG) { qs4[i] = qvec(row, h, i); }
|
| 317 |
-
workgroupBarrier();
|
| 318 |
-
var localMax: f32 = -1e30;
|
| 319 |
-
for (var j = tid; j < LEN; j = j + WG) {
|
| 320 |
-
var dot4 = vec4<f32>(0.0);
|
| 321 |
-
for (var i = 0u; i < D4; i = i + 1u) { dot4 = dot4 + qs4[i] * kvvec(row, h, j, i, 22u); }
|
| 322 |
-
let sc = (dot4.x + dot4.y + dot4.z + dot4.w) * SCALE;
|
| 323 |
-
scores[j] = sc;
|
| 324 |
-
localMax = max(localMax, sc);
|
| 325 |
-
}
|
| 326 |
-
let m1 = subgroupMax(localMax);
|
| 327 |
-
if (subgroupElect()) { sgm[sgId] = m1; }
|
| 328 |
-
workgroupBarrier(); // also publishes scores for phase 2
|
| 329 |
-
var rowMax = sgm[0];
|
| 330 |
-
for (var i = 1u; i < nSg; i = i + 1u) { rowMax = max(rowMax, sgm[i]); }
|
| 331 |
-
var localSum: f32 = 0.0;
|
| 332 |
-
for (var j = tid; j < LEN; j = j + WG) {
|
| 333 |
-
let e = exp(scores[j] - rowMax);
|
| 334 |
-
scores[j] = e;
|
| 335 |
-
localSum = localSum + e;
|
| 336 |
-
}
|
| 337 |
-
let s2 = subgroupAdd(localSum);
|
| 338 |
-
if (subgroupElect()) { sgs[sgId] = s2; }
|
| 339 |
-
workgroupBarrier(); // publishes exp'd scores for phase 3
|
| 340 |
-
var denom = sgs[0];
|
| 341 |
-
for (var i = 1u; i < nSg; i = i + 1u) { denom = denom + sgs[i]; }
|
| 342 |
-
let dq = tid % D4;
|
| 343 |
-
let jg = tid / D4;
|
| 344 |
-
var acc = vec4<f32>(0.0);
|
| 345 |
-
if (jg < JT) {
|
| 346 |
-
for (var j = jg; j < LEN; j = j + JT) {
|
| 347 |
-
acc = acc + scores[j] * kvvec(row, h, j, dq, 33u);
|
| 348 |
-
}
|
| 349 |
-
}
|
| 350 |
-
part[tid] = acc;
|
| 351 |
-
workgroupBarrier();
|
| 352 |
-
if (tid < D4) {
|
| 353 |
-
var o = vec4<f32>(0.0);
|
| 354 |
-
for (var g2 = 0u; g2 < JT; g2 = g2 + 1u) { o = o + part[g2 * D4 + tid]; }
|
| 355 |
-
o = o / denom;
|
| 356 |
-
let yoff = gi * D + tid * 4u;
|
| 357 |
-
out[yoff] = o.x;
|
| 358 |
-
out[yoff + 1u] = o.y;
|
| 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>;
|
| 366 |
-
@compute @workgroup_size(256)
|
| 367 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 368 |
-
let g = wid.x; let tid = lid.x;
|
| 369 |
-
var sum: f32 = 0.0;
|
| 370 |
-
for (var i = tid; i < D; i = i + WG) { sum = sum + (vhash(i, g) - 512.0) / 256.0; }
|
| 371 |
-
red[tid] = sum;
|
| 372 |
-
workgroupBarrier();
|
| 373 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 374 |
-
if (tid < s) { red[tid] = red[tid] + red[tid + s]; }
|
| 375 |
-
workgroupBarrier();
|
| 376 |
-
}
|
| 377 |
-
out[g * WG + tid] = red[0];
|
| 378 |
-
}`,r=t=>{let n=0;for(let i=0;i<Y;i++)n+=Z(i,t);return n};return x(e.device,o,{wg:256,outPerGroup:256,want:r})});S("adreno_probe3_vbuf_sum_wg256",e=>{const o=`${T(256)}
|
| 379 |
-
var<workgroup> vbuf: array<f32, WG>;
|
| 380 |
-
var<workgroup> red: array<f32, WG>;
|
| 381 |
-
@compute @workgroup_size(256)
|
| 382 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 383 |
-
let g = wid.x; let tid = lid.x;
|
| 384 |
-
vbuf[tid] = vhash(tid, g);
|
| 385 |
-
red[tid] = vhash(tid, g);
|
| 386 |
-
workgroupBarrier();
|
| 387 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 388 |
-
if (tid < s) { red[tid] = red[tid] + red[tid + s]; }
|
| 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-CqGqVTv4.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
{"version":3,"mappings":"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","names":["GROUPS","REPS","payload","tid","g","WGSL_HASH","runProbe","device","code","wg","outPerGroup","want","tol","dispatchY","module","errors","m","pipeline","totalGroups","outElems","outBuf","bindGroup","badLanes","badGroups","firstBad","badPerRep","rep","encoder","pass","got","readback","repBad","i","w","v","header","treeBcastCode","maxWant","sumWant","s","registerTest","ctx","t","p","lane","j","ADDLN_D","WGSL_ADDLN_DATA","xval","rval","gval","bval","addLnWant","d","muOnly","cache","row","sum","mu","sq","inv","LN_EPS","addLnGenCode","runAddLnReal","sg","D_MODEL","rows","x","r","gamma","beta","getPipeline","addLnSource","usage","params","bufs","a","createBuffer","yBuf","buffer","binding","b","ATTN","attnElem","id","salt","attnGenCode","p12","attnRef","gi","D","H","LEN","h","q","scores","dot","e","denom","out","acc","rowMax","detectTreeReductionBug","__vitePreload","treeBug","xx","smallF","idx","toHalf","f32ToF16","runAttnRealDims","B","M","L","lens","HD","k","scale","len","mx","attentionSource","elem","lensBuf","raw","expandF16","K","vrow","n","kk","gemmRowLnSource","bb","runAttnBlockDims","QB","JB","attentionBlockSource","fnv","bytes","hashModel","root","bins","bin","buf","detail","err"],"ignoreList":[],"sources":["../../src/debug/tests/adreno_probe.js"],"sourcesContent":["// Adreno reduction-bug bisect probes (2026-07 Android \"dịch loạn\" regression).\r\n//\r\n// Evidence from the failing device (Adreno 7xx, subgroups min 64):\r\n// FAIL attention.wgsl (f16 AND f32, outputs ~0) add_layernorm.wgsl (both dtypes)\r\n// PASS attention_block, gemm_gemv, argmax_penalty — same tree-reduce idiom\r\n// The static discriminator between the two sets is unclear (argmax has an\r\n// early return + a WG-wide tree + barriers and passes), so these standalone\r\n// micro-kernels bisect the space on-device. Every probe is deterministic:\r\n// payloads are small-integer hashes (exact in f32), so expected values are\r\n// exact and tol is 0. Each runs GROUPS workgroups × REPS dispatches because\r\n// the real failures hit only SOME workgroups per dispatch (5/32 in\r\n// attn_encoder_f32) — a scheduling-dependent bug needs volume to show up.\r\n//\r\n// Probe map (expected on a healthy device: all PASS):\r\n// tree_bcast_wg64 tree reduce + all-thread read of red[0], single wave\r\n// tree_bcast_wg128 same at attention's WG (first tree step crosses waves)\r\n// tree_sum_wg256 sum tree + all-thread broadcast at add_ln's WG\r\n// tree_single_wg128 same tree, only tid 0 reads the result (argmax shape)\r\n// tree_twice_wg128 max tree, broadcast, then sum tree REUSING red\r\n// (attention's exact phase-1/2 sequence)\r\n// skiploop_wg128 attention phase 1 verbatim: len=16 so most threads\r\n// skip the scan loop and carry the -1e30 neutral\r\n// share_wg128 no tree — write shared, barrier, read another wave's\r\n// slot (attention_block-style visibility control)\r\n// uload_wg128 fix candidate A: workgroupUniformLoad(&red[0])\r\n// sg_wg256 fix candidate B: subgroupAdd + elect + serial fold\r\n// (add_layernorm's IF_SG variant shape)\r\n// ROUND 2 (probe2_*): round 1 all PASSED on the failing device — the naked\r\n// reduction idiom is fine on Adreno. The bug needs more of the real kernels'\r\n// context. Ladder: full structural replicas of add_ln / attention with\r\n// IN-SHADER synthetic data (no bindings) vs the REAL add_ln kernel at volume\r\n// (256 rows × 4 reps). gen FAIL → miscompile is in the shader structure\r\n// (bisect further via the _mu / _p12 cut-downs); gen PASS + real FAIL → the\r\n// trigger is in the binding/load path (uniform params, storage reads, layout).\r\nimport { registerTest } from '../registry.js';\r\nimport { createBuffer, readback } from '../gpu-utils.js';\r\nimport { getPipeline } from '../../engine/pipelines.js';\r\nimport { D_MODEL, LN_EPS } from '../../engine/constants.js';\r\nimport { f32ToF16, expandF16 } from '../../engine/f16.js';\r\nimport addLnSource from '../../engine/kernels/add_layernorm.wgsl?raw';\r\nimport attentionSource from '../../engine/kernels/attention.wgsl?raw';\r\nimport attentionBlockSource from '../../engine/kernels/attention_block.wgsl?raw';\r\nimport gemmRowLnSource from '../../engine/kernels/gemm_row_ln.wgsl?raw';\r\n\r\nconst GROUPS = 256;\r\nconst REPS = 4;\r\n\r\n// Deterministic payload, exact in f32: (((tid+1)·2654435761) ^ ((g+1)·40503)) & 1023.\r\n// WGSL u32 arithmetic wraps; Math.imul matches it bit-for-bit.\r\nconst payload = (tid, g) => ((Math.imul(tid + 1, 2654435761) ^ Math.imul(g + 1, 40503)) >>> 0) & 1023;\r\n\r\nconst WGSL_HASH = /* wgsl */ `\r\nfn vhash(tid: u32, g: u32) -> f32 {\r\n return f32((((tid + 1u) * 2654435761u) ^ ((g + 1u) * 40503u)) & 1023u);\r\n}\r\n`;\r\n\r\n// One probe run: build pipeline from `code`, dispatch GROUPS workgroups REPS\r\n// times (fresh encoder each rep), compare every lane against `want(g, tid)`.\r\n// outPerGroup = lanes written per workgroup (WG for broadcast probes, 1 for\r\n// the single-reader probe).\r\nasync function runProbe(device, code, { wg, outPerGroup, want, tol = 0, dispatchY = 1 }) {\r\n const module = device.createShaderModule({ code });\r\n const info = await module.getCompilationInfo();\r\n const errors = info.messages.filter((m) => m.type === 'error');\r\n if (errors.length) {\r\n return { pass: false, detail: { compileErrors: errors.map((m) => m.message).slice(0, 3) } };\r\n }\r\n const pipeline = device.createComputePipeline({\r\n layout: 'auto',\r\n compute: { module, entryPoint: 'main' },\r\n });\r\n const totalGroups = GROUPS * dispatchY;\r\n const outElems = totalGroups * outPerGroup;\r\n const outBuf = device.createBuffer({\r\n size: outElems * 4,\r\n usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,\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\r\n let badLanes = 0;\r\n const badGroups = new Set();\r\n let firstBad = null;\r\n const badPerRep = [];\r\n for (let rep = 0; rep < REPS; rep++) {\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(GROUPS, dispatchY);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n const got = new Float32Array(await readback(device, outBuf, outElems * 4));\r\n let repBad = 0;\r\n for (let g = 0; g < totalGroups; g++) {\r\n for (let i = 0; i < outPerGroup; i++) {\r\n const w = want(g, i);\r\n const v = got[g * outPerGroup + i];\r\n if (!(Math.abs(v - w) <= tol)) {\r\n repBad++;\r\n badGroups.add(g);\r\n if (!firstBad) firstBad = { rep, g, lane: i, got: v, want: w };\r\n }\r\n }\r\n }\r\n badPerRep.push(repBad);\r\n badLanes += repBad;\r\n }\r\n outBuf.destroy();\r\n return {\r\n pass: badLanes === 0,\r\n detail: {\r\n wg, groups: totalGroups, reps: REPS, badLanes, badGroups: badGroups.size, badPerRep,\r\n ...(firstBad ? { firstBad } : {}),\r\n },\r\n };\r\n}\r\n\r\nconst header = (wg) => /* wgsl */ `\r\n@group(0) @binding(0) var<storage, read_write> out: array<f32>;\r\nconst WG: u32 = ${wg}u;\r\n${WGSL_HASH}\r\n`;\r\n\r\n// Tree reduce (max) over red[WG] + broadcast read by ALL threads — the shape\r\n// attention.wgsl and add_layernorm.wgsl share and argmax does not.\r\nfunction treeBcastCode(wg) {\r\n return /* wgsl */ `${header(wg)}\r\nvar<workgroup> red: 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 red[tid] = vhash(tid, g);\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }\r\n workgroupBarrier();\r\n }\r\n out[g * WG + tid] = red[0];\r\n}`;\r\n}\r\n\r\nconst maxWant = (wg) => (g) => {\r\n let m = -Infinity;\r\n for (let t = 0; t < wg; t++) m = Math.max(m, payload(t, g));\r\n return m;\r\n};\r\nconst sumWant = (wg) => (g) => {\r\n let s = 0;\r\n for (let t = 0; t < wg; t++) s += payload(t, g);\r\n return s;\r\n};\r\n\r\nregisterTest('adreno_probe_tree_bcast_wg64', (ctx) =>\r\n runProbe(ctx.device, treeBcastCode(64), { wg: 64, outPerGroup: 64, want: maxWant(64) }));\r\n\r\nregisterTest('adreno_probe_tree_bcast_wg128', (ctx) =>\r\n runProbe(ctx.device, treeBcastCode(128), { wg: 128, outPerGroup: 128, want: maxWant(128) }));\r\n\r\n// Sum tree at add_ln's WG=256.\r\nregisterTest('adreno_probe_tree_sum_wg256', (ctx) => {\r\n const code = /* wgsl */ `${header(256)}\r\nvar<workgroup> red: array<f32, WG>;\r\n@compute @workgroup_size(256)\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 red[tid] = vhash(tid, g);\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { red[tid] = red[tid] + red[tid + s]; }\r\n workgroupBarrier();\r\n }\r\n out[g * WG + tid] = red[0];\r\n}`;\r\n return runProbe(ctx.device, code, { wg: 256, outPerGroup: 256, want: sumWant(256) });\r\n});\r\n\r\n// Same tree, but only tid 0 reads red[0] — argmax_penalty's (passing) shape.\r\nregisterTest('adreno_probe_tree_single_wg128', (ctx) => {\r\n const code = /* wgsl */ `${header(128)}\r\nvar<workgroup> red: array<f32, WG>;\r\n@compute @workgroup_size(128)\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 red[tid] = vhash(tid, g);\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }\r\n workgroupBarrier();\r\n }\r\n if (tid == 0u) { out[g] = red[0]; }\r\n}`;\r\n return runProbe(ctx.device, code, { wg: 128, outPerGroup: 1, want: maxWant(128) });\r\n});\r\n\r\n// Max tree → broadcast → sum tree reusing red — attention's exact phase-1/2\r\n// sequence. want = max + Σ(payload·0.5 + 1) (all halves: exact in f32).\r\nregisterTest('adreno_probe_tree_twice_wg128', (ctx) => {\r\n const code = /* wgsl */ `${header(128)}\r\nvar<workgroup> red: array<f32, WG>;\r\n@compute @workgroup_size(128)\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 red[tid] = vhash(tid, g);\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }\r\n workgroupBarrier();\r\n }\r\n let m = red[0];\r\n workgroupBarrier(); // red[0] reads done before the sum pass reuses red\r\n red[tid] = vhash(tid, g) * 0.5 + 1.0;\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { red[tid] = red[tid] + red[tid + s]; }\r\n workgroupBarrier();\r\n }\r\n out[g * WG + tid] = m + red[0];\r\n}`;\r\n const want = (g) => {\r\n let m = -Infinity; let s = 0;\r\n for (let t = 0; t < 128; t++) {\r\n const p = payload(t, g);\r\n m = Math.max(m, p);\r\n s += p * 0.5 + 1;\r\n }\r\n return m + s;\r\n };\r\n return runProbe(ctx.device, code, { wg: 128, outPerGroup: 128, want });\r\n});\r\n\r\n// attention.wgsl phase 1 verbatim at encoder shape: len=16 « WG, so threads\r\n// 16..127 skip the scan loop entirely and carry the -1e30 neutral into the\r\n// max tree; all threads then broadcast-read the result.\r\nregisterTest('adreno_probe_skiploop_wg128', (ctx) => {\r\n const code = /* wgsl */ `${header(128)}\r\nconst LEN: u32 = 16u;\r\nvar<workgroup> scores: array<f32, LEN>;\r\nvar<workgroup> red: array<f32, WG>;\r\n@compute @workgroup_size(128)\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 localMax: f32 = -1e30;\r\n for (var j = tid; j < LEN; j = j + WG) {\r\n let sc = vhash(j, g);\r\n scores[j] = sc;\r\n localMax = max(localMax, sc);\r\n }\r\n red[tid] = localMax;\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }\r\n workgroupBarrier();\r\n }\r\n // Consume scores too so the compiler cannot drop it: out = rowMax + scores[tid%LEN].\r\n out[g * WG + tid] = red[0] + scores[tid % LEN];\r\n}`;\r\n const want = (g, lane) => {\r\n let m = -Infinity;\r\n for (let j = 0; j < 16; j++) m = Math.max(m, payload(j, g));\r\n return m + payload(lane % 16, g);\r\n };\r\n return runProbe(ctx.device, code, { wg: 128, outPerGroup: 128, want });\r\n});\r\n\r\n// No tree at all: write own slot, one barrier, read a slot 64 threads away\r\n// (guaranteed cross-wave at Adreno's wave 64). attention_block-style control.\r\nregisterTest('adreno_probe_share_wg128', (ctx) => {\r\n const code = /* wgsl */ `${header(128)}\r\nvar<workgroup> sh: array<f32, WG>;\r\n@compute @workgroup_size(128)\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 sh[tid] = vhash(tid, g);\r\n workgroupBarrier();\r\n out[g * WG + tid] = sh[(tid + 64u) % WG];\r\n}`;\r\n return runProbe(ctx.device, code, {\r\n wg: 128, outPerGroup: 128, want: (g, lane) => payload((lane + 64) % 128, g),\r\n });\r\n});\r\n\r\n// Fix candidate A: broadcast via workgroupUniformLoad instead of a plain read.\r\nregisterTest('adreno_probe_uload_wg128', (ctx) => {\r\n const code = /* wgsl */ `${header(128)}\r\nvar<workgroup> red: array<f32, WG>;\r\n@compute @workgroup_size(128)\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 red[tid] = vhash(tid, g);\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }\r\n workgroupBarrier();\r\n }\r\n out[g * WG + tid] = workgroupUniformLoad(&red[0]);\r\n}`;\r\n return runProbe(ctx.device, code, { wg: 128, outPerGroup: 128, want: maxWant(128) });\r\n});\r\n\r\n// Fix candidate B: subgroupAdd + elect + serial fold (add_layernorm IF_SG\r\n// shape) with an all-thread broadcast of the folded total.\r\nregisterTest('adreno_probe_sg_wg256', (ctx) => {\r\n if (!ctx.hasSubgroups) return { skip: true, reason: 'subgroups feature unavailable' };\r\n const code = /* wgsl */ `enable subgroups;\r\n${header(256)}\r\nvar<workgroup> sgSum: array<f32, WG / 4u>;\r\n@compute @workgroup_size(256)\r\nfn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>,\r\n @builtin(subgroup_size) sgSize: u32) {\r\n let g = wid.x; let tid = lid.x;\r\n let s1 = subgroupAdd(vhash(tid, g));\r\n let sgId = tid / sgSize;\r\n if (subgroupElect()) { sgSum[sgId] = s1; }\r\n workgroupBarrier();\r\n let nSg = (WG + sgSize - 1u) / sgSize;\r\n var total = 0.0;\r\n for (var i = 0u; i < nSg; i = i + 1u) { total = total + sgSum[i]; }\r\n out[g * WG + tid] = total;\r\n}`;\r\n return runProbe(ctx.device, code, { wg: 256, outPerGroup: 256, want: sumWant(256) });\r\n});\r\n\r\n// ------------------------------------------------------------- round 2 ---\r\n\r\n// Shared synthetic-data formulas (exact small ints scaled by powers of two —\r\n// identical in WGSL f32 and JS f64). JS mirrors are below each probe.\r\nconst ADDLN_D = 448;\r\nconst WGSL_ADDLN_DATA = /* wgsl */ `\r\nfn xval(i: u32, g: u32) -> f32 { return (vhash(i, g) - 512.0) / 256.0; }\r\nfn rval(i: u32, g: u32) -> f32 { return (vhash(i + 7777u, g) - 512.0) / 256.0; }\r\nfn gval(i: u32) -> f32 { return 1.0 + (vhash(i, 12345u) - 512.0) / 1024.0; }\r\nfn bval(i: u32) -> f32 { return (vhash(i, 54321u) - 512.0) / 512.0; }\r\n`;\r\nconst xval = (i, g) => (payload(i, g) - 512) / 256;\r\nconst rval = (i, g) => (payload(i + 7777, g) - 512) / 256;\r\nconst gval = (i) => 1 + (payload(i, 12345) - 512) / 1024;\r\nconst bval = (i) => (payload(i, 54321) - 512) / 512;\r\n\r\n// f64 add_ln reference for row g: full output, or (v - mu) when muOnly.\r\nfunction addLnWant(d, muOnly) {\r\n const cache = new Map();\r\n return (g, i) => {\r\n let row = cache.get(g);\r\n if (!row) {\r\n const v = new Float64Array(d);\r\n let sum = 0;\r\n for (let j = 0; j < d; j++) { v[j] = xval(j, g) + rval(j, g); sum += v[j]; }\r\n const mu = sum / d;\r\n let sq = 0;\r\n for (let j = 0; j < d; j++) sq += (v[j] - mu) * (v[j] - mu);\r\n const inv = 1 / Math.sqrt(sq / d + LN_EPS);\r\n row = new Float64Array(d);\r\n for (let j = 0; j < d; j++) {\r\n row[j] = muOnly ? v[j] - mu : gval(j) * (v[j] - mu) * inv + bval(j);\r\n }\r\n cache.set(g, row);\r\n }\r\n return row[i];\r\n };\r\n}\r\n\r\n// Structural replica of add_layernorm.wgsl (f32, WG 256, D 448) with\r\n// in-shader data — no uniform, no storage reads. muOnly stops after the\r\n// first reduction (out = v - mu).\r\nfunction addLnGenCode(muOnly) {\r\n return /* wgsl */ `${header(256)}\r\nconst D: u32 = ${ADDLN_D}u;\r\nconst EPS: f32 = ${LN_EPS};\r\n${WGSL_ADDLN_DATA}\r\nvar<workgroup> vbuf: array<f32, D>;\r\nvar<workgroup> scratch: array<f32, WG>;\r\n@compute @workgroup_size(256)\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 = xval(i, g) + rval(i, g);\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${muOnly ? `\r\n for (var i = tid; i < D; i = i + WG) { out[g * D + i] = vbuf[i] - mu; }\r\n` : `\r\n var sq: f32 = 0.0;\r\n for (var i = tid; i < D; i = i + WG) {\r\n let dev = vbuf[i] - mu;\r\n sq = sq + dev * dev;\r\n }\r\n scratch[tid] = sq;\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 inv = inverseSqrt(scratch[0] / f32(D) + EPS);\r\n for (var i = tid; i < D; i = i + WG) {\r\n out[g * D + i] = gval(i) * (vbuf[i] - mu) * inv + bval(i);\r\n }\r\n`}\r\n}`;\r\n}\r\n\r\nregisterTest('adreno_probe2_addln_gen', (ctx) =>\r\n runProbe(ctx.device, addLnGenCode(false), {\r\n wg: 256, outPerGroup: ADDLN_D, want: addLnWant(ADDLN_D, false), tol: 1e-3,\r\n }));\r\n\r\nregisterTest('adreno_probe2_addln_gen_mu', (ctx) =>\r\n runProbe(ctx.device, addLnGenCode(true), {\r\n wg: 256, outPerGroup: ADDLN_D, want: addLnWant(ADDLN_D, true), tol: 1e-3,\r\n }));\r\n\r\n// The REAL add_layernorm.wgsl (f32, via getPipeline exactly like production)\r\n// at probe volume: 256 rows, deterministic buffers, 4 dispatches. sg=true\r\n// builds the IF_SG (subgroupAdd) variant — production fix candidate.\r\nasync function runAddLnReal(ctx, sg) {\r\n const { device } = ctx;\r\n const d = D_MODEL;\r\n const rows = GROUPS;\r\n const x = new Float32Array(rows * d);\r\n const r = new Float32Array(rows * d);\r\n const gamma = new Float32Array(d);\r\n const beta = new Float32Array(d);\r\n for (let g = 0; g < rows; g++) {\r\n for (let i = 0; i < d; i++) {\r\n x[g * d + i] = xval(i, g);\r\n r[g * d + i] = rval(i, g);\r\n }\r\n }\r\n for (let i = 0; i < d; i++) { gamma[i] = gval(i); beta[i] = bval(i); }\r\n const want = addLnWant(d, false);\r\n\r\n const pipeline = getPipeline(device, 'add_ln', addLnSource, {\r\n t: 'f32', wg: 256, sg, defines: { D: d, EPS: LN_EPS },\r\n });\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const params = device.createBuffer({ size: 16, usage: GPUBufferUsage.UNIFORM, mappedAtCreation: true });\r\n new Uint32Array(params.getMappedRange()).set([rows, 0, 0, 0]);\r\n params.unmap();\r\n const bufs = [x, r, gamma, beta].map((a) => createBuffer(device, a, usage));\r\n const yBuf = device.createBuffer({ size: rows * d * 4, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [params, ...bufs, yBuf].map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n\r\n const tol = 1e-3;\r\n let badLanes = 0;\r\n const badGroups = new Set();\r\n let firstBad = null;\r\n const badPerRep = [];\r\n for (let rep = 0; rep < REPS; rep++) {\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(rows);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n const got = new Float32Array(await readback(device, yBuf, rows * d * 4));\r\n let repBad = 0;\r\n for (let g = 0; g < rows; g++) {\r\n for (let i = 0; i < d; i++) {\r\n const w = want(g, i);\r\n const v = got[g * d + i];\r\n if (!(Math.abs(v - w) <= tol)) {\r\n repBad++;\r\n badGroups.add(g);\r\n if (!firstBad) firstBad = { rep, g, lane: i, got: v, want: w };\r\n }\r\n }\r\n }\r\n badPerRep.push(repBad);\r\n badLanes += repBad;\r\n }\r\n for (const b of [params, ...bufs, yBuf]) b.destroy();\r\n return {\r\n pass: badLanes === 0,\r\n detail: {\r\n kernel: sg ? 'add_ln (real, f32, sg)' : 'add_ln (real, f32)',\r\n rows, d, reps: REPS, tol, badLanes,\r\n badGroups: badGroups.size, badPerRep, ...(firstBad ? { firstBad } : {}),\r\n },\r\n };\r\n}\r\n\r\nregisterTest('adreno_probe2_addln_real', (ctx) => runAddLnReal(ctx, false));\r\n\r\n// Structural replica of attention.wgsl (f32, WG 128, D 56, H 4, len 3 of\r\n// L 4 — the exact attn_encoder_f32 failing shape) with in-shader data.\r\n// p12 stops after phase 2 (out = rowMax + denom per thread).\r\nconst ATTN = { D: 56, D4: 14, WG: 128, H: 4, LEN: 3, JT: Math.floor(128 / 14) };\r\nconst attnElem = (id, salt, g) => (payload(id, salt + 3 * g) - 512) / 512;\r\n\r\nfunction attnGenCode(p12) {\r\n return /* wgsl */ `${header(ATTN.WG)}\r\nconst D: u32 = ${ATTN.D}u;\r\nconst D4: u32 = ${ATTN.D4}u;\r\nconst H: u32 = ${ATTN.H}u;\r\nconst LEN: u32 = ${ATTN.LEN}u;\r\nconst JT: u32 = WG / D4;\r\nconst SCORES_CAP: u32 = 352u;\r\nconst SCALE: f32 = ${1 / Math.sqrt(ATTN.D)};\r\nfn elem(id: u32, salt: u32, g: u32) -> f32 { return (vhash(id, salt + 3u * g) - 512.0) / 512.0; }\r\nfn qvec(g: u32, h: u32, i4: u32) -> vec4<f32> {\r\n let base = h * 64u + i4 * 4u;\r\n return vec4<f32>(elem(base, 11u, g), elem(base + 1u, 11u, g), elem(base + 2u, 11u, g), elem(base + 3u, 11u, g));\r\n}\r\nfn kvvec(g: u32, h: u32, j: u32, i4: u32, salt: u32) -> vec4<f32> {\r\n let base = (j * H + h) * 64u + i4 * 4u;\r\n return vec4<f32>(elem(base, salt, g), elem(base + 1u, salt, g), elem(base + 2u, salt, g), elem(base + 3u, salt, g));\r\n}\r\nvar<workgroup> qs4: array<vec4<f32>, D4>;\r\nvar<workgroup> scores: array<f32, SCORES_CAP>;\r\nvar<workgroup> red: array<f32, WG>;\r\nvar<workgroup> part: array<vec4<f32>, WG>;\r\n@compute @workgroup_size(${ATTN.WG})\r\nfn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {\r\n let row = wid.x; let h = wid.y; let tid = lid.x;\r\n let gi = row * H + h;\r\n for (var i = tid; i < D4; i = i + WG) { qs4[i] = qvec(row, h, i); }\r\n workgroupBarrier();\r\n var localMax: f32 = -1e30;\r\n for (var j = tid; j < LEN; j = j + WG) {\r\n var dot4 = vec4<f32>(0.0);\r\n for (var i = 0u; i < D4; i = i + 1u) { dot4 = dot4 + qs4[i] * kvvec(row, h, j, i, 22u); }\r\n let sc = (dot4.x + dot4.y + dot4.z + dot4.w) * SCALE;\r\n scores[j] = sc;\r\n localMax = max(localMax, sc);\r\n }\r\n red[tid] = localMax;\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { red[tid] = max(red[tid], red[tid + s]); }\r\n workgroupBarrier();\r\n }\r\n let rowMax = red[0];\r\n workgroupBarrier();\r\n var localSum: f32 = 0.0;\r\n for (var j = tid; j < LEN; j = j + WG) {\r\n let e = exp(scores[j] - rowMax);\r\n scores[j] = e;\r\n localSum = localSum + e;\r\n }\r\n red[tid] = localSum;\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { red[tid] = red[tid] + red[tid + s]; }\r\n workgroupBarrier();\r\n }\r\n let denom = red[0];\r\n${p12 ? `\r\n out[gi * WG + tid] = rowMax + denom;\r\n` : `\r\n let dq = tid % D4;\r\n let jg = tid / D4;\r\n var acc = vec4<f32>(0.0);\r\n if (jg < JT) {\r\n for (var j = jg; j < LEN; j = j + JT) {\r\n acc = acc + scores[j] * kvvec(row, h, j, dq, 33u);\r\n }\r\n }\r\n part[tid] = acc;\r\n workgroupBarrier();\r\n if (tid < D4) {\r\n var o = vec4<f32>(0.0);\r\n for (var g2 = 0u; g2 < JT; g2 = g2 + 1u) { o = o + part[g2 * D4 + tid]; }\r\n o = o / denom;\r\n let yoff = gi * D + tid * 4u;\r\n out[yoff] = o.x;\r\n out[yoff + 1u] = o.y;\r\n out[yoff + 2u] = o.z;\r\n out[yoff + 3u] = o.w;\r\n }\r\n`}\r\n}`;\r\n}\r\n\r\n// f64 reference per (gi = row·H + h): softmax attention over len 3.\r\nfunction attnRef(gi) {\r\n const { D, H, LEN } = ATTN;\r\n const row = Math.floor(gi / H);\r\n const h = gi % H;\r\n const q = new Float64Array(D);\r\n for (let d = 0; d < D; d++) q[d] = attnElem(h * 64 + d, 11, row);\r\n const scores = new Float64Array(LEN);\r\n for (let j = 0; j < LEN; j++) {\r\n let dot = 0;\r\n for (let d = 0; d < D; d++) dot += q[d] * attnElem((j * H + h) * 64 + d, 22, row);\r\n scores[j] = dot / Math.sqrt(D);\r\n }\r\n const m = Math.max(...scores);\r\n const e = scores.map((s) => Math.exp(s - m));\r\n const denom = e.reduce((a, b) => a + b, 0);\r\n const out = new Float64Array(D);\r\n for (let d = 0; d < D; d++) {\r\n let acc = 0;\r\n for (let j = 0; j < LEN; j++) acc += e[j] * attnElem((j * H + h) * 64 + d, 33, row);\r\n out[d] = acc / denom;\r\n }\r\n return { rowMax: m, denom, out };\r\n}\r\n\r\nregisterTest('adreno_probe2_attn_gen', (ctx) => {\r\n const cache = new Map();\r\n const want = (gi, lane) => {\r\n if (!cache.has(gi)) cache.set(gi, attnRef(gi));\r\n return cache.get(gi).out[lane];\r\n };\r\n return runProbe(ctx.device, attnGenCode(false), {\r\n wg: ATTN.WG, outPerGroup: ATTN.D, want, tol: 1e-3, dispatchY: ATTN.H,\r\n });\r\n});\r\n\r\nregisterTest('adreno_probe2_attn_gen_p12', (ctx) => {\r\n const cache = new Map();\r\n const want = (gi) => {\r\n if (!cache.has(gi)) {\r\n const { rowMax, denom } = attnRef(gi);\r\n cache.set(gi, rowMax + denom);\r\n }\r\n return cache.get(gi);\r\n };\r\n return runProbe(ctx.device, attnGenCode(true), {\r\n wg: ATTN.WG, outPerGroup: ATTN.WG, want, tol: 1e-3, dispatchY: ATTN.H,\r\n });\r\n});\r\n\r\n// ------------------------------------------------------------- round 3 ---\r\n//\r\n// Round 2 on the failing device: ALL gen replicas FAIL, identically to the\r\n// real kernel (addln_gen firstBad == addln_real firstBad) → binding path is\r\n// irrelevant, the miscompile is in the shader structure. addln failures are\r\n// perfectly DETERMINISTIC (same badLanes every rep); attn_gen_p12's\r\n// firstBad -6.4e31 = 64·(-1e30) → in the second reduction, one whole wave's\r\n// re-written red[] slots were read as their PHASE-1 leftovers.\r\n// Round 3: (a) run the fix candidates on the failing structures — the real\r\n// add_ln sg variant, sg attention, uload broadcasts; (b) two mechanism\r\n// probes isolating the remaining delta between passing round-1 shapes and\r\n// failing round-2 shapes (strided multi-trip partial loop; second shared\r\n// array consumed post-broadcast).\r\n\r\nregisterTest('adreno_probe3_addln_real_sg', (ctx) =>\r\n ctx.hasSubgroups ? runAddLnReal(ctx, true) : { skip: true, reason: 'subgroups feature unavailable' });\r\n\r\n// addln replica with workgroupUniformLoad broadcasts (mu and inv).\r\nregisterTest('adreno_probe3_addln_gen_uload', (ctx) => {\r\n const code = /* wgsl */ `${header(256)}\r\nconst D: u32 = ${ADDLN_D}u;\r\nconst EPS: f32 = ${LN_EPS};\r\n${WGSL_ADDLN_DATA}\r\nvar<workgroup> vbuf: array<f32, D>;\r\nvar<workgroup> scratch: array<f32, WG>;\r\n@compute @workgroup_size(256)\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 = xval(i, g) + rval(i, g);\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 = workgroupUniformLoad(&scratch[0]) / f32(D);\r\n var sq: f32 = 0.0;\r\n for (var i = tid; i < D; i = i + WG) {\r\n let dev = vbuf[i] - mu;\r\n sq = sq + dev * dev;\r\n }\r\n scratch[tid] = sq;\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 inv = inverseSqrt(workgroupUniformLoad(&scratch[0]) / f32(D) + EPS);\r\n for (var i = tid; i < D; i = i + WG) {\r\n out[g * D + i] = gval(i) * (vbuf[i] - mu) * inv + bval(i);\r\n }\r\n}`;\r\n return runProbe(ctx.device, code, {\r\n wg: 256, outPerGroup: ADDLN_D, want: addLnWant(ADDLN_D, false), tol: 1e-3,\r\n });\r\n});\r\n\r\n// Attention replica, full output, with the reductions swapped for subgroup\r\n// ops (subgroupMax/subgroupAdd + elect + serial fold — decoder_mega IF_SG /\r\n// add_ln IF_SG shape; two separate partial arrays, no red[] reuse).\r\nregisterTest('adreno_probe3_attn_gen_sg', (ctx) => {\r\n if (!ctx.hasSubgroups) return { skip: true, reason: 'subgroups feature unavailable' };\r\n const code = /* wgsl */ `enable subgroups;\r\n${header(ATTN.WG)}\r\nconst D: u32 = ${ATTN.D}u;\r\nconst D4: u32 = ${ATTN.D4}u;\r\nconst H: u32 = ${ATTN.H}u;\r\nconst LEN: u32 = ${ATTN.LEN}u;\r\nconst JT: u32 = WG / D4;\r\nconst SCORES_CAP: u32 = 352u;\r\nconst SCALE: f32 = ${1 / Math.sqrt(ATTN.D)};\r\nfn elem(id: u32, salt: u32, g: u32) -> f32 { return (vhash(id, salt + 3u * g) - 512.0) / 512.0; }\r\nfn qvec(g: u32, h: u32, i4: u32) -> vec4<f32> {\r\n let base = h * 64u + i4 * 4u;\r\n return vec4<f32>(elem(base, 11u, g), elem(base + 1u, 11u, g), elem(base + 2u, 11u, g), elem(base + 3u, 11u, g));\r\n}\r\nfn kvvec(g: u32, h: u32, j: u32, i4: u32, salt: u32) -> vec4<f32> {\r\n let base = (j * H + h) * 64u + i4 * 4u;\r\n return vec4<f32>(elem(base, salt, g), elem(base + 1u, salt, g), elem(base + 2u, salt, g), elem(base + 3u, salt, g));\r\n}\r\nvar<workgroup> qs4: array<vec4<f32>, D4>;\r\nvar<workgroup> scores: array<f32, SCORES_CAP>;\r\nvar<workgroup> sgm: array<f32, WG / 4u>;\r\nvar<workgroup> sgs: array<f32, WG / 4u>;\r\nvar<workgroup> part: array<vec4<f32>, WG>;\r\n@compute @workgroup_size(${ATTN.WG})\r\nfn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>,\r\n @builtin(subgroup_size) sgSize: u32) {\r\n let row = wid.x; let h = wid.y; let tid = lid.x;\r\n let gi = row * H + h;\r\n let sgId = tid / sgSize;\r\n let nSg = (WG + sgSize - 1u) / sgSize;\r\n for (var i = tid; i < D4; i = i + WG) { qs4[i] = qvec(row, h, i); }\r\n workgroupBarrier();\r\n var localMax: f32 = -1e30;\r\n for (var j = tid; j < LEN; j = j + WG) {\r\n var dot4 = vec4<f32>(0.0);\r\n for (var i = 0u; i < D4; i = i + 1u) { dot4 = dot4 + qs4[i] * kvvec(row, h, j, i, 22u); }\r\n let sc = (dot4.x + dot4.y + dot4.z + dot4.w) * SCALE;\r\n scores[j] = sc;\r\n localMax = max(localMax, sc);\r\n }\r\n let m1 = subgroupMax(localMax);\r\n if (subgroupElect()) { sgm[sgId] = m1; }\r\n workgroupBarrier(); // also publishes scores for phase 2\r\n var rowMax = sgm[0];\r\n for (var i = 1u; i < nSg; i = i + 1u) { rowMax = max(rowMax, sgm[i]); }\r\n var localSum: f32 = 0.0;\r\n for (var j = tid; j < LEN; j = j + WG) {\r\n let e = exp(scores[j] - rowMax);\r\n scores[j] = e;\r\n localSum = localSum + e;\r\n }\r\n let s2 = subgroupAdd(localSum);\r\n if (subgroupElect()) { sgs[sgId] = s2; }\r\n workgroupBarrier(); // publishes exp'd scores for phase 3\r\n var denom = sgs[0];\r\n for (var i = 1u; i < nSg; i = i + 1u) { denom = denom + sgs[i]; }\r\n let dq = tid % D4;\r\n let jg = tid / D4;\r\n var acc = vec4<f32>(0.0);\r\n if (jg < JT) {\r\n for (var j = jg; j < LEN; j = j + JT) {\r\n acc = acc + scores[j] * kvvec(row, h, j, dq, 33u);\r\n }\r\n }\r\n part[tid] = acc;\r\n workgroupBarrier();\r\n if (tid < D4) {\r\n var o = vec4<f32>(0.0);\r\n for (var g2 = 0u; g2 < JT; g2 = g2 + 1u) { o = o + part[g2 * D4 + tid]; }\r\n o = o / denom;\r\n let yoff = gi * D + tid * 4u;\r\n out[yoff] = o.x;\r\n out[yoff + 1u] = o.y;\r\n out[yoff + 2u] = o.z;\r\n out[yoff + 3u] = o.w;\r\n }\r\n}`;\r\n const cache = new Map();\r\n const want = (gi, lane) => {\r\n if (!cache.has(gi)) cache.set(gi, attnRef(gi));\r\n return cache.get(gi).out[lane];\r\n };\r\n return runProbe(ctx.device, code, {\r\n wg: ATTN.WG, outPerGroup: ATTN.D, want, tol: 1e-3, dispatchY: ATTN.H,\r\n });\r\n});\r\n\r\n// Attention replica with workgroupUniformLoad broadcasts (rowMax and denom),\r\n// tree reductions unchanged.\r\nregisterTest('adreno_probe3_attn_gen_uload', (ctx) => {\r\n const code = attnGenCode(false)\r\n .replace('let rowMax = red[0];\\n workgroupBarrier();', 'let rowMax = workgroupUniformLoad(&red[0]);')\r\n .replace('let denom = red[0];', 'let denom = workgroupUniformLoad(&red[0]);');\r\n if (!code.includes('workgroupUniformLoad')) throw new Error('uload rewrite did not apply');\r\n const cache = new Map();\r\n const want = (gi, lane) => {\r\n if (!cache.has(gi)) cache.set(gi, attnRef(gi));\r\n return cache.get(gi).out[lane];\r\n };\r\n return runProbe(ctx.device, code, {\r\n wg: ATTN.WG, outPerGroup: ATTN.D, want, tol: 1e-3, dispatchY: ATTN.H,\r\n });\r\n});\r\n\r\n// Mechanism A: round-1 naked sum tree + broadcast, but the partial comes\r\n// from a strided loop with NON-UNIFORM trip counts (2 iterations for\r\n// tid < 192, 1 for tid >= 192) — the delta add_ln adds over tree_sum_wg256.\r\nregisterTest('adreno_probe3_striped_sum_wg256', (ctx) => {\r\n const code = /* wgsl */ `${header(256)}\r\nconst D: u32 = ${ADDLN_D}u;\r\nvar<workgroup> red: array<f32, WG>;\r\n@compute @workgroup_size(256)\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) { sum = sum + (vhash(i, g) - 512.0) / 256.0; }\r\n red[tid] = sum;\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { red[tid] = red[tid] + red[tid + s]; }\r\n workgroupBarrier();\r\n }\r\n out[g * WG + tid] = red[0];\r\n}`;\r\n const want = (g) => {\r\n let s = 0;\r\n for (let i = 0; i < ADDLN_D; i++) s += xval(i, g);\r\n return s;\r\n };\r\n return runProbe(ctx.device, code, { wg: 256, outPerGroup: 256, want });\r\n});\r\n\r\n// Mechanism B: naked sum tree + broadcast, plus a SECOND shared array\r\n// written uniformly pre-reduction and read cross-wave post-broadcast.\r\nregisterTest('adreno_probe3_vbuf_sum_wg256', (ctx) => {\r\n const code = /* wgsl */ `${header(256)}\r\nvar<workgroup> vbuf: array<f32, WG>;\r\nvar<workgroup> red: array<f32, WG>;\r\n@compute @workgroup_size(256)\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 vbuf[tid] = vhash(tid, g);\r\n red[tid] = vhash(tid, g);\r\n workgroupBarrier();\r\n for (var s = WG / 2u; s > 0u; s = s >> 1u) {\r\n if (tid < s) { red[tid] = red[tid] + red[tid + s]; }\r\n workgroupBarrier();\r\n }\r\n out[g * WG + tid] = red[0] + vbuf[(tid + 64u) % WG];\r\n}`;\r\n const want = (g, lane) => sumWant(256)(g) + payload((lane + 64) % 256, g);\r\n return runProbe(ctx.device, code, { wg: 256, outPerGroup: 256, want });\r\n});\r\n\r\n// ------------------------------------------------------------- round 4 ---\r\n// The production fix (attention IF_SG + forced sg via autotune) shipped;\r\n// this reports what the engine's correctness probe decides on THIS device.\r\n// Expected: treeBug false on healthy devices, true on the affected Adreno\r\n// (where the app then forces sg at every reduction site). The kernel-level\r\n// verdicts live in attn_sg_* / addln (sg) / sg_golden / megasg_golden.\r\nregisterTest('adreno_probe4_detect', async (ctx) => {\r\n const { detectTreeReductionBug } = await import('../../engine/autotune.js');\r\n const treeBug = await detectTreeReductionBug(ctx.device);\r\n return {\r\n pass: typeof treeBug === 'boolean',\r\n detail: { treeBug, sgAvailable: !!ctx.hasSubgroups, willForceSg: treeBug && !!ctx.hasSubgroups },\r\n };\r\n});\r\n\r\n// ------------------------------------------------------------- round 5 ---\r\n// Hachimi-60 dims (d_model 576): the REAL add_ln sg kernel at D=576 —\r\n// WG 256 threads take 3/2 loop trips instead of moxhi-448's 2/2-or-1, and\r\n// the miscompile family is trip-count-sensitive. Mirrors runAddLnReal.\r\nregisterTest('adreno_probe5_addln_sg_d576', async (ctx) => {\r\n if (!ctx.hasSubgroups) return { skip: true, reason: 'subgroups feature unavailable' };\r\n const { device } = ctx;\r\n const d = 576;\r\n const rows = GROUPS;\r\n const x = new Float32Array(rows * d);\r\n const r = new Float32Array(rows * d);\r\n const gamma = new Float32Array(d);\r\n const beta = new Float32Array(d);\r\n for (let g = 0; g < rows; g++) {\r\n for (let i = 0; i < d; i++) {\r\n x[g * d + i] = xval(i, g);\r\n r[g * d + i] = rval(i, g);\r\n }\r\n }\r\n for (let i = 0; i < d; i++) { gamma[i] = gval(i); beta[i] = bval(i); }\r\n const cache = new Map();\r\n const want = (g, i) => {\r\n if (!cache.has(g)) {\r\n const v = new Float64Array(d);\r\n let sum = 0;\r\n for (let j = 0; j < d; j++) { v[j] = xval(j, g) + rval(j, g); sum += v[j]; }\r\n const mu = sum / d;\r\n let sq = 0;\r\n for (let j = 0; j < d; j++) sq += (v[j] - mu) * (v[j] - mu);\r\n const inv = 1 / Math.sqrt(sq / d + LN_EPS);\r\n cache.set(g, v.map((xx, j) => gval(j) * (xx - mu) * inv + bval(j)));\r\n }\r\n return cache.get(g)[i];\r\n };\r\n const pipeline = getPipeline(device, 'add_ln', addLnSource, {\r\n t: 'f32', wg: 256, sg: true, defines: { D: d, EPS: LN_EPS },\r\n });\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const params = device.createBuffer({ size: 16, usage: GPUBufferUsage.UNIFORM, mappedAtCreation: true });\r\n new Uint32Array(params.getMappedRange()).set([rows, 0, 0, 0]);\r\n params.unmap();\r\n const bufs = [x, r, gamma, beta].map((a) => createBuffer(device, a, usage));\r\n const yBuf = device.createBuffer({ size: rows * d * 4, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [params, ...bufs, yBuf].map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n const tol = 1e-3;\r\n let badLanes = 0;\r\n let firstBad = null;\r\n const badPerRep = [];\r\n for (let rep = 0; rep < REPS; rep++) {\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(rows);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n const got = new Float32Array(await readback(device, yBuf, rows * d * 4));\r\n let repBad = 0;\r\n for (let g = 0; g < rows; g++) {\r\n for (let i = 0; i < d; i++) {\r\n const w = want(g, i);\r\n if (!(Math.abs(got[g * d + i] - w) <= tol)) {\r\n repBad++;\r\n if (!firstBad) firstBad = { rep, g, lane: i, got: got[g * d + i], want: w };\r\n }\r\n }\r\n }\r\n badPerRep.push(repBad);\r\n badLanes += repBad;\r\n }\r\n for (const b of [params, ...bufs, yBuf]) b.destroy();\r\n return {\r\n pass: badLanes === 0,\r\n detail: { kernel: 'add_ln (real, f32, sg, D=576)', rows, d, reps: REPS, tol, badLanes, badPerRep, ...(firstBad ? { firstBad } : {}) },\r\n };\r\n});\r\n\r\n// ------------------------------------------------------------- round 6 ---\r\n// hachimi60 sg goldens read 0/30 (mega) and 10/30 (lean) on the affected\r\n// Adreno while every hachimi-dim f16 sg GEMV + add_ln@576 kernel passes.\r\n// Remaining lean-path kernels at hachimi dims, tested REAL, f32, CPU-checked:\r\n// attention (H8 D72 — D4 18, JT 7) short + long lens, and gemm_row_ln sg at\r\n// K=D=576 (the fused-LN b1 site; 576/WG loops turn 3-trip).\r\n\r\nconst smallF = (idx, salt) => (payload(idx & 0xfffff, salt) - 512) / 512;\r\n\r\n// Values from smallF are multiples of 1/512 in [-1, 1] — exact in f16, so\r\n// the f16 variants reuse the same f64 reference; only OUTPUT rounding needs\r\n// tolerance. toHalf packs an exact-f16 f32 array for storage.\r\nconst toHalf = (a) => {\r\n const h = new Uint16Array(a.length);\r\n for (let i = 0; i < a.length; i++) h[i] = f32ToF16(a[i]);\r\n return h;\r\n};\r\n\r\nasync function runAttnRealDims(ctx, { H, D, B, M, L, lens, sg, t = 'f32' }) {\r\n const { device } = ctx;\r\n const HD = H * D;\r\n const rows = B * M;\r\n const q = new Float32Array(rows * HD);\r\n const k = new Float32Array(B * L * HD);\r\n const v = new Float32Array(B * L * HD);\r\n for (let i = 0; i < q.length; i++) q[i] = smallF(i, 51);\r\n for (let i = 0; i < k.length; i++) k[i] = smallF(i, 52);\r\n for (let i = 0; i < v.length; i++) v[i] = smallF(i, 53);\r\n const scale = 1 / Math.sqrt(D);\r\n // f64 reference, all (b, m, h) rows\r\n const want = new Float64Array(rows * HD);\r\n for (let b = 0; b < B; b++) {\r\n for (let m = 0; m < M; m++) {\r\n const row = b * M + m;\r\n for (let h = 0; h < H; h++) {\r\n const len = lens[b];\r\n const scores = new Float64Array(len);\r\n for (let j = 0; j < len; j++) {\r\n let dot = 0;\r\n for (let d = 0; d < D; d++) {\r\n dot += q[row * HD + h * D + d] * k[(b * L + j) * HD + h * D + d];\r\n }\r\n scores[j] = dot * scale;\r\n }\r\n const mx = Math.max(...scores);\r\n const e = scores.map((x) => Math.exp(x - mx));\r\n const denom = e.reduce((a, x) => a + x, 0);\r\n for (let d = 0; d < D; d++) {\r\n let acc = 0;\r\n for (let j = 0; j < len; j++) acc += e[j] * v[(b * L + j) * HD + h * D + d];\r\n want[row * HD + h * D + d] = acc / denom;\r\n }\r\n }\r\n }\r\n }\r\n const pipeline = getPipeline(device, 'attention', attentionSource, {\r\n t, wg: 128, sg,\r\n defines: {\r\n H, D, SCORES_CAP: 352, ATTN_SCALE: scale,\r\n Q_STRIDE: HD, Q_OFF: 0, KV_STRIDE: HD, K_OFF: 0, V_OFF: 0,\r\n },\r\n });\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const params = device.createBuffer({ size: 32, usage: GPUBufferUsage.UNIFORM, mappedAtCreation: true });\r\n new Uint32Array(params.getMappedRange()).set([B, M, L, 1, 0, 0, 0, 0]);\r\n params.unmap();\r\n const elem = t === 'f16' ? 2 : 4;\r\n const bufs = [q, k, v].map((a) => createBuffer(device, t === 'f16' ? toHalf(a) : a, usage));\r\n const lensBuf = createBuffer(device, new Uint32Array(lens), usage);\r\n const yBuf = device.createBuffer({ size: rows * HD * elem, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [params, ...bufs, lensBuf, yBuf].map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n const tol = t === 'f16' ? 0.01 : 1e-3;\r\n let badLanes = 0;\r\n let firstBad = null;\r\n const badPerRep = [];\r\n for (let rep = 0; rep < REPS; rep++) {\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(rows, H);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n const raw = await readback(device, yBuf, rows * HD * elem);\r\n const got = t === 'f16' ? expandF16(new Uint16Array(raw)) : new Float32Array(raw);\r\n let repBad = 0;\r\n for (let i = 0; i < want.length; i++) {\r\n if (!(Math.abs(got[i] - want[i]) <= tol)) {\r\n repBad++;\r\n if (!firstBad) firstBad = { rep, i, got: got[i], want: want[i] };\r\n }\r\n }\r\n badPerRep.push(repBad);\r\n badLanes += repBad;\r\n }\r\n for (const b of [params, ...bufs, lensBuf, yBuf]) b.destroy();\r\n return {\r\n pass: badLanes === 0,\r\n detail: { kernel: `attention (real, ${t}${sg ? ', sg' : ''}, H${H} D${D})`, B, M, L, lens: lens.join(','), reps: REPS, tol, badLanes, badPerRep, ...(firstBad ? { firstBad } : {}) },\r\n };\r\n}\r\n\r\nregisterTest('adreno_probe6_attn_sg_h60_short', (ctx) => (ctx.hasSubgroups\r\n ? runAttnRealDims(ctx, { H: 8, D: 72, B: 2, M: 16, L: 16, lens: [16, 9], sg: true })\r\n : { skip: true, reason: 'subgroups feature unavailable' }));\r\nregisterTest('adreno_probe6_attn_sg_h60_long', (ctx) => (ctx.hasSubgroups\r\n ? runAttnRealDims(ctx, { H: 8, D: 72, B: 2, M: 4, L: 224, lens: [224, 131], sg: true })\r\n : { skip: true, reason: 'subgroups feature unavailable' }));\r\n\r\n// gemm_row_ln sg at hachimi dims (K = D = 576): the fused-LN site b1 lean\r\n// decode routes through at fuseLnMaxB 4.\r\nregisterTest('adreno_probe6_rowln_sg_d576', async (ctx) => {\r\n if (!ctx.hasSubgroups) return { skip: true, reason: 'subgroups feature unavailable' };\r\n const { device } = ctx;\r\n const K = 576;\r\n const D = 576;\r\n const M = 64;\r\n const x = new Float32Array(M * K);\r\n const w = new Float32Array(K * D);\r\n const b = new Float32Array(D);\r\n const r = new Float32Array(M * D);\r\n const gamma = new Float32Array(D);\r\n const beta = new Float32Array(D);\r\n for (let i = 0; i < x.length; i++) x[i] = smallF(i, 61) * 2;\r\n for (let i = 0; i < w.length; i++) w[i] = smallF(i, 62);\r\n for (let i = 0; i < r.length; i++) r[i] = smallF(i, 63) * 2;\r\n for (let i = 0; i < D; i++) {\r\n b[i] = smallF(i, 64);\r\n gamma[i] = 1 + smallF(i, 65) / 2;\r\n beta[i] = smallF(i, 66);\r\n }\r\n const want = new Float64Array(M * D);\r\n for (let m = 0; m < M; m++) {\r\n const vrow = new Float64Array(D);\r\n let sum = 0;\r\n for (let n = 0; n < D; n++) {\r\n let dot = 0;\r\n for (let kk = 0; kk < K; kk++) dot += x[m * K + kk] * w[kk * D + n];\r\n vrow[n] = dot + b[n] + r[m * D + n];\r\n sum += vrow[n];\r\n }\r\n const mu = sum / D;\r\n let sq = 0;\r\n for (let n = 0; n < D; n++) sq += (vrow[n] - mu) * (vrow[n] - mu);\r\n const inv = 1 / Math.sqrt(sq / D + LN_EPS);\r\n for (let n = 0; n < D; n++) want[m * D + n] = gamma[n] * (vrow[n] - mu) * inv + beta[n];\r\n }\r\n const pipeline = getPipeline(device, 'gemm_row_ln', gemmRowLnSource, {\r\n t: 'f32', wg: 128, sg: true, defines: { KDIM: K, D, EPS: LN_EPS },\r\n });\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const params = device.createBuffer({ size: 16, usage: GPUBufferUsage.UNIFORM, mappedAtCreation: true });\r\n new Uint32Array(params.getMappedRange()).set([M, 0, 0, 0]);\r\n params.unmap();\r\n const bufs = [x, w, b, r, gamma, beta].map((a) => createBuffer(device, a, usage));\r\n const yBuf = device.createBuffer({ size: M * D * 4, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [params, ...bufs, yBuf].map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n const tol = 2e-3;\r\n let badLanes = 0;\r\n let firstBad = null;\r\n const badPerRep = [];\r\n for (let rep = 0; rep < REPS; rep++) {\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(M);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n const got = new Float32Array(await readback(device, yBuf, M * D * 4));\r\n let repBad = 0;\r\n for (let i = 0; i < want.length; i++) {\r\n if (!(Math.abs(got[i] - want[i]) <= tol)) {\r\n repBad++;\r\n if (!firstBad) firstBad = { rep, i, got: got[i], want: want[i] };\r\n }\r\n }\r\n badPerRep.push(repBad);\r\n badLanes += repBad;\r\n }\r\n for (const bb of [params, ...bufs, yBuf]) bb.destroy();\r\n return {\r\n pass: badLanes === 0,\r\n detail: { kernel: 'gemm_row_ln (real, f32, sg, K=D=576)', M, reps: REPS, tol, badLanes, badPerRep, ...(firstBad ? { firstBad } : {}) },\r\n };\r\n});\r\n\r\n// ------------------------------------------------------------- round 7 ---\r\n// Round 6 (f32) passed everything at hachimi dims on the device, but\r\n// PRODUCTION runs f16 — if the second miscompile is f16-specific the f32\r\n// probes prove nothing. Same shapes, f16 storage (inputs exact in f16, same\r\n// f64 reference, tolerance covers output rounding only).\r\nregisterTest('adreno_probe7_attn_sg_h60_short_f16', (ctx) => (!ctx.hasSubgroups\r\n ? { skip: true, reason: 'subgroups feature unavailable' }\r\n : !ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runAttnRealDims(ctx, { H: 8, D: 72, B: 2, M: 16, L: 16, lens: [16, 9], sg: true, t: 'f16' })));\r\nregisterTest('adreno_probe7_attn_sg_h60_long_f16', (ctx) => (!ctx.hasSubgroups\r\n ? { skip: true, reason: 'subgroups feature unavailable' }\r\n : !ctx.hasF16 ? { skip: true, reason: 'no shader-f16' }\r\n : runAttnRealDims(ctx, { H: 8, D: 72, B: 2, M: 4, L: 224, lens: [224, 131], sg: true, t: 'f16' })));\r\n// Moxhi-dim f16 sg attention passed on-device via attn_sg_*; this pins the\r\n// f16 × hachimi-dim cell of the matrix for add_ln too.\r\nregisterTest('adreno_probe7_addln_sg_d576_f16', async (ctx) => {\r\n if (!ctx.hasSubgroups) return { skip: true, reason: 'subgroups feature unavailable' };\r\n if (!ctx.hasF16) return { skip: true, reason: 'no shader-f16' };\r\n const { device } = ctx;\r\n const d = 576;\r\n const rows = GROUPS;\r\n const x = new Float32Array(rows * d);\r\n const r = new Float32Array(rows * d);\r\n const gamma = new Float32Array(d);\r\n const beta = new Float32Array(d);\r\n for (let g = 0; g < rows; g++) {\r\n for (let i = 0; i < d; i++) {\r\n x[g * d + i] = xval(i, g) / 2; // /2: keep f16-exact (multiples of 1/512)\r\n r[g * d + i] = rval(i, g) / 2;\r\n }\r\n }\r\n for (let i = 0; i < d; i++) { gamma[i] = gval(i); beta[i] = bval(i); }\r\n const cache = new Map();\r\n const want = (g, i) => {\r\n if (!cache.has(g)) {\r\n const v = new Float64Array(d);\r\n let sum = 0;\r\n for (let j = 0; j < d; j++) { v[j] = x[g * d + j] + r[g * d + j]; sum += v[j]; }\r\n const mu = sum / d;\r\n let sq = 0;\r\n for (let j = 0; j < d; j++) sq += (v[j] - mu) * (v[j] - mu);\r\n const inv = 1 / Math.sqrt(sq / d + LN_EPS);\r\n cache.set(g, v.map((xx, j) => gamma[j] * (xx - mu) * inv + beta[j]));\r\n }\r\n return cache.get(g)[i];\r\n };\r\n const pipeline = getPipeline(device, 'add_ln', addLnSource, {\r\n t: 'f16', wg: 256, sg: true, defines: { D: d, EPS: LN_EPS },\r\n });\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const params = device.createBuffer({ size: 16, usage: GPUBufferUsage.UNIFORM, mappedAtCreation: true });\r\n new Uint32Array(params.getMappedRange()).set([rows, 0, 0, 0]);\r\n params.unmap();\r\n const bufs = [x, r, gamma, beta].map((a) => createBuffer(device, toHalf(a), usage));\r\n const yBuf = device.createBuffer({ size: rows * d * 2, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [params, ...bufs, yBuf].map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n const tol = 0.02;\r\n let badLanes = 0;\r\n let firstBad = null;\r\n const badPerRep = [];\r\n for (let rep = 0; rep < REPS; rep++) {\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(rows);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n const got = expandF16(new Uint16Array(await readback(device, yBuf, rows * d * 2)));\r\n let repBad = 0;\r\n for (let g = 0; g < rows; g++) {\r\n for (let i = 0; i < d; i++) {\r\n const w = want(g, i);\r\n if (!(Math.abs(got[g * d + i] - w) <= tol)) {\r\n repBad++;\r\n if (!firstBad) firstBad = { rep, g, lane: i, got: got[g * d + i], want: w };\r\n }\r\n }\r\n }\r\n badPerRep.push(repBad);\r\n badLanes += repBad;\r\n }\r\n for (const b of [params, ...bufs, yBuf]) b.destroy();\r\n return {\r\n pass: badLanes === 0,\r\n detail: { kernel: 'add_ln (real, f16, sg, D=576)', rows, d, reps: REPS, tol, badLanes, badPerRep, ...(firstBad ? { firstBad } : {}) },\r\n };\r\n});\r\n\r\n// ------------------------------------------------------------- round 8 ---\r\n// Encoder blocked attention at HACHIMI dims: D=72 → D4=18 → default QB=14\r\n// (workgroup 252 threads) — an entirely different tile geometry than moxhi's\r\n// QB16/224 that the on-device attn_block tests covered. The hachimi sg\r\n// goldens share the encoder between their mega (0/30) and lean (10/30) arms\r\n// while every decode kernel checks out — encoder kernels are the remaining\r\n// suspects.\r\nasync function runAttnBlockDims(ctx, { H, D, QB, JB, B, M, L, lens, t = 'f16' }) {\r\n const { device } = ctx;\r\n const HD = H * D;\r\n const rows = B * M;\r\n const q = new Float32Array(rows * HD);\r\n const k = new Float32Array(B * L * HD);\r\n const v = new Float32Array(B * L * HD);\r\n for (let i = 0; i < q.length; i++) q[i] = smallF(i, 71);\r\n for (let i = 0; i < k.length; i++) k[i] = smallF(i, 72);\r\n for (let i = 0; i < v.length; i++) v[i] = smallF(i, 73);\r\n const scale = 1 / Math.sqrt(D);\r\n const want = new Float64Array(rows * HD);\r\n for (let b = 0; b < B; b++) {\r\n for (let m = 0; m < M; m++) {\r\n const row = b * M + m;\r\n for (let h = 0; h < H; h++) {\r\n const len = lens[b];\r\n const scores = new Float64Array(len);\r\n for (let j = 0; j < len; j++) {\r\n let dot = 0;\r\n for (let d = 0; d < D; d++) {\r\n dot += q[row * HD + h * D + d] * k[(b * L + j) * HD + h * D + d];\r\n }\r\n scores[j] = dot * scale;\r\n }\r\n const mx = Math.max(...scores);\r\n const e = scores.map((x) => Math.exp(x - mx));\r\n const denom = e.reduce((a, x) => a + x, 0);\r\n for (let d = 0; d < D; d++) {\r\n let acc = 0;\r\n for (let j = 0; j < len; j++) acc += e[j] * v[(b * L + j) * HD + h * D + d];\r\n want[row * HD + h * D + d] = acc / denom;\r\n }\r\n }\r\n }\r\n }\r\n const pipeline = getPipeline(device, 'attention_block', attentionBlockSource, {\r\n t,\r\n defines: {\r\n H, D, QB, JB, ATTN_SCALE: 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 },\r\n });\r\n const usage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;\r\n const params = device.createBuffer({ size: 32, usage: GPUBufferUsage.UNIFORM, mappedAtCreation: true });\r\n new Uint32Array(params.getMappedRange()).set([B, M, L, 1, 0, 0, 0, 0]);\r\n params.unmap();\r\n const elem = t === 'f16' ? 2 : 4;\r\n const bufs = [q, k, v].map((a) => createBuffer(device, t === 'f16' ? toHalf(a) : a, usage));\r\n const lensBuf = createBuffer(device, new Uint32Array(lens), usage);\r\n const yBuf = device.createBuffer({ size: rows * HD * elem, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC });\r\n const bindGroup = device.createBindGroup({\r\n layout: pipeline.getBindGroupLayout(0),\r\n entries: [params, ...bufs, lensBuf, yBuf].map((buffer, binding) => ({ binding, resource: { buffer } })),\r\n });\r\n const tol = t === 'f16' ? 0.01 : 1e-3;\r\n let badLanes = 0;\r\n let firstBad = null;\r\n const badPerRep = [];\r\n for (let rep = 0; rep < REPS; rep++) {\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(Math.ceil(M / QB), H, B);\r\n pass.end();\r\n device.queue.submit([encoder.finish()]);\r\n const raw = await readback(device, yBuf, rows * HD * elem);\r\n const got = t === 'f16' ? expandF16(new Uint16Array(raw)) : new Float32Array(raw);\r\n let repBad = 0;\r\n for (let i = 0; i < want.length; i++) {\r\n if (!(Math.abs(got[i] - want[i]) <= tol)) {\r\n repBad++;\r\n if (!firstBad) firstBad = { rep, i, got: got[i], want: want[i] };\r\n }\r\n }\r\n badPerRep.push(repBad);\r\n badLanes += repBad;\r\n }\r\n for (const b of [params, ...bufs, lensBuf, yBuf]) b.destroy();\r\n return {\r\n pass: badLanes === 0,\r\n detail: { kernel: `attention_block (real, ${t}, H${H} D${D} QB${QB} JB${JB})`, B, M, L, lens: lens.join(','), reps: REPS, tol, badLanes, badPerRep, ...(firstBad ? { firstBad } : {}) },\r\n };\r\n}\r\n\r\nregisterTest('adreno_probe8_attnblock_h60_f16', (ctx) => (!ctx.hasF16\r\n ? { skip: true, reason: 'no shader-f16' }\r\n : runAttnBlockDims(ctx, { H: 8, D: 72, QB: 14, JB: 32, B: 2, M: 33, L: 33, lens: [33, 17], t: 'f16' })));\r\nregisterTest('adreno_probe8_attnblock_h60_big_f16', (ctx) => (!ctx.hasF16\r\n ? { skip: true, reason: 'no shader-f16' }\r\n : runAttnBlockDims(ctx, { H: 8, D: 72, QB: 14, JB: 32, B: 2, M: 96, L: 96, lens: [96, 49], t: 'f16' })));\r\n\r\n// Weights-bytes integrity: FNV-1a over every fetched shard of both models.\r\n// A deterministic 10/30 hachimi verdict with all kernels clean could also be\r\n// corrupted-but-cached weight bytes on the device — compare this hash across\r\n// devices (must be identical; the files are identical on the server).\r\nregisterTest('adreno_probe8_weights_hash', async () => {\r\n const fnv = (h, bytes) => {\r\n for (let i = 0; i < bytes.length; i++) {\r\n h ^= bytes[i];\r\n h = Math.imul(h, 16777619) >>> 0;\r\n }\r\n return h;\r\n };\r\n const hashModel = async (root) => {\r\n const manifest = await (await fetch(`${root}/manifest.json`)).json();\r\n const bins = manifest.bins ?? ['weights.bin'];\r\n let h = 2166136261 >>> 0;\r\n let bytes = 0;\r\n for (const bin of bins) {\r\n const buf = new Uint8Array(await (await fetch(`${root}/${bin}`)).arrayBuffer());\r\n bytes += buf.length;\r\n h = fnv(h, buf);\r\n }\r\n return { hash: h.toString(16), bytes, bins: bins.length };\r\n };\r\n const detail = { moxhi: await hashModel('/weights') };\r\n try {\r\n detail.hachimi60 = await hashModel('/weights/hachimi60');\r\n } catch (err) {\r\n detail.hachimi60 = { error: String(err?.message ?? err) };\r\n }\r\n return { pass: true, detail };\r\n});\r\n\r\n// Failure-surface map for the attention_block h60 break (QB14/D72/f16 FAILS\r\n// on the device): vary one axis at a time to find a safe routing.\r\nregisterTest('adreno_probe8b_attnblock_h60_qb8', (ctx) => (!ctx.hasF16\r\n ? { skip: true, reason: 'no shader-f16' }\r\n : runAttnBlockDims(ctx, { H: 8, D: 72, QB: 8, JB: 32, B: 2, M: 33, L: 33, lens: [33, 17], t: 'f16' })));\r\nregisterTest('adreno_probe8b_attnblock_h60_qb12', (ctx) => (!ctx.hasF16\r\n ? { skip: true, reason: 'no shader-f16' }\r\n : runAttnBlockDims(ctx, { H: 8, D: 72, QB: 12, JB: 32, B: 2, M: 33, L: 33, lens: [33, 17], t: 'f16' })));\r\nregisterTest('adreno_probe8b_attnblock_h60_qb14_jb16', (ctx) => (!ctx.hasF16\r\n ? { skip: true, reason: 'no shader-f16' }\r\n : runAttnBlockDims(ctx, { H: 8, D: 72, QB: 14, JB: 16, B: 2, M: 33, L: 33, lens: [33, 17], t: 'f16' })));\r\nregisterTest('adreno_probe8b_attnblock_h60_qb14_f32', (ctx) =>\r\n runAttnBlockDims(ctx, { H: 8, D: 72, QB: 14, JB: 32, B: 2, M: 33, L: 33, lens: [33, 17], t: 'f32' }));\r\n// QB14 at MOXHI head dim (D 56, 196 threads): separates the QB axis from D.\r\nregisterTest('adreno_probe8b_attnblock_d56_qb14', (ctx) => (!ctx.hasF16\r\n ? { skip: true, reason: 'no shader-f16' }\r\n : runAttnBlockDims(ctx, { H: 8, D: 56, QB: 14, JB: 32, B: 2, M: 33, L: 33, lens: [33, 17], t: 'f16' })));\r\n"],"file":"adreno_probe-CqGqVTv4.js"}
|
|
|
|
|
|
assets/app_stage-DrqfcKH2.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 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-DrqfcKH2.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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-DMqT6ikS.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 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-DMqT6ikS.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 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-CKXRwPoI.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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/attention-1v-Zzb1X.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
| 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
|
| 5 |
-
// so the copy is a contiguous-chunk scatter with no per-element shuffling.\r
|
| 6 |
-
//\r
|
| 7 |
-
// Two build-time modes (exactly one of APPEND / SPLIT):\r
|
| 8 |
-
// APPEND (decode step): fused is fusedQKV [B, 3·H·D] (q at 0, k at H·D,\r
|
| 9 |
-
// v at 2·H·D). Thread (b, i) writes BOTH caches at position t:\r
|
| 10 |
-
// Kc[(b*Lmax + t)*H*D + i] = fused[b*3HD + HD + i]\r
|
| 11 |
-
// Vc[(b*Lmax + t)*H*D + i] = fused[b*3HD + 2HD + i]\r
|
| 12 |
-
// Total threads B·H·D. Uses params.B, params.t, params.Lmax.\r
|
| 13 |
-
// SPLIT — currently unused by the engine (attention reads fused K/V buffers\r
|
| 14 |
-
// directly via its Q_STRIDE/KV_STRIDE/*_OFF defines); kept for tests and\r
|
| 15 |
-
// as a fallback. Cross K/V after encoder: fused is fusedKV [B·S, 2·H·D] (k at 0,\r
|
| 16 |
-
// v at H·D). Here the [B, L, H, D] buffers have L = S exactly (allocated\r
|
| 17 |
-
// to the padded bucket length), so row = b·S + j indexes both sides:\r
|
| 18 |
-
// Kc[row*H*D + i] = fused[row*2HD + i]\r
|
| 19 |
-
// Vc[row*H*D + i] = fused[row*2HD + HD + i]\r
|
| 20 |
-
// Total threads rows·H·D. Uses params.rows only.\r
|
| 21 |
-
//\r
|
| 22 |
-
// Template placeholders (buildShader in pipelines.js):\r
|
| 23 |
-
// ENABLE_F16 the f16 enable directive when T is f16, else empty\r
|
| 24 |
-
// T storage type of fused/Kc/Vc (f16|f32) — straight copy,\r
|
| 25 |
-
// no conversion\r
|
| 26 |
-
// WG workgroup size\r
|
| 27 |
-
// H, D heads (8), head dim (56)\r
|
| 28 |
-
// IF_APPEND/IF_SPLIT mode blocks\r
|
| 29 |
-
{{ENABLE_IMMEDIATE}}\r
|
| 30 |
-
{{ENABLE_F16}}\r
|
| 31 |
-
\r
|
| 32 |
-
struct Params {\r
|
| 33 |
-
B: u32, // APPEND: batch\r
|
| 34 |
-
t: u32, // APPEND: decode step (write position)\r
|
| 35 |
-
Lmax: u32, // APPEND: K/V cache position capacity (stride)\r
|
| 36 |
-
rows: u32, // SPLIT: B·S fused rows\r
|
| 37 |
-
}\r
|
| 38 |
-
\r
|
| 39 |
-
{{PARAM_BINDING}}var<{{PARAM_ADDRESS}}> params: Params;\r
|
| 40 |
-
@group(0) @binding(1) var<storage, read> fused: array<{{T}}>;\r
|
| 41 |
-
@group(0) @binding(2) var<storage, read_write> Kc: array<{{T}}>;\r
|
| 42 |
-
@group(0) @binding(3) var<storage, read_write> Vc: array<{{T}}>;\r
|
| 43 |
-
\r
|
| 44 |
-
const HD: u32 = {{H}}u * {{D}}u;\r
|
| 45 |
-
\r
|
| 46 |
-
@compute @workgroup_size({{WG}})\r
|
| 47 |
-
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {\r
|
| 48 |
-
{{IF_APPEND}}\r
|
| 49 |
-
if (gid.x >= params.B * HD) { return; }\r
|
| 50 |
-
let b = gid.x / HD;\r
|
| 51 |
-
let i = gid.x % HD; // h*D + d\r
|
| 52 |
-
let dst = (b * params.Lmax + params.t) * HD + i;\r
|
| 53 |
-
Kc[dst] = fused[b * 3u * HD + HD + i];\r
|
| 54 |
-
Vc[dst] = fused[b * 3u * HD + 2u * HD + i];\r
|
| 55 |
-
{{/IF_APPEND}}\r
|
| 56 |
-
{{IF_SPLIT}}\r
|
| 57 |
-
if (gid.x >= params.rows * HD) { return; }\r
|
| 58 |
-
let r = gid.x / HD; // b*S + j\r
|
| 59 |
-
let i = gid.x % HD; // h*D + d\r
|
| 60 |
-
Kc[r * HD + i] = fused[r * 2u * HD + i];\r
|
| 61 |
-
Vc[r * HD + i] = fused[r * 2u * HD + HD + i];\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-1v-Zzb1X.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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":"4aAAA,MAAAA,GAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,ECgBTC,EAAIC,GAAOC,EAAIC,GAAUC,EAAKJ,EAAIE,EAExC,SAASG,EAAWC,EAAM,CACxB,IAAIC,EAAID,IAAS,EACjB,MAAO,IAAM,CACXC,EAAKA,EAAI,WAAc,EACvB,IAAIC,EAAI,KAAK,KAAKD,EAAKA,IAAM,GAAK,EAAIA,CAAC,EACvC,OAAAC,EAAKA,EAAI,KAAK,KAAKA,EAAKA,IAAM,EAAI,GAAKA,CAAC,EAAKA,IACpCA,EAAKA,IAAM,MAAS,GAAK,UACpC,CACF,CAEA,SAASC,EAAQC,EAAGC,EAAK,CACvB,MAAMC,EAAM,IAAI,aAAaF,CAAC,EAC9B,QAASG,EAAI,EAAGA,EAAIH,EAAGG,IAAKD,EAAIC,CAAC,EAAI,KAAK,OAAOF,EAAG,EAAK,EAAG,EAC5D,OAAOC,CACT,CAIA,SAASE,EAAKC,EAAQ,EAAG,CACvB,GAAI,IAAM,MAAO,MAAO,CAAE,KAAMA,EAAQ,IAAKA,GAC7C,MAAMC,EAAO,IAAI,YAAYD,EAAO,MAAM,EAC1C,QAASF,EAAI,EAAGA,EAAIE,EAAO,OAAQF,IAAKG,EAAKH,CAAC,EAAII,GAASF,EAAOF,CAAC,CAAC,EACpE,MAAO,CAAE,KAAMG,EAAM,IAAKE,EAAUF,CAAI,EAC1C,CAEA,SAASG,EAAYC,EAAQC,EAAM,CACjC,MAAMC,EAAO,KAAK,KAAMD,EAAK,OAAS,EAAK,EAAE,EAAI,GAC3CE,EAAMH,EAAO,aAAa,CAAE,KAAAE,EAAM,MAAO,eAAe,QAAS,iBAAkB,EAAI,CAAE,EAC/F,WAAI,YAAYC,EAAI,eAAc,CAAE,EAAE,IAAIF,CAAI,EAC9CE,EAAI,MAAK,EACFA,CACT,CAEA,SAASC,EAAUhB,EAAG,CAAE,OAAOA,IAAM,MAAQ,EAAI,CAAG,CAIpD,SAASiB,GAAkBL,EAAQ,EAAGM,EAAU,CAAA,EAAIC,EAAK,GAAO,CAC9D,OAAOC,EAAYR,EAAQ,YAAaS,GAAiB,CACvD,EAAG,GAAI,IAAK,GAAAF,EACZ,QAAS,CACP,EAAA3B,EAAG,EAAAE,EAAG,WAAA4B,GAAY,WAAAC,EAClB,SAAU3B,EAAI,MAAO,EAAG,UAAWA,EAAI,MAAO,EAAG,MAAO,EACxD,GAAGsB,CACT,CACA,CAAG,CACH,CAGA,SAASM,GAAuBZ,EAAQ,EAAG,CAAE,GAAAa,EAAI,GAAAC,CAAE,EAAIR,EAAU,GAAI,CACnE,OAAOE,EAAYR,EAAQ,kBAAmBe,GAAsB,CAClE,EACA,QAAS,CACP,EAAAnC,EAAG,EAAAE,EAAG,GAAI+B,EAAI,GAAIC,EAAI,WAAAH,EACtB,SAAU3B,EAAI,MAAO,EAAG,UAAWA,EAAI,MAAO,EAAG,MAAO,EACxD,OAAQ,GAAO,SAAU,GACzB,GAAGsB,CACT,CACA,CAAG,CACH,CAEA,SAASU,EAAiBhB,EAAQ,EAAGiB,EAAM,CACzC,OAAOT,EAAYR,EAAQ,YAAarB,GAAgB,CACtD,EAAG,GAAI,IAAK,QAAS,CAAE,EAAAC,EAAG,EAAAE,EAAG,OAAQmC,IAAS,SAAU,MAAOA,IAAS,OAAO,CACnF,CAAG,CACH,CAEA,SAASC,EAASlB,EAAQmB,EAAUC,EAASC,EAAKC,EAAM,EAAGC,EAAM,EAAG,CAClE,MAAMC,EAAYxB,EAAO,gBAAgB,CACvC,OAAQmB,EAAS,mBAAmB,CAAC,EACrC,QAASC,EAAQ,IAAI,CAACK,EAAQC,KAAa,CAAE,QAAAA,EAAS,SAAU,CAAE,OAAAD,CAAM,CAAE,EAAG,CACjF,CAAG,EACKE,EAAU3B,EAAO,uBACjB4B,EAAOD,EAAQ,mBACrBC,EAAK,YAAYT,CAAQ,EACzBS,EAAK,aAAa,EAAGJ,CAAS,EAC9BI,EAAK,mBAAmBP,EAAKC,EAAKC,CAAG,EACrCK,EAAK,IAAG,EACR5B,EAAO,MAAM,OAAO,CAAC2B,EAAQ,OAAM,CAAE,CAAC,CACxC,CAIA,eAAeE,EAAuB7B,EAAQ,EAAG,CAAE,KAAA8B,EAAM,KAAAC,EAAM,KAAAC,EAAM,QAAAC,EAAS,EAAAC,EAAG,EAAAC,EAAG,EAAAC,EAAG,QAAAC,EAAS,KAAAC,EAAM,QAAAhC,EAAS,MAAAiC,EAAO,GAAAhC,GAAMiC,EAAMC,EAAKC,EAAO,CAC5I,MAAMvB,EAAWoB,EACb3B,GAAuBZ,EAAQ,EAAGuC,EAAOjC,CAAO,EAChDD,GAAkBL,EAAQ,EAAGM,EAASC,CAAE,EACtCoC,EAAS5C,EAAYC,EAAQ,CAACkC,EAAGC,EAAGC,EAAGC,EAASC,GAAQ,EAAG,EAAG,EAAG,CAAC,CAAC,EACnEM,EAAU,CAACD,CAAM,EACvB,IAAIE,EAAOZ,EACNY,IACHA,EAAO7C,EAAO,aAAa,CAAE,MAAO,kBAAmB,KAAM,EAAG,MAAO,eAAe,OAAO,CAAE,EAC/F4C,EAAQ,KAAKC,CAAI,GAEnB,MAAMC,EAAWZ,EAAIC,EAAInD,EACnB+D,EAAO/C,EAAO,aAAa,CAC/B,KAAM,KAAK,KAAM8C,EAAW1C,EAAU,CAAC,EAAK,CAAC,EAAI,EACjD,MAAO,eAAe,QAAU,eAAe,QACnD,CAAG,EACGmC,EACFrB,EAASlB,EAAQmB,EAAU,CAACwB,EAAQb,EAAMC,EAAMC,EAAMa,EAAME,CAAI,EAAG,KAAK,KAAKZ,EAAII,EAAM,EAAE,EAAG3D,EAAGsD,CAAC,EAEhGhB,EAASlB,EAAQmB,EAAU,CAACwB,EAAQb,EAAMC,EAAMC,EAAMa,EAAME,CAAI,EAAGb,EAAIC,EAAGvD,CAAC,EAE7E,MAAMoE,EAAM,MAAMC,EAASjD,EAAQ+C,EAAMD,EAAW1C,EAAU,CAAC,CAAC,EAC1D8C,EAAM,IAAM,MAAQpD,EAAU,IAAI,YAAYkD,CAAG,CAAC,EAAI,IAAI,aAAaA,CAAG,EAChF,UAAWG,IAAK,CAAC,GAAGP,EAASG,CAAI,EAAGI,EAAE,UAEtC,KAAM,CAAE,SAAAC,EAAU,WAAAC,EAAY,MAAAC,CAAK,EAAKC,EAAaL,EAAKV,EAAMC,CAAG,EACnE,MAAO,CACL,KAAMW,IAAa,EACnB,OAAQ,CACN,GAAGV,EAAO,IAAAD,EAAK,SAAAW,EACf,WAAY,OAAOC,CAAU,EAC7B,GAAID,EAAW,EAAI,CAAE,MAAAE,EAAO,IAAK,OAAOJ,EAAII,CAAK,CAAC,EAAG,KAAM,OAAOd,EAAKc,CAAK,CAAC,CAAC,EAAK,EACzF,CACA,CACA,CAMA,eAAeE,EAAeC,EAAK,CAAE,EAAAvB,EAAG,EAAAC,EAAG,EAAAC,EAAG,KAAAS,EAAM,EAAAzD,EAAG,IAAAqD,EAAK,KAAAvD,EAAM,MAAAqD,EAAO,GAAAhC,EAAK,EAAK,EAAI,CACrF,KAAM,CAAE,OAAAP,CAAM,EAAKyD,EACblE,EAAMN,EAAWC,CAAI,EACrBwE,EAAIhE,EAAKL,EAAQ6C,EAAIC,EAAInD,EAAIO,CAAG,EAAGH,CAAC,EACpCuE,EAAIjE,EAAKL,EAAQ6C,EAAIE,EAAIpD,EAAIO,CAAG,EAAGH,CAAC,EACpCwE,EAAIlE,EAAKL,EAAQ6C,EAAIE,EAAIpD,EAAIO,CAAG,EAAGH,CAAC,EACpCoD,EAAOqB,EAAaH,EAAE,IAAKC,EAAE,IAAKC,EAAE,IAAK,CAAE,EAAA1B,EAAG,EAAAC,EAAG,EAAAvD,EAAG,EAAAE,EAAG,EAAAsD,EAAG,KAAAS,CAAI,CAAE,EAEhEiB,EAAQ,eAAe,QAAU,eAAe,SAChDhC,EAAOiC,EAAa/D,EAAQ0D,EAAE,KAAMI,CAAK,EACzC/B,EAAOgC,EAAa/D,EAAQ2D,EAAE,KAAMG,CAAK,EACzC9B,EAAO+B,EAAa/D,EAAQ4D,EAAE,KAAME,CAAK,EACzC7B,EAAU8B,EAAa/D,EAAQ,IAAI,YAAY6C,CAAI,EAAGiB,CAAK,EAC3DE,EAAS,MAAMnC,EACnB7B,EAAQZ,EAAG,CAAE,KAAA0C,EAAM,KAAAC,EAAM,KAAAC,EAAM,QAAAC,EAAS,EAAAC,EAAG,EAAAC,EAAG,EAAAC,EAAG,QAAS,EAAG,MAAAG,EAAO,GAAAhC,CAAE,EACtEiC,EAAMC,EAAK,CACT,OAAQF,EAAQ,qBAAqBA,EAAM,EAAE,MAAMA,EAAM,EAAE,GAAK,YAChE,KAAM,UAAW,EAAAL,EAAG,EAAAC,EAAG,EAAAC,EAAG,KAAMS,EAAK,KAAK,GAAG,EAAG,EAAAzD,CACtD,CAAK,EACH,UAAW+D,IAAK,CAACrB,EAAMC,EAAMC,EAAMC,CAAO,EAAGkB,EAAE,UAC/C,OAAOa,CACT,CAOA,eAAeC,EAAoBR,EAAK,CAAE,EAAAvB,EAAG,EAAAgC,EAAG,KAAArB,EAAM,EAAAzD,EAAG,IAAAqD,EAAK,KAAAvD,EAAM,MAAAqD,GAAS,CAC3E,KAAM,CAAE,OAAAvC,CAAM,EAAKyD,EACblE,EAAMN,EAAWC,CAAI,EACrBiF,EAAOjC,EAAIgC,EACXE,EAAQ1E,EAAKL,EAAQ8E,EAAO,EAAInF,EAAIO,CAAG,EAAGH,CAAC,EAC3CiF,EAAO,IAAI,aAAaF,EAAOnF,CAAE,EACjCsF,EAAO,IAAI,aAAaH,EAAOnF,CAAE,EACjCuF,EAAO,IAAI,aAAaJ,EAAOnF,CAAE,EACvC,QAASwF,EAAI,EAAGA,EAAIL,EAAMK,IACxBH,EAAK,IAAID,EAAM,IAAI,SAASI,EAAI,EAAIxF,EAAIwF,EAAI,EAAIxF,EAAKA,CAAE,EAAGwF,EAAIxF,CAAE,EAChEsF,EAAK,IAAIF,EAAM,IAAI,SAASI,EAAI,EAAIxF,EAAKA,EAAIwF,EAAI,EAAIxF,EAAK,EAAIA,CAAE,EAAGwF,EAAIxF,CAAE,EACzEuF,EAAK,IAAIH,EAAM,IAAI,SAASI,EAAI,EAAIxF,EAAK,EAAIA,EAAIwF,EAAI,EAAIxF,EAAK,EAAIA,CAAE,EAAGwF,EAAIxF,CAAE,EAE/E,MAAMwD,EAAOqB,EAAaQ,EAAMC,EAAMC,EAAM,CAAE,EAAArC,EAAG,EAAGgC,EAAG,EAAAtF,EAAG,EAAAE,EAAG,EAAGoF,EAAG,KAAArB,CAAI,CAAE,EAEnEiB,EAAQ,eAAe,QAAU,eAAe,SAChDW,EAAWV,EAAa/D,EAAQoE,EAAM,KAAMN,CAAK,EACjD7B,EAAU8B,EAAa/D,EAAQ,IAAI,YAAY6C,CAAI,EAAGiB,CAAK,EAC3DE,EAAS,MAAMnC,EACnB7B,EAAQZ,EACR,CACE,KAAMqF,EAAU,KAAMA,EAAU,KAAMA,EAAU,QAAAxC,EAAS,EAAAC,EAAG,EAAGgC,EAAG,EAAGA,EAAG,QAAS,EAAG,MAAA3B,EACpF,QAAS,CAAE,SAAU,EAAIvD,EAAI,MAAO,EAAG,UAAW,EAAIA,EAAI,MAAOA,EAAI,MAAO,EAAIA,CAAE,CACxF,EACIwD,EAAMC,EAAK,CACT,OAAQF,EAAQ,qBAAqBA,EAAM,EAAE,MAAMA,EAAM,EAAE,GAAK,YAChE,KAAM,gBAAiB,EAAAL,EAAG,EAAAgC,EAAG,KAAMrB,EAAK,KAAK,GAAG,EAAG,EAAAzD,CACzD,CAAK,EACH,UAAW+D,IAAK,CAACsB,EAAUxC,CAAO,EAAGkB,EAAE,UACvC,OAAOa,CACT,CAQA,eAAeU,EAAcjB,EAAK,CAAE,EAAAvB,EAAG,KAAAyC,EAAM,MAAAC,EAAO,EAAAxF,EAAG,IAAAqD,EAAK,KAAAvD,EAAM,GAAAqB,EAAK,EAAK,EAAI,CAC9E,KAAM,CAAE,OAAAP,CAAM,EAAKyD,EACblE,EAAMN,EAAWC,CAAI,EACrB4E,EAAQ,eAAe,QAAU,eAAe,SAIhDe,EAAa3C,EAAIyC,EAAO3F,EAAKoB,EAAUhB,CAAC,EACxC2C,EAAO/B,EAAO,aAAa,CAAE,KAAM6E,EAAY,MAAO,eAAe,OAAO,CAAE,EAC9E7C,EAAOhC,EAAO,aAAa,CAAE,KAAM6E,EAAY,MAAO,eAAe,OAAO,CAAE,EAE9EC,EAAa9D,EAAiBhB,EAAQZ,EAAG,QAAQ,EACjDkF,EAAO,IAAI,aAAapC,EAAIyC,EAAO3F,CAAE,EACrCuF,EAAO,IAAI,aAAarC,EAAIyC,EAAO3F,CAAE,EACrC+F,EAAO,IAAI,aAAa7C,EAAIlD,CAAE,EACpC,QAASsD,EAAO,EAAGA,EAAOsC,EAAOtC,IAAQ,CACvC,MAAM8B,EAAQ1E,EAAKL,EAAQ6C,EAAI,EAAIlD,EAAIO,CAAG,EAAGH,CAAC,EACxCqF,EAAWV,EAAa/D,EAAQoE,EAAM,KAAMN,CAAK,EACjDnB,EAAS5C,EAAYC,EAAQ,CAACkC,EAAGI,EAAMqC,EAAM,CAAC,CAAC,EACrDzD,EAASlB,EAAQ8E,EAAY,CAACnC,EAAQ8B,EAAU1C,EAAMC,CAAI,EAAG,KAAK,KAAME,EAAIlD,EAAM,GAAG,CAAC,EACtF,QAASmE,EAAI,EAAGA,EAAIjB,EAAGiB,IAAK,CAC1B,MAAM6B,GAAO7B,EAAIwB,EAAOrC,GAAQtD,EAChCsF,EAAK,IAAIF,EAAM,IAAI,SAASjB,EAAI,EAAInE,EAAKA,EAAImE,EAAI,EAAInE,EAAK,EAAIA,CAAE,EAAGgG,CAAG,EACtET,EAAK,IAAIH,EAAM,IAAI,SAASjB,EAAI,EAAInE,EAAK,EAAIA,EAAImE,EAAI,EAAInE,EAAK,EAAIA,CAAE,EAAGgG,CAAG,EACtE1C,IAASsC,EAAQ,GAGnBG,EAAK,IAAIX,EAAM,IAAI,SAASjB,EAAI,EAAInE,EAAImE,EAAI,EAAInE,EAAKA,CAAE,EAAGmE,EAAInE,CAAE,CAEpE,CACAyF,EAAS,QAAO,CAClB,CACA,MAAMf,EAAIhE,EAAKqF,EAAM3F,CAAC,EAChB0C,EAAOiC,EAAa/D,EAAQ0D,EAAE,KAAMI,CAAK,EACzCtB,EAAOqB,EAAaH,EAAE,IAAKY,EAAMC,EAAM,CAC3C,EAAArC,EAAG,EAAG,EAAG,EAAAtD,EAAG,EAAAE,EAAG,EAAG6F,EAAM,KAAM,MAAMzC,CAAC,EAAE,KAAK0C,CAAK,CACrD,CAAG,EACKZ,EAAS,MAAMnC,EACnB7B,EAAQZ,EAAG,CAAE,KAAA0C,EAAM,KAAAC,EAAM,KAAAC,EAAM,QAAS,KAAM,EAAAE,EAAG,EAAG,EAAG,EAAGyC,EAAM,QAAS,EAAG,KAAMC,EAAQ,EAAG,GAAArE,CAAE,EAC/FiC,EAAMC,EAAK,CAAE,OAAQ,sBAAuB,KAAM,SAAU,EAAAP,EAAG,KAAAyC,EAAM,MAAAC,EAAO,EAAAxF,CAAC,CAAE,EACjF,UAAW+D,IAAK,CAACrB,EAAMC,EAAMC,CAAI,EAAGmB,EAAE,UACtC,OAAOa,CACT,CAMA,eAAeiB,EAAaxB,EAAK,CAAE,EAAAvB,EAAG,EAAAgC,EAAG,KAAArB,EAAM,EAAAzD,EAAG,IAAAqD,EAAK,KAAAvD,EAAM,GAAAqB,EAAK,EAAK,EAAI,CACzE,KAAM,CAAE,OAAAP,CAAM,EAAKyD,EACblE,EAAMN,EAAWC,CAAI,EACrB4E,EAAQ,eAAe,QAAU,eAAe,SAChDK,EAAOjC,EAAIgC,EAEXE,EAAQ1E,EAAKL,EAAQ8E,EAAO,EAAInF,EAAIO,CAAG,EAAGH,CAAC,EAC3CqF,EAAWV,EAAa/D,EAAQoE,EAAM,KAAMN,CAAK,EACjDe,EAAaV,EAAOnF,EAAKoB,EAAUhB,CAAC,EACpC2C,EAAO/B,EAAO,aAAa,CAAE,KAAM6E,EAAY,MAAO,eAAe,OAAO,CAAE,EAC9E7C,EAAOhC,EAAO,aAAa,CAAE,KAAM6E,EAAY,MAAO,eAAe,OAAO,CAAE,EAC9EK,EAAYlE,EAAiBhB,EAAQZ,EAAG,OAAO,EAC/CuD,EAAS5C,EAAYC,EAAQ,CAACkC,EAAG,EAAG,EAAGiC,CAAI,CAAC,EAClDjD,EAASlB,EAAQkF,EAAW,CAACvC,EAAQ8B,EAAU1C,EAAMC,CAAI,EAAG,KAAK,KAAMmC,EAAOnF,EAAM,GAAG,CAAC,EAExF,MAAMsF,EAAO,IAAI,aAAaH,EAAOnF,CAAE,EACjCuF,EAAO,IAAI,aAAaJ,EAAOnF,CAAE,EACvC,QAASwF,EAAI,EAAGA,EAAIL,EAAMK,IACxBF,EAAK,IAAIF,EAAM,IAAI,SAASI,EAAI,EAAIxF,EAAIwF,EAAI,EAAIxF,EAAKA,CAAE,EAAGwF,EAAIxF,CAAE,EAChEuF,EAAK,IAAIH,EAAM,IAAI,SAASI,EAAI,EAAIxF,EAAKA,EAAIwF,EAAI,EAAIxF,EAAK,EAAIA,CAAE,EAAGwF,EAAIxF,CAAE,EAE3E,MAAM0E,EAAIhE,EAAKL,EAAQ6C,EAAIlD,EAAIO,CAAG,EAAGH,CAAC,EAChC0C,EAAOiC,EAAa/D,EAAQ0D,EAAE,KAAMI,CAAK,EACzC7B,EAAU8B,EAAa/D,EAAQ,IAAI,YAAY6C,CAAI,EAAGiB,CAAK,EAC3DtB,EAAOqB,EAAaH,EAAE,IAAKY,EAAMC,EAAM,CAAE,EAAArC,EAAG,EAAG,EAAG,EAAAtD,EAAG,EAAAE,EAAG,EAAGoF,EAAG,KAAArB,CAAI,CAAE,EACpEmB,EAAS,MAAMnC,EACnB7B,EAAQZ,EAAG,CAAE,KAAA0C,EAAM,KAAAC,EAAM,KAAAC,EAAM,QAAAC,EAAS,EAAAC,EAAG,EAAG,EAAG,EAAGgC,EAAG,QAAS,EAAG,GAAA3D,CAAE,EACrEiC,EAAMC,EAAK,CAAE,OAAQ,qBAAsB,KAAM,QAAS,EAAAP,EAAG,EAAAgC,EAAG,KAAMrB,EAAK,KAAK,GAAG,EAAG,EAAAzD,CAAC,CAAE,EAC3F,UAAW+D,IAAK,CAACsB,EAAU3C,EAAMC,EAAMC,EAAMC,CAAO,EAAGkB,EAAE,UACzD,OAAOa,CACT,CAEA,SAASmB,EAAYC,EAAMC,EAAI,CAC7BC,EAAaF,EAAO3B,GAClBA,EAAI,OAAS4B,EAAG5B,CAAG,EAAI,CAAE,KAAM,GAAM,OAAQ,eAAe,CAAE,CAClE,CAIA0B,EAAY,mBAAqB1B,GAC/BD,EAAeC,EAAK,CAAE,EAAG,EAAG,EAAG,GAAI,EAAG,GAAI,KAAM,CAAC,GAAI,CAAC,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,GAAG,CAAE,CAAC,EAC5F0B,EAAY,yBAA2B1B,GACrCQ,EAAoBR,EAAK,CAAE,EAAG,EAAG,EAAG,GAAI,KAAM,CAAC,GAAI,CAAC,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,GAAG,CAAE,CAAC,EAC1F0B,EAAY,kBAAoB1B,GAC9BiB,EAAcjB,EAAK,CAAE,EAAG,EAAG,KAAM,GAAI,MAAO,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,GAAG,CAAE,CAAC,EAClF0B,EAAY,iBAAmB1B,GAC7BwB,EAAaxB,EAAK,CAAE,EAAG,EAAG,EAAG,GAAI,KAAM,CAAC,GAAI,EAAE,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,GAAG,CAAE,CAAC,EAEpF6B,EAAa,mBAAqB7B,GAChCD,EAAeC,EAAK,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,KAAM,CAAC,CAAC,EAAG,EAAG,MAAO,IAAK,KAAM,KAAM,GAAG,CAAE,CAAC,EAOtF0B,EAAY,yBAA2B1B,GACrCD,EAAeC,EAAK,CAClB,EAAG,EAAG,EAAG,GAAI,EAAG,GAAI,KAAM,CAAC,GAAI,CAAC,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,IAC9D,MAAO,CAAE,GAAI,EAAG,GAAI,EAAE,CAC1B,CAAG,CAAC,EACJ0B,EAAY,+BAAiC1B,GAC3CQ,EAAoBR,EAAK,CACvB,EAAG,EAAG,EAAG,GAAI,KAAM,CAAC,GAAI,GAAI,CAAC,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,IAC3D,MAAO,CAAE,GAAI,GAAI,GAAI,EAAE,CAC3B,CAAG,CAAC,EACJ0B,EAAY,oCAAsC1B,GAChDQ,EAAoBR,EAAK,CACvB,EAAG,EAAG,EAAG,GAAI,KAAM,CAAC,GAAI,EAAE,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,IACxD,MAAO,CAAE,GAAI,EAAG,GAAI,EAAE,CAC1B,CAAG,CAAC,EACJ6B,EAAa,yBAA2B7B,GACtCD,EAAeC,EAAK,CAClB,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,KAAM,CAAC,GAAI,CAAC,EAAG,EAAG,MAAO,IAAK,KAAM,KAAM,IAC7D,MAAO,CAAE,GAAI,EAAG,GAAI,EAAE,CAC1B,CAAG,CAAC,EAOJ,MAAM8B,EAAU9B,GAASA,EAAI,aAAe,KAAO,CAAE,KAAM,GAAM,OAAQ,+BAA+B,EACxG6B,EAAa,sBAAwB7B,GAAQ8B,EAAO9B,CAAG,IAChDA,EAAI,OACLD,EAAeC,EAAK,CAAE,EAAG,EAAG,EAAG,GAAI,EAAG,GAAI,KAAM,CAAC,GAAI,CAAC,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,GAAI,GAAM,EADrF,CAAE,KAAM,GAAM,OAAQ,eAAe,EACkD,EAC3G6B,EAAa,qBAAuB7B,GAAQ8B,EAAO9B,CAAG,IAC/CA,EAAI,OACLiB,EAAcjB,EAAK,CAAE,EAAG,EAAG,KAAM,GAAI,MAAO,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,GAAI,EAAI,CAAE,EAD3E,CAAE,KAAM,GAAM,OAAQ,eAAe,EACwC,EACjG6B,EAAa,oBAAsB7B,GAAQ8B,EAAO9B,CAAG,IAC9CA,EAAI,OACLwB,EAAaxB,EAAK,CAAE,EAAG,EAAG,EAAG,GAAI,KAAM,CAAC,GAAI,EAAE,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,GAAI,GAAM,EAD7E,CAAE,KAAM,GAAM,OAAQ,eAAe,EAC0C,EACnG6B,EAAa,sBAAwB7B,GAAQ8B,EAAO9B,CAAG,GAClDD,EAAeC,EAAK,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,EAAG,KAAM,CAAC,CAAC,EAAG,EAAG,MAAO,IAAK,KAAM,KAAM,IAAK,GAAI,EAAI,CAAE,CAAC,EAQnG6B,EAAa,2BAA6B7B,GAAQ8B,EAAO9B,CAAG,IACrDA,EAAI,OACLD,EAAeC,EAAK,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,IAAK,KAAM,CAAC,IAAK,GAAG,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,GAAI,GAAM,EADxF,CAAE,KAAM,GAAM,OAAQ,eAAe,EACqD,EAC9G6B,EAAa,0BAA4B7B,GAAQ8B,EAAO9B,CAAG,IACpDA,EAAI,OACLiB,EAAcjB,EAAK,CAAE,EAAG,EAAG,KAAM,IAAK,MAAO,IAAK,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,GAAI,EAAI,CAAE,EAD9E,CAAE,KAAM,GAAM,OAAQ,eAAe,EAC2C,EACpG6B,EAAa,yBAA2B7B,GAAQ8B,EAAO9B,CAAG,IACnDA,EAAI,OACLwB,EAAaxB,EAAK,CAAE,EAAG,EAAG,EAAG,IAAK,KAAM,CAAC,IAAK,GAAG,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,GAAI,GAAM,EADhF,CAAE,KAAM,GAAM,OAAQ,eAAe,EAC6C,EAItG6B,EAAa,wBAA0B7B,GAAUA,EAAI,OACjDD,EAAeC,EAAK,CAAE,EAAG,EAAG,EAAG,EAAG,EAAG,IAAK,KAAM,CAAC,IAAK,GAAG,EAAG,EAAG,MAAO,IAAK,IAAM,KAAM,IAAK,EADlC,CAAE,KAAM,GAAM,OAAQ,eAAe,CACD,EAClG6B,EAAa,uBAAyB7B,GAAUA,EAAI,OAChDiB,EAAcjB,EAAK,CAAE,EAAG,EAAG,KAAM,IAAK,MAAO,IAAK,EAAG,MAAO,IAAK,IAAM,KAAM,GAAG,CAAE,EADzB,CAAE,KAAM,GAAM,OAAQ,eAAe,CACV"}
|
|
|
|
|
|
assets/attn_sweep-CxMb0QH-.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 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-CxMb0QH-.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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/autotune-Bwt_lWMv.js
DELETED
|
@@ -1,44 +0,0 @@
|
|
| 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;
|
| 5 |
-
fn vhash(i: u32, g: u32) -> f32 {
|
| 6 |
-
return f32((((i + 1u) * 2654435761u) ^ ((g + 1u) * 40503u)) & 1023u);
|
| 7 |
-
}
|
| 8 |
-
var<workgroup> vbuf: array<f32, D>;
|
| 9 |
-
var<workgroup> scratch: array<f32, WG>;
|
| 10 |
-
@compute @workgroup_size(256)
|
| 11 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 12 |
-
let g = wid.x; let tid = lid.x;
|
| 13 |
-
var sum: f32 = 0.0;
|
| 14 |
-
for (var i = tid; i < D; i = i + WG) {
|
| 15 |
-
let v = (vhash(i, g) - 512.0) / 256.0 + (vhash(i + 7777u, g) - 512.0) / 256.0;
|
| 16 |
-
vbuf[i] = v;
|
| 17 |
-
sum = sum + v;
|
| 18 |
-
}
|
| 19 |
-
scratch[tid] = sum;
|
| 20 |
-
workgroupBarrier();
|
| 21 |
-
for (var s = WG / 2u; s > 0u; s = s >> 1u) {
|
| 22 |
-
if (tid < s) { scratch[tid] = scratch[tid] + scratch[tid + s]; }
|
| 23 |
-
workgroupBarrier();
|
| 24 |
-
}
|
| 25 |
-
let mu = scratch[0] / f32(D);
|
| 26 |
-
workgroupBarrier();
|
| 27 |
-
for (var i = tid; i < D; i = i + WG) { out[g * D + i] = vbuf[i] - mu; }
|
| 28 |
-
}`;try{const i=e.createShaderModule({code:r}),s=e.createComputePipeline({layout:"auto",compute:{module:i,entryPoint:"main"}}),a=e.createBuffer({size:8*448*4,usage:GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC}),l=e.createBuffer({size:8*448*4,usage:GPUBufferUsage.COPY_DST|GPUBufferUsage.MAP_READ}),m=e.createBindGroup({layout:s.getBindGroupLayout(0),entries:[{binding:0,resource:{buffer:a}}]}),p=e.createCommandEncoder(),u=p.beginComputePass();u.setPipeline(s),u.setBindGroup(0,m),u.dispatchWorkgroups(8),u.end(),p.copyBufferToBuffer(a,0,l,0,8*448*4),e.queue.submit([p.finish()]),await l.mapAsync(GPUMapMode.READ);const h=new Float32Array(l.getMappedRange().slice(0));l.unmap(),a.destroy(),l.destroy();const c=(d,b)=>(Math.imul(d+1,2654435761)^Math.imul(b+1,40503))>>>0&1023;for(let d=0;d<8;d++){const b=new Float64Array(448);let M=0;for(let f=0;f<448;f++)b[f]=(c(f,d)-512)/256+(c(f+7777,d)-512)/256,M+=b[f];const B=M/448;for(let f=0;f<448;f++)if(!(Math.abs(h[d*448+f]-(b[f]-B))<=.001))return!0}return!1}catch{return null}}async function te(e,t){const r=[4,8,16,32].filter(s=>s<=Math.min(t??0,64));if(!r.length)return null;const i=(s,a)=>((Math.imul(s+1,2654435761)^Math.imul(a+1,40503))>>>0&1023)/64;try{for(const s of r){const a=64/s,l=`
|
| 29 |
-
enable subgroups;
|
| 30 |
-
@group(0) @binding(0) var<storage, read_write> out: array<f32>;
|
| 31 |
-
const TK: u32 = ${s}u;
|
| 32 |
-
fn vhash(i: u32, g: u32) -> f32 {
|
| 33 |
-
return f32((((i + 1u) * 2654435761u) ^ ((g + 1u) * 40503u)) & 1023u) / 64.0;
|
| 34 |
-
}
|
| 35 |
-
@compute @workgroup_size(64)
|
| 36 |
-
fn main(@builtin(workgroup_id) wid: vec3<u32>, @builtin(local_invocation_id) lid: vec3<u32>) {
|
| 37 |
-
let g = wid.x; let tid = lid.x;
|
| 38 |
-
var vr = vhash(tid, g);
|
| 39 |
-
for (var s = TK / 2u; s > 0u; s = s >> 1u) {
|
| 40 |
-
vr = vr + subgroupShuffleDown(vr, s);
|
| 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
DELETED
|
@@ -1 +0,0 @@
|
|
| 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
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 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
DELETED
|
@@ -1 +0,0 @@
|
|
| 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":"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"}
|
|
|
|
|
|
assets/autotune-CaFlLr-b.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
assets/baseline-DFLF_Mw1.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 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-DFLF_Mw1.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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/batch_cap_ab-67ewcIZi.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 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-67ewcIZi.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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/bench-BarR4Zp5.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
| 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-BarR4Zp5.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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-D3sid5uF.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
| 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>
|
| 5 |
-
<button id="verify" disabled>Verify vs golden (30)</button>
|
| 6 |
-
<button id="bench" disabled>Benchmark</button>
|
| 7 |
-
<label><input type="checkbox" id="includeRef"> Include reference runtimes</label>
|
| 8 |
-
<button id="export" disabled>Export JSON</button>
|
| 9 |
-
</p>
|
| 10 |
-
<p id="status" style="color:#8bc"></p>
|
| 11 |
-
<div id="benchTable"></div>
|
| 12 |
-
<pre id="out" style="white-space:pre-wrap"></pre>
|
| 13 |
-
`;const k=document.querySelector("#load"),b=document.querySelector("#verify"),$=document.querySelector("#bench"),F=document.querySelector("#includeRef"),w=document.querySelector("#export"),y=document.querySelector("#status"),M=document.querySelector("#benchTable"),j=document.querySelector("#out"),a=e=>{j.textContent+=`${e}
|
| 14 |
-
`};let l=null;k.addEventListener("click",async()=>{k.disabled=!0;try{a("loading engine…");const e=await v(),n=e.hasF16?"f16":"f32",i=new URLSearchParams(location.search),o=i.get("immediates")==="0"?"off":"auto",t=await R(),m=i.get("shortlist")!=="0",c=n==="f16"&&m?E(t.idToToken):null,s=await L(e.device,"/weights",{targetDtype:n,lmHeadQ8:n==="f16",ffnWT:n==="f16",projWT:n==="f16",directQ8:i.get("directq8")!=="0",...c?{lmHeadIds:c}:{}});let d=null,p="off";if(i.get("tune")!=="0"){a("autotuning routing on this device…");const r=await q({...e,dtype:n},s,{immediates:o});d=r.tuned,p=r.partial?"partial":"measured",r.partial&&a(`autotune partial (${r.partial}) — defaults + correctness verdicts only`)}const u={shortlist:c?c.length:0,autotune:p,tuned:d,directQ8:s.q8Stats.directTensors>0,q8Stats:s.q8Stats,immediates:o==="auto"&&e.hasImmediates?"on":"off"};l={ctx:{...e,dtype:n},weights:s,tok:t,tuned:d,stack:u,immediates:o},a(`engine ready: ${e.adapterInfo.description||e.adapterInfo.vendor} (${n}, ${c?`shortlist ${c.length}`:"full vocab"}, autotune ${p})`),d&&a(`tuned: ${JSON.stringify(d)}`),b.disabled=!1,$.disabled=!1}catch(e){a(`LOAD FAILED: ${e?.message??e}`),k.disabled=!1}});b.addEventListener("click",async()=>{b.disabled=!0;const{ctx:e,weights:n,tok:i}=l;let o=0,t=0,m=0,c=0;try{for(let u=0;u<g.items.length;u++){const r=g.items[u],{rows:S,metrics:x}=await T(e,n,i,[r.source],{maxNewTokens:r.maxNewTokens,...I(l.tuned,1),immediates:l.immediates});c+=x.tokPerSec;const h=B(S[0].ids,r.ids);h.verdict==="exact"?o++:h.verdict==="forced-eos"?t++:m++,a(`[${String(u).padStart(2)}] ${h.verdict.toUpperCase().padEnd(10)} ${x.tokPerSec.toFixed(0)} tok/s ${r.source}`),h.verdict==="mismatch"&&(a(` step ${h.step}`),a(` engine: ${S[0].text}`),a(` golden: ${r.text}`))}const s=g.items.length,d=Math.ceil(.95*s),p=o+t>=d;a(`
|
| 15 |
-
${p?"PASS":"FAIL"}: exact=${o} forced-eos=${t} mismatch=${m} (need ${d}/${s}) avg ${(c/s).toFixed(1)} tok/s @ batch=1`)}catch(s){a(`VERIFY FAILED: ${s?.message??s}
|
| 16 |
-
${s?.stack??""}`)}finally{b.disabled=!1}});let f=null;function A(e){const n=e.runs,i=(t,m)=>t.min?` (${t.min[m]}–${t.max[m]})`:"",o=n.map(t=>t.error?`<tr><td>${t.runtime}</td><td>${t.preset}</td><td>${t.batch}</td>
|
| 17 |
-
<td colspan="4" style="color:#f55">ERROR: ${t.error}</td></tr>`:`<tr><td>${t.runtime}</td><td>${t.preset}</td><td>${t.batch}</td>
|
| 18 |
-
<td>${t.median.tokPerSec}${i(t,"tokPerSec")}</td>
|
| 19 |
-
<td>${t.median.e2eCharsPerSec}${i(t,"e2eCharsPerSec")}</td>
|
| 20 |
-
<td>${t.median.tokens}</td>
|
| 21 |
-
<td>${t.median.decodeMs??t.median.translateMs}</td></tr>`).join("");M.innerHTML=`
|
| 22 |
-
<table border="1" cellpadding="4" style="border-collapse:collapse">
|
| 23 |
-
<tr><th>runtime</th><th>preset</th><th>batch</th>
|
| 24 |
-
<th>tok/s median (min–max)</th><th>chars/s median (min–max)</th>
|
| 25 |
-
<th>tokens</th><th>decode ms</th></tr>
|
| 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-D3sid5uF.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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/bench-DsT6x25S.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/reference-BXrEo0-e.js","assets/autotune-CaFlLr-b.js"])))=>i.map(i=>d[i]);
|
| 2 |
+
import{E as G,t as V,a as J,m as z,b as K,i as Y,l as X,e as Z,c as nn,d as tn}from"./autotune-CaFlLr-b.js";function F(t){for(let e=1;e<t.length;e++)if(t[e]===G)return t.slice(0,e+1);return t.slice()}function en(t,e){const i=F(t),c=F(e),n=Math.min(i.length,c.length);let o=0;for(;o<n&&i[o]===c[o];)o++;if(o===i.length&&o===c.length)return{verdict:"exact"};if(o===n){const r=i.length>c.length?i:c;if(r.length===n+1&&r[n]===G)return{verdict:"forced-eos"}}return{verdict:"mismatch",step:o}}const cn="modulepreload",on=function(t){return"/"+t},I={},an=function(e,i,c){let n=Promise.resolve();if(i&&i.length>0){let p=function(u){return Promise.all(u.map(h=>Promise.resolve(h).then(s=>({status:"fulfilled",value:s}),s=>({status:"rejected",reason:s}))))};document.getElementsByTagName("link");const r=document.querySelector("meta[property=csp-nonce]"),a=r?.nonce||r?.getAttribute("nonce");n=p(i.map(u=>{if(u=on(u),u in I)return;I[u]=!0;const h=u.endsWith(".css"),s=h?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${u}"]${s}`))return;const g=document.createElement("link");if(g.rel=h?"stylesheet":cn,h||(g.as="script"),g.crossOrigin="",g.href=u,a&&g.setAttribute("nonce",a),document.head.appendChild(g),h)return new Promise((m,l)=>{g.addEventListener("load",m),g.addEventListener("error",()=>l(new Error(`Unable to preload CSS for ${u}`)))})}))}function o(r){const a=new Event("vite:preloadError",{cancelable:!0});if(a.payload=r,window.dispatchEvent(a),!a.defaultPrevented)throw r}return n.then(r=>{for(const a of r||[])a.status==="rejected"&&o(a.reason);return e().catch(o)})};function j(t,e=220){const i=String(t).replace(/\r\n/g,`
|
| 3 |
+
`).split(`
|
| 4 |
+
`),c=[],n=[],o=Math.max(80,Number(e)||220),r=/[^。!?!?;;]+[。!?!?;;]*/g;for(const a of i){const p=a.trim();if(!p){n.push(null);continue}const u=p.match(r)||[p];let h="";const s=[],g=()=>{h&&(s.push(c.length),c.push(h),h="")};for(const m of u){if(m.length>o){g();for(let l=0;l<m.length;l+=o)s.push(c.length),c.push(m.slice(l,l+o));continue}h&&(h+m).length>o&&g(),h+=m}g(),n.push(s)}return{chunks:c,plan:n}}const sn=["他缓缓拔出长剑,目光冷得像冰。","夜色渐深,客栈里只剩下几盏残灯。","“你到底是什么人?”她低声问道。","山风呼啸,卷起满地的落叶。","老者捋了捋胡须,微微一笑。","这一掌的力道,足以开碑裂石!","“师父,弟子知错了。”少年跪在地上。","江湖上的恩怨,从来没有那么简单。","她转身离去,再也没有回头。","剑光一闪,血溅三尺。","大殿之内,众人鸦雀无声。","他喝了口酒,眼中闪过一丝痛楚。","“今晚三更,后山竹林见。”","马蹄声由远及近,尘土飞扬。","这门功夫,他练了整整二十年。","暮色四合之际,一行人马终于抵达了山脚下的小镇,镇口的酒旗在风中猎猎作响;为首的中年汉子翻身下马,环顾四周,见街道两旁的店铺早已关门闭户,只有远处一家客栈还透出昏黄的灯光,他皱了皱眉,低声吩咐众人收起兵刃,不要惊扰了镇上的百姓。","传闻中的藏剑山庄坐落在群山环抱之中,庄内古木参天,流水潺潺,青石铺就的小径蜿蜒曲折;每逢三月桃花盛开,四方豪杰便会齐聚于此,或论剑,或品茶,或只是远远地望一眼那位传说中的庄主,据说他已经三十年没有拔过剑了,可江湖上没有人敢小看他。","那一夜大雨倾盆,雷声滚滚,破庙里的火堆忽明忽暗;少年抱着怀中的剑谱,听着庙外杂乱的脚步声越来越近,心跳如鼓,他知道,追兵一旦破门而入,自己便再无生路,可师父临终前的嘱托犹在耳边,这本剑谱无论如何都不能落入奸人之手。","掌门之位悬空已有三年,门中各脉明争暗斗从未停歇;大师兄稳重却优柔寡断,二师姐剑法超群却性情孤傲,三师弟聪明伶俐却资历尚浅,长老们各怀心思,谁也不肯先开口,直到那个雪夜,山门外传来一声长啸,所有人都放下了手中的茶盏。","集市上人声鼎沸,卖艺的汉子赤膊耍着一杆铁枪,围观的人群不时爆发出阵阵喝彩声;忽然人群一阵骚动,几名黑衣人分开众人径直走向那名枪手,为首之人冷冷地丢下一块乌黑的令牌,喧闹的集市霎时安静了下来,连风都仿佛停了。","信使跪在堂下,双手呈上一封火漆密函,堂上众人面面相觑;老庄主拆开信笺,只看了一眼,脸色便骤然大变,他缓缓起身,望着窗外沉沉的夜色,半晌才道:传令下去,即刻封山,任何人不得进出,违令者一律逐出师门,永不再录。","三十年前的那场大火烧毁了半座城池,也烧断了两大世家百年的情谊;如今旧事重提,当年的幸存者死的死,散的散,唯有城南那口枯井旁的老槐树还记得一切,树下埋着的,不只是一坛陈年的女儿红,还有一个再也无人敢提起的名字。","渡口的老船夫眯着眼打量来客,见那书生衣衫褴褛却腰悬长剑,不由得多问了一句;书生笑而不答,只将一锭碎银放在船头,转身望向对岸茫茫的芦苇荡,江风吹起他的衣角,露出内衬上暗绣的金线纹样,老船夫握着船桨的手,忽然抖了一下。","林昭推门而入,林昭的剑还在滴着血,可林昭的声音却平静得可怕。","沈青山望着窗外,沈青山知道,今夜之后江湖上再无沈青山这个名字。","“林昭!林昭你给我站住!”她追出门外,可林昭的身影早已消失在夜色之中。","众人都说沈青山败了,可沈青山不这么认为,沈青山收剑入鞘,转身走下擂台。","林昭救过他一次,林昭也骗过他一次,所以当林昭再次出现时,他不知该拔剑还是敬酒。","沈青山的刀快,沈青山的心更狠,凡是见过沈青山出手的人,都不愿再与他为敌。","有人说林昭死在了雁门关外,有人说林昭隐居山林,还有人说,林昭根本就没有存在过。"],A=`第三章 夜雨断魂崖
|
| 5 |
+
|
| 6 |
+
暮色沉沉,秋雨初歇。断魂崖下的山道上,一行五骑冒着湿冷的山风缓缓而行。为首的正是青城派大弟子沈孤鸿,他勒住缰绳,抬头望了望崖顶那株歪脖老松,眉头微微一皱。三年前师父便是在此处失踪的,尸骨无存,只留下半截断剑。断剑如今就贴身藏在他怀中,隔着三层油布,仍似有一股寒意透出来,时时提醒着他此行的真正目的。
|
| 7 |
+
|
| 8 |
+
“师兄,天色不早了。”身后的小师妹柳如烟催马上前,低声道,“前面十里便是落雁镇,不如先寻个客栈歇脚,明日一早再上崖查探。”沈孤鸿摇了摇头。他心中隐隐觉得不安,这条山道太静了,静得连一声鸦啼都没有。往年这个时节,崖下的枫林里总有猎户往来,如今却连半个人影也见不着。他翻身下马,蹲下身子,指尖拂过路面的泥土,泥中赫然印着几行新鲜的马蹄印,蹄印极深,来者必是负重疾驰,而且就在半个时辰之内。
|
| 9 |
+
|
| 10 |
+
果然,行不到三里,前方林中忽然传来一声唿哨。刹那间,道旁的枯草丛中窜出十几条黑影,个个蒙面持刀,将五人围在了当中。沈孤鸿不惊反笑:“诸位在此恭候多时,想必不是为了求财。”为首的蒙面人嘿嘿一笑,声音沙哑:“沈大侠好眼力。留下东西,饶你们全尸。”他手中那口九环大刀随着话音缓缓抬起,刀环相击,铮铮作响。
|
| 11 |
+
|
| 12 |
+
柳如烟手按剑柄,正要拔剑,却被沈孤鸿抬手拦住。他缓缓扫视四周,忽然朗声道:“阁下既是青城故人,何必遮遮掩掩?三年前崖顶一别,赵师叔的刀法想必更精进了。”此言一出,那蒙面首领浑身一震,握刀的手竟微微发起抖来。风卷着雨丝掠过山道,一时间竟无人再敢上前半步,只余刀环轻响。
|
| 13 |
+
|
| 14 |
+
雨又下了起来,先是淅淅沥沥,继而如注如倾,豆大的雨点砸在刀锋上溅起一片白雾,砸在众人斗笠上噼啪作响,山道两旁的枫叶被打得纷纷坠落,和着泥水粘在青石板上,远处的雷声一阵接着一阵滚过山脊,闪电撕开铅灰色的云层,把崖壁上那些经年累月被风霜侵蚀出的沟壑照得纤毫毕现,沟壑间隐约可见一道道旧年的剑痕,剑痕纵横交错,深者入石三寸,浅者也有半指,显然当年在此动手的绝非泛泛之辈,而这一切都在电光熄灭的瞬间重新沉入黑暗,仿佛从未存在过一般,只余下漫天雨幕和一片肃杀之气笼罩着进退两难的众人。
|
| 15 |
+
|
| 16 |
+
“动手!”蒙面首领一声令下,十几口钢刀同时劈落。沈孤鸿长啸一声,青虹出鞘。剑光过处,雨珠纷纷断成两截。他的身形在刀丛中穿梭如游鱼,看似险象环生,实则每一步都踏在众刀客力道将尽的空隙上。这正是青城绝学“听雨十三式”,以静制动,后发先至。柳如烟与三名师弟结成剑阵护住马匹,一时倒也不落下风。剑阵旋转开合,四柄长剑在雨中织成一张光网,泼水难入。
|
| 17 |
+
|
| 18 |
+
激斗中,沈孤鸿故意卖了个破绽,引那首领一刀劈空,随即剑走偏锋,挑落了对方的面巾。电光再闪,照亮一张刀疤纵横的脸。柳如烟失声惊呼:“赵、赵师叔!你不是三年前就随师父一同殉难了么?”那人面色惨白,仰天惨笑:“殉难?好一个殉难!”笑声未落,两行浊泪已混着雨水淌进了刀疤纵横的沟壑里。
|
| 19 |
+
|
| 20 |
+
他一边挥刀格挡,一边嘶声说起当年之事,原来三年前掌门带着他上崖赴约,约他们的人自称故友,实则早已投靠了漠北的血狼堡,崖顶设下的不是酒宴而是天罗地网,掌门为护他断后,独自一人挡住堡中四大供奉,力战半夜,剑断之后犹以掌搏敌,最终被逼坠崖,而他自己重伤被擒,堡主以一味奇毒控住他的心脉,逼他每月回堡领取解药,从此不得不听命行事,充当血狼堡安插在川中的眼线,这三年来他无一日不想将真相告知青城,却又无一日敢开口,只因堡主放话,他若泄密,便先屠青城满门再断他解药,叫他眼睁睁看着同门死绝之后自己再毒发身亡。
|
| 21 |
+
|
| 22 |
+
沈孤鸿听罢,久久无言。雨水顺着他的剑尖滴落,在脚下汇成一线殷红。“师叔,”他终于开口,声音低沉,“今夜你奉命截杀的东西,究竟是什么?”赵师叔惨然道:“一封信。据说信中写着血狼堡这些年在中原布下的所有暗桩名录。堡主得知此信已到你手,宁可血洗川中也要毁去。”他说到此处,喉头一阵腥甜,显是体内毒性又发作了,扶着刀柄才勉强站稳。
|
| 23 |
+
|
| 24 |
+
柳如烟急道:“师兄,我们何曾有过什么名录!”沈孤鸿却缓缓从怀中取出一只油布包裹,层层揭开,里面竟是那半截断剑。他持剑向天,任雨水冲刷剑身,锈迹剥落处,剑脊上细密的刻痕渐渐显露出来。“师父坠崖之前,把名录刻在了自己的佩剑上。”他环视众人,一字一句道,“血狼堡要毁的不是信,是这柄剑。他们三年前没找到它,今夜也休想拿走。”
|
| 25 |
+
|
| 26 |
+
崖顶忽然亮起一片火把,人喊马嘶之声顺着风雨滚滚而下,少说也有三百之众,火光中一面黑底血狼大旗猎猎招展,旗下一名白发老者按剑而立,正是血狼堡四大供奉之首、人称“夺魂手”的燕北归,他身侧两列弓手已然张弓搭箭,箭簇上幽蓝的毒光在火把映照下明明灭灭,而山道后方的退路上也响起了密集的马蹄声,分明是早有一支伏兵截断了归途,前有强敌后有追兵,头顶是万仞绝壁,脚下是湍急的涧水,当真是插翅难飞的死地,饶是沈孤鸿一向沉稳,此刻掌心也不由得沁出了冷汗。
|
| 27 |
+
|
| 28 |
+
“师叔,”他忽然低声道,“烦你带我师妹师弟们从涧底水路走,剑我留下。”赵师叔一怔:“你要以身做饵?”沈孤鸿笑了笑,雨水从他年轻的脸上流过:“名录已在剑上,剑毁了还有拓本。可青城的人若都折在这里,谁去把它送到武林盟?”他不再多言,提剑独自迎着火光走上山道。雷声隆隆,一道闪电划过,照见他的背影挺拔如崖顶那株老松。
|
| 29 |
+
|
| 30 |
+
燕北归居高临下望着那道逆着火光而来的孤影,眼中掠过一丝讶异,随即化作冷笑。他抬手止住弓手,缓步下崖,枯瘦的五指在夜雨中张开又合拢,发出一串细碎的骨响。“三年前你师父也是这样走上来的。”他的声音不高,却穿透雨幕清清楚楚地送进每个人耳中,“他断剑之后我曾许他一条生路,只要交出名录,青城上下既往不咎。他说了八个字——宁碎剑骨,不负江湖。今日我把这句话原样送还给你,小子,你可以选一条聪明些的路。”
|
| 31 |
+
|
| 32 |
+
沈孤鸿止步于三丈之外,横剑当胸。断剑无锋,剑身上斑驳的刻痕在火光下如同一行行无声的名字。“前辈既然记得家师的话,”他淡淡道,“又何必问我第二遍?”燕北归叹了口气,不再言语。两人身形同时消失在原地,再现时已在崖畔相交,一掌一剑,迸出的劲风将周遭三丈内的雨点尽数震成齑粉。四周的黑衣人只觉眼前人影幢幢,根本看不清招式,只听得金铁交鸣之声密如骤雨,又戛然而止。
|
| 33 |
+
|
| 34 |
+
赵师叔趁乱引着柳如烟等人坠下涧底,冰冷的涧水没过头顶的一瞬,柳如烟犹自回头,只见崖畔两道身影在电光中分而复合,合而复分,那柄断剑的寒芒每一次亮起都比前一次更接近咽喉,也更接近深渊,她张口想喊,灌进来的却只有一口冰水,赵师叔死死攥住她的手腕,两人顺着湍流向下游卷去,耳边的厮杀声、雷声、马嘶声渐渐都被水声吞没,唯有那一点剑芒烙在她眼底,任凭涧水如何冲刷也冲刷不去,多年以后她仍会在雨夜里惊醒,梦见那点寒星坠向无底的黑暗。
|
| 35 |
+
|
| 36 |
+
那一夜断魂崖的厮杀声直到五更方歇。后来江湖上有人说,曾见一个青衫剑客独战数百人,剑折之后夺刀再战,刀卷之后赤手空拳;也有人说,天明时分崖下的涧水都是红的。唯一可以确证的是,半月之后,一份写满名字的血书送到了武林盟主的案头,落款只有八个字:青城沈氏,以剑为凭。自那以后,川中道上再无血狼堡的旗号,而断魂崖顶的老松之下,多了一座无碑的剑冢,年年秋深,总有人遥遥望见一个白衣女子在冢前置酒三杯,风雨无阻。
|
| 37 |
+
`,rn=["刀出如龙,寒气逼人。","他在桥头站了一夜。","“放下剑,我饶你不死。”","钟声响起,山门缓缓开启。","她的暗器从不落空。","灯火摇曳,人影散乱。","一杯酒,敬当年的兄弟。","掌风过处,烛火尽灭。","他背上的伤疤又开始疼了。","“来者何人,报上名来!”","雪落无声,剑亦无声。","这条路,他走了半生。","密道尽头透出一线微光。","恩人一诺,死生不忘。","毒发之时,他咬碎了牙关。","旗帜倒下,城头易主。","江水东流,带不走旧恨。"];function D(t){if(t==="short32")return[...sn.slice(0,15),...rn];if(t==="chapter3k")return j(A).chunks;if(t==="file23k"){const e=j(A).chunks;return Array.from({length:8},()=>e).flat()}throw new Error(`unknown preset: ${t}`)}const H=t=>[...t].sort((e,i)=>i.length-e.length),$=t=>Number(t.toFixed(1));function hn(t){const e=[...t].sort((c,n)=>c-n),i=e.length>>1;return e.length%2?e[i]:(e[i-1]+e[i])/2}async function U(t,e,i,c,n,o=null,r={}){let a=0,p=0,u=0,h=0;const s={uniformBuffersCreated:0,dummyBuffersCreated:0,bindGroupsCreated:0,bindGroupCacheHits:0,bindGroupEvictions:0,immediateSets:0};for(let m=0;m<c.length;m+=n){const l=c.slice(m,m+n),{metrics:T}=await V(t,e,i,l,{...J(o,l.length),...r});a+=T.encoderMs,p+=T.decodeMs,u+=T.tokensGenerated,h+=T.submits;for(const L of Object.keys(s))s[L]+=T.dispatch?.[L]??0}const g=c.reduce((m,l)=>m+l.length,0);return{encoderMs:$(a),decodeMs:$(p),tokens:u,submits:h,dispatch:s,tokPerSec:$(u/p*1e3),e2eCharsPerSec:$(g/(a+p)*1e3)}}const un=["encoderMs","decodeMs","tokens","tokPerSec","e2eCharsPerSec"],_={"tfjs-wasm-q8":{device:"wasm",dtype:"q8"},"tfjs-webgpu-fp16":{device:"webgpu",dtype:"fp16"}};async function mn(t,e,i,{presets:c=["short32","chapter3k"],batches:n=[1,4,8,16],repeats:o=3,includeReference:r=!1,referencePresets:a=c,referenceBatches:p=[1,4],referenceCells:u=Object.keys(_).flatMap(m=>a.flatMap(l=>p.map(T=>({runtime:m,preset:l,batch:T})))),tuned:h=null,engineOptions:s={},onStatus:g=()=>{}}={}){const m=[],l=Object.fromEntries(c.map(f=>[f,H(D(f))])),T=f=>Array.isArray(n)?n:n[f],L=e.dtype==="f16"?2:4,B=async f=>{const b=i.encode(l[f][0]),x=z(t,K(b.length),L),k=[];for(const w of T(f)){const d=Math.min(w,x);d!==w&&g(`${f}: batch ${w} clamped to device max ${d}`),k.some(N=>N.batch===d)||k.push({batch:d,...d!==w?{requestedBatch:w}:{}})}return k};g("warmup…"),await U(t,e,i,l[c[0]],(await B(c[0]))[0].batch,h,s);for(const f of c)for(const{batch:b,requestedBatch:x}of await B(f)){const k=[];for(let d=0;d<o;d++)g(`webmt ${f} b${b} repeat ${d+1}/${o}…`),k.push(await U(t,e,i,l[f],b,h,s));const w=Object.fromEntries(un.map(d=>[d,$(hn(k.map(N=>N[d])))]));m.push({runtime:"webmt",preset:f,batch:b,...x?{requestedBatch:x}:{},repeats:k,median:w,min:{tokPerSec:Math.min(...k.map(d=>d.tokPerSec)),e2eCharsPerSec:Math.min(...k.map(d=>d.e2eCharsPerSec))},max:{tokPerSec:Math.max(...k.map(d=>d.tokPerSec)),e2eCharsPerSec:Math.max(...k.map(d=>d.e2eCharsPerSec))}})}if(r){const{runReference:f}=await an(async()=>{const{runReference:b}=await import("./reference-BXrEo0-e.js");return{runReference:b}},__vite__mapDeps([0,1]));for(const{runtime:b,preset:x,batch:k}of u){const{device:w,dtype:d}=_[b]??{};if(!w)throw new Error(`unknown reference runtime: ${b}`);const N=l[x]??H(D(x));g(`${b} ${x} b${k} (single run)…`);try{const v=await f({device:w,dtype:d,sources:N,batchSize:k,onStatus:W=>g(`${b} ${x} b${k}: ${W}`)}),O={loadMs:Math.round(v.loadMs),translateMs:Math.round(v.translateMs),tokens:v.tokens,tokPerSec:$(v.tokPerSec),e2eCharsPerSec:$(v.charsPerSec)};m.push({runtime:b,preset:x,batch:k,repeats:[O],median:O})}catch(v){m.push({runtime:b,preset:x,batch:k,error:String(v?.message??v)})}}}return m}function ln(t,e,{date:i,stack:c}={}){const n=new Date,o=`${n.getFullYear()}-${String(n.getMonth()+1).padStart(2,"0")}-${String(n.getDate()).padStart(2,"0")}`;return{schema:"webmt-bench-v1",date:i??o,adapterInfo:e,...c?{stack:c}:{},baselineRef:"docs/bench/baseline.json",runs:t}}const gn={repetitionPenalty:1.2,greedy:!0,maxNewTokensFormula:"max(24, min(192, ceil(chars*3.2)+12))",dtype:"fp32"},dn=JSON.parse('[{"source":"他缓缓拔出长剑,目光冷得像冰。","ids":[0,754,1237,1501,1594,1039,654,339,18937,821,475,1072,321,1951,18948,2],"maxNewTokens":60,"text":"Hắn chậm rãi rút trường kiếm ra, ánh mắt lạnh như băng."},{"source":"夜色渐深,客栈里只剩下几盏残灯。","ids":[0,4988,1082,2875,659,18937,332,1542,7495,394,404,329,889,1742,3286,1631,18948,2],"maxNewTokens":64,"text":"Đêm dần buông xuống, trong khách điếm chỉ còn lại vài ngọn đèn tàn."},{"source":"“你到底是什么人?”她低声问道。","ids":[0,337,11090,997,514,292,843,632,1958,1460,1298,848,18948,2],"maxNewTokens":64,"text":"\\"Rốt cuộc ngươi là ai?\\" Nàng thấp giọng hỏi."},{"source":"山风呼啸,卷起满地的落叶。","ids":[0,7521,976,2771,2813,2164,448,2189,8052,916,871,18948,2],"maxNewTokens":54,"text":"Gió núi gào thét cuốn lên lá rụng đầy đất."},{"source":"老者捋了捋胡须,微微一笑。","ids":[0,1577,732,3592,12443,5089,18937,1820,708,18948,2],"maxNewTokens":54,"text":"Lão giả vuốt chòm râu, mỉm cười."},{"source":"这一掌的力道,足以开碑裂石!","ids":[0,4522,565,313,309,1724,324,1004,469,1057,4088,3282,1155,19020,2],"maxNewTokens":57,"text":"Lực đạo của một chưởng này đủ để mở bia nứt đá!"},{"source":"“师父,弟子知错了。”少年跪在地上。","ids":[0,337,4338,1129,18937,739,576,498,1621,483,482,2439,1356,3199,459,477,871,18948,2],"maxNewTokens":70,"text":"\\"Sư phụ, đệ tử biết sai rồi.\\" Thiếu niên quỳ trên mặt đất."},{"source":"江湖上的恩怨,从来没有那么简单。","ids":[0,4489,3247,5634,1071,667,616,1463,1790,321,488,18948,2],"maxNewTokens":64,"text":"Ân oán giang hồ chưa từng đơn giản như vậy."},{"source":"她转身离去,再也没有回头。","ids":[0,1958,1795,331,1044,367,18937,290,404,1143,437,329,551,18948,2],"maxNewTokens":54,"text":"Nàng xoay người rời đi, không còn quay đầu lại nữa."},{"source":"剑光一闪,血溅三尺。","ids":[0,1089,1017,2213,448,18937,1073,2126,1549,8635,692,4479,18948,2],"maxNewTokens":44,"text":"Kiếm quang lóe lên, máu bắn tung tóe ba thước."},{"source":"大殿之内,众人鸦雀无声。","ids":[0,795,497,1140,18937,874,331,2505,15669,284,399,18948,2],"maxNewTokens":51,"text":"Trong đại điện, mọi người im phăng phắc."},{"source":"他喝了口酒,眼中闪过一丝痛楚。","ids":[0,754,2184,309,3793,2251,18937,332,475,2213,448,775,1879,3822,18948,2],"maxNewTokens":60,"text":"Hắn uống một ngụm rượu, trong mắt lóe lên vẻ đau đớn."},{"source":"“今晚三更,后山竹林见。”","ids":[0,337,18955,396,781,2124,692,18937,1035,453,2507,3016,1262,1523,482,2],"maxNewTokens":54,"text":"\\"Tối nay canh ba, gặp ở rừng trúc hậu sơn.\\""},{"source":"马蹄声由远及近,尘土飞扬。","ids":[0,3469,10058,1853,389,863,372,935,18937,2772,871,1549,1033,18948,2],"maxNewTokens":54,"text":"Tiếng vó ngựa từ xa đến gần, bụi đất tung bay."},{"source":"这门功夫,他练了整整二十年。","ids":[0,1322,583,1895,324,18937,343,335,627,1557,480,1195,549,18948,2],"maxNewTokens":57,"text":"Môn công phu này, hắn đã luyện suốt hai mươi năm."},{"source":"暮色四合之际,一行人马终于抵达了山脚下的小镇,镇口的酒旗在风中猎猎作响;为首的中年汉子翻身下马,环顾四周,见街道两旁的店铺早已关门闭户,只有远处一家客栈还透出昏黄的灯光,他皱了皱眉,低声吩咐众人收起兵刃,不要惊扰了镇上的百姓。","ids":[0,6394,561,1601,2738,2875,659,18937,2161,331,870,434,334,372,369,1054,1722,810,777,640,976,18937,2542,2251,453,981,1722,1549,1033,332,1423,19873,5623,576,921,1356,1062,437,2187,659,1853,18937,439,1100,1156,559,18937,458,591,981,1159,480,569,653,335,1157,2348,981,2348,3509,18937,394,298,309,2688,14099,863,863,404,10866,339,821,3286,1058,3305,18937,343,2012,1317,18937,1460,1298,3323,1830,874,331,493,1036,1327,535,18937,290,369,4688,5916,3393,832,332,1722,18948,2],"maxNewTokens":192,"text":"Vào lúc hoàng hôn buông xuống, đoàn người cuối cùng cũng đến được thị trấn nhỏ dưới chân núi, cờ rượu ở cửa trấn tung bay trong gió; hán tử trung niên dẫn đầu nhảy xuống ngựa, nhìn quanh bốn phía, thấy các cửa hàng hai bên đường đã sớm đóng cửa đóng kín, chỉ có một quán trọ xa xa còn hắt ra ánh đèn vàng vọt, hắn nhíu mày, thấp giọng dặn dò mọi người thu hồi binh khí, không được quấy nhiễu bách tính trong trấn."},{"source":"传闻中的藏剑山庄坐落在群山环抱之中,庄内古木参天,流水潺潺,青石铺就的小径蜿蜒曲折;每逢三月桃花盛开,四方豪杰便会齐聚于此,或论剑,或品茶,或只是远远地望一眼那位传说中的庄主,据说他已经三十年没有拔过剑了,可江湖上没有人敢小看他。","ids":[0,4694,1089,1523,1814,332,813,2410,2494,1630,929,1378,1868,313,4822,976,18937,569,332,2826,1160,1994,651,5765,862,18937,911,2133,15966,3276,18937,620,653,810,1576,1155,1402,10574,4220,4402,1134,19290,18939,19873,1224,455,1499,692,1391,2842,3389,6259,18937,2333,3778,1156,690,329,1410,5781,617,606,18937,1153,2013,654,18937,1153,2525,2686,18937,1153,394,439,863,466,559,555,3664,691,332,813,2410,598,309,625,18937,772,383,343,335,692,1195,549,290,1594,654,483,18937,428,459,5634,1071,290,843,1126,1179,705,343,18948,2],"maxNewTokens":192,"text":"Tàng Kiếm sơn trang trong truyền thuyết tọa lạc giữa vòng vây của dãy núi, bên trong thôn cổ thụ cao ngất trời, nước chảy róc rách, con đường nhỏ lát đá xanh uốn lượn khúc khuỷu; mỗi khi tháng ba hoa đào nở rộ, hào kiệt bốn phương lại tụ họp tại đây, hoặc luận kiếm, hoặc thưởng trà, hoặc chỉ nhìn xa về phía vị Trang chủ trong truyền thuyết kia một cái, nghe nói hắn đã ba mươi năm không rút kiếm rồi, nhưng trên giang hồ không ai dám coi thường hắn."},{"source":"那一夜大雨倾盆,雷声滚滚,破庙里的火堆忽明忽暗;少年抱着怀中的剑谱,听着庙外杂乱的脚步声越来越近,心跳���鼓,他知道,追兵一旦破门而入,自己便再无生路,可师父临终前的嘱托犹在耳边,这本剑谱无论如何都不能落入奸人之手。","ids":[0,4988,393,2121,321,4987,911,18937,3950,12395,1272,18937,3342,1481,332,5354,1654,561,857,561,1381,19873,1248,1356,2567,654,7636,332,626,18937,1871,772,623,736,640,2564,1587,569,688,5354,696,715,935,18937,3825,2399,10836,15013,18948,754,498,18937,309,455,763,2062,1824,373,981,1996,416,18937,512,508,290,404,653,1037,551,18937,428,725,3323,1830,452,455,3028,2870,313,595,1129,521,5290,270,518,569,1776,18937,2164,654,7636,324,658,457,506,334,290,338,1132,416,464,680,501,18948,2],"maxNewTokens":192,"text":"Đêm đó mưa như trút nước, sấm rền vang, đống lửa trong miếu đổ lúc sáng lúc tối; thiếu niên ôm kiếm phổ trong lòng, lắng nghe tiếng bước chân hỗn loạn bên ngoài miếu ngày càng gần, tim đập thình thịch. Hắn biết, một khi quân truy đuổi phá cửa xông vào, mình sẽ không còn đường sống nữa, nhưng lời dặn dò trước khi lâm chung của sư phụ vẫn văng vẳng bên tai, cuốn kiếm phổ này dù thế nào cũng không thể rơi vào tay gian nhân."},{"source":"掌门之位悬空已有三年,门中各脉明争暗斗从未停歇;大师兄稳重却优柔寡断,二师姐剑法超群却性情孤傲,三师弟聪明伶俐却资历尚浅,长老们各怀心思,谁也不肯先开口,直到那个雪夜,山门外传来一声长啸,所有人都放下了手中的茶盏。","ids":[0,2404,1092,1724,716,335,3547,3248,3761,692,549,18937,591,1454,332,716,1184,1097,1155,3852,667,616,1234,2653,19873,741,595,1144,1310,1870,428,329,720,820,1248,1124,1439,18937,2186,595,1691,654,496,3450,2745,428,832,803,1158,3324,18937,1451,595,739,833,1441,11877,1125,428,1020,2338,404,5002,3454,18937,591,841,655,471,922,649,1020,1854,18937,290,843,1131,1057,1172,452,18937,432,372,1368,2051,1053,18937,569,688,1523,716,813,372,309,623,269,18991,1012,18937,948,363,874,331,471,1414,3969,2686,332,464,659,18948,2],"maxNewTokens":192,"text":"Vị trí chưởng môn đã treo lơ lửng ba năm, các mạch trong môn phái đấu đá ngầm chưa từng ngừng nghỉ; Đại sư huynh trầm ổn nhưng lại do dự thiếu quyết đoán, Nhị sư tỷ kiếm pháp siêu quần nhưng tính tình cô ngạo, Tam sư đệ thông minh lanh lợi nhưng tư lịch còn nông cạn, các trưởng lão đều mang tâm tư riêng, không ai chịu mở miệng trước, cho đến đêm tuyết ấy, bên ngoài sơn môn truyền đến một tiếng hú dài, tất cả mọi người đều đặt chén trà trong tay xuống."},{"source":"集市上人声鼎沸,卖艺的汉子赤膊耍着一杆铁枪,围观的人群不时爆发出阵阵喝彩声;忽然人群一阵骚动,几名黑衣人分开众人径直走向那名枪手,为首之人冷冷地丢下一块乌黑的令牌,喧闹的集市霎时安静了下来,连风都仿佛停了。","ids":[0,1521,453,7196,5922,4759,3588,2359,18937,2328,1899,989,1920,3938,8267,2961,4687,309,1328,1562,829,18937,1014,331,1868,884,2287,2554,329,714,339,616,6261,623,8860,7359,1263,2525,18948,15010,558,1014,331,7694,6091,18937,713,790,2275,613,501,3671,874,331,339,367,1112,466,559,790,829,672,598,18937,757,1400,437,1072,2527,2690,659,309,2641,1696,1739,1019,6325,18937,7196,5922,4759,332,2414,1576,1800,1239,660,329,18937,801,363,1423,334,321,1234,329,18948,2],"maxNewTokens":192,"text":"Người ở chợ ồn ào náo nhiệt, gã đàn ông bán nghệ cởi trần múa một cây thiết thương, đám người vây xem thỉnh thoảng lại phát ra từng tràng tiếng reo hò tán thưởng. Bỗng nhiên đám người xôn xao, mấy tên hắc y nhân tách mọi người ra đi thẳng về phía tên thương thủ kia, kẻ cầm đầu lạnh lùng ném xuống một khối lệnh bài đen nhánh, chợ ồn ào trong chốc lát yên tĩnh trở lại, ngay cả gió cũng như ngừng lại."},{"source":"信使跪在堂下,双手呈上一封火漆密函,堂上众人面面相觑;老庄主拆开信笺,只看了一眼,脸色便骤然大变,他缓缓起身,望着窗外沉沉的夜色,半晌才道:传令下去,即刻封山,任何人不得进出,违令者一律逐出师门,永不再录。","ids":[0,7964,732,3199,777,653,18937,480,464,2549,448,309,906,1300,1693,1523,1383,18937,874,331,459,653,439,962,3456,5611,19873,655,1814,691,1057,906,1300,339,18937,394,1982,475,309,625,18937,853,477,746,842,558,497,818,18948,3866,1237,1501,844,1777,18937,439,1924,1368,2339,1133,688,981,2644,18937,1250,696,534,383,19026,3471,1696,659,18937,770,647,906,1523,18937,729,643,843,290,369,339,416,18937,757,887,2028,1696,471,449,7938,762,828,595,716,18937,4487,3830,290,2282,329,551,18948,2],"maxNewTokens":192,"text":"Sứ giả quỳ dưới đường, hai tay dâng lên một phong thư mật sơn đỏ, mọi người trên đường nhìn nhau ngơ ngác; lão trang chủ mở phong thư ra, chỉ liếc mắt một cái, sắc mặt liền đột nhiên đại biến. Ông chậm rãi đứng dậy, nhìn màn đêm dày đặc ngoài cửa sổ, nửa ngày mới nói: Truyền lệnh xuống, lập tức phong sơn, bất kỳ ai không được ra vào, kẻ vi phạm lệnh đều bị trục xuất khỏi sư môn, vĩnh viễn không ghi lại nữa."},{"source":"三十年前的那场大火烧毁了半座城池,也烧断了两大世家百年的情谊;如今旧事重提,当年的幸存者死的死,散的散,唯有城南那口枯井旁的老槐树还记得一切,树下埋着的,不只是一坛陈年的女儿红,还有一个再也无人敢提起的名字。","ids":[0,1839,1624,14105,692,1195,549,452,335,373,2464,1250,1888,442,1593,18937,334,3626,11367,803,1526,988,549,313,480,497,457,619,19873,781,631,2145,1663,329,18937,331,1037,2204,549,1791,784,784,18937,1408,6677,18937,394,298,1328,7359,19014,1932,569,8833,3163,559,1582,442,404,1455,719,948,363,18937,777,2762,1328,5951,290,394,309,4725,2280,1823,1199,909,1307,18937,368,404,298,625,790,290,843,1126,1663,372,551,18948,2],"maxNewTokens":192,"text":"Trận hỏa hoạn ba mươi năm trước đã phá hủy nửa tòa thành trì, cũng thiêu rụi tình nghĩa trăm năm của hai đại thế gia; nay chuyện cũ nhắc lại, người sống sót năm xưa chết chết, tan rã, chỉ có cây hòe già bên giếng khô phía nam thành còn nhớ rõ tất cả, dưới gốc cây chôn không chỉ một vò Nữ Nhi Hồng lâu đời, mà còn có cái tên không ai dám nhắc đến nữa."},{"source":"渡口的老船夫眯着眼打量来客,见那书生衣衫褴褛却腰悬长剑,不由得多问了一句;书生笑而不答,只将一锭碎银放在船头,转身望向对岸茫茫的芦苇荡,江风吹起他的衣角,露出内衬上暗绣的金线纹样,老船夫握着船桨的手,忽然抖了一下。","ids":[0,1577,2200,1895,453,7445,263,19013,4280,475,793,1149,1542,563,18937,458,1300,687,598,2745,1290,3276,286,1984,428,6834,1390,3547,1039,654,18937,290,828,848,785,309,1055,19873,1698,687,708,368,290,1361,18937,394,1414,309,266,573,1807,2922,453,1866,2200,18937,1795,331,439,466,559,5205,278,446,5032,3814,569,598,2658,18948,7521,2408,3424,1549,2747,1290,313,343,18937,950,339,1391,1634,1563,3038,11130,1918,18938,569,332,18948,9126,655,2200,1895,1175,2670,17524,1689,558,2169,448,309,625,18948,2],"maxNewTokens":192,"text":"Lão thuyền phu ở bến đò nheo mắt đánh giá khách tới, thấy thư sinh kia quần áo rách rưới nhưng thắt lưng treo trường kiếm, không khỏi hỏi thêm một câu; Thư sinh cười mà không đáp, chỉ đặt một thỏi bạc vụn ở mũi thuyền, xoay người nhìn về phía lau sậy mênh mông bên kia bờ. Gió sông thổi tung góc áo của hắn, lộ ra hoa văn kim tuyến thêu thùa bên trong. Tay lão thuyền phu nắm mái chèo bỗng nhiên run lên một cái."},{"source":"林昭推门而入,林昭的剑还在滴着血,可林昭的声音却平静得可怕。","ids":[0,1090,4264,2182,981,736,416,18937,654,313,1090,4264,521,404,520,810,1073,18937,428,877,1096,313,343,329,815,1239,372,1094,953,18948,2],"maxNewTokens":108,"text":"Lâm Chiêu đẩy cửa bước vào, kiếm của Lâm Chiêu vẫn còn đang nhỏ máu, nhưng thanh âm của hắn lại bình tĩnh đến đáng sợ."},{"source":"沈青山望着窗外,沈青山知道,今夜之后江湖上再无沈青山这个名字。","ids":[0,3560,734,730,439,339,688,981,2644,18937,3560,734,730,498,776,18937,465,1368,781,459,5634,1071,290,404,625,790,3560,734,730,506,551,18948,2],"maxNewTokens":112,"text":"Thẩm Thanh Sơn nhìn ra ngoài cửa sổ, Thẩm Thanh Sơn biết rằng, sau đêm nay trên giang hồ không còn cái tên Thẩm Thanh Sơn nào nữa."},{"source":"“林昭!林昭你给我站住!”她追出门外,可林昭的身影早已消失在夜色之中。","ids":[0,415,18989,424,4264,19020,1090,4264,18937,514,844,329,432,382,568,1958,1824,339,688,981,18937,428,479,1249,313,1090,4264,335,1157,818,920,332,1924,1368,18948,2],"maxNewTokens":124,"text":"“Lâm Chiêu! Lâm Chiêu, ngươi đứng lại cho ta!” Nàng đuổi ra ngoài cửa, nhưng thân ảnh của Lâm Chiêu đã sớm biến mất trong màn đêm."},{"source":"众人都说沈青山败了,可沈青山不这么认为,沈青山收剑入鞘,转身走下擂台。","ids":[0,3032,331,471,383,3560,734,730,335,2665,18937,428,3560,734,730,290,676,488,18937,3560,734,730,493,654,416,3998,18937,1795,331,736,659,1963,2058,18948,2],"maxNewTokens":124,"text":"Mọi người đều nói Thẩm Thanh Sơn đã thua, nhưng Thẩm Thanh Sơn không nghĩ vậy, Thẩm Thanh Sơn thu kiếm vào vỏ, xoay người bước xuống lôi đài."},{"source":"林昭救过他一次,林昭也骗过他一次,所以当林昭再次出现时,他不知该拔剑还是敬酒。","ids":[0,1090,4264,335,1372,343,309,638,18937,1090,4264,334,3539,5136,343,309,638,18937,432,599,455,1090,4264,762,516,638,551,18937,343,290,498,599,1594,654,802,292,1809,2251,18948,2],"maxNewTokens":137,"text":"Lâm Chiêu đã cứu hắn một lần, Lâm Chiêu cũng lừa gạt hắn một lần, cho nên khi Lâm Chiêu xuất hiện lần nữa, hắn không biết nên rút kiếm hay là kính rượu."},{"source":"沈青山的刀快,沈青山的心更狠,凡是见过沈青山出手的人,都不愿再与他为敌。","ids":[0,3271,313,3560,734,730,894,18937,626,3560,734,730,715,785,1631,2492,18937,729,749,843,616,458,3560,734,730,339,464,471,290,582,660,442,757,1734,412,343,551,18948,2],"maxNewTokens":128,"text":"Đao của Thẩm Thanh Sơn nhanh, lòng Thẩm Thanh Sơn càng thêm tàn nhẫn, bất cứ ai từng thấy Thẩm Thanh Sơn ra tay đều không muốn trở thành kẻ địch với hắn nữa."},{"source":"有人说林昭死在了雁门关外,有人说林昭隐居山林,还有人说,林昭根本就没有存在过。","ids":[0,1480,331,383,1090,4264,784,453,688,10521,1322,1592,18937,298,331,383,343,1279,3715,332,2507,976,18937,329,404,298,331,383,18937,1090,4264,1107,624,667,616,1512,617,18948,2],"maxNewTokens":137,"text":"Có người nói Lâm Chiêu chết ở ngoài Nhạn Môn Quan, có người nói hắn ẩn cư trong rừng núi, lại còn có người nói, Lâm Chiêu căn bản chưa từng tồn tại."}]'),C={config:gn,items:dn},pn=document.querySelector("#app");pn.innerHTML=`
|
| 38 |
+
<h1>webMT bench</h1>
|
| 39 |
+
<p>
|
| 40 |
+
<button id="load">Load engine</button>
|
| 41 |
+
<button id="verify" disabled>Verify vs golden (30)</button>
|
| 42 |
+
<button id="bench" disabled>Benchmark</button>
|
| 43 |
+
<label><input type="checkbox" id="includeRef"> Include reference runtimes</label>
|
| 44 |
+
<button id="export" disabled>Export JSON</button>
|
| 45 |
+
</p>
|
| 46 |
+
<p id="status" style="color:#8bc"></p>
|
| 47 |
+
<div id="benchTable"></div>
|
| 48 |
+
<pre id="out" style="white-space:pre-wrap"></pre>
|
| 49 |
+
`;const R=document.querySelector("#load"),M=document.querySelector("#verify"),P=document.querySelector("#bench"),kn=document.querySelector("#includeRef"),Q=document.querySelector("#export"),q=document.querySelector("#status"),fn=document.querySelector("#benchTable"),bn=document.querySelector("#out"),y=t=>{bn.textContent+=`${t}
|
| 50 |
+
`};let S=null;R.addEventListener("click",async()=>{R.disabled=!0;try{y("loading engine…");const t=await Y(),e=t.hasF16?"f16":"f32",i=new URLSearchParams(location.search),c=i.get("immediates")==="0"?"off":"auto",n=await X(),o=i.get("shortlist")!=="0",r=e==="f16"&&o?Z(n.idToToken):null,a=await nn(t.device,"/weights",{targetDtype:e,lmHeadQ8:e==="f16",ffnWT:e==="f16",projWT:e==="f16",directQ8:i.get("directq8")!=="0",...r?{lmHeadIds:r}:{}});let p=null,u="off";if(i.get("tune")!=="0"){y("autotuning routing on this device…");const s=await tn({...t,dtype:e},a,{immediates:c});p=s.tuned,u=s.partial?"partial":"measured",s.partial&&y(`autotune partial (${s.partial}) — defaults + correctness verdicts only`)}const h={shortlist:r?r.length:0,autotune:u,tuned:p,directQ8:a.q8Stats.directTensors>0,q8Stats:a.q8Stats,immediates:c==="auto"&&t.hasImmediates?"on":"off"};S={ctx:{...t,dtype:e},weights:a,tok:n,tuned:p,stack:h,immediates:c},y(`engine ready: ${t.adapterInfo.description||t.adapterInfo.vendor} (${e}, ${r?`shortlist ${r.length}`:"full vocab"}, autotune ${u})`),p&&y(`tuned: ${JSON.stringify(p)}`),M.disabled=!1,P.disabled=!1}catch(t){y(`LOAD FAILED: ${t?.message??t}`),R.disabled=!1}});M.addEventListener("click",async()=>{M.disabled=!0;const{ctx:t,weights:e,tok:i}=S;let c=0,n=0,o=0,r=0;try{for(let h=0;h<C.items.length;h++){const s=C.items[h],{rows:g,metrics:m}=await V(t,e,i,[s.source],{maxNewTokens:s.maxNewTokens,...J(S.tuned,1),immediates:S.immediates});r+=m.tokPerSec;const l=en(g[0].ids,s.ids);l.verdict==="exact"?c++:l.verdict==="forced-eos"?n++:o++,y(`[${String(h).padStart(2)}] ${l.verdict.toUpperCase().padEnd(10)} ${m.tokPerSec.toFixed(0)} tok/s ${s.source}`),l.verdict==="mismatch"&&(y(` step ${l.step}`),y(` engine: ${g[0].text}`),y(` golden: ${s.text}`))}const a=C.items.length,p=Math.ceil(.95*a),u=c+n>=p;y(`
|
| 51 |
+
${u?"PASS":"FAIL"}: exact=${c} forced-eos=${n} mismatch=${o} (need ${p}/${a}) avg ${(r/a).toFixed(1)} tok/s @ batch=1`)}catch(a){y(`VERIFY FAILED: ${a?.message??a}
|
| 52 |
+
${a?.stack??""}`)}finally{M.disabled=!1}});let E=null;function yn(t){const e=t.runs,i=(n,o)=>n.min?` (${n.min[o]}–${n.max[o]})`:"",c=e.map(n=>n.error?`<tr><td>${n.runtime}</td><td>${n.preset}</td><td>${n.batch}</td>
|
| 53 |
+
<td colspan="4" style="color:#f55">ERROR: ${n.error}</td></tr>`:`<tr><td>${n.runtime}</td><td>${n.preset}</td><td>${n.batch}</td>
|
| 54 |
+
<td>${n.median.tokPerSec}${i(n,"tokPerSec")}</td>
|
| 55 |
+
<td>${n.median.e2eCharsPerSec}${i(n,"e2eCharsPerSec")}</td>
|
| 56 |
+
<td>${n.median.tokens}</td>
|
| 57 |
+
<td>${n.median.decodeMs??n.median.translateMs}</td></tr>`).join("");fn.innerHTML=`
|
| 58 |
+
<table border="1" cellpadding="4" style="border-collapse:collapse">
|
| 59 |
+
<tr><th>runtime</th><th>preset</th><th>batch</th>
|
| 60 |
+
<th>tok/s median (min–max)</th><th>chars/s median (min–max)</th>
|
| 61 |
+
<th>tokens</th><th>decode ms</th></tr>
|
| 62 |
+
${c}
|
| 63 |
+
</table>`}P.addEventListener("click",async()=>{P.disabled=!0;const{ctx:t,weights:e,tok:i}=S;try{const c=await mn(t,e,i,{includeReference:kn.checked,referencePresets:["short32"],tuned:S.tuned,engineOptions:{immediates:S.immediates},onStatus:n=>{q.textContent=n}});E=ln(c,t.adapterInfo,{stack:S.stack}),yn(E),q.textContent="benchmark complete",Q.disabled=!1}catch(c){q.textContent="",y(`BENCH FAILED: ${c?.message??c}
|
| 64 |
+
${c?.stack??""}`)}finally{P.disabled=!1}});Q.addEventListener("click",()=>{if(!E)return;const t=new Blob([JSON.stringify(E,null,2)],{type:"application/json"}),e=document.createElement("a");e.href=URL.createObjectURL(t),e.download=`webmt-bench-${E.date}.json`,e.click(),URL.revokeObjectURL(e.href)});
|
assets/chapter3k-DSdzHZt5.js
DELETED
|
@@ -1,35 +0,0 @@
|
|
| 1 |
-
const r=`第三章 夜雨断魂崖\r
|
| 2 |
-
\r
|
| 3 |
-
暮色沉沉,秋雨初歇。断魂崖下的山道上,一行五骑冒着湿冷的山风缓缓而行。为首的正是青城派大弟子沈孤鸿,他勒住缰绳,抬头望了望崖顶那株歪脖老松,眉头微微一皱。三年前师父便是在此处失踪的,尸骨无存,只留下半截断剑。断剑如今就贴身藏在他怀中,隔着三层油布,仍似有一股寒意透出来,时时提醒着他此行的真正目的。\r
|
| 4 |
-
\r
|
| 5 |
-
“师兄,天色不早了。”身后的小师妹柳如烟催马上前,低声道,“前面十里便是落雁镇,不如先寻个客栈歇脚,明日一早再上崖查探。”沈孤鸿摇了摇头。他心中隐隐觉得不安,这条山道太静了,静得连一声鸦啼都没有。往年这个时节,崖下的枫林里总有猎户往来,如今却连半个人影也见不着。他翻身下马,蹲下身子,指尖拂过路面的泥土,泥中赫然印着几行新鲜的马蹄印,蹄印极深,来者必是负重疾驰,而且就在半个时辰之内。\r
|
| 6 |
-
\r
|
| 7 |
-
果然,行不到三里,前方林中忽然传来一声唿哨。刹那间,道旁的枯草丛中窜出十几条黑影,个个蒙面持刀,将五人围在了当中。沈孤鸿不惊反笑:“诸位在此恭候多时,想必不是为了求财。”为首的蒙面人嘿嘿一笑,声音沙哑:“沈大侠好眼力。留下东西,饶你们全尸。”他手中那口九环大刀随着话音缓缓抬起,刀环相击,铮铮作响。\r
|
| 8 |
-
\r
|
| 9 |
-
柳如烟手按剑柄,正要拔剑,却被沈孤鸿抬手拦住。他缓缓扫视四周,忽然朗声道:“阁下既是青城故人,何必遮遮掩掩?三年前崖顶一别,赵师叔的刀法想必更精进了。”此言一出,那蒙面首领浑身一震,握刀的手竟微微发起抖来。风卷着雨丝掠过山道,一时间竟无人再敢上前半步,只余刀环轻响。\r
|
| 10 |
-
\r
|
| 11 |
-
雨又下了起来,先是淅淅沥沥,继而如注如倾,豆大的雨点砸在刀锋上溅起一片白雾,砸在众人斗笠上噼啪作响,山道两旁的枫叶被打得纷纷坠落,和着泥水粘在青石板上,远处的雷声一阵接着一阵滚过山脊,闪电撕开铅灰色的云层,把崖壁上那些经年累月被风霜侵蚀出的沟壑照得纤毫毕现,沟壑间隐约可见一道道旧年的剑痕,剑痕纵横交错,深者入石三寸,浅者也有半指,显然当年在此动手的绝非泛泛之辈,而这一切都在电光熄灭的瞬间重新沉入黑暗,仿佛从未存在过一般,只余下漫天雨幕和一片肃杀之气笼罩着进退两难的众人。\r
|
| 12 |
-
\r
|
| 13 |
-
“动手!”蒙面首领一声令下,十几口钢刀同时劈落。沈孤鸿长啸一声,青虹出鞘。剑光过处,雨珠纷纷断成两截。他的身形在刀丛中穿梭如游鱼,看似险象环生,实则每一步都踏在众刀客力道将尽的空隙上。这正是青城绝学“听雨十三式”,以静制动,后发先至。柳如烟与三名师弟结成剑阵护住马匹,一时倒也不落下风。剑阵旋转开合,四柄长剑在雨中织成一张光网,泼水难入。\r
|
| 14 |
-
\r
|
| 15 |
-
激斗中,沈孤鸿故意卖了个破绽,引那首领一刀劈空,随即剑走偏锋,挑落了对方的面巾。电光再闪,照亮一张刀疤纵横的脸。柳如烟失声惊呼:“赵、赵师叔!你不是三年前就随师父一同殉难了么?”那人面色惨白,仰天惨笑:“殉难?好一个殉难!”笑声未落,两行浊泪已混着雨水淌进了刀疤纵横的沟壑里。\r
|
| 16 |
-
\r
|
| 17 |
-
他一边挥刀格挡,一边嘶声说起当年之事,原来三年前掌门带着他上崖赴约,约他们的人自称故友,实则早已投靠了漠北的血狼堡,崖顶设下的不是酒宴而是天罗地网,掌门为护他断后,独自一人挡住堡中四大供奉,力战半夜,剑断之后犹以掌搏敌,最终被逼坠崖,而他自己重伤被擒,堡主以一味奇毒控住他的心脉,逼他每月回堡领取解药,从此不得不听命行事,充当血狼堡安插在川中的眼线,这三年来他无一日不想将真相告知青城,却又无一日敢开口,只因堡主放话,他若泄密,便先屠青城满门再断他解药,叫他眼睁睁看着同门死绝之后自己再毒发身亡。\r
|
| 18 |
-
\r
|
| 19 |
-
沈孤鸿听罢,久久无言。雨水顺着他的剑尖滴落,在脚下汇成一线殷红。“师叔,”他终于开口,声音低沉,“今夜你奉命截杀的东西,究竟是什么?”赵师叔惨然道:“一封信。据说信中写着血狼堡这些年在中原布下的所有暗桩名录。堡主得知此信已到你手,宁可血洗川中也要毁去。”他说到此处,喉头一阵腥甜,显是体内毒性又发作了,扶着刀柄才勉强站稳。\r
|
| 20 |
-
\r
|
| 21 |
-
柳如烟急道:“师兄,我们何曾有过什么名录!”沈孤鸿却缓缓从怀中取出一只油布包裹,层层揭开,里面竟是那半截断剑。他持剑向天,任雨水冲刷剑身,锈迹剥落处,剑脊上细密的刻痕渐渐显露出来。“师父坠崖之前,把名录刻在了自己的佩剑上。”他环视众人,一字一句道,“血狼堡要毁的不是信,是这柄剑。他们三年前没找到它,今夜也休想拿走。”\r
|
| 22 |
-
\r
|
| 23 |
-
崖顶忽然亮起一片火把,人喊马嘶之声顺着风雨滚滚而下,少说也有三百之众,火光中一面黑底血狼大旗猎猎招展,旗下一名白发老者按剑而立,正是血狼堡四大供奉之首、人称“夺魂手”的燕北归,他身侧两列弓手已然张弓搭箭,箭簇上幽蓝的毒光在火把映照下明明灭灭,而山道后方的退路上也响起了密集的马蹄声,分明是早有一支伏兵截断了归途,前有强敌后有追兵,头顶是万仞绝壁,脚下是湍急的涧水,当真是插翅难飞的死地,饶是沈孤鸿一向沉稳,此刻掌心也不由得沁出了冷汗。\r
|
| 24 |
-
\r
|
| 25 |
-
“师叔,”他忽然低声道,“烦你带我师妹师弟们从涧底水路走,剑我留下。”赵师叔一怔:“你要以身做饵?”沈孤鸿笑了笑,雨水从他年轻的脸上流过:“名录已在剑上,剑毁了还有拓本。可青城的人若都折在这里,谁去把它送到武林盟?”他不再多言,提剑独自迎着火光走上山道。雷声隆隆,一道闪电划过,照见他的背影挺拔如崖顶那株老松。\r
|
| 26 |
-
\r
|
| 27 |
-
燕北归居高临下望着那道逆着火光而来的孤影,眼中掠过一丝讶异,随即化作冷笑。他抬手止住弓手,缓步下崖,枯瘦的五指在夜雨中张开又合拢,发出一串细碎的骨响。“三年前你师父也是这样走上来的。”他的声音不高,却穿透雨幕清清楚楚地送进每个人耳中,“他断剑之后我曾许他一条生路,只要交出名录,青城上下既往不咎。他说了八个字——宁碎剑骨,不负江湖。今日我把这句话原样送还给你,小子,你可以选一条聪明些的路。”\r
|
| 28 |
-
\r
|
| 29 |
-
沈孤鸿止步于三丈之外,横剑当胸。断剑无锋,剑身上斑驳的刻痕在火光下如同一行行无声的名字。“前辈既然记得家师的话,”他淡淡道,“又何必问我第二遍?”燕北归叹了口气,不再言语。两人身形同时消失在原地,再现时已在崖畔相交,一掌一剑,迸出的劲风将周遭三丈内的雨点尽数震成齑粉。四周的黑衣人只觉眼前人影幢幢,根本看不清招式,只听得金铁交鸣之声密如骤雨,又戛然而止。\r
|
| 30 |
-
\r
|
| 31 |
-
赵师叔趁乱引着柳如烟等人坠下涧底,冰冷的涧水没过头顶的一瞬,柳如烟犹自回头,只见崖畔两道身影在电光中分而复合,合而复分,那柄断剑的寒芒每一次亮起都比前一次更接近咽喉,也更接近深渊,她张口想喊,灌进来的却只有一口冰水,赵师叔死死攥住她的手腕,两人顺着湍流向下游卷去,耳边的厮杀声、雷声、马嘶声渐渐都被水声吞没,唯有那一点剑芒烙在她眼底,任凭涧水如何冲刷也冲刷不去,多年以后她仍会在雨夜里惊醒,梦见那点寒星坠向无底的黑暗。\r
|
| 32 |
-
\r
|
| 33 |
-
那一夜断魂崖的厮杀声直到五更方歇。后来江湖上有人说,曾见一个青衫剑客独战数百人,剑折之后夺刀再战,刀卷之后赤手空拳;也有人说,天明时分崖下的涧水都是红的。唯一可以确证的是,半月之后,一份写满名字的血书送到了武林盟主的案头,落款只有八个字:青城沈氏,以剑为凭。自那以后,川中道上再无血狼堡的旗号,而断魂崖顶的老松之下,多了一座无碑的剑冢,年年秋深,总有人遥遥望见一个白衣女子在冢前置酒三杯,风雨无阻。\r
|
| 34 |
-
`;export{r as c};
|
| 35 |
-
//# sourceMappingURL=chapter3k-DSdzHZt5.js.map
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
assets/chapter3k-DSdzHZt5.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
{"version":3,"file":"chapter3k-DSdzHZt5.js","sources":["../../fixtures/chapter3k.txt?raw"],"sourcesContent":["export default \"第三章 夜雨断魂崖\\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柳如烟急道:“师兄,我们何曾有过什么名录!”沈孤鸿却缓缓从怀中取出一���油布包裹,层层揭开,里面竟是那半截断剑。他持剑向天,任雨水冲刷剑身,锈迹剥落处,剑脊上细密的刻痕渐渐显露出来。“师父坠崖之前,把名录刻在了自己的佩剑上。”他环视众人,一字一句道,“血狼堡要毁的不是信,是这柄剑。他们三年前没找到它,今夜也休想拿走。”\\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\""],"names":["chapterText"],"mappings":"AAAA,MAAAA,EAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;"}
|
|
|
|
|
|
assets/compact_equiv-ehtvJC3N.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 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
DELETED
|
@@ -1 +0,0 @@
|
|
| 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-CSVWRdrh.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 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-CSVWRdrh.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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
DELETED
|
@@ -1,12 +0,0 @@
|
|
| 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
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","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/dec_compact_sweep-DTumwRLm.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 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-DTumwRLm.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 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-CRbQBEBp.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
import{r as R}from"./debug-CPpXXfWA.js";import{l as W}from"./weights-DxIJF1EY.js";import{l as q}from"./tokenizer-BmI7pHmp.js";import{t as B}from"./generate-Ca3ORHiA.js";import{autotuneRouting as C,tunedOptions as v}from"./autotune-Bwt_lWMv.js";import{f as z}from"./constants-CSVWRdrh.js";import{t as H,s as P,p as Q}from"./t2s-DjPa3Hpi.js";import{b as U,p as G}from"./engine-C4r8fF2d.js";import{c as I}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,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-CRbQBEBp.js.map
|
|
|
|
|
|
|
|
|
assets/dec_group_sweep-CRbQBEBp.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
{"version":3,"file":"dec_group_sweep-CRbQBEBp.js","sources":["../../src/debug/tests/dec_group_sweep.js"],"sourcesContent":["// groupSteps A/B on REAL file-mode batches — the decode round's second\r\n// utilization axis. dec_compact_sweep proved the compaction THRESHOLD\r\n// insensitive (uniform sorted rows die in one wave), so the remaining dead-row\r\n// waste is detection LATENCY: a row that emits EOS mid-group keeps computing\r\n// until its group's readback lands — up to groupSteps × inFlight steps.\r\n// Smaller groups cut that latency but pay per-submit overhead (the reason\r\n// GROUP_STEPS=8 was chosen in M4a); this measures where the trade lands on\r\n// the real workload. Token-exact at any value: arms must produce identical\r\n// texts or the test fails.\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 = [8, 4, 16]; // 8 = production baseline first (warmup parity)\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_group_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 (groupSteps) => {\r\n const t0 = performance.now();\r\n let steps = 0;\r\n let compactions = 0;\r\n let submits = 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 groupSteps,\r\n });\r\n steps += metrics.steps;\r\n compactions += metrics.compactions;\r\n submits += metrics.submits;\r\n texts.push(...out.map((r) => r.text));\r\n }\r\n return { wallMs: performance.now() - t0, steps, compactions, submits, texts };\r\n };\r\n\r\n await runArm(ARMS[0]); // warmup: pipeline compiles + tokenizer LRU fill\r\n const walls = Object.fromEntries(ARMS.map((g) => [`g${g}`, []]));\r\n const last = {};\r\n for (let r = 0; r < ROUNDS; r++) {\r\n for (const g of ARMS) {\r\n const res = await runArm(g);\r\n walls[`g${g}`].push(Number(res.wallMs.toFixed(1)));\r\n last[`g${g}`] = res;\r\n }\r\n }\r\n\r\n const base = last[`g${ARMS[0]}`];\r\n let mismatch = 0;\r\n for (const g of ARMS.slice(1)) {\r\n const t = last[`g${g}`];\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((g) => [`g${g}`, Number(median(walls[`g${g}`]).toFixed(1))]),\r\n );\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] / meds[`g${ARMS[0]}`])).toFixed(1)}% vs g8`,\r\n perArm: Object.fromEntries(Object.entries(last).map(([k, v]) => [k, {\r\n steps: v.steps, compactions: v.compactions, submits: v.submits,\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","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","e","runArm","groupSteps","t0","steps","compactions","submits","texts","srcs","out","metrics","translateBatch","tunedOptions","DECODE_CAP","walls","g","last","base","mismatch","t","meds","bestName","x","y","k","v"],"mappings":"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"}
|
|
|
|
|
|
assets/dec_lmhead_sweep-BPuLSi-e.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
import{r as y}from"./debug-CPpXXfWA.js";import{l as B}from"./weights-DxIJF1EY.js";import{l as R,t as D}from"./tokenizer-BmI7pHmp.js";import{r as O}from"./encoder-CZXKGzzg.js";import{c as T}from"./decoder-BUiaGDqb.js";import{autotuneRouting as j,tunedOptions as v}from"./autotune-Bwt_lWMv.js";import{t as x}from"./profile-9RIrShZy.js";import{t as E,s as N,p as U}from"./t2s-DjPa3Hpi.js";import{pickRows as W}from"./dec_profile-BiK_GKoQ.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"./pipelines-BbLc75sB.js";import"./device-BotbBNoe.js";import"./shortlist-C151mR5c.js";import"./chapter3k-DSdzHZt5.js";const _=7,b=48,z=l=>{const e=[...l].sort((o,n)=>o-n),a=e.length>>1;return e.length%2?e[a]:(e[a-1]+e[a])/2},i={lmHeadFuse:"off"},p=[{name:"q8",lmHead:"q8",lmHeadFlags:{tm8:!0}},{name:"q8_unf",lmHead:"q8",lmHeadFlags:{tm8:!0},...i},{name:"q8_unf_bn128",lmHead:"q8",lmHeadFlags:{tm8:!0,bn:128},...i},{name:"q8_unf_bk32_sh16",lmHead:"q8",lmHeadFlags:{tm8:!0,bkk:32,sh16:!0},...i},{name:"q8_unf_bn128_bk32_sh16",lmHead:"q8",lmHeadFlags:{tm8:!0,bn:128,bkk:32,sh16:!0},...i},{name:"q8_unf_bm128_bk32_sh16",lmHead:"q8",lmHeadFlags:{tm8:!0,bm:128,bkk:32,sh16:!0},...i},{name:"f16",lmHead:"tiled",lmHeadFlags:{tm8:!0}},{name:"f16_unf_bn128_bk32_sh16",lmHead:"tiled",lmHeadFlags:{tm8:!0,bn:128,bkk:32,sh16:!0},...i}];y("dec_lmhead_sweep",async l=>{if(!l.hasF16)return{skip:!0,reason:"production stack needs shader-f16"};const{device:e}=l;let a=null;try{const n=await fetch("/local/qingshan.txt");if(n.ok){const r=E(await n.text()),c=N(r.text);a=U(c.sentences,c.paras,200).rows}}catch{}const o=await B(e,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0,projWT:!0});try{const n=await R(),r={device:e,dtype:"f16",limits:l.limits},{tuned:c}=await j(r,o),h=[];for(const[w,F,q]of[["novel576",576,37],["pack192",192,216]]){const u=await D(n,W(a,F,q)),d=await O(r,o,u);await e.queue.onSubmittedWorkDone();try{const H=v(c,u.B),g=async t=>{const s=T(r,o,{B:u.B,S:d.S,maxSteps:b,...H,lmHead:t.lmHead,lmHeadFlags:t.lmHeadFlags,lmHeadFuse:t.lmHeadFuse??H.lmHeadFuse}),{stepUs:S}=await x(r,o,d,s,{steps:b});return s.destroy(),S};for(const t of p)await g(t);const f=Object.fromEntries(p.map(t=>[t.name,[]]));for(let t=0;t<_;t++)for(const s of p)f[s.name].push(await g(s));const m=Object.fromEntries(p.map(t=>[t.name,Number(z(f[t.name]).toFixed(1))])),k=Object.keys(m).reduce((t,s)=>m[s]<m[t]?s:t);h.push({shape:w,B:u.B,S:d.S,stepUs:m,best:`${k} ${(100*(1-m[k]/m.q8)).toFixed(1)}% vs q8`,runs:f})}finally{d.arena.destroy()}}return{pass:!0,detail:{source:a?"qingshan_local":"chapter3k",steps:b,rounds:_,table:h}}}finally{o.buffer.destroy()}},{slow:!0});
|
| 2 |
-
//# sourceMappingURL=dec_lmhead_sweep-BPuLSi-e.js.map
|
|
|
|
|
|
|
|
|
assets/dec_lmhead_sweep-BPuLSi-e.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
{"version":3,"file":"dec_lmhead_sweep-BPuLSi-e.js","sources":["../../src/debug/tests/dec_lmhead_sweep.js"],"sourcesContent":["// lm_head geometry/dtype A/B at the FILE pipeline's real shapes — the decode\r\n// round's first lever. dec_profile (2026-07-09) put lm_head at 44.7% of the\r\n// novel576 step (1201µs, ~10.3 TFLOPS effective) and 35.3% of pack192,\r\n// already q8+tm8+fused-argmax — but that config was tuned at B=16..64 where\r\n// the site is W-traffic-bound. At B=576 it's COMPUTE-bound, so two untested\r\n// axes open up:\r\n// - tile geometry: bn128 (fewer W loads + fewer argmax partials: NT\r\n// 375→188), bm128 (576 rows = 4.5 row-tiles) — never swept on the\r\n// K=448/N=24000 shape (the encoder round only swept FFN shapes).\r\n// - dtype: the f16 W path skips the per-element dequant ALU; its extra\r\n// 10.75MB/step of W traffic is noise at these arithmetic intensities.\r\n// - fusion: one unfused arm prices the IF_ARGMAX epilogue (which also\r\n// BLOCKS sh16/dbuf staging — worth knowing what the fuse costs).\r\n// Constraints (16KB shared, 256 threads): the fused epilogue adds a\r\n// BM·(BN/4)·4 pIdx array and requires BK ≥ BN/4 — that LOCKS fused geometry\r\n// at 64/64/16 (bn128/bm128 fused = 20480B > 16KB). So the geometry arms run\r\n// UNFUSED and must beat the baseline by more than the ~110MB/step logits\r\n// round-trip the fuse saves at B=576; unfused also unlocks sh16 staging\r\n// (blocked under fused: pVal aliases f32 Xs) and BK=32.\r\n//\r\n// Metric: normal-mode decode step wall (timeDecodeSteps), arms interleaved\r\n// per round, medians over ROUNDS — same protocol as lm_head_sweep. Non-\r\n// lm_head routing comes from tunedOptions so the rest of the step matches\r\n// production. Token correctness is NOT checked here — the winning config\r\n// gets its own argmax_fuse/golden gate before shipping.\r\nimport { registerTest } from '../registry.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 { createDecodeState } from '../../engine/decoder.js';\r\nimport { autotuneRouting, tunedOptions } from '../../engine/autotune.js';\r\nimport { timeDecodeSteps } from '../../bench/profile.js';\r\nimport { segmentSource, packSentences } from '../../app/split.js';\r\nimport { t2s } from '../../app/t2s.js';\r\nimport { pickRows } from './dec_profile.js';\r\n\r\nconst ROUNDS = 7;\r\nconst STEPS = 48;\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 UNF = { lmHeadFuse: 'off' };\r\nconst ARMS = [\r\n { name: 'q8', lmHead: 'q8', lmHeadFlags: { tm8: true } }, // production baseline\r\n { name: 'q8_unf', lmHead: 'q8', lmHeadFlags: { tm8: true }, ...UNF },\r\n { name: 'q8_unf_bn128', lmHead: 'q8', lmHeadFlags: { tm8: true, bn: 128 }, ...UNF },\r\n { name: 'q8_unf_bk32_sh16', lmHead: 'q8', lmHeadFlags: { tm8: true, bkk: 32, sh16: true }, ...UNF },\r\n { name: 'q8_unf_bn128_bk32_sh16', lmHead: 'q8', lmHeadFlags: { tm8: true, bn: 128, bkk: 32, sh16: true }, ...UNF },\r\n { name: 'q8_unf_bm128_bk32_sh16', lmHead: 'q8', lmHeadFlags: { tm8: true, bm: 128, bkk: 32, sh16: true }, ...UNF },\r\n { name: 'f16', lmHead: 'tiled', lmHeadFlags: { tm8: true } }, // fused, f16 W (no dequant ALU)\r\n { name: 'f16_unf_bn128_bk32_sh16', lmHead: 'tiled', lmHeadFlags: { tm8: true, bn: 128, bkk: 32, sh16: true }, ...UNF },\r\n];\r\n\r\nregisterTest('dec_lmhead_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 realRows = null;\r\n try {\r\n const res = await fetch('/local/qingshan.txt');\r\n if (res.ok) {\r\n const conv = t2s(await res.text());\r\n const seg = segmentSource(conv.text);\r\n realRows = packSentences(seg.sentences, seg.paras, 200).rows;\r\n }\r\n } catch { /* fixture fallback */ }\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 = { device, dtype: 'f16', limits: ctx.limits };\r\n const { tuned } = await autotuneRouting(gctx, weights);\r\n\r\n const table = [];\r\n for (const [name, B, targetLen] of [['novel576', 576, 37], ['pack192', 192, 216]]) {\r\n const batch = await tokenizeBatch(tok, pickRows(realRows, B, targetLen));\r\n const encRun = await runEncoder(gctx, weights, batch);\r\n await device.queue.onSubmittedWorkDone();\r\n try {\r\n const base = tunedOptions(tuned, batch.B);\r\n const timeArm = async (arm) => {\r\n const state = createDecodeState(gctx, weights, {\r\n B: batch.B, S: encRun.S, maxSteps: STEPS, ...base,\r\n lmHead: arm.lmHead, lmHeadFlags: arm.lmHeadFlags,\r\n lmHeadFuse: arm.lmHeadFuse ?? base.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); // warmup: pipeline compiles\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 const meds = Object.fromEntries(\r\n ARMS.map((a) => [a.name, Number(median(times[a.name]).toFixed(1))]),\r\n );\r\n const bestName = Object.keys(meds).reduce((x, y) => (meds[y] < meds[x] ? y : x));\r\n table.push({\r\n shape: name,\r\n B: batch.B,\r\n S: encRun.S,\r\n stepUs: meds,\r\n best: `${bestName} ${(100 * (1 - meds[bestName] / meds.q8)).toFixed(1)}% vs q8`,\r\n runs: times,\r\n });\r\n } finally {\r\n encRun.arena.destroy();\r\n }\r\n }\r\n return {\r\n pass: true,\r\n detail: { source: realRows ? 'qingshan_local' : 'chapter3k', steps: STEPS, rounds: ROUNDS, table },\r\n };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n}, { slow: true });\r\n"],"names":["ROUNDS","STEPS","median","xs","s","a","b","m","UNF","ARMS","registerTest","ctx","device","realRows","res","conv","t2s","seg","segmentSource","packSentences","weights","loadWeights","tok","loadTokenizer","gctx","tuned","autotuneRouting","table","name","B","targetLen","batch","tokenizeBatch","pickRows","encRun","runEncoder","base","tunedOptions","timeArm","arm","state","createDecodeState","stepUs","timeDecodeSteps","times","r","meds","bestName","x","y"],"mappings":"gwBAoCA,MAAMA,EAAS,EACTC,EAAQ,GAERC,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,EAAM,CAAE,WAAY,OACpBC,EAAO,CACX,CAAE,KAAM,KAAM,OAAQ,KAAM,YAAa,CAAE,IAAK,GAAM,EACtD,CAAE,KAAM,SAAU,OAAQ,KAAM,YAAa,CAAE,IAAK,IAAQ,GAAGD,CAAG,EAClE,CAAE,KAAM,eAAgB,OAAQ,KAAM,YAAa,CAAE,IAAK,GAAM,GAAI,GAAG,EAAI,GAAGA,CAAG,EACjF,CAAE,KAAM,mBAAoB,OAAQ,KAAM,YAAa,CAAE,IAAK,GAAM,IAAK,GAAI,KAAM,EAAI,EAAI,GAAGA,CAAG,EACjG,CAAE,KAAM,yBAA0B,OAAQ,KAAM,YAAa,CAAE,IAAK,GAAM,GAAI,IAAK,IAAK,GAAI,KAAM,EAAI,EAAI,GAAGA,CAAG,EAChH,CAAE,KAAM,yBAA0B,OAAQ,KAAM,YAAa,CAAE,IAAK,GAAM,GAAI,IAAK,IAAK,GAAI,KAAM,EAAI,EAAI,GAAGA,CAAG,EAChH,CAAE,KAAM,MAAO,OAAQ,QAAS,YAAa,CAAE,IAAK,GAAM,EAC1D,CAAE,KAAM,0BAA2B,OAAQ,QAAS,YAAa,CAAE,IAAK,GAAM,GAAI,IAAK,IAAK,GAAI,KAAM,EAAI,EAAI,GAAGA,CAAG,CACtH,EAEAE,EAAa,mBAAoB,MAAOC,GAAQ,CAC9C,GAAI,CAACA,EAAI,OAAQ,MAAO,CAAE,KAAM,GAAM,OAAQ,qCAC9C,KAAM,CAAE,OAAAC,CAAM,EAAKD,EAEnB,IAAIE,EAAW,KACf,GAAI,CACF,MAAMC,EAAM,MAAM,MAAM,qBAAqB,EAC7C,GAAIA,EAAI,GAAI,CACV,MAAMC,EAAOC,EAAI,MAAMF,EAAI,KAAI,CAAE,EAC3BG,EAAMC,EAAcH,EAAK,IAAI,EACnCF,EAAWM,EAAcF,EAAI,UAAWA,EAAI,MAAO,GAAG,EAAE,IAC1D,CACF,MAAQ,CAAyB,CAEjC,MAAMG,EAAU,MAAMC,EAAYT,EAAQ,WAAY,CACpD,YAAa,MAAO,SAAU,GAAM,MAAO,GAAM,OAAQ,EAC7D,CAAG,EACD,GAAI,CACF,MAAMU,EAAM,MAAMC,IACZC,EAAO,CAAE,OAAAZ,EAAQ,MAAO,MAAO,OAAQD,EAAI,QAC3C,CAAE,MAAAc,CAAK,EAAK,MAAMC,EAAgBF,EAAMJ,CAAO,EAE/CO,EAAQ,CAAA,EACd,SAAW,CAACC,EAAMC,EAAGC,CAAS,GAAK,CAAC,CAAC,WAAY,IAAK,EAAE,EAAG,CAAC,UAAW,IAAK,GAAG,CAAC,EAAG,CACjF,MAAMC,EAAQ,MAAMC,EAAcV,EAAKW,EAASpB,EAAUgB,EAAGC,CAAS,CAAC,EACjEI,EAAS,MAAMC,EAAWX,EAAMJ,EAASW,CAAK,EACpD,MAAMnB,EAAO,MAAM,sBACnB,GAAI,CACF,MAAMwB,EAAOC,EAAaZ,EAAOM,EAAM,CAAC,EAClCO,EAAU,MAAOC,GAAQ,CAC7B,MAAMC,EAAQC,EAAkBjB,EAAMJ,EAAS,CAC7C,EAAGW,EAAM,EAAG,EAAGG,EAAO,EAAG,SAAUjC,EAAO,GAAGmC,EAC7C,OAAQG,EAAI,OAAQ,YAAaA,EAAI,YACrC,WAAYA,EAAI,YAAcH,EAAK,UAC/C,CAAW,EACK,CAAE,OAAAM,CAAM,EAAK,MAAMC,EAAgBnB,EAAMJ,EAASc,EAAQM,EAAO,CAAE,MAAOvC,CAAK,CAAE,EACvF,OAAAuC,EAAM,QAAO,EACNE,CACT,EACA,UAAWH,KAAO9B,EAAM,MAAM6B,EAAQC,CAAG,EACzC,MAAMK,EAAQ,OAAO,YAAYnC,EAAK,IAAKJ,GAAM,CAACA,EAAE,KAAM,CAAA,CAAE,CAAC,CAAC,EAC9D,QAASwC,EAAI,EAAGA,EAAI7C,EAAQ6C,IAC1B,UAAWN,KAAO9B,EAAMmC,EAAML,EAAI,IAAI,EAAE,KAAK,MAAMD,EAAQC,CAAG,CAAC,EAEjE,MAAMO,EAAO,OAAO,YAClBrC,EAAK,IAAKJ,GAAM,CAACA,EAAE,KAAM,OAAOH,EAAO0C,EAAMvC,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAC5E,EACc0C,EAAW,OAAO,KAAKD,CAAI,EAAE,OAAO,CAACE,EAAGC,IAAOH,EAAKG,CAAC,EAAIH,EAAKE,CAAC,EAAIC,EAAID,CAAE,EAC/ErB,EAAM,KAAK,CACT,MAAOC,EACP,EAAGG,EAAM,EACT,EAAGG,EAAO,EACV,OAAQY,EACR,KAAM,GAAGC,CAAQ,KAAK,KAAO,EAAID,EAAKC,CAAQ,EAAID,EAAK,KAAK,QAAQ,CAAC,CAAC,UACtE,KAAMF,CAChB,CAAS,CACH,QAAC,CACCV,EAAO,MAAM,SACf,CACF,CACA,MAAO,CACL,KAAM,GACN,OAAQ,CAAE,OAAQrB,EAAW,iBAAmB,YAAa,MAAOZ,EAAO,OAAQD,EAAQ,MAAA2B,CAAK,CACtG,CACE,QAAC,CACCP,EAAQ,OAAO,SACjB,CACF,EAAG,CAAE,KAAM,GAAM"}
|
|
|
|
|
|
assets/dec_profile-BiK_GKoQ.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
import{r as P}from"./debug-CPpXXfWA.js";import{l as q}from"./weights-DxIJF1EY.js";import{e as v}from"./shortlist-C151mR5c.js";import{l as U,t as M}from"./tokenizer-BmI7pHmp.js";import{r as O}from"./encoder-CZXKGzzg.js";import{c as _}from"./decoder-BUiaGDqb.js";import{autotuneRouting as R,tunedOptions as W}from"./autotune-Bwt_lWMv.js";import{t as j,p as E}from"./profile-9RIrShZy.js";import{s as D,t as $,p as F}from"./t2s-DjPa3Hpi.js";import{c as H}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"./constants-CSVWRdrh.js";import"./f16-wKKZr58e.js";import"./pipelines-BbLc75sB.js";import"./device-BotbBNoe.js";const f=48;function I(n,i,o){if(n){const s=[...n].sort((e,a)=>Math.abs(e.length-o)-Math.abs(a.length-o));if(s.length>=i)return s.slice(0,i)}const c=D(H).sentences.filter(s=>s.length>=8);return Array.from({length:i},(s,e)=>{const a=c[e%c.length],r=a.slice(e*7%Math.max(1,a.length-8));return(r.length>=o?r:(r+a).slice(0,Math.max(8,o))).slice(0,o)})}P("dec_profile",async n=>{if(!n.hasTimestamps)return{skip:!0,reason:"no timestamp-query"};if(!n.hasF16)return{skip:!0,reason:"production stack needs shader-f16"};const{device:i}=n;let o=null;try{const e=await fetch("/local/qingshan.txt");if(e.ok){const a=$(await e.text()),r=D(a.text);o=F(r.sentences,r.paras,200).rows}}catch{}const c=await U(),s=await q(i,"/weights",{targetDtype:"f16",lmHeadQ8:!0,ffnWT:!0,projWT:!0,lmHeadIds:v(c.idToToken)});try{const e={device:i,dtype:"f16",hasTimestamps:n.hasTimestamps,limits:n.limits},{tuned:a}=await R(e,s),r=async(x,z,B)=>{const m=await M(c,I(o,z,B)),p=await O(e,s,m);await i.queue.onSubmittedWorkDone();try{const S={B:m.B,S:p.S,maxSteps:f,...W(a,m.B)},k=_(e,s,S),b=await j(e,s,p,k,{steps:f});k.destroy();const y=_(e,s,S),l=await E(e,s,p,y,{steps:f});y.destroy();const T=t=>/self_attn/.test(t)?"self_attn":/cross_attn/.test(t)?"cross_attn":/lm_head|argmax/.test(t)?"lm_head+argmax":/add_ln|embed/.test(t)?"addln+embed":/_red/.test(t)?"gemm_reduce":"gemm",u={};for(const t of l.rows)u[T(t.label)]=(u[T(t.label)]??0)+t.pct;return{name:x,B:m.B,S:p.S,stepUs:b.stepUs,rowTokPerSec:Math.round(m.B/b.stepUs*1e6),profStepSumUs:l.stepSumUs,zeroDeltaPct:l.zeroDeltaPct,families:Object.fromEntries(Object.entries(u).sort(([,t],[,d])=>d-t).map(([t,d])=>[t,Number(d.toFixed(1))])),top:l.rows.slice(0,14).map(t=>`${t.label} ${t.avgUs}µs ${t.pct}%`)}}finally{p.arena.destroy()}},h=await r("novel576",576,37),g=await r("pack192",192,216),w=h.zeroDeltaPct>60||g.zeroDeltaPct>60;return{pass:!w,detail:{note:"tuned routing (translateBatch parity); pct = relative pass-split weights",source:o?"qingshan_local":"chapter3k",tuned:a,...w?{warning:"timestamps look quantized — numbers unusable"}:{},novel576:h,pack192:g}}}finally{s.buffer.destroy()}},{slow:!0});export{I as pickRows};
|
| 2 |
-
//# sourceMappingURL=dec_profile-BiK_GKoQ.js.map
|
|
|
|
|
|
|
|
|
assets/dec_profile-BiK_GKoQ.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
{"version":3,"file":"dec_profile-BiK_GKoQ.js","sources":["../../src/debug/tests/dec_profile.js"],"sourcesContent":["// dec_profile: per-kernel timestamp profile of the decode step at the FILE\r\n// pipeline's REAL shapes and REAL routing — the data source for the decode\r\n// round (post-overlap wall: decode ~64% share, ~200ms/batch median).\r\n//\r\n// Two shapes, straight out of the length-sorted 青山 plan:\r\n// novel576 B=576, ~37-char rows → S=64 bucket — where most of the file's\r\n// decode time lives (the S-aware cap's big batches).\r\n// pack192 B=192, ~216-char rows → S=224 bucket — the long-row tail.\r\n// Routing comes from autotuneRouting + tunedOptions(tuned, B), i.e. exactly\r\n// what translateBatch would run on this device (NOT decoder.js 'auto' like\r\n// prod_profile) — on the 5070 Ti that means all-5 tiled proj + splitK +\r\n// fused q8 lm_head.\r\n//\r\n// Caveats: profile mode splits every dispatch into its own timestamped pass\r\n// (pct = relative weights, stepUs from timeDecodeSteps is the honest wall);\r\n// steps run t=0..STEPS-1 with a fresh state, so self-attn KV reads match\r\n// novel-row reality (~30-45 tokens out) but UNDERESTIMATE the pack192 tail\r\n// (real t reaches ~200 there).\r\n//\r\n// Text source: /local/qingshan.txt rows when present, else synthetic slices\r\n// of chapter3k at the same lengths.\r\nimport { registerTest } from '../registry.js';\r\nimport { loadWeights } from '../../engine/weights.js';\r\nimport { emittableIds } from '../../engine/shortlist.js';\r\nimport { loadTokenizer, tokenizeBatch } from '../../engine/tokenizer.js';\r\nimport { runEncoder } from '../../engine/encoder.js';\r\nimport { createDecodeState } from '../../engine/decoder.js';\r\nimport { autotuneRouting, tunedOptions } from '../../engine/autotune.js';\r\nimport { profileDecodeSteps, timeDecodeSteps } from '../../bench/profile.js';\r\nimport { segmentSource, packSentences } from '../../app/split.js';\r\nimport { t2s } from '../../app/t2s.js';\r\nimport chapterText from '../../../fixtures/chapter3k.txt?raw';\r\n\r\nconst STEPS = 48;\r\n\r\n// Rows for one shape: prefer real qingshan rows nearest the target length,\r\n// fall back to chapter slices padded/cut to it. (Shared with dec_lmhead_sweep.)\r\nexport function pickRows(rows, count, targetLen) {\r\n if (rows) {\r\n const sorted = [...rows].sort(\r\n (a, b) => Math.abs(a.length - targetLen) - Math.abs(b.length - targetLen),\r\n );\r\n if (sorted.length >= count) return sorted.slice(0, count);\r\n }\r\n const chunks = segmentSource(chapterText).sentences.filter((s) => s.length >= 8);\r\n return Array.from({ length: count }, (_, i) => {\r\n const c = chunks[i % chunks.length];\r\n const s = c.slice((i * 7) % Math.max(1, c.length - 8));\r\n return (s.length >= targetLen ? s : (s + c).slice(0, Math.max(8, targetLen))).slice(0, targetLen);\r\n });\r\n}\r\n\r\nregisterTest('dec_profile', async (ctx) => {\r\n if (!ctx.hasTimestamps) return { skip: true, reason: 'no timestamp-query' };\r\n if (!ctx.hasF16) return { skip: true, reason: 'production stack needs shader-f16' };\r\n const { device } = ctx;\r\n\r\n let realRows = null;\r\n try {\r\n const res = await fetch('/local/qingshan.txt');\r\n if (res.ok) {\r\n const conv = t2s(await res.text());\r\n const seg = segmentSource(conv.text);\r\n realRows = packSentences(seg.sentences, seg.paras, 200).rows;\r\n }\r\n } catch { /* fixture fallback */ }\r\n\r\n // Mirror production: the app ships the static lm_head shortlist, so the\r\n // profile carries it too (pre-shortlist full-vocab numbers live in the\r\n // ledger's earlier decode rounds).\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 = { device, dtype: 'f16', hasTimestamps: ctx.hasTimestamps, limits: ctx.limits };\r\n const { tuned } = await autotuneRouting(gctx, weights);\r\n\r\n const runShape = async (name, B, targetLen) => {\r\n const batch = await tokenizeBatch(tok, pickRows(realRows, B, targetLen));\r\n const encRun = await runEncoder(gctx, weights, batch);\r\n await device.queue.onSubmittedWorkDone();\r\n try {\r\n const opts = { B: batch.B, S: encRun.S, maxSteps: STEPS, ...tunedOptions(tuned, batch.B) };\r\n const stateT = createDecodeState(gctx, weights, opts);\r\n const normal = await timeDecodeSteps(gctx, weights, encRun, stateT, { steps: STEPS });\r\n stateT.destroy();\r\n\r\n const stateP = createDecodeState(gctx, weights, opts);\r\n const prof = await profileDecodeSteps(gctx, weights, encRun, stateP, { steps: STEPS });\r\n stateP.destroy();\r\n\r\n // Group the per-site rows into kernel families for the summary.\r\n const famOf = (l) => (\r\n /self_attn/.test(l) ? 'self_attn'\r\n : /cross_attn/.test(l) ? 'cross_attn'\r\n : /lm_head|argmax/.test(l) ? 'lm_head+argmax'\r\n : /add_ln|embed/.test(l) ? 'addln+embed'\r\n : /_red/.test(l) ? 'gemm_reduce' : 'gemm');\r\n const fams = {};\r\n for (const r of prof.rows) fams[famOf(r.label)] = (fams[famOf(r.label)] ?? 0) + r.pct;\r\n return {\r\n name,\r\n B: batch.B,\r\n S: encRun.S,\r\n stepUs: normal.stepUs,\r\n rowTokPerSec: Math.round((batch.B / normal.stepUs) * 1e6),\r\n profStepSumUs: prof.stepSumUs,\r\n zeroDeltaPct: prof.zeroDeltaPct,\r\n families: Object.fromEntries(Object.entries(fams)\r\n .sort(([, a], [, b]) => b - a)\r\n .map(([k, v]) => [k, Number(v.toFixed(1))])),\r\n top: prof.rows.slice(0, 14).map((r) => `${r.label} ${r.avgUs}µs ${r.pct}%`),\r\n };\r\n } finally {\r\n encRun.arena.destroy();\r\n }\r\n };\r\n\r\n const novel576 = await runShape('novel576', 576, 37);\r\n const pack192 = await runShape('pack192', 192, 216);\r\n const quantized = novel576.zeroDeltaPct > 60 || pack192.zeroDeltaPct > 60;\r\n return {\r\n pass: !quantized,\r\n detail: {\r\n note: 'tuned routing (translateBatch parity); pct = relative pass-split weights',\r\n source: realRows ? 'qingshan_local' : 'chapter3k',\r\n tuned,\r\n ...(quantized ? { warning: 'timestamps look quantized — numbers unusable' } : {}),\r\n novel576,\r\n pack192,\r\n },\r\n };\r\n } finally {\r\n weights.buffer.destroy();\r\n }\r\n}, { slow: true });\r\n"],"names":["STEPS","pickRows","rows","count","targetLen","sorted","a","b","chunks","segmentSource","chapterText","_","i","c","s","registerTest","ctx","device","realRows","res","conv","t2s","seg","packSentences","tok","loadTokenizer","weights","loadWeights","emittableIds","gctx","tuned","autotuneRouting","runShape","name","B","batch","tokenizeBatch","encRun","runEncoder","opts","tunedOptions","stateT","createDecodeState","normal","timeDecodeSteps","stateP","prof","profileDecodeSteps","famOf","l","fams","r","k","v","novel576","pack192","quantized"],"mappings":"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"}
|
|
|
|
|
|
assets/decoder-BUiaGDqb.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
import{c as ue}from"./encoder-CZXKGzzg.js";import{deviceSupportsImmediates as Qe}from"./device-BotbBNoe.js";import{v as I,w as Ye,x as Je,y as Xe,p as Ze,q as ve,i as W,j as eo,k as oo,z as ro,A as Ce,l as no,t as to}from"./pipelines-BbLc75sB.js";import{h as Me,f as B,B as H,c as fe,D as M,F as x,V as _e,j as N,d as Q,H as Y}from"./constants-CSVWRdrh.js";function so(d,t){if(!Number.isInteger(t)||t<1||t>B)throw new Error(`decode maxSteps must be an integer in [1, ${B}], got ${t}`);if(d==null)return B;if(!Number.isInteger(d)||d<1)throw new Error(`kvCapacity must be a positive integer, got ${d}`);return Math.min(d,t,B)}function co({current:d,required:t,maxSteps:o,groupSteps:e=8}){for(const[u,l]of Object.entries({current:d,required:t,maxSteps:o,groupSteps:e}))if(!Number.isInteger(l)||l<1)throw new Error(`KV grow ${u} must be a positive integer, got ${l}`);if(d>B||o>B)throw new Error(`KV grow capacity exceeds decode cap ${B}`);if(t>o)throw new Error(`KV grow requires ${t} steps but run maxSteps=${o}`);if(t<=d)return d;const s=Math.max(t,d*2),g=Math.ceil(s/e)*e;return Math.min(o,B,g)}function $e(d,{B:t,capacity:o,HD:e,eb:s,usage:g}){const u=ue(d),l=[],c=[];try{for(let i=0;i<N;i++)l.push(u.buf(t*o*e*s,g,`dec kvK.${i} cap${o}`)),c.push(u.buf(t*o*e*s,g,`dec kvV.${i} cap${o}`))}catch(i){throw u.destroy(),i}return{arena:u,kvCacheK:l,kvCacheV:c}}function ao(d,t,{B:o,S:e,maxSteps:s,kvCapacity:g=null,lmHead:u="auto",lmHeadFlags:l=null,lmHeadFuse:c="auto",tiledProj:i="auto",ffn:f="auto",ffnFlags:r=null,fuseLn:U="auto",proj:v="auto",ffnSplitK:K="auto",projSplitK:b="auto",decodeMega:n="auto",sg:k="auto",immediates:P="auto",inPlaceCompact:p=!1}){Me(t.model,"createDecodeState weights");const m=Q*Y,y=3*m,{device:q}=d,C=t.dtype==="f16"?2:4,a=so(g,s),w=d?.limits?.maxStorageBufferBindingSize??134217728,$=[[`kv cache max [B, ${B}, ${m}]`,o*B*m*C],["f32 logits [B, 24000]",o*_e*4],["token ring [maxSteps, B]",s*o*4]];for(const[A,T]of $)if(T>w)throw new Error(`createDecodeState: ${A} = ${T} bytes exceeds maxStorageBufferBindingSize=${w} at B=${o} — reduce batch`);const h=ue(q),E=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC,S=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST|GPUBufferUsage.COPY_SRC,_=E|GPUBufferUsage.COPY_DST,L=$e(q,{B:o,capacity:a,HD:m,eb:C,usage:_});try{const{kvCacheK:A,kvCacheV:T}=L,R=h.buf(s*o*4,S,"dec token ring"),G=h.buf(o*4,S,"dec done"),F=h.buf(o*H*4,S,"dec bitmask"),V=new Uint32Array(o*H);for(let D=0;D<o;D++)V[D*H+(fe>>5)]=1<<(fe&31);q.queue.writeBuffer(F,0,V);const O=[h.buf(o*M*C,E,"dec hidden a"),h.buf(o*M*C,E,"dec hidden b")],Oe=h.buf(o*M*C,E,"dec sublayer y"),Ae=h.buf(o*m*C,E,"dec attn out"),De=h.buf(o*y*C,E,"dec qkv out"),Be=h.buf(o*x*C,E,"dec ffn tmp"),Te=h.buf(o*m*C,E,"dec cross q"),J=u==="q8"||u==="auto"&&o>=Ue&&t.tensors.has("lm_head.q8");if(J&&!t.tensors.has("lm_head.q8"))throw new Error("lmHead 'q8' needs weights loaded with lmHeadQ8: true");const oe=J||u==="tiled"||u==="auto"&&o>=Ue,X=(()=>{if(f==="q8"){if(!t.tensors.has("dec.0.fc1.q8"))throw new Error("ffn 'q8' needs weights loaded with ffnQ8: true");return"q8"}if(f==="wt"){if(!t.tensors.has("dec.0.fc1.wt"))throw new Error("ffn 'wt' needs weights loaded with ffnWT: true");return"wt"}return f==="f16"?"nwt":o<Se&&t.tensors.has("dec.0.fc1.wt")?"wt":"nwt"})(),re=K==="auto"?{fc1:Pe.fc1,fc2:Pe.fc2}:typeof K=="number"||!K?{fc1:K||0,fc2:K||0}:{fc1:K.fc1||0,fc2:K.fc2||0},Ve=X==="q8"?[]:Ke.filter(D=>re[D]>0),le=new Set(i==="auto"?o>=Se?Ke:o>=io?Ve:[]:i);if(c==="on"&&!oe)throw new Error("lmHeadFuse 'on' needs a tiled lm_head (B >= 16 or lmHead 'tiled'/'q8')");const ne=c!=="off"&&oe&&(l?.tiledV??2)===2,te=t.lmHeadShort??null,se=!!(te&&J),Z=se?te.ids.length:_e,ee=Math.ceil(Z/32),me=Math.ceil(Z/(l?.bn??64)),Le=ne?null:h.buf(o*Z*4,E,"dec logits"),Re=ne?h.buf(o*me*8,E,"dec argmax partials"):null;let ce=null;if(se){const D=te.ids.indexOf(fe);if(D<0)throw new Error("lm_head shortlist must contain decoderStart");ce=h.buf(o*ee*4,S,"dec bitmaskL");const ye=new Uint32Array(o*ee);for(let ie=0;ie<o;ie++)ye[ie*ee+(D>>5)]=1<<(D&31);q.queue.writeBuffer(ce,0,ye)}const Ge=U==="on"||U==="auto"&&o<=uo,he=D=>le.has(D)&&X!=="q8",z={fc1:he("fc1")?re.fc1:0,fc2:he("fc2")?re.fc2:0},ge=(()=>{if(v==="wt"){if(!t.tensors.has("dec.0.self_qkv.wt"))throw new Error("proj 'wt' needs weights loaded with projWT: true");return"wt"}return v==="f16"?"nwt":t.tensors.has("dec.0.self_qkv.wt")?"wt":"nwt"})(),Fe=b==="auto"?{qkv:o>=Ee.qkv?qe.qkv:0,out:o>=Ee.out?qe.out:0}:typeof b=="number"||!b?{qkv:b||0,out:b||0}:{qkv:b.qkv||0,out:b.out||0},j=ge==="wt"?Fe:{qkv:0,out:0},we=r?.bkk??16,ke=Math.max(z.fc1?I(M,z.fc1,we).nz*o*x*4:0,z.fc2?I(x,z.fc2,we).nz*o*M*4:0,j.qkv?I(M,j.qkv).nz*o*y*4:0,j.out?I(m,j.out).nz*o*M*4:0),Ne=ke?h.buf(ke,E,"dec splitK parts"):null,pe=t.dtype==="f16"&&X!=="q8"&&Ye()<=16384;if(n==="on"&&!pe)throw new Error("decodeMega 'on' needs f16 weights, ffn != 'q8', and dims inside the 16KB shared budget");const Ie=n==="on"||n==="auto"&&pe&&o<=fo,He=p?h.buf(o*4,GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,"dec compact map"):null,xe=p?h.buf((N*3+2)*de,GPUBufferUsage.UNIFORM|GPUBufferUsage.COPY_DST,"dec compact params"):null,ze=!!d.hasSubgroups&&(d.subgroupMinSize??0)>=16;if(k==="on"&&!ze)throw new Error("sg 'on' needs the subgroups feature and subgroupMinSize ≥ 16");const je=k==="on";if(!["auto","on","off"].includes(P))throw new Error(`immediates must be 'auto', 'on', or 'off', got ${P}`);const be=!!d.hasImmediates||Qe(q);if(P==="on"&&!be)throw new Error("immediates 'on' needs WGSL immediate_address_space support");const We=P==="on"||P==="auto"&&be,ae={B:o,S:e,maxSteps:s,kvCapacity:a,arena:h,kvArena:L.arena,lmHeadTiled:oe,lmHeadQ8:J,lmHeadFused:ne,lmHeadFlags:l,lmNT:me,lmShort:se,lmN:Z,lmMaskWords:ee,bitmaskL:ce,tiledProjKinds:le,ffnMode:X,ffnFlags:r,lnFused:Ge,projMode:ge,ffnSK:z,projSK:j,skParts:Ne,mega:Ie,sg:je,immediate:We,inPlaceCompact:p,kvCacheK:A,kvCacheV:T,tokenRing:R,done:G,bitmask:F,logits:Le,argmaxPartials:Re,hidden:O,y:Oe,attnOut:Ae,qkvOut:De,ffnTmp:Be,crossQOut:Te,compactMap:He,compactParams:xe,destroy(){ae.kvArena?.destroy(),ae.kvArena=null,h.destroy()}};return ae}catch(A){throw L.arena.destroy(),h.destroy(),A}}function po(d,t,o,{requiredCapacity:e,submittedSteps:s,groupSteps:g=8}={}){if(Me(t.model,"growDecodeKV weights"),!o?.kvArena||!Array.isArray(o.kvCacheK)||!Array.isArray(o.kvCacheV))throw new Error("growDecodeKV: state has no owned KV generation");if(!Number.isInteger(s)||s<0||s>o.kvCapacity)throw new Error(`growDecodeKV: submittedSteps=${s} outside [0, ${o.kvCapacity}]`);const u=co({current:o.kvCapacity,required:e,maxSteps:o.maxSteps,groupSteps:g});if(u===o.kvCapacity)return{grown:!1,oldCapacity:o.kvCapacity,newCapacity:o.kvCapacity,copiedSteps:s,bindGroupsPurged:0};const{device:l}=d,c=Q*Y,i=t.dtype==="f16"?2:4,f=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST,r=$e(l,{B:o.B,capacity:u,HD:c,eb:i,usage:f}),U=o.kvCapacity,v=o.kvCacheK,K=o.kvCacheV,b=o.kvArena,n=s*c*i;let k=!1;try{if(n>0){const m=l.createCommandEncoder({label:`grow decode KV ${U} -> ${u}`}),y=U*c*i,q=u*c*i;for(let C=0;C<o.B;C++)for(let a=0;a<N;a++)m.copyBufferToBuffer(v[a],C*y,r.kvCacheK[a],C*q,n),m.copyBufferToBuffer(K[a],C*y,r.kvCacheV[a],C*q,n);l.queue.submit([m.finish()]),k=!0}}catch(m){throw r.arena.destroy(),m}let P=Promise.resolve();if(k&&typeof l.queue.onSubmittedWorkDone=="function")try{P=l.queue.onSubmittedWorkDone()}catch{}const p=Je(l,[...v,...K]);return o.kvCacheK=r.kvCacheK,o.kvCacheV=r.kvCacheV,o.kvArena=r.arena,o.kvCapacity=u,b.destroyDeferred(P),{grown:!0,oldCapacity:U,newCapacity:u,copiedSteps:s,bindGroupsPurged:p}}const de=256,Ue=16,Ke=["fc1","fc2"],Se=128,Pe={fc1:8,fc2:8},io=32,qe={qkv:8,out:8},Ee={qkv:64,out:128},fo=4,uo=4;function bo(d,t,o,{liveIdx:e,t0:s,cap:g,lens:u,lastTok:l}){const c=Q*Y,i=2*c,{device:f}=d,{state:r,crossKV:U,S:v}=o,K=t.dtype==="f16"?2:4,b=e.length,n=ao(d,t,{B:b,S:v,maxSteps:g,kvCapacity:r.kvCapacity,lmHead:r.lmHeadQ8?"q8":r.lmHeadTiled?"tiled":"gemv",lmHeadFlags:r.lmHeadFlags,lmHeadFuse:r.lmHeadFused?"on":"off",tiledProj:[...r.tiledProjKinds],ffn:{q8:"q8",wt:"wt",nwt:"f16"}[r.ffnMode],ffnFlags:r.ffnFlags,fuseLn:r.lnFused?"on":"off",proj:r.projMode==="wt"?"wt":"f16",ffnSplitK:{...r.ffnSK},projSplitK:{...r.projSK},decodeMega:r.mega?"on":"off",sg:r.sg?"on":"off",immediates:r.immediate?"on":"off"}),k=ue(f),P=GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_SRC|GPUBufferUsage.COPY_DST,p=[k.buf(b*v*i*K,P,"compact crossKV dec.0"),k.buf(b*v*i*K,P,"compact crossKV dec.1")],m=k.buf(b*4,GPUBufferUsage.STORAGE|GPUBufferUsage.COPY_DST,"compact lens");f.queue.writeBuffer(m,0,u),f.queue.writeBuffer(n.tokenRing,(s-1)*b*4,l);const y=f.createCommandEncoder({label:`compact B ${r.B} -> ${b}`}),q=r.kvCapacity*c*K,C=n.kvCapacity*c*K,a=Math.min(s,r.kvCapacity,n.kvCapacity)*c*K,w=v*i*K,$=H*4;for(let h=0;h<b;h++){const E=e[h];for(let S=0;S<N;S++)y.copyBufferToBuffer(r.kvCacheK[S],E*q,n.kvCacheK[S],h*C,a),y.copyBufferToBuffer(r.kvCacheV[S],E*q,n.kvCacheV[S],h*C,a),y.copyBufferToBuffer(U[S],E*w,p[S],h*w,w);if(y.copyBufferToBuffer(r.bitmask,E*$,n.bitmask,h*$,$),r.bitmaskL&&n.bitmaskL){const S=r.lmMaskWords*4;y.copyBufferToBuffer(r.bitmaskL,E*S,n.bitmaskL,h*S,S)}}return f.queue.submit([y.finish()]),{state:n,crossKV:p,lensBuf:m,S:v,arena:k}}function lo(d,t){if(!Array.isArray(d))throw new Error("compact in place: liveIdx must be an array");const o=d.length;if(o<1||o>t)throw new Error(`compact in place: bad live count ${o} (B=${t})`);for(let e=0;e<o;e++){const s=d[e];if(!Number.isInteger(s)||s<0||s>=t||e>0&&s<=d[e-1])throw new Error(`compact in place: liveIdx must ascend within [0, ${t}) — [${d}]`)}}function mo({t0:d,S:t,eb:o,kvCapacity:e=B,lmMaskWords:s=0,lmShort:g=!1}){const u=Q*Y,l=e*u*o/4,c=Math.min(d,e)*u*o/4,i=t*2*u*o/4,f=[];for(let r=0;r<N;r++)f.push({key:`kvK.${r}`,strideU32:l,copyU32:c}),f.push({key:`kvV.${r}`,strideU32:l,copyU32:c}),f.push({key:`crossKV.${r}`,strideU32:i,copyU32:i});f.push({key:"bitmask",strideU32:H,copyU32:H}),g&&f.push({key:"bitmaskL",strideU32:s,copyU32:s});for(const r of f)if(!Number.isInteger(r.strideU32)||r.strideU32<1||!Number.isInteger(r.copyU32)||r.copyU32<1||r.copyU32>r.strideU32)throw new Error(`compact in place: invalid u32 row shape at ${r.key}`);return f}function yo(d,t,o,{liveIdx:e,t0:s,lens:g,lastTok:u}){const{device:l}=d,{state:c,crossKV:i,lensBuf:f,S:r}=o,U=c.B,v=e.length;if(lo(e,U),!c.inPlaceCompact||!c.compactMap||!c.compactParams)throw new Error("compact in place: state was not created for in-place compaction");if(!Number.isInteger(s)||s<1||s>c.maxSteps)throw new Error(`compact in place: bad t0=${s} for maxSteps=${c.maxSteps}`);if(g?.length!==v||u?.length!==v)throw new Error(`compact in place: CPU row data mismatch live=${v} lens=${g?.length} token=${u?.length}`);const K=t.dtype==="f16"?2:4,b=mo({t0:s,S:r,eb:K,kvCapacity:c.kvCapacity,lmMaskWords:c.lmMaskWords,lmShort:!!c.bitmaskL}),n={bitmask:c.bitmask};for(let k=0;k<N;k++)n[`kvK.${k}`]=c.kvCacheK[k],n[`kvV.${k}`]=c.kvCacheV[k],n[`crossKV.${k}`]=i[k];if(c.bitmaskL&&(n.bitmaskL=c.bitmaskL),e.some((k,P)=>k!==P)){l.queue.writeBuffer(c.compactMap,0,Uint32Array.from(e));const k=de/4,P=new Uint32Array(k*b.length);b.forEach((y,q)=>{P.set([v,y.strideU32,y.copyU32,0],q*k)}),l.queue.writeBuffer(c.compactParams,0,P);const p=l.createCommandEncoder({label:`compact in place B ${U} -> ${v}`}),m=p.beginComputePass({label:"compact gather"});b.forEach((y,q)=>{ro(l,m,{data:n[y.key],map:c.compactMap,params:{buffer:c.compactParams,offset:q*de,size:16},rowStrideU32:y.strideU32,copyLenU32:y.copyU32})}),m.end(),l.queue.submit([p.finish()])}return l.queue.writeBuffer(f,0,g),l.queue.writeBuffer(c.done,0,new Uint32Array(v)),l.queue.writeBuffer(c.tokenRing,(s-1)*v*4,u),c.B=v,o}function vo(d,t,o,e,s,g){const u=Q*Y,l=3*u,c=2*u,{device:i}=d,{B:f}=e,r={t:t.dtype,immediate:e.immediate},U=e.sg?{sg:!0}:{},v={...r,gemv:!0,...U},K={...r,tiled:!0},b=a=>e.tiledProjKinds.has(a)?K:v,n=a=>t.bindingFor(a),k=[];let P=0;const p=({scratch:a})=>{k.push(...a),P++};let m=0;const y=a=>{p(to(i,g,{x:e.y,r:e.hidden[m],gamma:n(`${a}.weight`),beta:n(`${a}.bias`),y:e.hidden[1-m],rows:f,flags:{...r,...U}})),m=1-m},q=(a,w,$,h)=>{p(no(i,g,{x:a,w:n(`${w}.weight`),b:n(`${w}.bias`),r:e.hidden[m],gamma:n(`${$}.weight`),beta:n(`${$}.bias`),y:e.hidden[1-m],M:f,K:h,N:M,flags:{...r,...U}})),m=1-m};if(e.mega)for(let a=0;a<N;a++)p(Xe(i,g,{weights:t,layer:a,embed:a===0,ring:e.tokenRing,kCache:e.kvCacheK[a],vCache:e.kvCacheV[a],crossKV:o.crossKV[a],lens:o.lensBuf,x:e.hidden[0],B:f,t:s,S:o.S,kvCapacity:e.kvCapacity,flags:{...r,...U}}));else{p(Ze(i,g,{ids:e.tokenRing,table:n("shared.weight"),posEmbed:n("pos_embed"),y:e.hidden[m],mode:"decode",nRows:f,step:s,batch:f,flags:r}));for(let a=0;a<N;a++){const w=_=>`dec.${a}.${_}`,$=(_,{x:L,y:A,b:T,K:R,N:G,storeKV:F=null})=>{const V=_==="self_qkv"?e.projSK.qkv:e.projSK.out;if(V){p(W(i,g,{x:L,w:n(w(`${_}.wt`)),y:null,M:f,K:R,N:G,splitK:{parts:e.skParts,sk:V},flags:{...r,tiled:!0,tm8:!0,wt:!0}})),p(Ce(i,g,{parts:e.skParts,b:T,y:A,M:f,N:G,nz:I(R,V).nz,storeKV:F,flags:r}));return}const O=e.projMode==="wt"?{w:n(w(`${_}.wt`)),flags:{...r,gemv:!0,wt:!0,...U}}:{w:n(w(`${_}.weight`)),flags:b(_)};p(W(i,g,{x:L,w:O.w,b:T,y:A,M:f,K:R,N:G,storeKV:F,flags:O.flags}))};$("self_qkv",{x:e.hidden[m],b:n(w("self_qkv.bias")),y:e.qkvOut,K:M,N:l,storeKV:{kCache:e.kvCacheK[a],vCache:e.kvCacheV[a],t:s,Lmax:e.kvCapacity}}),p(ve(i,g,{q:e.qkvOut,k:e.kvCacheK[a],v:e.kvCacheV[a],y:e.attnOut,B:f,M:1,L:e.kvCapacity,lenMode:0,step:s,qStride:l,flags:{...r,...U}})),e.lnFused?q(e.attnOut,w("self_out"),w("ln1"),u):($("self_out",{x:e.attnOut,b:n(w("self_out.bias")),y:e.y,K:u,N:M}),y(w("ln1"))),$("cross_q",{x:e.hidden[m],b:n(w("cross_q.bias")),y:e.crossQOut,K:M,N:u}),p(ve(i,g,{q:e.crossQOut,k:o.crossKV[a],v:o.crossKV[a],lens:o.lensBuf,y:e.attnOut,B:f,M:1,L:o.S,lenMode:1,kvStride:c,kOff:0,vOff:u,flags:{...r,...U}})),e.lnFused?q(e.attnOut,w("cross_out"),w("ln2"),u):($("cross_out",{x:e.attnOut,b:n(w("cross_out.bias")),y:e.y,K:u,N:M}),y(w("ln2")));const h=_=>e.tiledProjKinds.has(_)?{tiled:!0,tm8:!0}:{gemv:!0,...U},E=_=>e.ffnMode==="q8"?{w:n(w(`${_}.q8`)),scales:n(w(`${_}.scales`)),flags:{...r,wt:!0,wq8:!0,...h(_),...e.ffnFlags}}:e.ffnMode==="wt"?{w:n(w(`${_}.wt`)),flags:{...r,wt:!0,...h(_),...e.ffnFlags}}:{w:n(w(`${_}.weight`)),flags:b(_)},S=(_,{x:L,y:A,b:T,K:R,N:G,silu:F=!1})=>{const V=e.ffnSK[_],O=E(_);if(!V){p(W(i,g,{x:L,w:O.w,scales:O.scales,b:T,y:A,M:f,K:R,N:G,flags:F?{...O.flags,silu:!0}:O.flags}));return}p(W(i,g,{x:L,w:O.w,y:null,M:f,K:R,N:G,splitK:{parts:e.skParts,sk:V},flags:O.flags})),p(Ce(i,g,{parts:e.skParts,b:T,y:A,M:f,N:G,nz:I(R,V,O.flags.bkk??16).nz,flags:{...r,silu:F}}))};S("fc1",{x:e.hidden[m],b:n(w("fc1.bias")),y:e.ffnTmp,K:M,N:x,silu:!0}),e.lnFused&&e.ffnMode!=="q8"?q(e.ffnTmp,w("fc2"),w("ln3"),x):(S("fc2",{x:e.ffnTmp,b:n(w("fc2.bias")),y:e.y,K:x,N:M}),y(w("ln3")))}}const C=e.lmShort?{n:e.lmN,maskWords:e.lmMaskWords,idmap:n("lm_head.idmap"),gmask:e.bitmask}:null;return p(W(i,g,{x:e.hidden[m],w:e.lmHeadQ8?n("lm_head.q8"):n("shared.weight"),...e.lmHeadQ8?{scales:n("lm_head.scales")}:{},y:e.logits,...e.lmHeadFused?{fusedArgmax:e.lmShort?{partials:e.argmaxPartials,lbias:n("lm_head.sbias"),seen:e.bitmaskL,maskWords:e.lmMaskWords}:{partials:e.argmaxPartials,lbias:n("final_logits_bias"),seen:e.bitmask}}:{},M:f,K:M,N:e.lmN,flags:{...r,outT:"f32",wt:!0,...e.lmHeadTiled?{tiled:!0,...e.lmHeadQ8?{wq8:!0,tm8:!0}:{},...e.lmHeadFlags}:{gemv:!0,...U}}})),e.lmHeadFused?p(eo(i,g,{partials:e.argmaxPartials,bitmask:e.lmShort?e.bitmaskL:e.bitmask,done:e.done,tokens:e.tokenRing,B:f,t:s,NT:e.lmNT,short:C,flags:{immediate:e.immediate}})):p(oo(i,g,{logits:e.logits,bias:n(e.lmShort?"lm_head.sbias":"final_logits_bias"),bitmask:e.lmShort?e.bitmaskL:e.bitmask,done:e.done,tokens:e.tokenRing,B:f,t:s,short:C,flags:{immediate:e.immediate}})),{dispatches:P,scratch:k}}export{yo as a,bo as b,ao as c,vo as e,po as g};
|
| 2 |
-
//# sourceMappingURL=decoder-BUiaGDqb.js.map
|
|
|
|
|
|
|
|
|
assets/decoder-BUiaGDqb.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
{"version":3,"file":"decoder-BUiaGDqb.js","sources":["../../src/engine/decoder.js"],"sourcesContent":["// Decoder: per-run persistent state + a single decode step recorded into the\r\n// caller's compute pass. One step = 25 dispatches:\r\n// embed DECODE (1)\r\n// per layer ×2 (11 each):\r\n// x = LN1(x + SelfAttn(x)) gemm self_qkv (epilogue scatters k|v into the\r\n// caches — no separate kv_append dispatch)\r\n// → attention → gemm self_out → add_ln\r\n// x = LN2(x + CrossAttn(x)) gemm cross_q → attention (K/V = encoder crossKV) → gemm cross_out → add_ln\r\n// x = LN3(x + FFN(x)) gemm fc1 (SiLU) → gemm fc2 → add_ln\r\n// LM head gemm x @ shared.weightᵀ → f32 logits (1) — final_logits_bias is\r\n// NOT added here; the argmax kernel adds it (matching HF ordering)\r\n// argmax_penalty → token ring (1)\r\n// (tiled lm_head default: the two fuse — gemm emits argmax partials, no\r\n// logits store, and argmax_reduce writes the ring; same dispatch count)\r\n//\r\n// LN output must not alias its residual input (read + read_write usage\r\n// conflict — see encoder.js), so the hidden state ping-pongs hidden[0] ↔\r\n// hidden[1]. Three LNs per layer × 2 layers = 6 swaps: a step both starts and\r\n// ends with the hidden state in hidden[0].\r\n\r\nimport { createArena } from './arena.js';\r\nimport { deviceSupportsImmediates } from './device.js';\r\nimport {\r\n dispatchGemm, dispatchAttention, dispatchAddLn, dispatchEmbed,\r\n dispatchArgmaxPenalty, dispatchArgmaxReduce, dispatchGemmRowLn,\n dispatchGemmReduce, dispatchDecoderMega, decodeMegaSharedBytes, splitKParts,\n dispatchCompactGather, purgeBindGroupsForBuffers,\n} from './pipelines.js';\nimport {\r\n D_MODEL, HEADS, HEAD_DIM, FFN, VOCAB, DECODE_CAP, BITMASK_WORDS, DEC_LAYERS,\r\n DECODER_START, assertModelActive,\r\n} from './constants.js';\r\n\r\n// Per-run persistent decode state: K/V caches, token ring, done flags,\n// repetition bitmask, logits, and the step's activation buffers. K/V use a\n// separate replaceable arena so a planner-sized generation can grow without\n// rebuilding the rest of the decode state. state.destroy() frees both owners.\n//\r\n// ctx = {device}; S is unused for sizing (kept for symmetry/debug) — cross\r\n// K/V stay in encRun's buffers. maxSteps bounds the token ring.\r\n//\r\n// lmHead: 'auto' (default) | 'gemv' | 'tiled' | 'q8' — which kernel serves the\r\n// [B,448]×[448,24000] logits projection. The tuned GEMV re-sweeps the 21.5MB\r\n// embedding matrix every ceil(B/MT=8) rows, so past B≈32 the tiled kernel\r\n// (one W sweep total) wins; below that the GEMV's latency shape wins.\r\n// 'auto' picks tiled at B ≥ LM_HEAD_TILED_MIN_B (threshold measured by the\r\n// lm_head_sweep debug test); the explicit values exist for that sweep.\r\n// lmHeadFlags: extra GEMM flags merged at the lm_head site when tiled (sweep\r\n// hook for kernel-geometry A/Bs, e.g. {tm8: true} or {tiledV: 1}).\r\n//\r\n// tiledProj: 'auto' (default) | array of projection site kinds routed to the\r\n// tiled kernel instead of the GEMV — subset of ['self_out', 'cross_q',\r\n// 'cross_out', 'fc1', 'fc2'] (self_qkv stays GEMV: its storeKV cache-scatter\r\n// epilogue is a GEMV-only feature). 'auto' = PROJ_TILED_KINDS at\r\n// B ≥ PROJ_TILED_MIN_B, else none (measured by proj_sweep).\r\n//\r\n// lmHeadFuse: 'auto' (default) | 'on' | 'off' — fuse the greedy argmax into\r\n// the tiled lm_head's epilogue (gemm_tiled2 IF_ARGMAX + argmax_reduce): the\r\n// [B, 24000] f32 logits are never materialized. Bit-identical token picks\r\n// (same f32 ops, same tie order — argmax_fuse gate), so 'auto' fuses whenever\r\n// the tiled v2 kernel serves lm_head; 'off' is the A/B control. The GEMV\r\n// path (B < 16) keeps the unfused argmax_penalty scan.\r\n// fuseLn: 'auto' (default) | 'on' | 'off' — fuse the three LN-terminated\r\n// projections (self_out+ln1, cross_out+ln2, fc2+ln3) into single\r\n// gemm_row_ln dispatches (25 → 19 per step). One workgroup per row caps the\r\n// fused GEMM at M workgroups, so 'auto' fuses only at B ≤ FUSE_LN_MAX_B\r\n// (measured by fuse_ln_sweep); numerics shift at f32-ULP level (accumulation\r\n// order), gated by m3/goldens like every routing change. When ffnMode is\r\n// 'q8' the fc2 site stays unfused (the fused kernel reads float weights and\r\n// would silently unquantize it); self_out/cross_out still fuse.\r\n// proj: 'auto' | 'f16' | 'wt' — W layout for the four attention-side decode\r\n// projections (self_qkv incl. its storeKV cache scatter, self_out, cross_q,\r\n// cross_out). 'f16' = the original [K,N] tensors (GEMV NWT: the whole W is\r\n// re-read per batch ROW — 46.6% of the b128 step, prod_profile 2026-07-06);\r\n// 'wt' = transposed copies (loadWeights {projWT: true}, +4.8MB) on the GEMV\r\n// WT path (one W-tile per MT=8 rows). 'auto' picks 'wt' whenever the copies\r\n// were loaded (range confirmed by proj_wt_sweep).\r\n// ffnSplitK: 'auto' (default) | 0 | sk | {fc1, fc2} — split-K for the TILED\r\n// fc1/fc2 sites (the B ≥ PROJ_TILED_MIN_B route), which are workgroup-starved\r\n// (fc2 at b128: N=448 → 7×2 = 14 workgroups). sk partitions K over grid.z\r\n// and a gemm_reduce dispatch folds the partials + bias/SiLU (two dispatches\r\n// per site instead of one). Only applies where the site actually runs tiled\r\n// non-q8; numerics shift at the f32 re-association seams (gated like every\r\n// routing change). 'auto' = FFN_SPLITK_AUTO at the tiled sites.\r\n// projSplitK: 'auto' (default) | 0 | sk | {qkv, out} — the same split-K\r\n// medicine for the four attention-side projections (post-split-K profile:\r\n// self_qkv ×2 = 24.6% of the b64 step, the three N=448 sites ×2 = 24.1%).\r\n// Routes tiled(+splitK) on the WT copies instead of the GEMV WT sweep;\r\n// self_qkv's K/V-cache scatter moves into the gemm_reduce epilogue\r\n// (bit-identical to Y's slices, the kv_append contract). Needs projMode\r\n// 'wt'. 'auto' = PROJ_SPLITK_AUTO per site group from its\r\n// PROJ_SPLITK_MIN_B threshold (qkv ≥ 64, out ≥ 128 — set by the E2E A/B,\r\n// not the steady-state sweep; see the consts' comment).\r\n// decodeMega: 'auto' (default) | 'on' | 'off' — the small-batch decode-step\r\n// MEGAKERNEL (decoder_mega.wgsl): one dispatch per LAYER computes a whole\r\n// row's layer in one workgroup (embed folds into layer 0), so a step becomes\r\n// mega L0 → mega L1 → lm_head → argmax = 4 dispatches instead of 19. The\r\n// one-workgroup-per-row shape serializes each row's weight streaming through\r\n// one SM, so it only wins where the step is dispatch-overhead-bound —\r\n// 'auto' engages at B ≤ DECODE_MEGA_MAX_B, and needs f16 weights with the\r\n// projWT+ffnWT transposed copies (q8 FFN has no mega path). Not bit-exact\r\n// vs the unfused chain (accumulation order differs at every site) — gated\r\n// by m3/goldens + mega_equiv like every routing change; pinned across\r\n// compaction like every knob.\r\nexport function normalizeKvCapacity(value, maxSteps) {\n if (!Number.isInteger(maxSteps) || maxSteps < 1 || maxSteps > DECODE_CAP) {\n throw new Error(`decode maxSteps must be an integer in [1, ${DECODE_CAP}], got ${maxSteps}`);\n }\n // Missing preserves the legacy allocation exactly. Explicit planner/forced\n // values are clamped to work the run can actually produce.\n if (value === null || value === undefined) return DECODE_CAP;\n if (!Number.isInteger(value) || value < 1) {\n throw new Error(`kvCapacity must be a positive integer, got ${value}`);\n }\n return Math.min(value, maxSteps, DECODE_CAP);\n}\n\nexport function nextKvCapacity({ current, required, maxSteps, groupSteps = 8 }) {\n for (const [name, value] of Object.entries({ current, required, maxSteps, groupSteps })) {\n if (!Number.isInteger(value) || value < 1) {\n throw new Error(`KV grow ${name} must be a positive integer, got ${value}`);\n }\n }\n if (current > DECODE_CAP || maxSteps > DECODE_CAP) {\n throw new Error(`KV grow capacity exceeds decode cap ${DECODE_CAP}`);\n }\n if (required > maxSteps) {\n throw new Error(`KV grow requires ${required} steps but run maxSteps=${maxSteps}`);\n }\n if (required <= current) return current;\n const wanted = Math.max(required, current * 2);\n const aligned = Math.ceil(wanted / groupSteps) * groupSteps;\n return Math.min(maxSteps, DECODE_CAP, aligned);\n}\n\nfunction allocateKvGeneration(device, { B, capacity, HD, eb, usage }) {\n const arena = createArena(device);\n const kvCacheK = [];\n const kvCacheV = [];\n try {\n for (let l = 0; l < DEC_LAYERS; l++) {\n kvCacheK.push(arena.buf(B * capacity * HD * eb, usage, `dec kvK.${l} cap${capacity}`));\n kvCacheV.push(arena.buf(B * capacity * HD * eb, usage, `dec kvV.${l} cap${capacity}`));\n }\n } catch (err) {\n arena.destroy();\n throw err;\n }\n return { arena, kvCacheK, kvCacheV };\n}\n\nexport function createDecodeState(ctx, weights, { B, S, maxSteps, kvCapacity = null, lmHead = 'auto', lmHeadFlags = null, lmHeadFuse = 'auto', tiledProj = 'auto', ffn = 'auto', ffnFlags = null, fuseLn = 'auto', proj = 'auto', ffnSplitK = 'auto', projSplitK = 'auto', decodeMega = 'auto', sg = 'auto', immediates = 'auto', inPlaceCompact = false }) {\n assertModelActive(weights.model, 'createDecodeState weights');\n const HD = HEADS * HEAD_DIM; // == D_MODEL (enforced by applyModelConfig)\r\n const QKV_N = 3 * HD; // fused q|k|v\r\n const { device } = ctx;\n const eb = weights.dtype === 'f16' ? 2 : 4;\n const normalizedKvCapacity = normalizeKvCapacity(kvCapacity, maxSteps);\n\r\n // Large-batch guard: every decode-side buffer is bound whole, so each must\r\n // fit maxStorageBufferBindingSize. The two candidates that grow with B are\r\n // the per-layer KV caches at their possible full-cap grow size and the f32 logits\n // [B, 24000] (~25.7 MB and ~12.3 MB at B=128/f16) — assert both up front\r\n // with a clear error instead of an opaque createBuffer validation failure.\r\n const bindingLimit = ctx?.limits?.maxStorageBufferBindingSize ?? 134217728;\r\n const biggest = [\r\n [`kv cache max [B, ${DECODE_CAP}, ${HD}]`, B * DECODE_CAP * HD * eb],\n ['f32 logits [B, 24000]', B * VOCAB * 4],\r\n ['token ring [maxSteps, B]', maxSteps * B * 4],\r\n ];\r\n for (const [what, bytes] of biggest) {\r\n if (bytes > bindingLimit) {\r\n throw new Error(\r\n `createDecodeState: ${what} = ${bytes} bytes exceeds ` +\r\n `maxStorageBufferBindingSize=${bindingLimit} at B=${B} — reduce batch`,\r\n );\r\n }\r\n }\r\n\r\n const arena = createArena(device);\n const act = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC;\r\n const rw = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC;\r\n\r\n // Self-attention K/V caches, [B, kvCapacity, H, D] each, per layer.\n // COPY_DST: compactDecodeState copies live-row prefixes into a fresh state.\n const kvUsage = act | GPUBufferUsage.COPY_DST;\n const kv = allocateKvGeneration(device, {\n B, capacity: normalizedKvCapacity, HD, eb, usage: kvUsage,\n });\n try {\n const { kvCacheK, kvCacheV } = kv;\n\r\n // tokenRing/done rely on WebGPU zero-initialization of fresh buffers.\r\n const tokenRing = arena.buf(maxSteps * B * 4, rw, 'dec token ring');\r\n const done = arena.buf(B * 4, rw, 'dec done');\r\n\r\n // Repetition bitmask: the DECODER_START bit pre-set per row — HF counts\r\n // decoder_start in the penalized input_ids too.\r\n const bitmask = arena.buf(B * BITMASK_WORDS * 4, rw, 'dec bitmask');\r\n const maskInit = new Uint32Array(B * BITMASK_WORDS);\r\n for (let b = 0; b < B; b++) {\r\n maskInit[b * BITMASK_WORDS + (DECODER_START >> 5)] = 1 << (DECODER_START & 31);\r\n }\r\n device.queue.writeBuffer(bitmask, 0, maskInit);\r\n\r\n // Step activations. hidden[0]/hidden[1] ping-pong across add_ln outputs.\r\n const hidden = [\r\n arena.buf(B * D_MODEL * eb, act, 'dec hidden a'),\r\n arena.buf(B * D_MODEL * eb, act, 'dec hidden b'),\r\n ];\r\n const y = arena.buf(B * D_MODEL * eb, act, 'dec sublayer y');\r\n const attnOut = arena.buf(B * HD * eb, act, 'dec attn out');\r\n const qkvOut = arena.buf(B * QKV_N * eb, act, 'dec qkv out');\r\n const ffnTmp = arena.buf(B * FFN * eb, act, 'dec ffn tmp');\r\n const crossQOut = arena.buf(B * HD * eb, act, 'dec cross q');\r\n\r\n // 'q8': the tiled v2 kernel's W8A16 path over the int8-quantized embedding\r\n // matrix (weights loaded with lmHeadQ8: true). Halves lm_head W traffic —\r\n // lm_head_sweep step wall vs f16 tiled: b16 780→639µs, b64 1406→1358µs.\r\n // NOT token-exact vs f16 (quantization error; golden 29/30 — q8_lmhead\r\n // gate), so 'auto' only picks it when the caller opted into quantization\r\n // at loadWeights — parity suites load without it and keep f16 semantics.\r\n const lmHeadQ8 = lmHead === 'q8'\r\n || (lmHead === 'auto' && B >= LM_HEAD_TILED_MIN_B && weights.tensors.has('lm_head.q8'));\r\n if (lmHeadQ8 && !weights.tensors.has('lm_head.q8')) {\r\n throw new Error(\"lmHead 'q8' needs weights loaded with lmHeadQ8: true\");\r\n }\r\n const lmHeadTiled =\r\n lmHeadQ8 || lmHead === 'tiled' || (lmHead === 'auto' && B >= LM_HEAD_TILED_MIN_B);\r\n // ffn: 'auto' | 'f16' | 'wt' | 'q8' — decode fc1/fc2 weight path.\r\n // 'f16' the original [K,N] tensors (GEMV NWT / tiled WNT). NWT re-streams\r\n // the whole W once per batch ROW — B×6.4MB per step.\r\n // 'wt' f16 transposed copies (loadWeights {ffnWT}): GEMV WT sweeps one\r\n // W tile for MT=8 rows (traffic ÷8), full f16 precision.\r\n // 'q8' int8 [N,K]-packed (loadWeights {ffnQ8}): WT traffic halved again,\r\n // BUT quality is below the golden bar (q8_full_golden 27/30 vs\r\n // need 29) — explicit opt-in only, never chosen by 'auto'.\r\n const ffnMode = (() => {\r\n if (ffn === 'q8') {\r\n if (!weights.tensors.has('dec.0.fc1.q8')) throw new Error(\"ffn 'q8' needs weights loaded with ffnQ8: true\");\r\n return 'q8';\r\n }\r\n if (ffn === 'wt') {\r\n if (!weights.tensors.has('dec.0.fc1.wt')) throw new Error(\"ffn 'wt' needs weights loaded with ffnWT: true\");\r\n return 'wt';\r\n }\r\n if (ffn === 'f16') return 'nwt';\r\n // auto: 'wt' below the tiled threshold (ffn_q8_sweep: step b64 1400→1209µs,\r\n // b16 770→667); at B ≥ 128 the tiled WNT staging beats WT (1788 vs 1856) —\r\n // keep the f16 [K,N] tensors there.\r\n return (B < PROJ_TILED_MIN_B && weights.tensors.has('dec.0.fc1.wt')) ? 'wt' : 'nwt';\r\n })();\r\n\r\n // Desired split-K per FFN site (before tiled-eligibility). Split-K widens\r\n // the tiled kernel's winning range: with sk8 the tiled route beats the\r\n // production GEMV from B ≥ FFN_SPLITK_MIN_B (ffn_splitk_sweep: b32 668→600,\r\n // b64 977→779, b128 1443→1267µs), so 'auto' tiledProj flips fc1/fc2 tiled\r\n // there too — but ONLY the split-K kinds (plain tiled still loses below\r\n // B=128, and the q8 kernel has no split-K path).\r\n const wantSK = ffnSplitK === 'auto'\r\n ? { fc1: FFN_SPLITK_AUTO.fc1, fc2: FFN_SPLITK_AUTO.fc2 }\r\n : typeof ffnSplitK === 'number' || !ffnSplitK\r\n ? { fc1: ffnSplitK || 0, fc2: ffnSplitK || 0 }\r\n : { fc1: ffnSplitK.fc1 || 0, fc2: ffnSplitK.fc2 || 0 };\r\n const skKinds = ffnMode === 'q8' ? [] : PROJ_TILED_KINDS.filter((k) => wantSK[k] > 0);\r\n const tiledProjKinds = new Set(\r\n tiledProj === 'auto'\r\n ? (B >= PROJ_TILED_MIN_B ? PROJ_TILED_KINDS\r\n : B >= FFN_SPLITK_MIN_B ? skKinds : [])\r\n : tiledProj,\r\n );\r\n\r\n // Fused lm_head argmax: tiled v2 only (the v1 fallback and the GEMV have no\r\n // fused epilogue). Token picks are bit-identical to the unfused path, so\r\n // 'auto' means \"whenever eligible\"; 'off' is the sweep control.\r\n if (lmHeadFuse === 'on' && !lmHeadTiled) {\r\n throw new Error(\"lmHeadFuse 'on' needs a tiled lm_head (B >= 16 or lmHead 'tiled'/'q8')\");\r\n }\r\n const lmHeadFused = lmHeadFuse !== 'off' && lmHeadTiled && (lmHeadFlags?.tiledV ?? 2) === 2;\r\n // Static lm_head shortlist (loadWeights {lmHeadIds}): the q8 tensor holds\r\n // only the emittable rows, so every lm_head consumer below sizes by lmN and\r\n // the argmax epilogues translate local→vocab via lm_head.idmap. Rides the\r\n // q8 route only — GEMV/f16-tiled states keep the full vocab.\r\n const lmShortMeta = weights.lmHeadShort ?? null;\r\n const lmShort = !!(lmShortMeta && lmHeadQ8);\r\n const lmN = lmShort ? lmShortMeta.ids.length : VOCAB;\r\n const lmMaskWords = Math.ceil(lmN / 32);\r\n // Partial (val, idx) pairs per [row, column-tile] — NT must match the BN\r\n // the lm_head dispatch will use.\r\n const lmNT = Math.ceil(lmN / (lmHeadFlags?.bn ?? 64));\r\n const logits = lmHeadFused ? null : arena.buf(B * lmN * 4, act, 'dec logits'); // always f32\r\n const argmaxPartials = lmHeadFused ? arena.buf(B * lmNT * 8, act, 'dec argmax partials') : null;\r\n\r\n // Local-space twin of the repetition bitmask: the fused epilogue and the\r\n // shortlisted argmax_penalty read/write THIS one (contiguous local bits —\r\n // the quad trick in gemm_tiled2 stays valid); the vocab-space `bitmask`\r\n // above stays maintained in parallel so a full-vocab state inheriting these\r\n // rows (routing is pinned, but belt-and-braces) reads correct history.\r\n // Same DECODER_START pre-set, at its local index.\r\n let bitmaskL = null;\r\n if (lmShort) {\r\n const startL = lmShortMeta.ids.indexOf(DECODER_START);\r\n if (startL < 0) throw new Error('lm_head shortlist must contain decoderStart');\r\n bitmaskL = arena.buf(B * lmMaskWords * 4, rw, 'dec bitmaskL');\r\n const initL = new Uint32Array(B * lmMaskWords);\r\n for (let b = 0; b < B; b++) {\r\n initL[b * lmMaskWords + (startL >> 5)] = 1 << (startL & 31);\r\n }\r\n device.queue.writeBuffer(bitmaskL, 0, initL);\r\n }\r\n\r\n const lnFused = fuseLn === 'on' || (fuseLn === 'auto' && B <= FUSE_LN_MAX_B);\r\n\r\n // Effective split-K per FFN site: 0 wherever the site doesn't run the\r\n // tiled non-q8 kernel (splitK is a tiled-v2 float-W feature). Resolved\r\n // here — not in encodeDecodeStep — so compaction can pin the exact values.\r\n const eligibleSK = (kind) => tiledProjKinds.has(kind) && ffnMode !== 'q8';\r\n const ffnSK = {\r\n fc1: eligibleSK('fc1') ? wantSK.fc1 : 0,\r\n fc2: eligibleSK('fc2') ? wantSK.fc2 : 0,\r\n };\r\n\r\n const projMode = (() => {\r\n if (proj === 'wt') {\r\n if (!weights.tensors.has('dec.0.self_qkv.wt')) throw new Error(\"proj 'wt' needs weights loaded with projWT: true\");\r\n return 'wt';\r\n }\r\n if (proj === 'f16') return 'nwt';\r\n return weights.tensors.has('dec.0.self_qkv.wt') ? 'wt' : 'nwt';\r\n })();\r\n\r\n // Effective split-K for the attention-side projections: qkv = self_qkv\r\n // (N=1344, cache scatter in the reduce), out = self_out/cross_q/cross_out\r\n // (N=448). Needs the WT copies (tiled wt layout) — 0 when projMode 'nwt'.\r\n const wantPSK = projSplitK === 'auto'\r\n ? {\r\n qkv: B >= PROJ_SPLITK_MIN_B.qkv ? PROJ_SPLITK_AUTO.qkv : 0,\r\n out: B >= PROJ_SPLITK_MIN_B.out ? PROJ_SPLITK_AUTO.out : 0,\r\n }\r\n : typeof projSplitK === 'number' || !projSplitK\r\n ? { qkv: projSplitK || 0, out: projSplitK || 0 }\r\n : { qkv: projSplitK.qkv || 0, out: projSplitK.out || 0 };\r\n const projSK = projMode === 'wt' ? wantPSK : { qkv: 0, out: 0 };\r\n\r\n // Shared raw-partials scratch for every split-K site, sized for the\r\n // largest active [nz, B, N] f32 layout (the sites run sequentially in the\r\n // step's dependency chain, so one buffer serves them all).\r\n const skBK = ffnFlags?.bkk ?? 16;\r\n const partsBytes = Math.max(\r\n ffnSK.fc1 ? splitKParts(D_MODEL, ffnSK.fc1, skBK).nz * B * FFN * 4 : 0,\r\n ffnSK.fc2 ? splitKParts(FFN, ffnSK.fc2, skBK).nz * B * D_MODEL * 4 : 0,\r\n projSK.qkv ? splitKParts(D_MODEL, projSK.qkv).nz * B * QKV_N * 4 : 0,\r\n projSK.out ? splitKParts(HD, projSK.out).nz * B * D_MODEL * 4 : 0,\r\n );\r\n const skParts = partsBytes ? arena.buf(partsBytes, act, 'dec splitK parts') : null;\r\n\r\n // Megakernel eligibility: f16 weights, a float FFN (mega reads the\r\n // original [K,N] .weight tensors — always present — but has no int8 path,\r\n // so a q8-FFN config must keep the unfused chain rather than silently\r\n // dropping the quantization), and a model whose dims fit the kernel's\r\n // 16KB workgroup-shared budget (Moxhi-30 13,184B, Hachimi-60 16,256B —\r\n // both inside; a larger member falls back to the split pipeline).\r\n const megaOk = weights.dtype === 'f16' && ffnMode !== 'q8'\r\n && decodeMegaSharedBytes() <= 16384;\r\n if (decodeMega === 'on' && !megaOk) {\r\n throw new Error(\r\n \"decodeMega 'on' needs f16 weights, ffn != 'q8', and dims inside the 16KB shared budget\");\r\n }\r\n const mega = decodeMega === 'on'\n || (decodeMega === 'auto' && megaOk && B <= DECODE_MEGA_MAX_B);\n\n // In-place compaction uses persistent plumbing so the ownership boundary\n // itself allocates no GPUBuffer. Rebuild/default states pay no memory for\n // the experiment. One aligned parameter slot serves each possible row-major\n // buffer (K/V/cross per layer plus global/local repetition masks).\n const compactMap = inPlaceCompact\n ? arena.buf(B * 4, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, 'dec compact map')\n : null;\n const compactParams = inPlaceCompact\n ? arena.buf(\n (DEC_LAYERS * 3 + 2) * COMPACT_PARAM_STRIDE,\n GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,\n 'dec compact params',\n )\n : null;\n\r\n // Subgroup reductions ('sg') at the WT-GEMV and LN(-fused) sites. Needs\r\n // the feature AND a TK-slice that can't straddle a subgroup (TK=16\r\n // default → subgroupMinSize ≥ 16; Intel can report 8). 'auto' stays OFF\r\n // until the sg sweeps pick per-device defaults; 'on' is the sweep arm.\r\n const sgOk = !!ctx.hasSubgroups && (ctx.subgroupMinSize ?? 0) >= 16;\r\n if (sg === 'on' && !sgOk) {\r\n throw new Error(\"sg 'on' needs the subgroups feature and subgroupMinSize ≥ 16\");\r\n }\r\n const sgOn = sg === 'on';\r\n\r\n if (!['auto', 'on', 'off'].includes(immediates)) {\r\n throw new Error(`immediates must be 'auto', 'on', or 'off', got ${immediates}`);\r\n }\r\n const immediateAvailable = !!ctx.hasImmediates || deviceSupportsImmediates(device);\r\n if (immediates === 'on' && !immediateAvailable) {\r\n throw new Error(\"immediates 'on' needs WGSL immediate_address_space support\");\r\n }\r\n const immediateOn = immediates === 'on' || (immediates === 'auto' && immediateAvailable);\r\n\r\n const state = {\n B, S, maxSteps, kvCapacity: normalizedKvCapacity, arena, kvArena: kv.arena,\n lmHeadTiled, lmHeadQ8, lmHeadFused, lmHeadFlags, lmNT,\n lmShort, lmN, lmMaskWords, bitmaskL,\n tiledProjKinds, ffnMode, ffnFlags, lnFused, projMode, ffnSK, projSK, skParts,\r\n mega, sg: sgOn, immediate: immediateOn, inPlaceCompact,\n kvCacheK, kvCacheV, tokenRing, done, bitmask, logits, argmaxPartials,\n hidden, y, attnOut, qkvOut, ffnTmp, crossQOut, compactMap, compactParams,\n destroy() {\n state.kvArena?.destroy();\n state.kvArena = null;\n arena.destroy();\n },\n };\n return state;\n } catch (err) {\n // A later persistent-state allocation can still fail at high B. Keep the\n // split ownership from leaking the already-created KV generation.\n kv.arena.destroy();\n arena.destroy();\n throw err;\n }\n}\n\n// Replace only the self-attention K/V generation. Copies are submitted after\n// any already-queued decode groups, and later groups are submitted after this\n// copy, so queue order supplies the synchronization without a CPU wait.\nexport function growDecodeKV(\n ctx, weights, state,\n { requiredCapacity, submittedSteps, groupSteps = 8 } = {},\n) {\n assertModelActive(weights.model, 'growDecodeKV weights');\n if (!state?.kvArena || !Array.isArray(state.kvCacheK) || !Array.isArray(state.kvCacheV)) {\n throw new Error('growDecodeKV: state has no owned KV generation');\n }\n if (!Number.isInteger(submittedSteps) || submittedSteps < 0\n || submittedSteps > state.kvCapacity) {\n throw new Error(\n `growDecodeKV: submittedSteps=${submittedSteps} outside [0, ${state.kvCapacity}]`,\n );\n }\n const nextCapacity = nextKvCapacity({\n current: state.kvCapacity,\n required: requiredCapacity,\n maxSteps: state.maxSteps,\n groupSteps,\n });\n if (nextCapacity === state.kvCapacity) {\n return {\n grown: false,\n oldCapacity: state.kvCapacity,\n newCapacity: state.kvCapacity,\n copiedSteps: submittedSteps,\n bindGroupsPurged: 0,\n };\n }\n\n const { device } = ctx;\n const HD = HEADS * HEAD_DIM;\n const eb = weights.dtype === 'f16' ? 2 : 4;\n const kvUsage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST;\n const next = allocateKvGeneration(device, {\n B: state.B, capacity: nextCapacity, HD, eb, usage: kvUsage,\n });\n const oldCapacity = state.kvCapacity;\n const oldK = state.kvCacheK;\n const oldV = state.kvCacheV;\n const oldArena = state.kvArena;\n const prefixBytes = submittedSteps * HD * eb;\n let submitted = false;\n try {\n if (prefixBytes > 0) {\n const encoder = device.createCommandEncoder({\n label: `grow decode KV ${oldCapacity} -> ${nextCapacity}`,\n });\n const oldRowBytes = oldCapacity * HD * eb;\n const newRowBytes = nextCapacity * HD * eb;\n for (let b = 0; b < state.B; b++) {\n for (let l = 0; l < DEC_LAYERS; l++) {\n encoder.copyBufferToBuffer(\n oldK[l], b * oldRowBytes, next.kvCacheK[l], b * newRowBytes, prefixBytes,\n );\n encoder.copyBufferToBuffer(\n oldV[l], b * oldRowBytes, next.kvCacheV[l], b * newRowBytes, prefixBytes,\n );\n }\n }\n device.queue.submit([encoder.finish()]);\n submitted = true;\n }\n } catch (err) {\n next.arena.destroy();\n throw err;\n }\n\n let drained = Promise.resolve();\n if (submitted && typeof device.queue.onSubmittedWorkDone === 'function') {\n try { drained = device.queue.onSubmittedWorkDone(); } catch { /* device loss surfaces elsewhere */ }\n }\n\n // Removing JS cache ownership is safe for already-submitted command buffers\n // and must happen before GPUBuffer.destroy() on the retired generation.\n const bindGroupsPurged = purgeBindGroupsForBuffers(device, [...oldK, ...oldV]);\n state.kvCacheK = next.kvCacheK;\n state.kvCacheV = next.kvCacheV;\n state.kvArena = next.arena;\n state.kvCapacity = nextCapacity;\n oldArena.destroyDeferred(drained);\n\n return {\n grown: true,\n oldCapacity,\n newCapacity: nextCapacity,\n copiedSteps: submittedSteps,\n bindGroupsPurged,\n };\n}\n\n// Uniform dynamic offsets must satisfy minUniformBufferOffsetAlignment. WebGPU\n// guarantees that 256-byte slots meet the default/supported alignment limit.\nconst COMPACT_PARAM_STRIDE = 256;\n\r\n// Measured crossover (lm_head_sweep, RTX 5070 Ti, medians of 7 interleaved):\r\n// step wall gemv→tiled at B=16: 833→791µs, B=32: 1273→1028µs, B=64:\r\n// 2137→1461µs — tiled wins from B=16 up; below that stays on the GEMV's\r\n// latency-optimized shape (unmeasured territory, and b1–b8 is where GEMV was\r\n// tuned). Details in notes-m4-tuning.md.\r\nconst LM_HEAD_TILED_MIN_B = 16;\r\n\r\n// Which projection kinds go tiled in 'auto' mode, and from what batch —\r\n// measured by proj_sweep (medians of 7 interleaved, step wall): tiled LOSES\r\n// at these sites for B ≤ 64 (b64: gemv-all 1438µs, ffn-tiled 1701, all-5\r\n// 1938 — N=448–1792 tiles yield only 7–28 workgroups, the GPU is starved;\r\n// unlike lm_head's N=24000 → 375). Only the FFN pair at B=128 wins\r\n// (2539→2347µs, −7.6%); the out/cross_q sites lose everywhere. Details in\r\n// notes-m4-tuning.md.\r\nconst PROJ_TILED_KINDS = ['fc1', 'fc2'];\r\nconst PROJ_TILED_MIN_B = 128;\r\n\r\n// Split-K factors 'auto' uses at the tiled FFN sites (0 = off), and the\r\n// batch where the split-K tiled route starts beating the GEMV one. The\r\n// starved shapes (fc2: N=448 → 14 workgroups, fc1: 56) gain nz× workgroups;\r\n// ffn_splitk_sweep (medians of 7 interleaved, step wall): sk8 b32 668→600µs\r\n// (−10%), b64 977→779 (−20%), b128 1443→1267 (−12%); b16's −3.7% sits\r\n// inside run noise (716µs outliers) — GEMV keeps it.\r\nconst FFN_SPLITK_AUTO = { fc1: 8, fc2: 8 };\r\nconst FFN_SPLITK_MIN_B = 32;\r\n\r\n// Split-K factors for the attention-side projections in 'auto' (0 = off),\r\n// and the batch each site GROUP engages from. The steady-state step sweep\r\n// (proj_splitk_sweep: sk8 both groups b64 −8.5%, b128 −25.1%) is NOT the\r\n// decider here — split-K is pinned across compaction, so an e2e run spends\r\n// most steps at live B far below the group size, where the N=448 trio tanks\r\n// (+13.8% at b32, +32% at b16). proj_splitk_e2e_ab (full translateBatch,\r\n// interleaved): qkv-only b64 −8.8% / b128 −10.5%; adding the out-trio at\r\n// b64 flips to +13.3% but reaches −18.1% at b128 — hence the split\r\n// thresholds. qkv never loses at any measured live B (b16 −0.4%).\r\nconst PROJ_SPLITK_AUTO = { qkv: 8, out: 8 };\r\nconst PROJ_SPLITK_MIN_B = { qkv: 64, out: 128 };\r\n\r\n// Largest batch where the decode megakernel wins (mega_sweep + mega_e2e_ab):\r\n// one workgroup per row means B workgroups for the whole layer — pure\r\n// latency shape. Below the threshold the step is dispatch-overhead-bound\r\n// (19 dispatches × ~15µs fixed cost) and collapsing a layer's 8 dispatches\r\n// into 1 wins; past it the starved GEMVs lose more than the overhead saved.\r\nconst DECODE_MEGA_MAX_B = 4;\r\n\r\n// Largest batch where the fused projection+LN kernel wins (fuse_ln_sweep,\r\n// medians of 7 interleaved: b1 608→486µs −20%, b4 −7.8%, b8 +21% LOSES,\r\n// b32 +37%): its one-workgroup-per-row shape starves the GPU as B grows, but\r\n// below the threshold the step is dispatch-overhead-bound and 6 fewer\r\n// dispatches win. 0 would disable 'auto' fusing entirely.\r\nconst FUSE_LN_MAX_B = 4;\r\n\r\n// EOS row compaction: build a fresh, smaller decode context holding only the\r\n// live rows of a running decode, so finished rows stop consuming GEMM rows\r\n// and attention workgroups. Called between step groups (t0 = the next step\r\n// index; the KV caches hold positions 0..t0-1).\r\n//\r\n// prev {state, crossKV, lensBuf, S} — the CURRENT decode view (crossKV/\r\n// lensBuf are runEncoder's on the first compaction, a previous\r\n// compaction's after that). The caller destroys the old pieces\r\n// AFTER the returned copies have been submitted (this function\r\n// submits them itself — old buffers are queue-retained).\r\n// liveIdx current-row indices to keep, in order (new row i = old liveIdx[i])\r\n// lens Uint32Array[newB] — source lengths of the kept rows\r\n// lastTok Uint32Array[newB] — step t0-1 tokens of the kept rows (from the\r\n// group readback); embed at step t0 reads ring[(t0-1)·B + b], and\r\n// ring history is NOT copied (the CPU already collected it)\r\n//\r\n// Kernel routing (lmHead/tiledProj + lmHeadFlags) is PINNED from the old\r\n// state rather than re-derived from the smaller B: per-row math is identical\r\n// in every kernel here, so a compacted run must produce token-exact output\r\n// vs the uncompacted run (compact_equiv gate) — re-routing at the new B could\r\n// legally flip near-tie argmaxes and would make that equivalence untestable.\r\n//\r\n// Returns {state, crossKV, lensBuf, S, arena} — `arena` owns the new\r\n// crossKV/lens buffers; destroy it alongside state.\r\nexport function compactDecodeState(ctx, weights, prev, { liveIdx, t0, cap, lens, lastTok }) {\n const HD = HEADS * HEAD_DIM;\r\n const CROSS_KV_STRIDE = 2 * HD; // fused k|v (encoder crossKV layout)\r\n const { device } = ctx;\r\n const { state, crossKV, S } = prev;\r\n const eb = weights.dtype === 'f16' ? 2 : 4;\r\n const newB = liveIdx.length;\r\n\r\n const next = createDecodeState(ctx, weights, {\n B: newB, S, maxSteps: cap, kvCapacity: state.kvCapacity,\n lmHead: state.lmHeadQ8 ? 'q8' : state.lmHeadTiled ? 'tiled' : 'gemv',\r\n lmHeadFlags: state.lmHeadFlags,\r\n lmHeadFuse: state.lmHeadFused ? 'on' : 'off',\r\n tiledProj: [...state.tiledProjKinds],\r\n ffn: { q8: 'q8', wt: 'wt', nwt: 'f16' }[state.ffnMode],\r\n ffnFlags: state.ffnFlags,\r\n fuseLn: state.lnFused ? 'on' : 'off',\r\n proj: state.projMode === 'wt' ? 'wt' : 'f16',\r\n ffnSplitK: { ...state.ffnSK },\r\n projSplitK: { ...state.projSK },\r\n decodeMega: state.mega ? 'on' : 'off',\r\n sg: state.sg ? 'on' : 'off',\r\n immediates: state.immediate ? 'on' : 'off',\r\n });\r\n const arena = createArena(device);\r\n const cross = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST;\r\n const newCrossKV = [\r\n arena.buf(newB * S * CROSS_KV_STRIDE * eb, cross, 'compact crossKV dec.0'),\r\n arena.buf(newB * S * CROSS_KV_STRIDE * eb, cross, 'compact crossKV dec.1'),\r\n ];\r\n const newLens = arena.buf(newB * 4, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, 'compact lens');\r\n device.queue.writeBuffer(newLens, 0, lens);\r\n // Step t0-1 tokens land where the next step's embed will read them.\r\n device.queue.writeBuffer(next.tokenRing, (t0 - 1) * newB * 4, lastTok);\r\n\r\n const enc = device.createCommandEncoder({ label: `compact B ${state.B} -> ${newB}` });\r\n const oldKvRow = state.kvCapacity * HD * eb;\n const newKvRow = next.kvCapacity * HD * eb;\n const kvPrefix = Math.min(t0, state.kvCapacity, next.kvCapacity) * HD * eb;\n const crossRow = S * CROSS_KV_STRIDE * eb;\r\n const maskRow = BITMASK_WORDS * 4;\r\n for (let i = 0; i < newB; i++) {\r\n const o = liveIdx[i];\r\n for (let l = 0; l < DEC_LAYERS; l++) {\r\n enc.copyBufferToBuffer(\n state.kvCacheK[l], o * oldKvRow, next.kvCacheK[l], i * newKvRow, kvPrefix,\n );\n enc.copyBufferToBuffer(\n state.kvCacheV[l], o * oldKvRow, next.kvCacheV[l], i * newKvRow, kvPrefix,\n );\n enc.copyBufferToBuffer(crossKV[l], o * crossRow, newCrossKV[l], i * crossRow, crossRow);\r\n }\r\n enc.copyBufferToBuffer(state.bitmask, o * maskRow, next.bitmask, i * maskRow, maskRow);\r\n if (state.bitmaskL && next.bitmaskL) {\r\n const maskRowL = state.lmMaskWords * 4;\r\n enc.copyBufferToBuffer(state.bitmaskL, o * maskRowL, next.bitmaskL, i * maskRowL, maskRowL);\r\n }\r\n }\r\n device.queue.submit([enc.finish()]);\r\n\r\n return { state: next, crossKV: newCrossKV, lensBuf: newLens, S, arena };\n}\n\n// The same-buffer gather is safe only for the stable live-row ordering used by\n// the decode loop. Strictly ascending integer indices imply liveIdx[i] >= i,\n// so every row moves down and an earlier destination cannot be a later source.\nexport function validateLiveIdx(liveIdx, oldB) {\n if (!Array.isArray(liveIdx)) throw new Error('compact in place: liveIdx must be an array');\n const newB = liveIdx.length;\n if (newB < 1 || newB > oldB) {\n throw new Error(`compact in place: bad live count ${newB} (B=${oldB})`);\n }\n for (let i = 0; i < newB; i++) {\n const value = liveIdx[i];\n if (!Number.isInteger(value) || value < 0 || value >= oldB\n || (i > 0 && value <= liveIdx[i - 1])) {\n throw new Error(\n `compact in place: liveIdx must ascend within [0, ${oldB}) — [${liveIdx}]`,\n );\n }\n }\n}\n\n// Pure row geometry for the in-place gather. Strides and copy lengths are u32\n// counts because the kernel aliases native f16/f32 data as raw storage words.\nexport function inPlaceGatherPlan({\n t0, S, eb, kvCapacity = DECODE_CAP, lmMaskWords = 0, lmShort = false,\n}) {\n const HD = HEADS * HEAD_DIM;\n const kvStride = (kvCapacity * HD * eb) / 4;\n const kvCopy = (Math.min(t0, kvCapacity) * HD * eb) / 4;\n const crossStride = (S * 2 * HD * eb) / 4;\n const plan = [];\n for (let l = 0; l < DEC_LAYERS; l++) {\n plan.push({ key: `kvK.${l}`, strideU32: kvStride, copyU32: kvCopy });\n plan.push({ key: `kvV.${l}`, strideU32: kvStride, copyU32: kvCopy });\n plan.push({ key: `crossKV.${l}`, strideU32: crossStride, copyU32: crossStride });\n }\n plan.push({ key: 'bitmask', strideU32: BITMASK_WORDS, copyU32: BITMASK_WORDS });\n if (lmShort) {\n plan.push({ key: 'bitmaskL', strideU32: lmMaskWords, copyU32: lmMaskWords });\n }\n for (const item of plan) {\n if (!Number.isInteger(item.strideU32) || item.strideU32 < 1\n || !Number.isInteger(item.copyU32) || item.copyU32 < 1\n || item.copyU32 > item.strideU32) {\n throw new Error(`compact in place: invalid u32 row shape at ${item.key}`);\n }\n }\n return plan;\n}\n\n// Gather live rows downward inside the current buffers, preserving every\n// GPUBuffer identity and the pinned kernel route. No buffer is allocated or\n// destroyed at this boundary, so pooled/immediate bind groups stay valid and\n// WebKit sees no old+new resource generation overlap.\nexport function compactDecodeStateInPlace(\n ctx, weights, prev, { liveIdx, t0, lens, lastTok },\n) {\n const { device } = ctx;\n const { state, crossKV, lensBuf, S } = prev;\n const oldB = state.B;\n const newB = liveIdx.length;\n validateLiveIdx(liveIdx, oldB);\n if (!state.inPlaceCompact || !state.compactMap || !state.compactParams) {\n throw new Error('compact in place: state was not created for in-place compaction');\n }\n if (!Number.isInteger(t0) || t0 < 1 || t0 > state.maxSteps) {\n throw new Error(`compact in place: bad t0=${t0} for maxSteps=${state.maxSteps}`);\n }\n if (lens?.length !== newB || lastTok?.length !== newB) {\n throw new Error(\n `compact in place: CPU row data mismatch live=${newB} lens=${lens?.length} token=${lastTok?.length}`,\n );\n }\n\n const eb = weights.dtype === 'f16' ? 2 : 4;\n const plan = inPlaceGatherPlan({\n t0, S, eb, kvCapacity: state.kvCapacity,\n lmMaskWords: state.lmMaskWords, lmShort: !!state.bitmaskL,\n });\n const targets = { bitmask: state.bitmask };\n for (let l = 0; l < DEC_LAYERS; l++) {\n targets[`kvK.${l}`] = state.kvCacheK[l];\n targets[`kvV.${l}`] = state.kvCacheV[l];\n targets[`crossKV.${l}`] = crossKV[l];\n }\n if (state.bitmaskL) targets.bitmaskL = state.bitmaskL;\n\n // When finished rows already form a suffix, all live data is in its final\n // prefix. Stride-dependent CPU rewrites below are still required.\n if (liveIdx.some((source, i) => source !== i)) {\n device.queue.writeBuffer(state.compactMap, 0, Uint32Array.from(liveIdx));\n const slotU32 = COMPACT_PARAM_STRIDE / 4;\n const slab = new Uint32Array(slotU32 * plan.length);\n plan.forEach((item, index) => {\n slab.set([newB, item.strideU32, item.copyU32, 0], index * slotU32);\n });\n device.queue.writeBuffer(state.compactParams, 0, slab);\n const encoder = device.createCommandEncoder({\n label: `compact in place B ${oldB} -> ${newB}`,\n });\n const pass = encoder.beginComputePass({ label: 'compact gather' });\n plan.forEach((item, index) => {\n dispatchCompactGather(device, pass, {\n data: targets[item.key],\n map: state.compactMap,\n params: {\n buffer: state.compactParams,\n offset: index * COMPACT_PARAM_STRIDE,\n size: 16,\n },\n rowStrideU32: item.strideU32,\n copyLenU32: item.copyU32,\n });\n });\n pass.end();\n device.queue.submit([encoder.finish()]);\n }\n\n device.queue.writeBuffer(lensBuf, 0, lens);\n device.queue.writeBuffer(state.done, 0, new Uint32Array(newB));\n // Embed at step t0 reads only the immediately preceding token row. All\n // earlier rows were already collected on CPU; all later rows use newB.\n device.queue.writeBuffer(state.tokenRing, (t0 - 1) * newB * 4, lastTok);\n state.B = newB;\n return prev;\n}\n\n// Record one decode step (step index t) into the caller's compute pass — no\n// submit here. encRun is runEncoder's result (crossKV/lensBuf/S must match\r\n// state.B's batch). Per-dispatch scratch uniforms are collected and returned;\r\n// the caller destroys them after submitting. (Measured at 4.8% of decode wall\r\n// in M4a — persistent uniforms were never needed; targets met without them.)\r\n//\r\n// Returns {dispatches, scratch}. Logits land in state.logits (f32, bias NOT\r\n// included), the picked token in state.tokenRing[t·B + b].\r\nexport function encodeDecodeStep(ctx, weights, encRun, state, t, pass) {\r\n const HD = HEADS * HEAD_DIM; // == D_MODEL\r\n const QKV_N = 3 * HD; // fused q|k|v\r\n const CROSS_KV_STRIDE = 2 * HD; // fused k|v (encoder crossKV layout)\r\n const { device } = ctx;\r\n const { B } = state;\r\n const flags = { t: weights.dtype, immediate: state.immediate };\r\n // Decode projections are tiny-M GEMVs (M = B): the plain gemm kernel is\r\n // occupancy/latency-bound there (Task 17 profile) — route them through the\r\n // GEMV kernel. At large B the GEMV's per-8-row W re-sweep loses to the\r\n // tiled kernel; state.tiledProjKinds (proj_sweep-measured) flips sites.\r\n // Non-gemm kernels and the add_ln/embed sites keep `flags`.\r\n // Subgroup reductions (state.sg): applied at the GEMV, LN(-fused) and\r\n // attention sites — the other kernels have no SG variant and adding the\r\n // flag there would just fork their pipeline-cache entries. On devices\r\n // where autotune detects the Adreno tree-reduce miscompile, sg is FORCED\r\n // on: the sg variants are the only reduction shape that driver compiles\r\n // correctly (2026-07 Android probe rounds).\r\n const sgFlag = state.sg ? { sg: true } : {};\r\n const gemvFlags = { ...flags, gemv: true, ...sgFlag };\r\n const tiledFlags = { ...flags, tiled: true };\r\n const projFlags = (kind) => (state.tiledProjKinds.has(kind) ? tiledFlags : gemvFlags);\r\n const W = (name) => weights.bindingFor(name);\r\n\r\n const scratch = [];\r\n let dispatches = 0;\r\n const rec = ({ scratch: s }) => { scratch.push(...s); dispatches++; };\r\n\r\n // Hidden-state ping-pong: cur holds the current hidden state; each add_ln\r\n // writes into the OTHER buffer and swaps.\r\n let cur = 0;\r\n const addLn = (prefix) => {\r\n rec(dispatchAddLn(device, pass, {\r\n x: state.y, r: state.hidden[cur],\r\n gamma: W(`${prefix}.weight`), beta: W(`${prefix}.bias`),\r\n y: state.hidden[1 - cur], rows: B, flags: { ...flags, ...sgFlag },\r\n }));\r\n cur = 1 - cur;\r\n };\r\n // Fused projection + residual + LN (state.lnFused): one gemm_row_ln\r\n // dispatch replaces the gemm→state.y + addLn pair at an LN-terminated site.\r\n const projLnFused = (x, wPrefix, lnPrefix, K) => {\r\n rec(dispatchGemmRowLn(device, pass, {\r\n x, w: W(`${wPrefix}.weight`), b: W(`${wPrefix}.bias`),\r\n r: state.hidden[cur],\r\n gamma: W(`${lnPrefix}.weight`), beta: W(`${lnPrefix}.bias`),\r\n y: state.hidden[1 - cur], M: B, K, N: D_MODEL, flags: { ...flags, ...sgFlag },\r\n }));\r\n cur = 1 - cur;\r\n };\r\n\r\n // Megakernel route (state.mega): one dispatch per layer replaces the embed\r\n // + 8-dispatch layer chain — the step is mega L0 (embed folded) → mega L1\r\n // → lm_head → argmax. The final hidden state lands in hidden[0] (cur = 0).\r\n if (state.mega) {\r\n for (let l = 0; l < DEC_LAYERS; l++) {\r\n rec(dispatchDecoderMega(device, pass, {\n weights, layer: l, embed: l === 0,\n ring: state.tokenRing, kCache: state.kvCacheK[l], vCache: state.kvCacheV[l],\n crossKV: encRun.crossKV[l], lens: encRun.lensBuf, x: state.hidden[0],\n B, t, S: encRun.S, kvCapacity: state.kvCapacity,\n flags: { ...flags, ...sgFlag },\n }));\r\n }\r\n } else {\r\n // Embedding: t=0 → DECODER_START, else tokenRing[(t-1)·B + b]; pos = t.\r\n rec(dispatchEmbed(device, pass, {\r\n ids: state.tokenRing, table: W('shared.weight'), posEmbed: W('pos_embed'),\r\n y: state.hidden[cur], mode: 'decode', nRows: B, step: t, batch: B, flags,\r\n }));\r\n\r\n for (let l = 0; l < DEC_LAYERS; l++) {\r\n const p = (name) => `dec.${l}.${name}`;\r\n // Attention-side projections: 'wt' swaps in the transposed copies on the\r\n // GEMV WT path (one W-tile per MT=8 rows instead of NWT's per-row full-W\r\n // re-read); the storeKV epilogue exists on both layouts. With split-K\r\n // (state.projSK, wt-only) the site becomes a tiled GEMM storing raw\r\n // partials plus a gemm_reduce fold — self_qkv's cache scatter rides the\r\n // reduce epilogue instead of the GEMV one.\r\n const projDispatch = (kind, { x, y, b, K, N, storeKV = null }) => {\r\n const sk = kind === 'self_qkv' ? state.projSK.qkv : state.projSK.out;\r\n if (sk) {\r\n rec(dispatchGemm(device, pass, {\r\n x, w: W(p(`${kind}.wt`)), y: null, M: B, K, N,\r\n splitK: { parts: state.skParts, sk },\r\n flags: { ...flags, tiled: true, tm8: true, wt: true },\r\n }));\r\n rec(dispatchGemmReduce(device, pass, {\r\n parts: state.skParts, b, y, M: B, N, nz: splitKParts(K, sk).nz,\r\n storeKV, flags,\r\n }));\r\n return;\r\n }\r\n const args = state.projMode === 'wt'\r\n ? { w: W(p(`${kind}.wt`)), flags: { ...flags, gemv: true, wt: true, ...sgFlag } }\r\n : { w: W(p(`${kind}.weight`)), flags: projFlags(kind) };\r\n rec(dispatchGemm(device, pass, { x, w: args.w, b, y, M: B, K, N, storeKV, flags: args.flags }));\r\n };\r\n\r\n // Self-attention block: x = LN1(x + SelfAttn(x)).\r\n projDispatch('self_qkv', {\r\n x: state.hidden[cur], b: W(p('self_qkv.bias')), y: state.qkvOut,\n K: D_MODEL, N: QKV_N,\n storeKV: {\n kCache: state.kvCacheK[l], vCache: state.kvCacheV[l],\n t, Lmax: state.kvCapacity,\n },\n });\n rec(dispatchAttention(device, pass, {\n q: state.qkvOut, k: state.kvCacheK[l], v: state.kvCacheV[l], y: state.attnOut,\n B, M: 1, L: state.kvCapacity, lenMode: 0, step: t,\n qStride: QKV_N, flags: { ...flags, ...sgFlag }, // K/V: default compact [B, L, H, D] strides\r\n }));\r\n if (state.lnFused) {\r\n projLnFused(state.attnOut, p('self_out'), p('ln1'), HD);\r\n } else {\r\n projDispatch('self_out', {\r\n x: state.attnOut, b: W(p('self_out.bias')), y: state.y,\r\n K: HD, N: D_MODEL,\r\n });\r\n addLn(p('ln1'));\r\n }\r\n\r\n // Cross-attention block: x = LN2(x + CrossAttn(x)). K/V read the fused\r\n // encoder crossKV [B·S, 2·HD] (k at 0, v at HD) via strides.\r\n projDispatch('cross_q', {\r\n x: state.hidden[cur], b: W(p('cross_q.bias')), y: state.crossQOut,\r\n K: D_MODEL, N: HD,\r\n });\r\n rec(dispatchAttention(device, pass, {\r\n q: state.crossQOut, k: encRun.crossKV[l], v: encRun.crossKV[l],\r\n lens: encRun.lensBuf, y: state.attnOut,\r\n B, M: 1, L: encRun.S, lenMode: 1,\r\n kvStride: CROSS_KV_STRIDE, kOff: 0, vOff: HD, flags: { ...flags, ...sgFlag },\r\n }));\r\n if (state.lnFused) {\r\n projLnFused(state.attnOut, p('cross_out'), p('ln2'), HD);\r\n } else {\r\n projDispatch('cross_out', {\r\n x: state.attnOut, b: W(p('cross_out.bias')), y: state.y,\r\n K: HD, N: D_MODEL,\r\n });\r\n addLn(p('ln2'));\r\n }\r\n\r\n // FFN block: x = LN3(x + FFN(x)). ffnMode 'wt'/'q8' swap in the [N,K]\r\n // tensors (f16 transposed / int8 packed) and run the WT layout on either\r\n // kernel (GEMV WT below the tiled threshold, tiled above) — one W-tile\r\n // per MT=8 rows instead of NWT's per-row full-W re-stream.\r\n const wtKernel = (kind) => (state.tiledProjKinds.has(kind)\r\n ? { tiled: true, tm8: true } : { gemv: true, ...sgFlag });\r\n const ffnArgs = (kind) => {\r\n if (state.ffnMode === 'q8') {\r\n return {\r\n w: W(p(`${kind}.q8`)), scales: W(p(`${kind}.scales`)),\r\n flags: { ...flags, wt: true, wq8: true, ...wtKernel(kind), ...state.ffnFlags },\r\n };\r\n }\r\n if (state.ffnMode === 'wt') {\r\n return { w: W(p(`${kind}.wt`)), flags: { ...flags, wt: true, ...wtKernel(kind), ...state.ffnFlags } };\r\n }\r\n return { w: W(p(`${kind}.weight`)), flags: projFlags(kind) };\r\n };\r\n // Split-K FFN site (state.ffnSK, tiled route only): the GEMM stores raw\r\n // f32 partials over grid.z K-partitions and gemm_reduce folds them with\r\n // the bias/SiLU epilogue — 14 starved workgroups become 14·nz.\r\n const fcSplit = (kind, { x, y, b, K, N, silu = false }) => {\r\n const sk = state.ffnSK[kind];\r\n const args = ffnArgs(kind);\r\n if (!sk) {\r\n rec(dispatchGemm(device, pass, {\r\n x, w: args.w, scales: args.scales, b, y, M: B, K, N,\r\n flags: silu ? { ...args.flags, silu: true } : args.flags,\r\n }));\r\n return;\r\n }\r\n rec(dispatchGemm(device, pass, {\r\n x, w: args.w, y: null, M: B, K, N,\r\n splitK: { parts: state.skParts, sk }, flags: args.flags,\r\n }));\r\n rec(dispatchGemmReduce(device, pass, {\r\n parts: state.skParts, b, y, M: B, N,\r\n nz: splitKParts(K, sk, args.flags.bkk ?? 16).nz,\r\n flags: { ...flags, silu },\r\n }));\r\n };\r\n fcSplit('fc1', {\r\n x: state.hidden[cur], b: W(p('fc1.bias')), y: state.ffnTmp,\r\n K: D_MODEL, N: FFN, silu: true,\r\n });\r\n // fc2 stays unfused in 'q8' mode — the fused kernel reads float weights.\r\n if (state.lnFused && state.ffnMode !== 'q8') {\r\n projLnFused(state.ffnTmp, p('fc2'), p('ln3'), FFN);\r\n } else {\r\n fcSplit('fc2', {\r\n x: state.ffnTmp, b: W(p('fc2.bias')), y: state.y,\r\n K: FFN, N: D_MODEL,\r\n });\r\n addLn(p('ln3'));\r\n }\r\n }\r\n } // end non-mega route\r\n\r\n // LM head: logits = x @ shared.weightᵀ ([24000,448] row-major → wt), f32\r\n // out, NO bias — final_logits_bias is added inside the argmax kernel.\r\n // Kernel per state.lmHeadTiled: GEMV re-sweeps the 21.5MB W per 8 rows —\r\n // batch-linear past B≈32 — while the tiled kernel reads W exactly once.\r\n // Fused (state.lmHeadFused): the tiled epilogue applies bias + penalty and\r\n // emits per-tile argmax partials instead of storing logits; argmax_reduce\r\n // finishes the row (same dispatch count, ~37MB/step less traffic at B=128).\r\n // Shortlist (state.lmShort): the q8 tensor holds only emittable rows, so N\r\n // shrinks to lmN, the bias/seen bindings switch to their local-space twins,\r\n // and the argmax epilogues translate the winner back to a vocab id.\r\n const lmShortArgs = state.lmShort ? {\r\n n: state.lmN, maskWords: state.lmMaskWords,\r\n idmap: W('lm_head.idmap'), gmask: state.bitmask,\r\n } : null;\r\n rec(dispatchGemm(device, pass, {\r\n x: state.hidden[cur],\r\n w: state.lmHeadQ8 ? W('lm_head.q8') : W('shared.weight'),\r\n ...(state.lmHeadQ8 ? { scales: W('lm_head.scales') } : {}),\r\n y: state.logits,\r\n ...(state.lmHeadFused ? {\r\n fusedArgmax: state.lmShort ? {\r\n partials: state.argmaxPartials, lbias: W('lm_head.sbias'),\r\n seen: state.bitmaskL, maskWords: state.lmMaskWords,\r\n } : {\r\n partials: state.argmaxPartials, lbias: W('final_logits_bias'), seen: state.bitmask,\r\n },\r\n } : {}),\r\n M: B, K: D_MODEL, N: state.lmN,\r\n flags: {\r\n ...flags, outT: 'f32', wt: true,\r\n ...(state.lmHeadTiled\r\n // q8 defaults to the 8×4 subtile (b16 665→639µs; a wash above).\r\n ? { tiled: true, ...(state.lmHeadQ8 ? { wq8: true, tm8: true } : {}), ...state.lmHeadFlags }\r\n : { gemv: true, ...sgFlag }),\r\n },\r\n }));\r\n\r\n if (state.lmHeadFused) {\r\n rec(dispatchArgmaxReduce(device, pass, {\r\n partials: state.argmaxPartials,\r\n bitmask: state.lmShort ? state.bitmaskL : state.bitmask,\r\n done: state.done, tokens: state.tokenRing, B, t, NT: state.lmNT,\r\n short: lmShortArgs,\r\n flags: { immediate: state.immediate },\r\n }));\r\n } else {\r\n rec(dispatchArgmaxPenalty(device, pass, {\r\n logits: state.logits,\r\n bias: W(state.lmShort ? 'lm_head.sbias' : 'final_logits_bias'),\r\n bitmask: state.lmShort ? state.bitmaskL : state.bitmask,\r\n done: state.done, tokens: state.tokenRing,\r\n B, t,\r\n short: lmShortArgs,\r\n flags: { immediate: state.immediate },\r\n }));\r\n }\r\n\r\n return { dispatches, scratch };\r\n}\r\n"],"names":["normalizeKvCapacity","value","maxSteps","DECODE_CAP","nextKvCapacity","current","required","groupSteps","name","wanted","aligned","allocateKvGeneration","device","B","capacity","HD","eb","usage","arena","createArena","kvCacheK","kvCacheV","l","DEC_LAYERS","err","createDecodeState","ctx","weights","S","kvCapacity","lmHead","lmHeadFlags","lmHeadFuse","tiledProj","ffn","ffnFlags","fuseLn","proj","ffnSplitK","projSplitK","decodeMega","sg","immediates","inPlaceCompact","assertModelActive","HEADS","HEAD_DIM","QKV_N","normalizedKvCapacity","bindingLimit","biggest","VOCAB","what","bytes","act","rw","kvUsage","kv","tokenRing","done","bitmask","BITMASK_WORDS","maskInit","b","DECODER_START","hidden","D_MODEL","y","attnOut","qkvOut","ffnTmp","FFN","crossQOut","lmHeadQ8","LM_HEAD_TILED_MIN_B","lmHeadTiled","ffnMode","PROJ_TILED_MIN_B","wantSK","FFN_SPLITK_AUTO","skKinds","PROJ_TILED_KINDS","k","tiledProjKinds","FFN_SPLITK_MIN_B","lmHeadFused","lmShortMeta","lmShort","lmN","lmMaskWords","lmNT","logits","argmaxPartials","bitmaskL","startL","initL","lnFused","FUSE_LN_MAX_B","eligibleSK","kind","ffnSK","projMode","wantPSK","PROJ_SPLITK_MIN_B","PROJ_SPLITK_AUTO","projSK","skBK","partsBytes","splitKParts","skParts","megaOk","decodeMegaSharedBytes","mega","DECODE_MEGA_MAX_B","compactMap","compactParams","COMPACT_PARAM_STRIDE","sgOk","sgOn","immediateAvailable","deviceSupportsImmediates","immediateOn","state","growDecodeKV","requiredCapacity","submittedSteps","nextCapacity","next","oldCapacity","oldK","oldV","oldArena","prefixBytes","submitted","encoder","oldRowBytes","newRowBytes","drained","bindGroupsPurged","purgeBindGroupsForBuffers","compactDecodeState","prev","liveIdx","t0","cap","lens","lastTok","CROSS_KV_STRIDE","crossKV","newB","cross","newCrossKV","newLens","enc","oldKvRow","newKvRow","kvPrefix","crossRow","maskRow","i","o","maskRowL","validateLiveIdx","oldB","inPlaceGatherPlan","kvStride","kvCopy","crossStride","plan","item","compactDecodeStateInPlace","lensBuf","targets","source","slotU32","slab","index","pass","dispatchCompactGather","encodeDecodeStep","encRun","t","flags","sgFlag","gemvFlags","tiledFlags","projFlags","W","scratch","dispatches","rec","s","cur","addLn","prefix","dispatchAddLn","projLnFused","x","wPrefix","lnPrefix","K","dispatchGemmRowLn","dispatchDecoderMega","dispatchEmbed","p","projDispatch","N","storeKV","sk","dispatchGemm","dispatchGemmReduce","args","dispatchAttention","wtKernel","ffnArgs","fcSplit","silu","lmShortArgs","dispatchArgmaxReduce","dispatchArgmaxPenalty"],"mappings":"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"}
|
|
|
|
|
|
assets/device-BotbBNoe.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
| 1 |
-
function u(i=globalThis.navigator?.gpu){return!!i?.wgslLanguageFeatures?.has?.("immediate_address_space")}const s=new WeakSet;function f(i){return!!i&&s.has(i)}async function d({requireF16:i=!1}={}){if(!navigator.gpu)throw new Error("WebGPU unavailable");const e=await navigator.gpu.requestAdapter({powerPreference:"high-performance"});if(!e)throw new Error("no adapter");const r=["shader-f16","timestamp-query","subgroups"].filter(n=>e.features.has(n));if(i&&!r.includes("shader-f16"))throw new Error("shader-f16 unsupported");const a=await e.requestDevice({requiredFeatures:r,requiredLimits:{maxStorageBufferBindingSize:Math.min(536870912,e.limits.maxStorageBufferBindingSize),maxBufferSize:Math.min(1073741824,e.limits.maxBufferSize)}}),t=u(navigator.gpu);return t&&s.add(a),{device:a,adapterInfo:{vendor:e.info?.vendor??"",architecture:e.info?.architecture??"",device:e.info?.device??"",description:e.info?.description??""},hasF16:r.includes("shader-f16"),hasTimestamps:r.includes("timestamp-query"),hasSubgroups:r.includes("subgroups"),hasImmediates:t,subgroupMinSize:e.info?.subgroupMinSize??0,subgroupMaxSize:e.info?.subgroupMaxSize??0,limits:{maxStorageBufferBindingSize:a.limits.maxStorageBufferBindingSize,maxBufferSize:a.limits.maxBufferSize}}}export{f as deviceSupportsImmediates,d as initDevice,u as supportsImmediates};
|
| 2 |
-
//# sourceMappingURL=device-BotbBNoe.js.map
|
|
|
|
|
|
|
|
|
assets/device-BotbBNoe.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
| 1 |
-
{"version":3,"file":"device-BotbBNoe.js","sources":["../../src/engine/device.js"],"sourcesContent":["// `immediate_address_space` is a WGSL language extension rather than a\r\n// requestDevice feature. Browsers exposing it also expose\r\n// GPUComputePassEncoder.setImmediates(); record() still checks the method at\r\n// use time so an inconsistent implementation fails loudly.\r\nexport function supportsImmediates(gpu = globalThis.navigator?.gpu) {\r\n return !!gpu?.wgslLanguageFeatures?.has?.('immediate_address_space');\r\n}\r\n\r\nconst immediateDevices = new WeakSet();\r\n\r\nexport function deviceSupportsImmediates(device) {\r\n return !!device && immediateDevices.has(device);\r\n}\r\n\r\nexport async function initDevice({ requireF16 = false } = {}) {\r\n if (!navigator.gpu) throw new Error('WebGPU unavailable');\r\n const adapter = await navigator.gpu.requestAdapter({ powerPreference: 'high-performance' });\r\n if (!adapter) throw new Error('no adapter');\r\n const want = ['shader-f16', 'timestamp-query', 'subgroups'];\r\n const features = want.filter((f) => adapter.features.has(f));\r\n if (requireF16 && !features.includes('shader-f16')) throw new Error('shader-f16 unsupported');\r\n const device = await adapter.requestDevice({\r\n requiredFeatures: features,\r\n requiredLimits: {\r\n // Ask for generous limits (clamped to what the adapter offers) so large\r\n // decode batches fit in single bindings; granted values are surfaced in\r\n // ctx.limits for the maxBatchForLimits guard.\r\n maxStorageBufferBindingSize: Math.min(536870912, adapter.limits.maxStorageBufferBindingSize),\r\n maxBufferSize: Math.min(1073741824, adapter.limits.maxBufferSize),\r\n },\r\n });\r\n const hasImmediates = supportsImmediates(navigator.gpu);\r\n if (hasImmediates) immediateDevices.add(device);\r\n return {\r\n device,\r\n adapterInfo: { vendor: adapter.info?.vendor ?? '', architecture: adapter.info?.architecture ?? '', device: adapter.info?.device ?? '', description: adapter.info?.description ?? '' },\r\n hasF16: features.includes('shader-f16'),\r\n hasTimestamps: features.includes('timestamp-query'),\r\n hasSubgroups: features.includes('subgroups'),\r\n hasImmediates,\r\n // Kernel SG variants assume a TK-slice never straddles a subgroup:\r\n // routing must require TK ≤ subgroupMinSize (power-of-two sizes ⇒ that\r\n // also gives sgSize % TK == 0). 0 when the adapter doesn't report it.\r\n subgroupMinSize: adapter.info?.subgroupMinSize ?? 0,\r\n subgroupMaxSize: adapter.info?.subgroupMaxSize ?? 0,\r\n limits: {\r\n maxStorageBufferBindingSize: device.limits.maxStorageBufferBindingSize,\r\n maxBufferSize: device.limits.maxBufferSize,\r\n },\r\n };\r\n}\r\n"],"names":["supportsImmediates","gpu","immediateDevices","deviceSupportsImmediates","device","initDevice","requireF16","adapter","features","f","hasImmediates"],"mappings":"AAIO,SAASA,EAAmBC,EAAM,WAAW,WAAW,IAAK,CAClE,MAAO,CAAC,CAACA,GAAK,sBAAsB,MAAM,yBAAyB,CACrE,CAEA,MAAMC,EAAmB,IAAI,QAEtB,SAASC,EAAyBC,EAAQ,CAC/C,MAAO,CAAC,CAACA,GAAUF,EAAiB,IAAIE,CAAM,CAChD,CAEO,eAAeC,EAAW,CAAE,WAAAC,EAAa,EAAK,EAAK,CAAA,EAAI,CAC5D,GAAI,CAAC,UAAU,IAAK,MAAM,IAAI,MAAM,oBAAoB,EACxD,MAAMC,EAAU,MAAM,UAAU,IAAI,eAAe,CAAE,gBAAiB,kBAAkB,CAAE,EAC1F,GAAI,CAACA,EAAS,MAAM,IAAI,MAAM,YAAY,EAE1C,MAAMC,EADO,CAAC,aAAc,kBAAmB,WAAW,EACpC,OAAQC,GAAMF,EAAQ,SAAS,IAAIE,CAAC,CAAC,EAC3D,GAAIH,GAAc,CAACE,EAAS,SAAS,YAAY,EAAG,MAAM,IAAI,MAAM,wBAAwB,EAC5F,MAAMJ,EAAS,MAAMG,EAAQ,cAAc,CACzC,iBAAkBC,EAClB,eAAgB,CAId,4BAA6B,KAAK,IAAI,UAAWD,EAAQ,OAAO,2BAA2B,EAC3F,cAAe,KAAK,IAAI,WAAYA,EAAQ,OAAO,aAAa,CACtE,CACA,CAAG,EACKG,EAAgBV,EAAmB,UAAU,GAAG,EACtD,OAAIU,GAAeR,EAAiB,IAAIE,CAAM,EACvC,CACL,OAAAA,EACA,YAAa,CAAE,OAAQG,EAAQ,MAAM,QAAU,GAAI,aAAcA,EAAQ,MAAM,cAAgB,GAAI,OAAQA,EAAQ,MAAM,QAAU,GAAI,YAAaA,EAAQ,MAAM,aAAe,EAAE,EACnL,OAAQC,EAAS,SAAS,YAAY,EACtC,cAAeA,EAAS,SAAS,iBAAiB,EAClD,aAAcA,EAAS,SAAS,WAAW,EAC3C,cAAAE,EAIA,gBAAiBH,EAAQ,MAAM,iBAAmB,EAClD,gBAAiBA,EAAQ,MAAM,iBAAmB,EAClD,OAAQ,CACN,4BAA6BH,EAAO,OAAO,4BAC3C,cAAeA,EAAO,OAAO,aACnC,CACA,CACA"}
|
|
|
|
|
|