Start · Sprachen · JavaScript · Referenz · GPUCommandEncoder.writeTimestamp()

GPUCommandEncoder.writeTimestamp()

Methode

Kodiert einen Befehl, der einen GPU-Zeitstempel in einen Eintrag eines <code>GPUQuerySet</code> vom Typ <code>"timestamp"</code> schreibt, sobald alle vorherigen Befehle ausgeführt sind.

seit JavaScript Veraltet und aus der WebGPU-Spezifikation entfernt deprecated seit ja Kategorie: webapi

Signatur

GPUCommandEncoder.prototype.writeTimestamp(querySet, queryIndex)

Beschreibung

Die Methode writeTimestamp() des GPUCommandEncoder nimmt einen Befehl in den Befehlspuffer auf. Dieser Befehl schreibt einen Zeitstempel in einen bestimmten Eintrag eines GPUQuerySet, sobald alle vorher kodierten Befehle desselben GPUCommandBuffer auf der GPU abgeschlossen sind. Wenn man zwei solche Zeitstempel rund um eine Folge von Befehlen setzt, kann man messen, wie lange die GPU dafür gebraucht hat. Das hilft bei der Leistungsanalyse von Render- und Compute-Durchläufen.

Die Zeitstempel sind 64-Bit-Ganzzahlen in Nanosekunden. Um sie auszulesen, überträgt man sie mit resolveQuerySet() in einen GPUBuffer (Nutzung QUERY_RESOLVE). Danach kopiert man sie in einen Puffer, den die CPU mappen kann, und liest sie dort über ein BigUint64Array aus.

Wichtig: writeTimestamp() wurde aus der WebGPU-Spezifikation entfernt. Der Standardweg ist heute die Eigenschaft timestampWrites in den Deskriptoren von beginRenderPass() und beginComputePass(). Sie misst Zeitstempel am Anfang und am Ende eines Durchlaufs. Neuen Code solltest du nur noch mit timestampWrites schreiben. writeTimestamp() ist höchstens als Rückfallebene für ältere, experimentelle Implementierungen gedacht.

Parameter

Name Typ Default Beschreibung
$querySet Pflicht GPUQuerySet Das Query-Set, in das geschrieben wird. Es muss mit type: "timestamp" erzeugt worden sein.
$queryIndex Pflicht number Index des Eintrags im querySet, in den der Zeitstempel geschrieben wird. Er muss kleiner als querySet.count sein.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Der Befehl wird nur kodiert und läuft erst auf der GPU, wenn der Befehlspuffer mit queue.submit() übermittelt wurde.

Beispiele

Gerät mit Timestamp-Feature anfordern und Query-Set erzeugen

const adapter = await navigator.gpu.requestAdapter();
if (!adapter.features.has('timestamp-query')) {
  throw new Error('timestamp-query wird nicht unterstützt');
}
const device = await adapter.requestDevice({
  requiredFeatures: ['timestamp-query'],
});

// Zwei Einträge: Start und Ende
const querySet = device.createQuerySet({ type: 'timestamp', count: 2 });
console.log(querySet.type, querySet.count);
timestamp 2

GPU-Zeit eines Compute-Durchlaufs messen (Legacy-Weg)

// Annahme: device, querySet (2 Einträge), pipeline, bindGroup existieren
const resolveBuffer = device.createBuffer({
  size: 16, // 2 × 8 Byte
  usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC,
});
const readBuffer = device.createBuffer({
  size: 16,
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
});

const encoder = device.createCommandEncoder();
encoder.writeTimestamp(querySet, 0); // Start

const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(64);
pass.end();

encoder.writeTimestamp(querySet, 1); // Ende
encoder.resolveQuerySet(querySet, 0, 2, resolveBuffer, 0);
encoder.copyBufferToBuffer(resolveBuffer, 0, readBuffer, 0, 16);
device.queue.submit([encoder.finish()]);

await readBuffer.mapAsync(GPUMapMode.READ);
const [start, end] = new BigUint64Array(readBuffer.getMappedRange());
console.log(`GPU-Zeit: ${Number(end - start) / 1e6} ms`);
readBuffer.unmap();
GPU-Zeit: 0.842 ms

Moderne Alternative: timestampWrites im Pass-Deskriptor

const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass({
  timestampWrites: {
    querySet,
    beginningOfPassWriteIndex: 0,
    endOfPassWriteIndex: 1,
  },
});
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(64);
pass.end();

encoder.resolveQuerySet(querySet, 0, 2, resolveBuffer, 0);
device.queue.submit([encoder.finish()]);

// Wichtig · Fallstricke

  • Veraltet: Die Methode steht nicht mehr in der WebGPU-Spezifikation. Nimm stattdessen timestampWrites in beginRenderPass() oder beginComputePass(). Prüfe vor dem Aufruf mit typeof encoder.writeTimestamp === 'function', ob die Methode vorhanden ist.
  • Das Gerät muss mit dem Feature "timestamp-query" angefordert werden. Sonst entsteht ein Validierungsfehler, und der Encoder wird ungültig.
  • Wenn querySet.type nicht "timestamp" ist oder queryIndex ≥ querySet.count ist, führt das zu einem Validierungsfehler.
  • Browser runden oder quantisieren die Zeitstempel aus Sicherheitsgründen, zum Schutz vor Timing-Angriffen. Einzelne Messwerte sind daher ungenau. Miss lieber mehrere Durchläufe und bilde den Mittelwert.
  • Die Werte sind BigInt. Bilde Differenzen mit BigInt-Arithmetik und wandle erst danach mit Number() um. In seltenen Fällen kann der Endwert kleiner als der Startwert sein, etwa bei einem Taktwechsel der GPU. Solche Messungen solltest du verwerfen.
  • Der Offset im Zielpuffer bei resolveQuerySet() muss ein Vielfaches von 256 sein.