@plasius/gpu-debug 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +231 -0
- package/LICENSE +203 -0
- package/README.md +332 -0
- package/dist/index.cjs +993 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +295 -0
- package/dist/index.d.ts +295 -0
- package/dist/index.js +961 -0
- package/dist/index.js.map +1 -0
- package/legal/CLA-REGISTRY.csv +2 -0
- package/legal/CLA.md +22 -0
- package/legal/CORPORATE_CLA.md +57 -0
- package/legal/INDIVIDUAL_CLA.md +91 -0
- package/package.json +99 -0
package/README.md
ADDED
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
# @plasius/gpu-debug
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@plasius/gpu-debug)
|
|
4
|
+
[](https://github.com/Plasius-LTD/gpu-debug/actions/workflows/ci.yml)
|
|
5
|
+
[](https://codecov.io/gh/Plasius-LTD/gpu-debug)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
[](./CODE_OF_CONDUCT.md)
|
|
8
|
+
[](./SECURITY.md)
|
|
9
|
+
[](./CHANGELOG.md)
|
|
10
|
+
|
|
11
|
+
Opt-in GPU debug instrumentation for Plasius WebGPU runtimes. The package tracks
|
|
12
|
+
caller-reported allocations, queue pressure, dispatch samples, and frame-budget
|
|
13
|
+
signals without claiming portable WebGPU exposes authoritative raw hardware
|
|
14
|
+
counters.
|
|
15
|
+
|
|
16
|
+
Apache-2.0. ESM + CJS builds. TypeScript types included.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @plasius/gpu-debug
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Browser Demo
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm run demo
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then open `http://localhost:8000/gpu-debug/demo/`.
|
|
31
|
+
|
|
32
|
+
`npm run demo` now visualizes debug telemetry against the shared 3D harbor
|
|
33
|
+
scene from the public `@plasius/gpu-shared` package surface, while
|
|
34
|
+
`npm run demo:example` keeps the console example path.
|
|
35
|
+
|
|
36
|
+
## What It Solves
|
|
37
|
+
|
|
38
|
+
- Exposes tracked GPU allocation totals by owner and category.
|
|
39
|
+
- Records queue depth, dispatch timings, and estimated invocation counts.
|
|
40
|
+
- Records DAG-ready lane depth and dependency-unlock activity when integrations
|
|
41
|
+
supply those samples.
|
|
42
|
+
- Records compact wavefront queue, hit-buffer, and termination summaries
|
|
43
|
+
without dumping raw GPU buffers.
|
|
44
|
+
- Summarizes frame-budget pressure alongside dispatch activity.
|
|
45
|
+
- Accepts optional host-supplied hardware hints such as memory capacity or core
|
|
46
|
+
count when a native or privileged runtime can provide them.
|
|
47
|
+
- Defaults to disabled so clients opt into the overhead explicitly.
|
|
48
|
+
- Keeps analytics/export outside the package; route any remote delivery through
|
|
49
|
+
`@plasius/analytics`.
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import {
|
|
55
|
+
createGpuDebugSession,
|
|
56
|
+
gpuDebugQueueClasses,
|
|
57
|
+
gpuPipelinePhases,
|
|
58
|
+
gpuResourceCategories,
|
|
59
|
+
summarizeWavefrontTelemetry,
|
|
60
|
+
} from "@plasius/gpu-debug";
|
|
61
|
+
|
|
62
|
+
const debug = createGpuDebugSession({
|
|
63
|
+
enabled: true,
|
|
64
|
+
adapter: {
|
|
65
|
+
label: "Apple M3 Max",
|
|
66
|
+
maxComputeInvocationsPerWorkgroup: 1024,
|
|
67
|
+
memoryCapacityHintBytes: 48 * 1024 * 1024 * 1024,
|
|
68
|
+
coreCountHint: 40,
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
console.log(gpuDebugQueueClasses);
|
|
73
|
+
console.log(gpuPipelinePhases);
|
|
74
|
+
console.log(gpuResourceCategories);
|
|
75
|
+
|
|
76
|
+
const releaseParticles = debug.trackAllocation({
|
|
77
|
+
id: "particles.buffer",
|
|
78
|
+
owner: "particles",
|
|
79
|
+
category: "buffer",
|
|
80
|
+
sizeBytes: 8 * 1024 * 1024,
|
|
81
|
+
label: "Particle state",
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
debug.recordQueue({
|
|
85
|
+
owner: "post-processing",
|
|
86
|
+
queueClass: "post-processing",
|
|
87
|
+
depth: 24,
|
|
88
|
+
capacity: 64,
|
|
89
|
+
frameId: "frame-101",
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
debug.recordReadyLane({
|
|
93
|
+
owner: "lighting",
|
|
94
|
+
queueClass: "lighting",
|
|
95
|
+
laneId: "priority-4",
|
|
96
|
+
priority: 4,
|
|
97
|
+
depth: 5,
|
|
98
|
+
capacity: 8,
|
|
99
|
+
frameId: "frame-101",
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
debug.recordDispatch({
|
|
103
|
+
id: "dispatch-101-post",
|
|
104
|
+
owner: "post-processing",
|
|
105
|
+
queueClass: "post-processing",
|
|
106
|
+
jobType: "post.process",
|
|
107
|
+
frameId: "frame-101",
|
|
108
|
+
durationMs: 1.8,
|
|
109
|
+
workgroups: { x: 48, y: 27, z: 1 },
|
|
110
|
+
workgroupSize: { x: 8, y: 8, z: 1 },
|
|
111
|
+
bytesRead: 2_097_152,
|
|
112
|
+
bytesWritten: 1_048_576,
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
debug.recordDependencyUnlock({
|
|
116
|
+
owner: "lighting",
|
|
117
|
+
queueClass: "lighting",
|
|
118
|
+
sourceJobType: "lighting.direct",
|
|
119
|
+
unlockedJobType: "lighting.resolve",
|
|
120
|
+
priority: 2,
|
|
121
|
+
frameId: "frame-101",
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
debug.recordFrame({
|
|
125
|
+
frameId: "frame-101",
|
|
126
|
+
frameTimeMs: 16.9,
|
|
127
|
+
targetFrameTimeMs: 16.67,
|
|
128
|
+
gpuBusyMs: 8.2,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
debug.recordPipelinePhase({
|
|
132
|
+
owner: "physics",
|
|
133
|
+
pipeline: "simulation",
|
|
134
|
+
stage: "worldSnapshot",
|
|
135
|
+
frameId: "frame-101",
|
|
136
|
+
durationMs: 0.7,
|
|
137
|
+
snapshotAgeFrames: 0,
|
|
138
|
+
snapshotAgeMs: 0,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
debug.recordWavefrontTelemetry({
|
|
142
|
+
owner: "wavefront",
|
|
143
|
+
queueClass: "render",
|
|
144
|
+
frameId: "frame-101",
|
|
145
|
+
bounceDepth: 0,
|
|
146
|
+
activeRayCount: 128,
|
|
147
|
+
queueCapacity: 256,
|
|
148
|
+
hitBufferCount: 92,
|
|
149
|
+
terminationReasons: [
|
|
150
|
+
{ reason: "emissive", count: 10 },
|
|
151
|
+
{ reason: "environment", count: 4 },
|
|
152
|
+
],
|
|
153
|
+
hitKinds: [
|
|
154
|
+
{ kind: "triangle", count: 78 },
|
|
155
|
+
{ kind: "environment", count: 4 },
|
|
156
|
+
],
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const snapshot = debug.getSnapshot();
|
|
160
|
+
console.log(snapshot);
|
|
161
|
+
console.log(summarizeWavefrontTelemetry(snapshot.wavefront));
|
|
162
|
+
releaseParticles();
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Hardware Counter Policy
|
|
166
|
+
|
|
167
|
+
Portable WebGPU does not currently guarantee authoritative access to:
|
|
168
|
+
|
|
169
|
+
- raw GPU core count,
|
|
170
|
+
- total adapter memory,
|
|
171
|
+
- vendor-specific live occupancy counters.
|
|
172
|
+
|
|
173
|
+
`@plasius/gpu-debug` therefore exposes:
|
|
174
|
+
|
|
175
|
+
- tracked allocations reported by the caller,
|
|
176
|
+
- estimated invocation and workgroup totals from dispatch metadata,
|
|
177
|
+
- queue-depth and frame-budget summaries,
|
|
178
|
+
- DAG-ready lane and dependency-unlock summaries when integrations report them,
|
|
179
|
+
- pipeline phase and snapshot-lag summaries when integrations report them,
|
|
180
|
+
- wavefront queue, hit-buffer, termination, and bounce-depth summaries when
|
|
181
|
+
integrations report compact telemetry,
|
|
182
|
+
- optional hardware hints provided by the host runtime.
|
|
183
|
+
|
|
184
|
+
If a native shell, browser extension, or proprietary platform layer can provide
|
|
185
|
+
accurate hints, pass them in explicitly. Otherwise treat the session snapshot as
|
|
186
|
+
an inferred optimization aid rather than a full hardware profiler.
|
|
187
|
+
|
|
188
|
+
## API
|
|
189
|
+
|
|
190
|
+
- `createGpuDebugSession(options?)`
|
|
191
|
+
- `estimateDispatchInvocations(sample)`
|
|
192
|
+
- `gpuDebugQueueClasses`
|
|
193
|
+
- `gpuPipelinePhases`
|
|
194
|
+
- `gpuResourceCategories`
|
|
195
|
+
- `summarizeWavefrontTelemetry(snapshot.wavefront)`
|
|
196
|
+
|
|
197
|
+
The exported constants are the docs-first enum contract for integrations that
|
|
198
|
+
need to validate or surface queue classes, pipeline phases, or tracked resource
|
|
199
|
+
categories without importing internal validation helpers.
|
|
200
|
+
|
|
201
|
+
## Worker and Frame Correlation
|
|
202
|
+
|
|
203
|
+
When worker-based packages use `@plasius/gpu-worker`, prefer passing stable
|
|
204
|
+
metadata and a shared `frameId` through the worker loop telemetry hooks.
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
import { createGpuDebugSession } from "@plasius/gpu-debug";
|
|
208
|
+
import { createWorkerLoop } from "@plasius/gpu-worker";
|
|
209
|
+
|
|
210
|
+
const debug = createGpuDebugSession({ enabled: true });
|
|
211
|
+
|
|
212
|
+
const loop = createWorkerLoop({
|
|
213
|
+
device,
|
|
214
|
+
frameId: () => `frame-${frameNumber}`,
|
|
215
|
+
worker: {
|
|
216
|
+
pipeline: workerPipeline,
|
|
217
|
+
workgroups: [2, 1, 1],
|
|
218
|
+
workgroupSize: 64,
|
|
219
|
+
owner: "particles",
|
|
220
|
+
queueClass: "simulation",
|
|
221
|
+
jobType: "worker.dequeue",
|
|
222
|
+
},
|
|
223
|
+
jobs: [
|
|
224
|
+
{
|
|
225
|
+
pipeline: simulatePipeline,
|
|
226
|
+
workgroupCount: [64, 1, 1],
|
|
227
|
+
workgroupSize: [64, 1, 1],
|
|
228
|
+
owner: "particles",
|
|
229
|
+
queueClass: "simulation",
|
|
230
|
+
jobType: "particles.simulate",
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
telemetry: {
|
|
234
|
+
onDispatch(sample) {
|
|
235
|
+
debug.recordDispatch({
|
|
236
|
+
owner: sample.owner,
|
|
237
|
+
queueClass: sample.queueClass,
|
|
238
|
+
jobType: sample.jobType,
|
|
239
|
+
frameId: sample.frameId,
|
|
240
|
+
workgroups: sample.workgroups,
|
|
241
|
+
workgroupSize: sample.workgroupSize,
|
|
242
|
+
});
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
debug.recordFrame({
|
|
248
|
+
frameId: `frame-${frameNumber}`,
|
|
249
|
+
frameTimeMs,
|
|
250
|
+
targetFrameTimeMs,
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
This keeps the package local-first: `@plasius/gpu-worker` emits local samples,
|
|
255
|
+
`@plasius/gpu-debug` stores and summarizes them, and any remote export still
|
|
256
|
+
belongs to `@plasius/analytics`.
|
|
257
|
+
|
|
258
|
+
For DAG-enabled integrations, callers can also feed ready-lane and dependency
|
|
259
|
+
unlock data into the same session:
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
debug.recordReadyLane({
|
|
263
|
+
owner: "lighting",
|
|
264
|
+
queueClass: "lighting",
|
|
265
|
+
laneId: "priority-3",
|
|
266
|
+
priority: 3,
|
|
267
|
+
depth: 2,
|
|
268
|
+
capacity: 8,
|
|
269
|
+
frameId: `frame-${frameNumber}`,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
debug.recordDependencyUnlock({
|
|
273
|
+
owner: "lighting",
|
|
274
|
+
queueClass: "lighting",
|
|
275
|
+
sourceJobType: "lighting.cache",
|
|
276
|
+
unlockedJobType: "lighting.resolve",
|
|
277
|
+
priority: 2,
|
|
278
|
+
frameId: `frame-${frameNumber}`,
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
debug.recordPipelinePhase({
|
|
282
|
+
owner: "physics",
|
|
283
|
+
pipeline: "simulation",
|
|
284
|
+
stage: "worldSnapshot",
|
|
285
|
+
frameId: `frame-${frameNumber}`,
|
|
286
|
+
durationMs: 0.8,
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Analytics Integration
|
|
291
|
+
|
|
292
|
+
This package does not ship its own analytics client. If snapshots or events need
|
|
293
|
+
to leave the local runtime, route them through `@plasius/analytics`.
|
|
294
|
+
|
|
295
|
+
## Demo
|
|
296
|
+
|
|
297
|
+
Run the console demo locally:
|
|
298
|
+
|
|
299
|
+
```bash
|
|
300
|
+
npm run demo
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
See [demo/README.md](./demo/README.md) for details.
|
|
304
|
+
|
|
305
|
+
## Development Checks
|
|
306
|
+
|
|
307
|
+
```bash
|
|
308
|
+
npm run lint
|
|
309
|
+
npm run typecheck
|
|
310
|
+
npm run test:coverage
|
|
311
|
+
npm run build
|
|
312
|
+
npm run pack:check
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Release Automation
|
|
316
|
+
|
|
317
|
+
GitHub Actions now carries the package delivery path:
|
|
318
|
+
|
|
319
|
+
- CI runs on pushes and pull requests to enforce lint, typecheck, audit, build,
|
|
320
|
+
coverage, and package verification.
|
|
321
|
+
- CD publishes to npm only through the manual GitHub workflow.
|
|
322
|
+
- A scheduled workflow opens monthly npm audit-fix pull requests.
|
|
323
|
+
|
|
324
|
+
## Files
|
|
325
|
+
|
|
326
|
+
- `src/types.ts`: public debug types and snapshot contracts.
|
|
327
|
+
- `src/session.ts`: opt-in debug session runtime and summary generation.
|
|
328
|
+
- `src/validation.ts`: shared runtime validation helpers.
|
|
329
|
+
- `tests/*.test.ts`: unit coverage for session behavior and bounded histories.
|
|
330
|
+
- `docs/adrs/*`: package architecture decisions.
|
|
331
|
+
- `docs/tdrs/*`: implementation design records.
|
|
332
|
+
- `docs/design/*`: integration and NFR design detail.
|