Diagnosing WebGPU Timestamp Query Jitter: A Structured Troubleshooting Guide
Diagnose and fix jitter in WebGPU timestamp queries. Follow a step‑by‑step check list to ensure monotonic timestamps, proper fences, and correct buffer usage for accurate frame timing.
05 Mar 2026, 06:06 UTC

Recognizable Condition
When you log GPU timestamps in a WebGPU render loop, you may see values that jump backward or fluctuate wildly. Frame‑time graphs become noisy and unreliable. This indicates that the timestamp data you read is either stale or not properly synchronized.
Root Causes & Quick Diagnostics
| Cause | Symptom | Check | Fix |
|---|---|---|---|
| Missing fence or queue submission after timestamp writes | Non‑monotonic timestamps | Look for queue.onSubmittedWorkDone() or a GPUFence after the encoder finishes. | Insert a fence or await queue.onSubmittedWorkDone() before mapping. |
| Reusing resolve buffer before GPU completes writing | Stale or duplicate timestamp values | Check if the same GPUBuffer is mapped for read while a previous frame is still pending. | Use a distinct buffer per frame or wait for the previous map promise to resolve. |
| Insufficient query set size (e.g., only one query) | Timestamp values overlap between frames | Inspect GPUQuerySetDescriptor.size relative to frames in flight. | Allocate at least 2 × maxFramesInFlight queries. |
| Using MAP_READ without MAP_WRITE on a reused buffer | Random jitter in resolved values | Verify buffer usage flags: GPUBufferUsage.MAP_READ | GPUBufferUsage.QUERY_RESOLVE. | Add MAP_WRITE if you intend to overwrite the buffer each frame. |
Ordered Checks & Fixes
- Validate Query Set Size
Allocate enough queries for all concurrent frames. Example for double‑buffering:
const querySet = device.createQuerySet({ type: "timestamp", count: 4, // 2 queries per frame × 2 frames }); - Ensure Proper Synchronization
After submitting commands that write timestamps, wait for completion before mapping the resolve buffer:
const commandEncoder = device.createCommandEncoder(); commandEncoder.writeTimestamp(querySet, 0); // start // … render passes … commandEncoder.writeTimestamp(querySet, 1); // end const resolveBuffer = device.createBuffer({ size: 8, // 8 bytes per timestamp usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.MAP_READ, }); commandEncoder.resolveQuerySet(querySet, 0, 2, resolveBuffer, 0); const commandBuffer = commandEncoder.finish(); queue.submit([commandBuffer]); // Wait for GPU to finish the work that writes the timestamps await queue.onSubmittedWorkDone(); // Now map for reading const [arrayBuffer] = await resolveBuffer.mapAsync(GPUMapMode.READ); const timestamps = new BigUint64Array(arrayBuffer); console.log(`Δt = ${timestamps[1] - timestamps[0]} ns`);Without the
await queue.onSubmittedWorkDone()(or a fence), the buffer may be read before the GPU has written the new timestamps. - Check Buffer Usage Flags
When reusing a buffer, include
MAP_WRITEif you plan to overwrite it each frame. MixingMAP_READandMAP_WRITEwithout explicit sync can cause races. - Verify Resolve Buffer Reuse
Each frame should map a fresh buffer or wait for the previous map promise to resolve. A quick test: log the promise’s completion time and compare it to the frame interval.
- Confirm Monotonicity
After applying the above fixes, run a short test: record start/end timestamps for 100 frames and plot the delta. The values should be non‑negative and relatively stable.
Escalation Criteria
- If jitter persists after all checks, verify that the GPU driver supports
timestamp queries(some older drivers may have bugs). - Check the WebGPU implementation logs for “timestamp query unsupported” messages.
- Consider filing a bug against the browser vendor if the behavior is consistent across devices.
Limitations & Practical Checks
Timestamp queries are a feature of the GPU driver and hardware. On very low‑end GPUs, the timestamp resolution may be coarse, leading to apparent jitter. Always compare against a baseline: run the same code on a known‑good device (e.g., recent Intel or AMD GPU) to confirm that the jitter is not hardware‑specific.
After each change, re‑run the verification test. If the delta values become non‑negative and fluctuate within ±10% of the mean, the issue is likely resolved.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.