Download memory_test.html from LJTSG/gemma-webgpu: direct link, hf CLI and curl.
- Browser
- Download file 3.13 kB
-
https://huggingface.co/LJTSG/gemma-webgpu/resolve/main/memory_test.html
- Command line
-
hf download hf://LJTSG/gemma-webgpu/memory_test.html
-
curl -L -o memory_test.html https://huggingface.co/LJTSG/gemma-webgpu/resolve/main/memory_test.html
3.13 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>WebGPU Memory Ceiling Test — Strix Halo</title> | |
| <style> | |
| body { font-family: monospace; background: #0d1117; color: #c9d1d9; padding: 24px; } | |
| h1 { color: #58a6ff; } | |
| #log { background: #010409; border: 1px solid #30363d; padding: 10px; white-space: pre-wrap; max-height: 600px; overflow-y: auto; } | |
| button { background: #238636; color: white; border: none; padding: 8px 16px; cursor: pointer; margin: 4px; border-radius: 4px; } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>WebGPU Memory Ceiling Test</h1> | |
| <p>Allocates increasingly large GPU buffers to find the maximum WebGPU memory on Strix Halo.</p> | |
| <button onclick="runTest()">Run Memory Test</button> | |
| <div id="log"></div> | |
| <script> | |
| const log = document.getElementById('log'); | |
| function l(msg) { log.textContent += msg + '\n'; log.scrollTop = log.scrollHeight; } | |
| async function runTest() { | |
| if (!navigator.gpu) { l('WebGPU not supported'); return; } | |
| const adapter = await navigator.gpu.requestAdapter(); | |
| if (!adapter) { l('No adapter'); return; } | |
| const limits = adapter.limits; | |
| l('=== Adapter Limits ==='); | |
| l('maxBufferSize: ' + (limits.maxBufferSize / 1024 / 1024 / 1024).toFixed(2) + ' GB'); | |
| l('maxStorageBufferBindingSize: ' + (limits.maxStorageBufferBindingSize / 1024 / 1024).toFixed(0) + ' MB'); | |
| const device = await adapter.requestDevice({ | |
| requiredLimits: { | |
| maxBufferSize: limits.maxBufferSize, | |
| maxStorageBufferBindingSize: limits.maxStorageBufferBindingSize, | |
| } | |
| }); | |
| device.lost.then(info => l('DEVICE LOST: ' + info.reason + ' ' + info.message)); | |
| l('\n=== Allocation Test ==='); | |
| l('Allocating 512MB buffers until failure...'); | |
| const buffers = []; | |
| const CHUNK = 512 * 1024 * 1024; // 512 MB | |
| let totalMB = 0; | |
| for (let i = 0; i < 128; i++) { // max 64GB | |
| try { | |
| device.pushErrorScope('out-of-memory'); | |
| device.pushErrorScope('validation'); | |
| const buf = device.createBuffer({ | |
| size: CHUNK, | |
| usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST, | |
| label: 'test_' + i, | |
| }); | |
| buffers.push(buf); | |
| totalMB += 512; | |
| const valErr = await device.popErrorScope(); | |
| const oomErr = await device.popErrorScope(); | |
| if (valErr) { l('Validation error at ' + totalMB + ' MB: ' + valErr.message); break; } | |
| if (oomErr) { l('OOM error at ' + totalMB + ' MB: ' + oomErr.message); break; } | |
| // Write 4 bytes to force commitment (must be multiple of 4) | |
| device.queue.writeBuffer(buf, 0, new Uint32Array([42])); | |
| await device.queue.onSubmittedWorkDone(); | |
| l('Allocated: ' + totalMB + ' MB (' + (totalMB / 1024).toFixed(1) + ' GB) - ' + (i + 1) + ' buffers'); | |
| } catch (e) { | |
| l('EXCEPTION at ' + totalMB + ' MB: ' + e.message); | |
| break; | |
| } | |
| } | |
| l('\n=== RESULT ==='); | |
| l('Maximum WebGPU allocation: ' + totalMB + ' MB (' + (totalMB / 1024).toFixed(1) + ' GB)'); | |
| l('Buffers allocated: ' + buffers.length); | |
| l('Buffer size: 512 MB each'); | |
| // Cleanup | |
| for (const buf of buffers) buf.destroy(); | |
| l('\nBuffers destroyed. Test complete.'); | |
| } | |
| </script> | |
| </body> | |
| </html> | |