LJTSG/gemma-webgpu-thinking-engine
022
1<!DOCTYPE html>2<html lang="en">3<head>4<meta charset="UTF-8">5<title>WebGPU Memory Ceiling Test — Strix Halo</title>6<style>7body { font-family: monospace; background: #0d1117; color: #c9d1d9; padding: 24px; }8h1 { color: #58a6ff; }9#log { background: #010409; border: 1px solid #30363d; padding: 10px; white-space: pre-wrap; max-height: 600px; overflow-y: auto; }10button { background: #238636; color: white; border: none; padding: 8px 16px; cursor: pointer; margin: 4px; border-radius: 4px; }11</style>12</head>13<body>14<h1>WebGPU Memory Ceiling Test</h1>15<p>Allocates increasingly large GPU buffers to find the maximum WebGPU memory on Strix Halo.</p>16<button onclick="runTest()">Run Memory Test</button>17<div id="log"></div>18 19<script>20const log = document.getElementById('log');21function l(msg) { log.textContent += msg + '\n'; log.scrollTop = log.scrollHeight; }22 23async function runTest() {24 if (!navigator.gpu) { l('WebGPU not supported'); return; }25 const adapter = await navigator.gpu.requestAdapter();26 if (!adapter) { l('No adapter'); return; }27 28 const limits = adapter.limits;29 l('=== Adapter Limits ===');30 l('maxBufferSize: ' + (limits.maxBufferSize / 1024 / 1024 / 1024).toFixed(2) + ' GB');31 l('maxStorageBufferBindingSize: ' + (limits.maxStorageBufferBindingSize / 1024 / 1024).toFixed(0) + ' MB');32 33 const device = await adapter.requestDevice({34 requiredLimits: {35 maxBufferSize: limits.maxBufferSize,36 maxStorageBufferBindingSize: limits.maxStorageBufferBindingSize,37 }38 });39 40 device.lost.then(info => l('DEVICE LOST: ' + info.reason + ' ' + info.message));41 42 l('\n=== Allocation Test ===');43 l('Allocating 512MB buffers until failure...');44 45 const buffers = [];46 const CHUNK = 512 * 1024 * 1024; // 512 MB47 let totalMB = 0;48 49 for (let i = 0; i < 128; i++) { // max 64GB50 try {51 device.pushErrorScope('out-of-memory');52 device.pushErrorScope('validation');53 54 const buf = device.createBuffer({55 size: CHUNK,56 usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,57 label: 'test_' + i,58 });59 buffers.push(buf);60 totalMB += 512;61 62 const valErr = await device.popErrorScope();63 const oomErr = await device.popErrorScope();64 65 if (valErr) { l('Validation error at ' + totalMB + ' MB: ' + valErr.message); break; }66 if (oomErr) { l('OOM error at ' + totalMB + ' MB: ' + oomErr.message); break; }67 68 // Write 4 bytes to force commitment (must be multiple of 4)69 device.queue.writeBuffer(buf, 0, new Uint32Array([42]));70 await device.queue.onSubmittedWorkDone();71 72 l('Allocated: ' + totalMB + ' MB (' + (totalMB / 1024).toFixed(1) + ' GB) - ' + (i + 1) + ' buffers');73 74 } catch (e) {75 l('EXCEPTION at ' + totalMB + ' MB: ' + e.message);76 break;77 }78 }79 80 l('\n=== RESULT ===');81 l('Maximum WebGPU allocation: ' + totalMB + ' MB (' + (totalMB / 1024).toFixed(1) + ' GB)');82 l('Buffers allocated: ' + buffers.length);83 l('Buffer size: 512 MB each');84 85 // Cleanup86 for (const buf of buffers) buf.destroy();87 l('\nBuffers destroyed. Test complete.');88}89</script>90</body>91</html>92 