From 48050b7ce2f70f5658e7f4f72cf4aa0fbb583342 Mon Sep 17 00:00:00 2001 From: Gregg Tavares Date: Fri, 3 Jan 2025 11:25:18 -0800 Subject: [PATCH] Rename RollingAverage to NonNegativeRollingAverage And, make it discard negative values. The spec says timestamp query can return a beginning timestamp with a value greater than an ending timestamp and such values should be discarded. The easiest place to do this is in the RollingAverage class but just doing it there without renaming it seemed bad since someone might use RollingAverage for other purposes and not realize it was discarding negative values. Further, it's possible offsite samples are linking directly to rolling-timing.js (which is the case if you export any sample) so leave that implementation as is and put NonNegativeRollingAverage in its own file. --- webgpu/lessons/webgpu-optimization.md | 12 ++++----- webgpu/lessons/webgpu-timing.md | 19 ++++++++----- .../js/non-negative-rolling-average.js | 23 ++++++++++++++++ webgpu/resources/js/rolling-average.js | 1 - ...l-material-per-object-uniform-buffers.html | 10 +++---- ...bgl-optimization-none-uniform-buffers.html | 10 +++---- webgpu/webgl-optimization-none.html | 10 +++---- ...ptimization-uniform-buffers-one-large.html | 10 +++---- ...pute-shaders-histogram-video-w-timing.html | 27 ++++--------------- webgpu/webgpu-optimization-none.html | 10 +++---- ...n-step3-global-vs-per-object-uniforms.html | 10 +++---- ...-optimization-step4-material-uniforms.html | 10 +++---- ...optimization-step5-use-buffer-offsets.html | 10 +++---- ...p6-use-mapped-buffers-dyanmic-offsets.html | 10 +++---- ...ep6-use-mapped-buffers-math-w-offsets.html | 10 +++---- ...optimization-step6-use-mapped-buffers.html | 10 +++---- ...mization-step7-double-buffer-2-submit.html | 10 +++---- ...on-step7-double-buffer-typedarray-set.html | 10 +++---- ...bgpu-optimization-step7-double-buffer.html | 10 +++---- ...ebgpu-timing-with-timestamp-w-average.html | 19 ++++++++----- webgpu/webgpu-timing-with-timing-helper.html | 19 ++++++++----- 21 files changed, 140 insertions(+), 120 deletions(-) create mode 100644 webgpu/resources/js/non-negative-rolling-average.js diff --git a/webgpu/lessons/webgpu-optimization.md b/webgpu/lessons/webgpu-optimization.md index 36784602..69bf005a 100644 --- a/webgpu/lessons/webgpu-optimization.md +++ b/webgpu/lessons/webgpu-optimization.md @@ -669,19 +669,19 @@ A few more things left to do. Let's add in resizing +observer.observe(canvas); ``` -Let's also add in some timing. We'll use the `RollingAverage` and `TimingHelper` classes +Let's also add in some timing. We'll use the `NonNegativeRollingAverage` and `TimingHelper` classes we made in [the article on timing](webgpu-timing.html). ```js // see https://webgpufundamentals.org/webgpu/lessons/webgpu-timing.html import TimingHelper from './resources/js/timing-helper.js'; // see https://webgpufundamentals.org/webgpu/lessons/webgpu-timing.html -import RollingAverage from './resources/js/rolling-average.js'; +import NonNegativeRollingAverage from './resources/js/non-negative-rolling-average.js'; -const fpsAverage = new RollingAverage(); -const jsAverage = new RollingAverage(); -const gpuAverage = new RollingAverage(); -const mathAverage = new RollingAverage(); +const fpsAverage = new NonNegativeRollingAverage(); +const jsAverage = new NonNegativeRollingAverage(); +const gpuAverage = new NonNegativeRollingAverage(); +const mathAverage = new NonNegativeRollingAverage(); ``` Then we'll time our JavaScript from the beginning to the end of our rendering code diff --git a/webgpu/lessons/webgpu-timing.md b/webgpu/lessons/webgpu-timing.md index f3bcaf24..ce60228c 100644 --- a/webgpu/lessons/webgpu-timing.md +++ b/webgpu/lessons/webgpu-timing.md @@ -567,7 +567,10 @@ average. Here's a class to help compute a rolling average. ```js -class RollingAverage { +// Note: We disallow negative values as this is used for timestamp queries +// where it's possible for a query to return a beginning time greater than the +// end time. See: https://gpuweb.github.io/gpuweb/#timestamp +class NonNegativeRollingAverage { #total = 0; #samples = []; #cursor = 0; @@ -576,9 +579,11 @@ class RollingAverage { this.#numSamples = numSamples; } addSample(v) { - this.#total += v - (this.#samples[this.#cursor] || 0); - this.#samples[this.#cursor] = v; - this.#cursor = (this.#cursor + 1) % this.#numSamples; + if (!Number.isNaN(v) && Number.isFinite(v) && v >= 0) { + this.#total += v - (this.#samples[this.#cursor] || 0); + this.#samples[this.#cursor] = v; + this.#cursor = (this.#cursor + 1) % this.#numSamples; + } } get() { return this.#total / this.#samples.length; @@ -592,9 +597,9 @@ oldest value is subtracted from the total as the new value is added. We can use it like this. ```js -+const fpsAverage = new RollingAverage(); -+const jsAverage = new RollingAverage(); -+const gpuAverage = new RollingAverage(); ++const fpsAverage = new NonNegativeRollingAverage(); ++const jsAverage = new NonNegativeRollingAverage(); ++const gpuAverage = new NonNegativeRollingAverage(); function render(now) { ... diff --git a/webgpu/resources/js/non-negative-rolling-average.js b/webgpu/resources/js/non-negative-rolling-average.js new file mode 100644 index 00000000..efee0f09 --- /dev/null +++ b/webgpu/resources/js/non-negative-rolling-average.js @@ -0,0 +1,23 @@ +// See https://webgpufundamentals.org/webgpu/lessons/webgpu-timing.html +// Note: We disallow negative values as this is used for timestamp queries +// where it's possible for a query to return a beginning time greater than the +// end time. See: https://gpuweb.github.io/gpuweb/#timestamp +export default class NonNegativeRollingAverage { + #total = 0; + #samples = []; + #cursor = 0; + #numSamples; + constructor(numSamples = 30) { + this.#numSamples = numSamples; + } + addSample(v) { + if (!Number.isNaN(v) && Number.isFinite(v) && v >= 0) { + this.#total += v - (this.#samples[this.#cursor] || 0); + this.#samples[this.#cursor] = v; + this.#cursor = (this.#cursor + 1) % this.#numSamples; + } + } + get() { + return this.#total / this.#samples.length; + } +} diff --git a/webgpu/resources/js/rolling-average.js b/webgpu/resources/js/rolling-average.js index a2f36c97..d4bf7df5 100644 --- a/webgpu/resources/js/rolling-average.js +++ b/webgpu/resources/js/rolling-average.js @@ -1,4 +1,3 @@ -// See https://webgpufundamentals.org/webgpu/lessons/webgpu-timing.html export default class RollingAverage { #total = 0; #samples = []; diff --git a/webgpu/webgl-optimization-global-material-per-object-uniform-buffers.html b/webgpu/webgl-optimization-global-material-per-object-uniform-buffers.html index 3ea39eb2..62fc67e7 100644 --- a/webgpu/webgl-optimization-global-material-per-object-uniform-buffers.html +++ b/webgpu/webgl-optimization-global-material-per-object-uniform-buffers.html @@ -46,7 +46,7 @@ //import 'https://greggman.github.io/webgl-lint/webgl-lint.js'; import GUI from '../3rdparty/muigui-0.x.module.js'; import * as twgl from '../3rdparty/twgl-full.module.js'; -import RollingAverage from './resources/js/rolling-average.js'; +import NonNegativeRollingAverage from './resources/js/non-negative-rolling-average.js'; class TimingHelper { #ext; @@ -118,10 +118,10 @@ }, }; -const fpsAverage = new RollingAverage(); -const jsAverage = new RollingAverage(); -const gpuAverage = new RollingAverage(); -const mathAverage = new RollingAverage(); +const fpsAverage = new NonNegativeRollingAverage(); +const jsAverage = new NonNegativeRollingAverage(); +const gpuAverage = new NonNegativeRollingAverage(); +const mathAverage = new NonNegativeRollingAverage(); /** Given a css color string, return an array of 4 values from 0 to 255 */ const cssColorToRGBA8 = (() => { diff --git a/webgpu/webgl-optimization-none-uniform-buffers.html b/webgpu/webgl-optimization-none-uniform-buffers.html index 450c8f2a..68476dd3 100644 --- a/webgpu/webgl-optimization-none-uniform-buffers.html +++ b/webgpu/webgl-optimization-none-uniform-buffers.html @@ -45,7 +45,7 @@