Humuhumu33 commited on
Commit
70592b3
Β·
verified Β·
1 Parent(s): e4b6a8f

keep-warm pulse: hold GPU boost clock while typing so casual chat decodes at boosted rate

Browse files
Files changed (1) hide show
  1. index.html +35 -0
index.html CHANGED
@@ -141,6 +141,41 @@ send.onclick = onSend;
141
  input.onkeydown = (e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); onSend(); } };
142
  input.oninput = () => { input.style.height = "auto"; input.style.height = Math.min(140, input.scrollHeight) + "px"; };
143
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  // ── SPEC-DECODE A/B HARNESS (?bench=spec) ── measures baseline greedy vs speculative on the operator's real
145
  // GPU across echo-heavy and free-form prompts: byte-identical check (G1), mean accepted tokens/verify (G2),
146
  // and decode tok/s for both. One load, one table β€” the honest verdict on whether spec-decode earns its place.
 
141
  input.onkeydown = (e) => { if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); onSend(); } };
142
  input.oninput = () => { input.style.height = "auto"; input.style.height = Math.min(140, input.scrollHeight) + "px"; };
143
 
144
+ // KEEP-WARM: casual chat lets the GPU cool between messages, so each reply decodes at a medium clock (~40ms/tok)
145
+ // instead of boosted (~20ms). While the user is typing/focused, run a tiny THROWAWAY GPU compute (scratch buffer,
146
+ // never touches the model KV) to hold the clock up β†’ the next message decodes boosted. Pauses during generation
147
+ // and when the tab is hidden. This is the idle-cooling fix for sustained high tok/s in normal use.
148
+ let _warmDev = null, _warmPipe = null, _warmBg = null, _warmBusy = false, _warmTimer = null;
149
+ function ensureWarmKit() {
150
+ if (_warmPipe) return true;
151
+ const dev = engine && engine._gpu && engine._gpu._dev && engine._gpu._dev();
152
+ if (!dev) return false;
153
+ _warmDev = dev;
154
+ const WGSL = `@group(0) @binding(0) var<storage,read_write> b: array<vec4<f32>>;
155
+ @compute @workgroup_size(64) fn main(@builtin(global_invocation_id) g:vec3<u32>){
156
+ let i = g.x % 65536u; var a = b[i]; for(var k=0u;k<1024u;k++){ a = a*1.0000001 + vec4<f32>(0.5); } b[i] = a; }`;
157
+ try {
158
+ _warmPipe = dev.createComputePipeline({ layout: "auto", compute: { module: dev.createShaderModule({ code: WGSL }), entryPoint: "main" } });
159
+ const buf = dev.createBuffer({ size: 65536 * 16, usage: GPUBufferUsage.STORAGE });
160
+ _warmBg = dev.createBindGroup({ layout: _warmPipe.getBindGroupLayout(0), entries: [{ binding: 0, resource: { buffer: buf } }] });
161
+ } catch (e) { console.warn("warmkit", e); return false; }
162
+ return true;
163
+ }
164
+ async function warmPulse(ms = 220) {
165
+ if (busy || _warmBusy || document.hidden || !armed) return; // never compete with real inference
166
+ if (!ensureWarmKit()) return;
167
+ _warmBusy = true;
168
+ try {
169
+ const end = performance.now() + ms;
170
+ while (performance.now() < end && !busy && !document.hidden) {
171
+ const e = _warmDev.createCommandEncoder(); const p = e.beginComputePass(); p.setPipeline(_warmPipe); p.setBindGroup(0, _warmBg); p.dispatchWorkgroups(4096); p.end(); _warmDev.queue.submit([e.finish()]);
172
+ await _warmDev.queue.onSubmittedWorkDone();
173
+ }
174
+ } catch (e) { /* ignore β€” best effort */ } finally { _warmBusy = false; }
175
+ }
176
+ input.addEventListener("focus", () => warmPulse(300));
177
+ input.addEventListener("keydown", () => { clearTimeout(_warmTimer); _warmTimer = setTimeout(() => warmPulse(220), 50); });
178
+
179
  // ── SPEC-DECODE A/B HARNESS (?bench=spec) ── measures baseline greedy vs speculative on the operator's real
180
  // GPU across echo-heavy and free-form prompts: byte-identical check (G1), mean accepted tokens/verify (G2),
181
  // and decode tok/s for both. One load, one table β€” the honest verdict on whether spec-decode earns its place.