mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-30 20:18:08 +00:00
[js/webgpu] Change timestamp-query-in-passes to timestamp-query (#18108)
Timestamp-query has a broader support than timestamp-query-in-passes on all the platforms, including macOS. Note that to enable timestamp-query, you still need to add switch "--enable-dawn-features=allow_unsafe_apis" to Chrome. By default, the lowest 16 bits are masked with 0 (at a granularity about 0.1ms) for privacy. To get the highest precision, you need to add another switch "--enable-webgpu-developer-features".
This commit is contained in:
parent
b7bee621cd
commit
52f4968359
2 changed files with 50 additions and 48 deletions
|
|
@ -126,14 +126,14 @@ export class WebGpuBackend {
|
|||
*/
|
||||
kernels: Map<number, [string, string, RunFunction, [((attribute: unknown) => unknown) | undefined, unknown]]>;
|
||||
|
||||
commandEncoder: GPUCommandEncoder|null = null;
|
||||
computePassEncoder: GPUComputePassEncoder|null = null;
|
||||
private commandEncoder: GPUCommandEncoder|null = null;
|
||||
private computePassEncoder: GPUComputePassEncoder|null = null;
|
||||
pendingDispatchNumber = 0;
|
||||
|
||||
supportTimestampQuery = false;
|
||||
profilingQuerySet: GPUQuerySet;
|
||||
profilingQueryData: GpuData;
|
||||
profilingTimeBase?: bigint;
|
||||
queryData?: GpuData;
|
||||
querySet?: GPUQuerySet;
|
||||
querySetCount = 2;
|
||||
queryTimeBase?: bigint;
|
||||
|
||||
env: Env;
|
||||
|
||||
|
|
@ -168,11 +168,9 @@ export class WebGpuBackend {
|
|||
},
|
||||
requiredFeatures,
|
||||
};
|
||||
// WebGPU Spec: Timestamp Queries Inside Passes
|
||||
// https://github.com/gpuweb/gpuweb/blob/main/proposals/timestamp-query-inside-passes.md
|
||||
if (adapter.features.has('timestamp-query-inside-passes')) {
|
||||
this.supportTimestampQuery = true;
|
||||
requiredFeatures.push('timestamp-query-inside-passes' as GPUFeatureName);
|
||||
|
||||
if (adapter.features.has('timestamp-query')) {
|
||||
requiredFeatures.push('timestamp-query');
|
||||
}
|
||||
if (adapter.features.has('shader-f16')) {
|
||||
requiredFeatures.push('shader-f16');
|
||||
|
|
@ -197,21 +195,14 @@ export class WebGpuBackend {
|
|||
}
|
||||
};
|
||||
|
||||
if (this.supportTimestampQuery) {
|
||||
this.profilingQuerySet = this.device.createQuerySet({
|
||||
type: 'timestamp',
|
||||
count: 2,
|
||||
});
|
||||
}
|
||||
|
||||
Object.defineProperty(this.env.webgpu, 'device', {value: this.device});
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
// currently, we do not do anything in this function. In all known use cases, we don't have the requirement to
|
||||
// actually dispose the WebGpuBackend instance, because it's always used as a singleton.
|
||||
//
|
||||
// revisit this place if we get real requirement to dispose the instance.
|
||||
if (typeof this.querySet !== 'undefined') {
|
||||
this.querySet.destroy();
|
||||
}
|
||||
this.gpuDataManager.dispose();
|
||||
}
|
||||
|
||||
getCommandEncoder(): GPUCommandEncoder {
|
||||
|
|
@ -223,7 +214,22 @@ export class WebGpuBackend {
|
|||
|
||||
getComputePassEncoder(): GPUComputePassEncoder {
|
||||
if (!this.computePassEncoder) {
|
||||
this.computePassEncoder = this.getCommandEncoder().beginComputePass();
|
||||
const computePassDescriptor: GPUComputePassDescriptor = {};
|
||||
if (this.isQueryEnabled()) {
|
||||
if (typeof this.querySet === 'undefined') {
|
||||
this.querySet = this.device.createQuerySet({
|
||||
type: 'timestamp',
|
||||
count: this.querySetCount,
|
||||
});
|
||||
}
|
||||
computePassDescriptor.timestampWrites = {
|
||||
querySet: this.querySet,
|
||||
beginningOfPassWriteIndex: 0,
|
||||
endOfPassWriteIndex: 1,
|
||||
};
|
||||
}
|
||||
|
||||
this.computePassEncoder = this.getCommandEncoder().beginComputePass(computePassDescriptor);
|
||||
}
|
||||
return this.computePassEncoder;
|
||||
}
|
||||
|
|
@ -245,6 +251,14 @@ export class WebGpuBackend {
|
|||
}
|
||||
}
|
||||
|
||||
isQueryEnabled(): boolean {
|
||||
if (this.device.features.has('timestamp-query') && this.env.webgpu.profilingMode === 'default') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* run a WebGPU program.
|
||||
* @param program a ProgramInfo instance
|
||||
|
|
|
|||
|
|
@ -38,14 +38,6 @@ export class ProgramManager {
|
|||
const device = this.backend.device;
|
||||
|
||||
const computePassEncoder = this.backend.getComputePassEncoder();
|
||||
const profilingEnabled = this.backend.supportTimestampQuery && this.backend.env.webgpu.profilingMode === 'default';
|
||||
if (profilingEnabled) {
|
||||
// profiling write start timestamp
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(computePassEncoder as any).writeTimestamp(this.backend.profilingQuerySet, 0);
|
||||
}
|
||||
|
||||
computePassEncoder.setPipeline(buildArtifact.computePipeline);
|
||||
const entries = [];
|
||||
for (const input of inputs) {
|
||||
|
|
@ -65,24 +57,20 @@ export class ProgramManager {
|
|||
|
||||
this.backend.pendingDispatchNumber++;
|
||||
|
||||
if (profilingEnabled) {
|
||||
// profiling write end timestamp
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(computePassEncoder as any).writeTimestamp(this.backend.profilingQuerySet, 1);
|
||||
if (this.backend.profilingQueryData == null) {
|
||||
this.backend.profilingQueryData =
|
||||
if (this.backend.isQueryEnabled()) {
|
||||
if (typeof this.backend.queryData === 'undefined') {
|
||||
this.backend.queryData = this.backend.gpuDataManager.create(
|
||||
// eslint-disable-next-line no-bitwise
|
||||
this.backend.gpuDataManager.create(16, GPUBufferUsage.COPY_SRC | GPUBufferUsage.QUERY_RESOLVE);
|
||||
this.backend.querySetCount * 8, GPUBufferUsage.COPY_SRC | GPUBufferUsage.QUERY_RESOLVE);
|
||||
}
|
||||
// eslint-disable-next-line no-bitwise
|
||||
const syncData = this.backend.gpuDataManager.create(16, GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST);
|
||||
const syncData = this.backend.gpuDataManager.create(
|
||||
// eslint-disable-next-line no-bitwise
|
||||
this.backend.querySetCount * 8, GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST);
|
||||
|
||||
this.backend.endComputePass();
|
||||
this.backend.getCommandEncoder().resolveQuerySet(
|
||||
this.backend.profilingQuerySet, 0, 2, this.backend.profilingQueryData.buffer, 0);
|
||||
this.backend.getCommandEncoder().resolveQuerySet(this.backend.querySet, 0, 2, this.backend.queryData.buffer, 0);
|
||||
this.backend.getCommandEncoder().copyBufferToBuffer(
|
||||
this.backend.profilingQueryData.buffer, 0, syncData.buffer, 0, 16);
|
||||
this.backend.queryData.buffer, 0, syncData.buffer, 0, this.backend.querySetCount * 8);
|
||||
this.backend.flush();
|
||||
|
||||
const kernelId = this.backend.currentKernelId!;
|
||||
|
|
@ -96,12 +84,12 @@ export class ProgramManager {
|
|||
|
||||
syncData.buffer.unmap();
|
||||
|
||||
if (typeof this.backend.profilingTimeBase === 'undefined') {
|
||||
this.backend.profilingTimeBase = startTimeU64;
|
||||
if (typeof this.backend.queryTimeBase === 'undefined') {
|
||||
this.backend.queryTimeBase = startTimeU64;
|
||||
}
|
||||
|
||||
const startTime = Number(startTimeU64 - this.backend.profilingTimeBase);
|
||||
const endTime = Number(endTimeU64 - this.backend.profilingTimeBase);
|
||||
const startTime = Number(startTimeU64 - this.backend.queryTimeBase);
|
||||
const endTime = Number(endTimeU64 - this.backend.queryTimeBase);
|
||||
|
||||
if (!Number.isSafeInteger(startTime) || !Number.isSafeInteger(endTime)) {
|
||||
throw new RangeError('incorrect timestamp range');
|
||||
|
|
|
|||
Loading…
Reference in a new issue