Spaces:
Running
Running
keep-warm pulse: hold GPU boost clock while typing so casual chat decodes at boosted rate
Browse files- 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.
|