@plasius/gpu-debug
v0.1.2
Published
Opt-in GPU debug instrumentation for tracked memory, dispatch, queue, and frame-budget metrics in Plasius WebGPU runtimes.
Maintainers
Readme
@plasius/gpu-debug
Opt-in GPU debug instrumentation for Plasius WebGPU runtimes. The package tracks caller-reported allocations, queue pressure, dispatch samples, and frame-budget signals without claiming portable WebGPU exposes authoritative raw hardware counters.
Apache-2.0. ESM + CJS builds. TypeScript types included.
Install
npm install @plasius/gpu-debugBrowser Demo
npm run demoThen open http://localhost:8000/gpu-debug/demo/.
npm run demo now visualizes debug telemetry against the shared 3D harbor
scene from @plasius/gpu-shared, while npm run demo:example keeps the
console example path.
What It Solves
- Exposes tracked GPU allocation totals by owner and category.
- Records queue depth, dispatch timings, and estimated invocation counts.
- Records DAG-ready lane depth and dependency-unlock activity when integrations supply those samples.
- Summarizes frame-budget pressure alongside dispatch activity.
- Accepts optional host-supplied hardware hints such as memory capacity or core count when a native or privileged runtime can provide them.
- Defaults to disabled so clients opt into the overhead explicitly.
- Keeps analytics/export outside the package; route any remote delivery through
@plasius/analytics.
Usage
import { createGpuDebugSession } from "@plasius/gpu-debug";
const debug = createGpuDebugSession({
enabled: true,
adapter: {
label: "Apple M3 Max",
maxComputeInvocationsPerWorkgroup: 1024,
memoryCapacityHintBytes: 48 * 1024 * 1024 * 1024,
coreCountHint: 40,
},
});
const releaseParticles = debug.trackAllocation({
id: "particles.buffer",
owner: "particles",
category: "buffer",
sizeBytes: 8 * 1024 * 1024,
label: "Particle state",
});
debug.recordQueue({
owner: "post-processing",
queueClass: "post-processing",
depth: 24,
capacity: 64,
frameId: "frame-101",
});
debug.recordReadyLane({
owner: "lighting",
queueClass: "lighting",
laneId: "priority-4",
priority: 4,
depth: 5,
capacity: 8,
frameId: "frame-101",
});
debug.recordDispatch({
id: "dispatch-101-post",
owner: "post-processing",
queueClass: "post-processing",
jobType: "post.process",
frameId: "frame-101",
durationMs: 1.8,
workgroups: { x: 48, y: 27, z: 1 },
workgroupSize: { x: 8, y: 8, z: 1 },
bytesRead: 2_097_152,
bytesWritten: 1_048_576,
});
debug.recordDependencyUnlock({
owner: "lighting",
queueClass: "lighting",
sourceJobType: "lighting.direct",
unlockedJobType: "lighting.resolve",
priority: 2,
frameId: "frame-101",
});
debug.recordFrame({
frameId: "frame-101",
frameTimeMs: 16.9,
targetFrameTimeMs: 16.67,
gpuBusyMs: 8.2,
});
debug.recordPipelinePhase({
owner: "physics",
pipeline: "simulation",
stage: "worldSnapshot",
frameId: "frame-101",
durationMs: 0.7,
snapshotAgeFrames: 0,
snapshotAgeMs: 0,
});
console.log(debug.getSnapshot());
releaseParticles();Hardware Counter Policy
Portable WebGPU does not currently guarantee authoritative access to:
- raw GPU core count,
- total adapter memory,
- vendor-specific live occupancy counters.
@plasius/gpu-debug therefore exposes:
- tracked allocations reported by the caller,
- estimated invocation and workgroup totals from dispatch metadata,
- queue-depth and frame-budget summaries,
- DAG-ready lane and dependency-unlock summaries when integrations report them,
- pipeline phase and snapshot-lag summaries when integrations report them,
- optional hardware hints provided by the host runtime.
If a native shell, browser extension, or proprietary platform layer can provide accurate hints, pass them in explicitly. Otherwise treat the session snapshot as an inferred optimization aid rather than a full hardware profiler.
API
createGpuDebugSession(options?)estimateDispatchInvocations(sample)
Worker and Frame Correlation
When worker-based packages use @plasius/gpu-worker, prefer passing stable
metadata and a shared frameId through the worker loop telemetry hooks.
import { createGpuDebugSession } from "@plasius/gpu-debug";
import { createWorkerLoop } from "@plasius/gpu-worker";
const debug = createGpuDebugSession({ enabled: true });
const loop = createWorkerLoop({
device,
frameId: () => `frame-${frameNumber}`,
worker: {
pipeline: workerPipeline,
workgroups: [2, 1, 1],
workgroupSize: 64,
owner: "particles",
queueClass: "simulation",
jobType: "worker.dequeue",
},
jobs: [
{
pipeline: simulatePipeline,
workgroupCount: [64, 1, 1],
workgroupSize: [64, 1, 1],
owner: "particles",
queueClass: "simulation",
jobType: "particles.simulate",
},
],
telemetry: {
onDispatch(sample) {
debug.recordDispatch({
owner: sample.owner,
queueClass: sample.queueClass,
jobType: sample.jobType,
frameId: sample.frameId,
workgroups: sample.workgroups,
workgroupSize: sample.workgroupSize,
});
},
},
});
debug.recordFrame({
frameId: `frame-${frameNumber}`,
frameTimeMs,
targetFrameTimeMs,
});This keeps the package local-first: @plasius/gpu-worker emits local samples,
@plasius/gpu-debug stores and summarizes them, and any remote export still
belongs to @plasius/analytics.
For DAG-enabled integrations, callers can also feed ready-lane and dependency unlock data into the same session:
debug.recordReadyLane({
owner: "lighting",
queueClass: "lighting",
laneId: "priority-3",
priority: 3,
depth: 2,
capacity: 8,
frameId: `frame-${frameNumber}`,
});
debug.recordDependencyUnlock({
owner: "lighting",
queueClass: "lighting",
sourceJobType: "lighting.cache",
unlockedJobType: "lighting.resolve",
priority: 2,
frameId: `frame-${frameNumber}`,
});
debug.recordPipelinePhase({
owner: "physics",
pipeline: "simulation",
stage: "worldSnapshot",
frameId: `frame-${frameNumber}`,
durationMs: 0.8,
});Analytics Integration
This package does not ship its own analytics client. If snapshots or events need
to leave the local runtime, route them through @plasius/analytics.
Demo
Run the console demo locally:
npm run demoSee demo/README.md for details.
Development Checks
npm run lint
npm run typecheck
npm run test:coverage
npm run build
npm run pack:checkRelease Automation
GitHub Actions now carries the package delivery path:
- CI runs on pushes and pull requests to enforce lint, typecheck, audit, build, coverage, and package verification.
- CD publishes to npm only through the manual GitHub workflow.
- A scheduled workflow opens monthly npm audit-fix pull requests.
Files
src/types.ts: public debug types and snapshot contracts.src/session.ts: opt-in debug session runtime and summary generation.src/validation.ts: shared runtime validation helpers.tests/*.test.ts: unit coverage for session behavior and bounded histories.docs/adrs/*: package architecture decisions.docs/tdrs/*: implementation design records.docs/design/*: integration and NFR design detail.
