SeaWolf-AI commited on
Commit
fcfc3c9
·
verified ·
1 Parent(s): ccd134a

GPU Lab: honest throughput note, no-wrap metrics

Browse files
Files changed (1) hide show
  1. gpulab.js +78 -77
gpulab.js CHANGED
@@ -1,77 +1,78 @@
1
- /* GPU Lab: run a small GPU kernel on the GPU unit wired into the weights of Meta Muse Glimmer 30B (option 3 backend).
2
- The result is checked against the reference executor and plain Python. Honors the sleep/wake of the GPU backend. */
3
- (() => {
4
- 'use strict';
5
- const K = {
6
- vadd: {label:'Vector add', make:n => ({a:rnd(n, 50), b:rnd(n, 50)}), py:d => ({c:d.a.map((v, i) => v + d.b[i])})},
7
- dot: {label:'Dot product', make:n => ({a:rnd(n, 12), b:rnd(n, 12)}), py:d => ({out:[d.a.reduce((s, v, i) => s + v * d.b[i], 0)]})},
8
- reduce: {label:'Reduce (sum)', make:n => ({x:rnd(n, 99)}), py:d => ({out:[d.x.reduce((s, v) => s + v, 0)]})},
9
- histogram: {label:'Histogram (16 bins)', make:n => ({x:rnd(n, 15)}), py:d => ({bins:Array.from({length:16}, (_, i) => d.x.filter(v => v === i).length)})},
10
- };
11
- function rnd(n, m) { return Array.from({length:n}, () => Math.floor(Math.random() * (m + 1))); }
12
- async function gpu(path, body, ms) {
13
- const ctl = new AbortController(); const to = setTimeout(() => ctl.abort(), ms || 300000);
14
- try {
15
- const r = await fetch('api/agx/' + path, body === undefined ? {cache:'no-store', signal:ctl.signal} : {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(body), signal:ctl.signal});
16
- if (r.status === 429) throw new Error('rate');
17
- if (!r.ok) throw new Error('http ' + r.status);
18
- return await r.json();
19
- } finally { clearTimeout(to); }
20
- }
21
- const css = document.createElement('style');
22
- css.textContent = `.gl{padding:14px;font-family:system-ui,'Segoe UI',sans-serif;display:flex;flex-direction:column;gap:12px;height:100%;overflow:auto}
23
- .gl h3{margin:0;font-size:18px}.gl .mut{color:var(--muted);font-size:13px}.gl .row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
24
- .gl .card{border:1px solid var(--border);border-radius:12px;padding:12px;background:var(--card)}.gl pre{margin:6px 0 0;white-space:pre-wrap;word-break:break-word;font:12px ui-monospace,Consolas,monospace;background:var(--bg);border-radius:8px;padding:8px}
25
- .gl .ok{color:#16A34A;font-weight:800}.gl .bad{color:#E11D48;font-weight:800}.gl .tag{font:800 11px system-ui;padding:3px 8px;border-radius:999px;background:#EEF2FF;color:#4338CA}
26
- .gl select,.gl input[type=range]{height:32px}.gl .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:8px}.gl .kv b{display:block;font-size:20px}`;
27
- document.head.append(css);
28
- window.VK_EXTRA_APPS = window.VK_EXTRA_APPS || [];
29
- window.VK_EXTRA_APPS.push(h => ({id:'gpulab', name:() => 'GPU Lab', color:'#0F766E',
30
- icon:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="8" y="8" width="8" height="8" rx="1"/><path d="M9 1v3M15 1v3M9 20v3M15 20v3M1 9h3M1 15h3M20 9h3M20 15h3"/></svg>',
31
- w:820, h:640, render(body) {
32
- body.style.padding = '0';
33
- const root = document.createElement('div'); root.className = 'gl'; body.append(root);
34
- root.innerHTML = `<div><h3>GPU Lab</h3><div class="mut">A GPU unit wired into the weights of Meta Muse Glimmer 30B runs a small kernel inside the model's own forward pass. The result is checked token by token against the reference executor and against plain Python.</div></div>
35
- <div class="card row"><label>Kernel <select data-k="k">${Object.entries(K).map(([k, v]) => `<option value="${k}">${v.label}</option>`).join('')}</select></label>
36
- <label>Length n <input type="range" min="4" max="16" value="8" data-k="n"> <b data-k="nv">8</b></label>
37
- <button class="btn" data-k="rand">Random inputs</button><button class="btn pri" data-k="run">Run on the GPU in the weights</button><span class="tag" data-k="state">checking backend...</span></div>
38
- <div class="card"><b>Inputs</b><pre data-k="in"></pre></div>
39
- <div class="card" data-k="out"><span class="mut">Pick a kernel and press Run. A run takes from a few seconds to about a minute, because every GPU step is computed by the model.</span></div>`;
40
- const q = k => root.querySelector(`[data-k="${k}"]`);
41
- let data = null, waking = false;
42
- const fresh = () => { data = K[q('k').value].make(+q('n').value); q('in').textContent = JSON.stringify(data); };
43
- q('k').onchange = fresh; q('n').oninput = () => { q('nv').textContent = q('n').value; fresh(); }; q('rand').onclick = fresh; fresh();
44
- async function health() {
45
- try { const r = await gpu('health', undefined, 10000); return !!(r && r.live); } catch (e) { return false; }
46
- }
47
- async function ensureAwake() {
48
- if (await health()) { q('state').textContent = 'GPU backend ready'; return true; }
49
- q('state').textContent = 'waking the in-weights model (about 4 min)...';
50
- if (waking) return false; waking = true;
51
- for (let i = 0; i < 40; i++) { await new Promise(r => setTimeout(r, 15000)); if (!root.isConnected) return false; if (await health()) { waking = false; q('state').textContent = 'GPU backend ready'; h.toast('GPU Lab: the in-weights model is awake'); return true; } }
52
- waking = false; q('state').textContent = 'still waking; try again shortly'; return false;
53
- }
54
- ensureAwake();
55
- q('run').onclick = async () => {
56
- const out = q('out'), k = q('k').value, n = +q('n').value;
57
- if (!(await health())) { out.innerHTML = '<span class="mut">The in-weights model is asleep to save cost. It is waking now (about 4 min). Agent Guard option 1 stays live meanwhile.</span>'; ensureAwake(); return; }
58
- q('run').disabled = true; out.innerHTML = '<span class="mut">Running inside the model...</span>';
59
- const t0 = performance.now();
60
- try {
61
- const r = await gpu('gpu', {kernel:k, data, n});
62
- if (r.error) throw new Error(r.error);
63
- const py = K[k].py(data), wall = (performance.now() - t0) / 1000;
64
- const okPy = JSON.stringify(r.outputs) === JSON.stringify(py);
65
- out.innerHTML = `<div class="grid"><div class="kv"><span class="mut">exact vs reference</span><b class="${r.equals_reference ? 'ok' : 'bad'}">${r.equals_reference ? '&#10003; exact' : '&#10007; differs'}</b></div>
66
- <div class="kv"><span class="mut">token-exact vs executor</span><b class="${r.token_exact ? 'ok' : 'bad'}">${r.token_exact ? '&#10003;' : '&#10007;'}</b></div>
67
- <div class="kv"><span class="mut">matches plain Python</span><b class="${okPy ? 'ok' : 'bad'}">${okPy ? '&#10003;' : '&#10007;'}</b></div>
68
- <div class="kv"><span class="mut">model tokens</span><b>${(r.tokens || 0).toLocaleString('en-US')}</b></div>
69
- <div class="kv"><span class="mut">GPU time in the model</span><b>${r.sec} s</b></div><div class="kv"><span class="mut">round trip</span><b>${wall.toFixed(1)} s</b></div></div>
70
- <b style="display:block;margin-top:10px">Output</b><pre>${JSON.stringify(r.outputs)}</pre><b>Plain Python</b><pre>${JSON.stringify(py)}</pre>`;
71
- } catch (e) {
72
- out.innerHTML = `<span class="mut">${e.message === 'rate' ? 'Too many requests from your network; try again in a few minutes.' : 'The in-weights model is busy or waking. Please try again in a minute.'}</span>`;
73
- ensureAwake();
74
- } finally { q('run').disabled = false; }
75
- };
76
- }}));
77
- })();
 
 
1
+ /* GPU Lab: run a small GPU kernel on the GPU unit wired into the weights of Meta Muse Glimmer 30B (option 3 backend).
2
+ The result is checked against the reference executor and plain Python. Honors the sleep/wake of the GPU backend. */
3
+ (() => {
4
+ 'use strict';
5
+ const K = {
6
+ vadd: {label:'Vector add', make:n => ({a:rnd(n, 50), b:rnd(n, 50)}), py:d => ({c:d.a.map((v, i) => v + d.b[i])})},
7
+ dot: {label:'Dot product', make:n => ({a:rnd(n, 12), b:rnd(n, 12)}), py:d => ({out:[d.a.reduce((s, v, i) => s + v * d.b[i], 0)]})},
8
+ reduce: {label:'Reduce (sum)', make:n => ({x:rnd(n, 99)}), py:d => ({out:[d.x.reduce((s, v) => s + v, 0)]})},
9
+ histogram: {label:'Histogram (16 bins)', make:n => ({x:rnd(n, 15)}), py:d => ({bins:Array.from({length:16}, (_, i) => d.x.filter(v => v === i).length)})},
10
+ };
11
+ function rnd(n, m) { return Array.from({length:n}, () => Math.floor(Math.random() * (m + 1))); }
12
+ async function gpu(path, body, ms) {
13
+ const ctl = new AbortController(); const to = setTimeout(() => ctl.abort(), ms || 300000);
14
+ try {
15
+ const r = await fetch('api/agx/' + path, body === undefined ? {cache:'no-store', signal:ctl.signal} : {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify(body), signal:ctl.signal});
16
+ if (r.status === 429) throw new Error('rate');
17
+ if (!r.ok) throw new Error('http ' + r.status);
18
+ return await r.json();
19
+ } finally { clearTimeout(to); }
20
+ }
21
+ const css = document.createElement('style');
22
+ css.textContent = `.gl{padding:14px;font-family:system-ui,'Segoe UI',sans-serif;display:flex;flex-direction:column;gap:12px;height:100%;overflow:auto}
23
+ .gl h3{margin:0;font-size:18px}.gl .mut{color:var(--muted);font-size:13px}.gl .row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
24
+ .gl .card{border:1px solid var(--border);border-radius:12px;padding:12px;background:var(--card)}.gl pre{margin:6px 0 0;white-space:pre-wrap;word-break:break-word;font:12px ui-monospace,Consolas,monospace;background:var(--bg);border-radius:8px;padding:8px}
25
+ .gl .ok{color:#16A34A;font-weight:800}.gl .bad{color:#E11D48;font-weight:800}.gl .tag{font:800 11px system-ui;padding:3px 8px;border-radius:999px;background:#EEF2FF;color:#4338CA}
26
+ .gl select,.gl input[type=range]{height:32px}.gl .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:8px}.gl .kv b{display:block;font-size:20px;white-space:nowrap}.gl .note{font-size:12px;color:var(--muted);border-left:3px solid #F59E0B;padding:4px 8px;background:var(--bg);border-radius:6px}`;
27
+ document.head.append(css);
28
+ window.VK_EXTRA_APPS = window.VK_EXTRA_APPS || [];
29
+ window.VK_EXTRA_APPS.push(h => ({id:'gpulab', name:() => 'GPU Lab', color:'#0F766E',
30
+ icon:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="8" y="8" width="8" height="8" rx="1"/><path d="M9 1v3M15 1v3M9 20v3M15 20v3M1 9h3M1 15h3M20 9h3M20 15h3"/></svg>',
31
+ w:820, h:640, render(body) {
32
+ body.style.padding = '0';
33
+ const root = document.createElement('div'); root.className = 'gl'; body.append(root);
34
+ root.innerHTML = `<div><h3>GPU Lab</h3><div class="mut">A GPU unit wired into the weights of Meta Muse Glimmer 30B runs a small kernel inside the model's own forward pass. The result is checked token by token against the reference executor and against plain Python.</div>
35
+ <div class="note" style="margin-top:8px">Exact and auditable, not a GPU replacement: a real GPU is roughly a trillion times faster in raw throughput.</div></div>
36
+ <div class="card row"><label>Kernel <select data-k="k">${Object.entries(K).map(([k, v]) => `<option value="${k}">${v.label}</option>`).join('')}</select></label>
37
+ <label>Length n <input type="range" min="4" max="16" value="8" data-k="n"> <b data-k="nv">8</b></label>
38
+ <button class="btn" data-k="rand">Random inputs</button><button class="btn pri" data-k="run">Run on the GPU in the weights</button><span class="tag" data-k="state">checking backend...</span></div>
39
+ <div class="card"><b>Inputs</b><pre data-k="in"></pre></div>
40
+ <div class="card" data-k="out"><span class="mut">Pick a kernel and press Run. A run takes from a few seconds to about a minute, because every GPU step is computed by the model.</span></div>`;
41
+ const q = k => root.querySelector(`[data-k="${k}"]`);
42
+ let data = null, waking = false;
43
+ const fresh = () => { data = K[q('k').value].make(+q('n').value); q('in').textContent = JSON.stringify(data); };
44
+ q('k').onchange = fresh; q('n').oninput = () => { q('nv').textContent = q('n').value; fresh(); }; q('rand').onclick = fresh; fresh();
45
+ async function health() {
46
+ try { const r = await gpu('health', undefined, 10000); return !!(r && r.live); } catch (e) { return false; }
47
+ }
48
+ async function ensureAwake() {
49
+ if (await health()) { q('state').textContent = 'GPU backend ready'; return true; }
50
+ q('state').textContent = 'waking the in-weights model (about 4 min)...';
51
+ if (waking) return false; waking = true;
52
+ for (let i = 0; i < 40; i++) { await new Promise(r => setTimeout(r, 15000)); if (!root.isConnected) return false; if (await health()) { waking = false; q('state').textContent = 'GPU backend ready'; h.toast('GPU Lab: the in-weights model is awake'); return true; } }
53
+ waking = false; q('state').textContent = 'still waking; try again shortly'; return false;
54
+ }
55
+ ensureAwake();
56
+ q('run').onclick = async () => {
57
+ const out = q('out'), k = q('k').value, n = +q('n').value;
58
+ if (!(await health())) { out.innerHTML = '<span class="mut">The in-weights model is asleep to save cost. It is waking now (about 4 min). Agent Guard option 1 stays live meanwhile.</span>'; ensureAwake(); return; }
59
+ q('run').disabled = true; out.innerHTML = '<span class="mut">Running inside the model...</span>';
60
+ const t0 = performance.now();
61
+ try {
62
+ const r = await gpu('gpu', {kernel:k, data, n});
63
+ if (r.error) throw new Error(r.error);
64
+ const py = K[k].py(data), wall = (performance.now() - t0) / 1000;
65
+ const okPy = JSON.stringify(r.outputs) === JSON.stringify(py);
66
+ out.innerHTML = `<div class="grid"><div class="kv"><span class="mut">exact vs reference</span><b class="${r.equals_reference ? 'ok' : 'bad'}">${r.equals_reference ? '&#10003; exact' : '&#10007; differs'}</b></div>
67
+ <div class="kv"><span class="mut">token-exact vs executor</span><b class="${r.token_exact ? 'ok' : 'bad'}">${r.token_exact ? '&#10003;' : '&#10007;'}</b></div>
68
+ <div class="kv"><span class="mut">matches plain Python</span><b class="${okPy ? 'ok' : 'bad'}">${okPy ? '&#10003;' : '&#10007;'}</b></div>
69
+ <div class="kv"><span class="mut">model tokens</span><b>${(r.tokens || 0).toLocaleString('en-US')}</b></div>
70
+ <div class="kv"><span class="mut">GPU time in the model</span><b>${r.sec} s</b></div><div class="kv"><span class="mut">round trip</span><b>${wall.toFixed(1)} s</b></div></div>
71
+ <b style="display:block;margin-top:10px">Output</b><pre>${JSON.stringify(r.outputs)}</pre><b>Plain Python</b><pre>${JSON.stringify(py)}</pre>`;
72
+ } catch (e) {
73
+ out.innerHTML = `<span class="mut">${e.message === 'rate' ? 'Too many requests from your network; try again in a few minutes.' : 'The in-weights model is busy or waking. Please try again in a minute.'}</span>`;
74
+ ensureAwake();
75
+ } finally { q('run').disabled = false; }
76
+ };
77
+ }}));
78
+ })();