Original https://github.com/OmarShehata/webgpu-compute-rasterizer/blob/main/how-to-use-timestamp-queries.md
This article shows how to use WebGPU's timestamp-query function to calculate the execution time of your GPU instructions.
In WebGPU, timestamp querying is an optional feature, not necessarily available in all implementations. As of this writing, it is disabled on browsers for security reasons (see gpuweb/gpuweb #2218 for specific reasons)
Overview
The following is a brief introduction to the process of timestamp query:
- When requesting a device object, add
timestamp-query
function request - Create a query set with a capacity of N (how many timestamps should be stored in the current frame)
- Create a storage-buffer object (storage-buffer) with a size of 8×N bytes, because the result of the timestamp query needs to be stored in 64 bits;
- Call
commandEncoder.writeTimestamp
method to record the timestamp; it will record the timestamp after all instructions have ended; - Call the
commandEncoder.resolveQuerySet
method to write the timestamp query result into the storage buffer - Copies the storage buffer into CPU-readable memory and decodes it as a BigInt64Array (see BigInt - JavaScript | MDN )
Teaching step by step
The full example can be found in this PR: Example usage of timestamp queries by OmarShehata Pull Request #5 OmarShehata/webgpu-compute-rasterizer GitHub
0. Let the browser have the timestamp query function
The default browser is to close the unsafe API, start the Chrome browser with the following parameters:
--disable-dawn-features=disallow_unsafe_apis
Translator's Note: From --disable-dawn-features
it can be seen that this startup parameter is unique to the Chrome system, and is not common to Firefox and Safari. The specific operation can be right-clicked on the shortcut of Chrome or Edge, followed by this string of strings after "Properties" - "Target".
1. Create Queryset and buffer objects
When requesting a device object, you need to add timestamp-query
to the requiredFeatures
array:
const device = await adapter.requestDevice({
requiredFeatures: ["timestamp-query"],
})
If the browser does not enable timestamp query or does not support it, an error will be reported:
Uncaught (in promise) TypeError: Failed to execute 'requestDevice' on 'GPUAdapter': Unsupported feature: timestamp-query
Then, create a queryset and querybuffer objects:
const capacity = 3 // 要存多少个查询结果
const querySet = device.createQuerySet({
type: "timestamp",
count: capacity,
})
const queryBuffer = device.createBuffer({
size: 8 * capacity,
usage: GPUBufferUsage.QUERY_RESOLVE
| GPUBufferUsage.STORAGE
| GPUBufferUsage.COPY_SRC
| GPUBufferUsage.COPY_DST,
})
2. Write the timestamp
Between the code that allocates the rendering pipeline, call the commandEncoder.writeTimestamp(querySet, index)
method to record the timestamp:
// 在各种指令编码过程中记录时间戳
commandEncoder.writeTimestamp(querySet, 0) // 初始时间戳
// draw(...)
commandEncoder.writeTimestamp(querySet, 1)
index
<= defined capacity value - 1.
3. Parse the timestamp into the buffer object
At the end of each frame of code, call the commandEncoder.resolveQuerySet
method to correctly write the storage buffer object:
commandEncoder.resolveQuerySet(
querySet,
0, // 从哪个查询开始
capacity, // 要写入多少个查询
queryBuffer,
0 // 写入缓冲对象的偏移值
)
4. Read the query result
That is, read data from a storage buffer object. After obtaining the ArrayBuffer, use the BigInt type array to read it. Timestamp values are in nanoseconds.
// === `commandEncoder.finish()` 调用之后 ===
// 使用下面的 readBuffer 函数读取 queryBuffer 对象中的数据
const arrayBuffer = await readBuffer(device, queryBuffer);
// 使用 BigInt 类型数组读取数据
const timingsNanoseconds = new BigInt64Array(arrayBuffer);
const readBuffer = async (device, buffer) => {
const size = buffer.size
const gpuReadBuffer = device.createBuffer({
size,
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
})
const copyEncoder = device.createCommandEncoder()
copyEncoder.copyBufferToBuffer(buffer, 0, gpuReadBuffer, 0, size)
const copyCommands = copyEncoder.finish()
device.queue.submit([copyCommands])
await gpuReadBuffer.mapAsync(GPUMapMode.READ)
return gpuReadBuffer.getMappedRange()
}
5. (Optional) Add tags
In order to make the output information more friendly, each timestamp can be labeled, which is helpful to distinguish the difference when outputting. Converting nanoseconds to milliseconds is also useful.
Thanks
Many thanks to Markus Schütz for the timestamp query example in Potree's About WebGPU implementation .
Thanks to Gu Yang in issue 3354 for explaining how to enable timestamp queries in Chrome.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。