webgpu-profiler
v0.1.2
Published
Live GPU memory profiler for WebGPU. Patches GPUDevice once and gives you exact byte-level snapshots of every buffer and texture, plus an optional React HUD overlay.
Maintainers
Readme
webgpu-profiler
Live GPU memory profiler for WebGPU. One call patches the device, then every buffer and texture is tracked. Optional React HUD overlay.

npm install webgpu-profilerUse
import { autoInstrument } from "webgpu-profiler";
// Once, at boot, before any renderer is created.
if (process.env.NODE_ENV !== "production") autoInstrument();import { MemoryHUD } from "webgpu-profiler/react";
// Anywhere in your tree, dev-only:
{process.env.NODE_ENV !== "production" && <MemoryHUD />}That's it. The HUD finds the active instrumentation automatically.
What it does
autoInstrument() patches GPUAdapter.prototype.requestDevice so any
GPUDevice returned anywhere in the app gets its createBuffer and
createTexture wrapped. Those are the only two WebGPU JS-side allocation
entry points, so every buffer and texture is captured with its descriptor.
The HUD polls a snapshot every second and shows a copyable breakdown.
API
| Symbol | Purpose |
|---|---|
| autoInstrument(options?) | Patch the adapter prototype to auto-instrument every new device. Returns a disposer. |
| instrumentDevice(device) | Manually instrument a single device. Idempotent. Returns a DeviceInstrumentation handle. |
| getActiveInstrumentation() | Read the most recently registered handle (null if none). |
| subscribeActiveInstrumentation(cb) | Subscribe to changes in the active handle. |
| profileMemory(inst) | Build a MemoryReport snapshot from a handle. |
| reportToText(report) | Plain-text rendering for clipboard / bug reports. |
| textureDescriptorBytes(desc) | Byte calc for a single GPUTextureDescriptor. |
| resolveExtent(size) | Normalize a GPUExtent3D to { width, height, depth }. |
| MemoryHUD (from /react) | Overlay component. All props optional. |
MemoryHUD props: instrumentation?, refreshMs? (1000), corner?
("top-right" / "top-left" / "bottom-right" / "bottom-left"),
className?, style?.
Building your own UI
If you're not using React, getActiveInstrumentation() and
subscribeActiveInstrumentation() let you react to instrumentation
changes from any code:
import {
getActiveInstrumentation,
subscribeActiveInstrumentation,
profileMemory,
} from "webgpu-profiler";
const unsubscribe = subscribeActiveInstrumentation(() => {
const inst = getActiveInstrumentation();
if (inst) console.log(profileMemory(inst));
});What is not counted
- Canvas swapchain backbuffer (created by
context.configure(), notcreateTexture). - Driver-internal allocations: residency caches, MSAA backing, pipeline objects, bind group layouts, staging buffers that bypass the JS API. Always opaque to JS by design.
Compare against your browser's per-tab GPU memory readout
(Chrome Shift+Esc, "GPU Memory" column) to see the residual gap, which
is typically 5 to 15 percent.
Caveats
- WebGPU only. WebGL's allocation model differs significantly and is not supported.
- Depth-stencil formats (
depth24plus,depth32float-stencil8, etc.) are reported as their JS-API minimums. Real driver footprint is often larger due to alignment and separate stencil planes. - ASTC bytes-per-pixel reflect the format's block size. Some implementations may pad differently.
License
MIT (c) Redmond Riddell
