webgpu-bench 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (183) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +120 -0
  3. package/dist/benchmarks/common.d.ts +71 -0
  4. package/dist/benchmarks/common.d.ts.map +1 -0
  5. package/dist/benchmarks/common.js +104 -0
  6. package/dist/benchmarks/common.js.map +1 -0
  7. package/dist/benchmarks/flopsCommon.d.ts +52 -0
  8. package/dist/benchmarks/flopsCommon.d.ts.map +1 -0
  9. package/dist/benchmarks/flopsCommon.js +78 -0
  10. package/dist/benchmarks/flopsCommon.js.map +1 -0
  11. package/dist/benchmarks/flopsConvert.d.ts +18 -0
  12. package/dist/benchmarks/flopsConvert.d.ts.map +1 -0
  13. package/dist/benchmarks/flopsConvert.js +61 -0
  14. package/dist/benchmarks/flopsConvert.js.map +1 -0
  15. package/dist/benchmarks/flopsF16.d.ts +12 -0
  16. package/dist/benchmarks/flopsF16.d.ts.map +1 -0
  17. package/dist/benchmarks/flopsF16.js +54 -0
  18. package/dist/benchmarks/flopsF16.js.map +1 -0
  19. package/dist/benchmarks/flopsF32.d.ts +12 -0
  20. package/dist/benchmarks/flopsF32.d.ts.map +1 -0
  21. package/dist/benchmarks/flopsF32.js +50 -0
  22. package/dist/benchmarks/flopsF32.js.map +1 -0
  23. package/dist/benchmarks/flopsI8.d.ts +16 -0
  24. package/dist/benchmarks/flopsI8.d.ts.map +1 -0
  25. package/dist/benchmarks/flopsI8.js +83 -0
  26. package/dist/benchmarks/flopsI8.js.map +1 -0
  27. package/dist/benchmarks/flopsMath.d.ts +28 -0
  28. package/dist/benchmarks/flopsMath.d.ts.map +1 -0
  29. package/dist/benchmarks/flopsMath.js +98 -0
  30. package/dist/benchmarks/flopsMath.js.map +1 -0
  31. package/dist/benchmarks/streamBandwidth.d.ts +17 -0
  32. package/dist/benchmarks/streamBandwidth.d.ts.map +1 -0
  33. package/dist/benchmarks/streamBandwidth.js +78 -0
  34. package/dist/benchmarks/streamBandwidth.js.map +1 -0
  35. package/dist/data/generate.d.ts +23 -0
  36. package/dist/data/generate.d.ts.map +1 -0
  37. package/dist/data/generate.js +41 -0
  38. package/dist/data/generate.js.map +1 -0
  39. package/dist/gpu/benchmarkRunner.d.ts +98 -0
  40. package/dist/gpu/benchmarkRunner.d.ts.map +1 -0
  41. package/dist/gpu/benchmarkRunner.js +178 -0
  42. package/dist/gpu/benchmarkRunner.js.map +1 -0
  43. package/dist/gpu/buffers.d.ts +8 -0
  44. package/dist/gpu/buffers.d.ts.map +1 -0
  45. package/dist/gpu/buffers.js +41 -0
  46. package/dist/gpu/buffers.js.map +1 -0
  47. package/dist/gpu/context.d.ts +16 -0
  48. package/dist/gpu/context.d.ts.map +1 -0
  49. package/dist/gpu/context.js +71 -0
  50. package/dist/gpu/context.js.map +1 -0
  51. package/dist/gpu/timing.d.ts +20 -0
  52. package/dist/gpu/timing.d.ts.map +1 -0
  53. package/dist/gpu/timing.js +55 -0
  54. package/dist/gpu/timing.js.map +1 -0
  55. package/dist/index.d.ts +12 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +7 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/sampling.d.ts +96 -0
  60. package/dist/sampling.d.ts.map +1 -0
  61. package/dist/sampling.js +239 -0
  62. package/dist/sampling.js.map +1 -0
  63. package/dist/shaders/flopsF16Mat4.d.ts +7 -0
  64. package/dist/shaders/flopsF16Mat4.d.ts.map +1 -0
  65. package/dist/shaders/flopsF16Mat4.js +40 -0
  66. package/dist/shaders/flopsF16Mat4.js.map +1 -0
  67. package/dist/shaders/flopsF16Matvec.d.ts +14 -0
  68. package/dist/shaders/flopsF16Matvec.d.ts.map +1 -0
  69. package/dist/shaders/flopsF16Matvec.js +58 -0
  70. package/dist/shaders/flopsF16Matvec.js.map +1 -0
  71. package/dist/shaders/flopsF16Scalar.d.ts +8 -0
  72. package/dist/shaders/flopsF16Scalar.d.ts.map +1 -0
  73. package/dist/shaders/flopsF16Scalar.js +71 -0
  74. package/dist/shaders/flopsF16Scalar.js.map +1 -0
  75. package/dist/shaders/flopsF16Vec4.d.ts +7 -0
  76. package/dist/shaders/flopsF16Vec4.d.ts.map +1 -0
  77. package/dist/shaders/flopsF16Vec4.js +35 -0
  78. package/dist/shaders/flopsF16Vec4.js.map +1 -0
  79. package/dist/shaders/flopsF32Div.d.ts +10 -0
  80. package/dist/shaders/flopsF32Div.d.ts.map +1 -0
  81. package/dist/shaders/flopsF32Div.js +71 -0
  82. package/dist/shaders/flopsF32Div.js.map +1 -0
  83. package/dist/shaders/flopsF32F16Convert.d.ts +11 -0
  84. package/dist/shaders/flopsF32F16Convert.d.ts.map +1 -0
  85. package/dist/shaders/flopsF32F16Convert.js +73 -0
  86. package/dist/shaders/flopsF32F16Convert.js.map +1 -0
  87. package/dist/shaders/flopsF32Log.d.ts +11 -0
  88. package/dist/shaders/flopsF32Log.d.ts.map +1 -0
  89. package/dist/shaders/flopsF32Log.js +71 -0
  90. package/dist/shaders/flopsF32Log.js.map +1 -0
  91. package/dist/shaders/flopsF32Mat4.d.ts +9 -0
  92. package/dist/shaders/flopsF32Mat4.d.ts.map +1 -0
  93. package/dist/shaders/flopsF32Mat4.js +38 -0
  94. package/dist/shaders/flopsF32Mat4.js.map +1 -0
  95. package/dist/shaders/flopsF32Matvec.d.ts +14 -0
  96. package/dist/shaders/flopsF32Matvec.d.ts.map +1 -0
  97. package/dist/shaders/flopsF32Matvec.js +58 -0
  98. package/dist/shaders/flopsF32Matvec.js.map +1 -0
  99. package/dist/shaders/flopsF32Pow.d.ts +10 -0
  100. package/dist/shaders/flopsF32Pow.d.ts.map +1 -0
  101. package/dist/shaders/flopsF32Pow.js +71 -0
  102. package/dist/shaders/flopsF32Pow.js.map +1 -0
  103. package/dist/shaders/flopsF32Rsqrt.d.ts +12 -0
  104. package/dist/shaders/flopsF32Rsqrt.d.ts.map +1 -0
  105. package/dist/shaders/flopsF32Rsqrt.js +72 -0
  106. package/dist/shaders/flopsF32Rsqrt.js.map +1 -0
  107. package/dist/shaders/flopsF32Scalar.d.ts +11 -0
  108. package/dist/shaders/flopsF32Scalar.d.ts.map +1 -0
  109. package/dist/shaders/flopsF32Scalar.js +72 -0
  110. package/dist/shaders/flopsF32Scalar.js.map +1 -0
  111. package/dist/shaders/flopsF32Sincos.d.ts +9 -0
  112. package/dist/shaders/flopsF32Sincos.d.ts.map +1 -0
  113. package/dist/shaders/flopsF32Sincos.js +68 -0
  114. package/dist/shaders/flopsF32Sincos.js.map +1 -0
  115. package/dist/shaders/flopsF32Sqrt.d.ts +9 -0
  116. package/dist/shaders/flopsF32Sqrt.d.ts.map +1 -0
  117. package/dist/shaders/flopsF32Sqrt.js +69 -0
  118. package/dist/shaders/flopsF32Sqrt.js.map +1 -0
  119. package/dist/shaders/flopsF32Vec4.d.ts +9 -0
  120. package/dist/shaders/flopsF32Vec4.d.ts.map +1 -0
  121. package/dist/shaders/flopsF32Vec4.js +33 -0
  122. package/dist/shaders/flopsF32Vec4.js.map +1 -0
  123. package/dist/shaders/flopsI32Div.d.ts +10 -0
  124. package/dist/shaders/flopsI32Div.d.ts.map +1 -0
  125. package/dist/shaders/flopsI32Div.js +71 -0
  126. package/dist/shaders/flopsI32Div.js.map +1 -0
  127. package/dist/shaders/flopsI32F16Convert.d.ts +10 -0
  128. package/dist/shaders/flopsI32F16Convert.d.ts.map +1 -0
  129. package/dist/shaders/flopsI32F16Convert.js +71 -0
  130. package/dist/shaders/flopsI32F16Convert.js.map +1 -0
  131. package/dist/shaders/flopsI32F32Convert.d.ts +10 -0
  132. package/dist/shaders/flopsI32F32Convert.d.ts.map +1 -0
  133. package/dist/shaders/flopsI32F32Convert.js +71 -0
  134. package/dist/shaders/flopsI32F32Convert.js.map +1 -0
  135. package/dist/shaders/flopsI8Dp4a.d.ts +23 -0
  136. package/dist/shaders/flopsI8Dp4a.d.ts.map +1 -0
  137. package/dist/shaders/flopsI8Dp4a.js +49 -0
  138. package/dist/shaders/flopsI8Dp4a.js.map +1 -0
  139. package/dist/shaders/flopsI8Mat4.d.ts +9 -0
  140. package/dist/shaders/flopsI8Mat4.d.ts.map +1 -0
  141. package/dist/shaders/flopsI8Mat4.js +41 -0
  142. package/dist/shaders/flopsI8Mat4.js.map +1 -0
  143. package/dist/shaders/flopsI8Matvec.d.ts +16 -0
  144. package/dist/shaders/flopsI8Matvec.d.ts.map +1 -0
  145. package/dist/shaders/flopsI8Matvec.js +57 -0
  146. package/dist/shaders/flopsI8Matvec.js.map +1 -0
  147. package/dist/shaders/flopsI8MatvecDp4a.d.ts +17 -0
  148. package/dist/shaders/flopsI8MatvecDp4a.d.ts.map +1 -0
  149. package/dist/shaders/flopsI8MatvecDp4a.js +60 -0
  150. package/dist/shaders/flopsI8MatvecDp4a.js.map +1 -0
  151. package/dist/shaders/flopsI8Scalar.d.ts +9 -0
  152. package/dist/shaders/flopsI8Scalar.d.ts.map +1 -0
  153. package/dist/shaders/flopsI8Scalar.js +70 -0
  154. package/dist/shaders/flopsI8Scalar.js.map +1 -0
  155. package/dist/shaders/flopsI8Vec4.d.ts +7 -0
  156. package/dist/shaders/flopsI8Vec4.d.ts.map +1 -0
  157. package/dist/shaders/flopsI8Vec4.js +31 -0
  158. package/dist/shaders/flopsI8Vec4.js.map +1 -0
  159. package/dist/shaders/flopsU32PackUnpack.d.ts +11 -0
  160. package/dist/shaders/flopsU32PackUnpack.d.ts.map +1 -0
  161. package/dist/shaders/flopsU32PackUnpack.js +55 -0
  162. package/dist/shaders/flopsU32PackUnpack.js.map +1 -0
  163. package/dist/shaders/streamRead.d.ts +10 -0
  164. package/dist/shaders/streamRead.d.ts.map +1 -0
  165. package/dist/shaders/streamRead.js +33 -0
  166. package/dist/shaders/streamRead.js.map +1 -0
  167. package/dist/shaders/streamWrite.d.ts +8 -0
  168. package/dist/shaders/streamWrite.d.ts.map +1 -0
  169. package/dist/shaders/streamWrite.js +29 -0
  170. package/dist/shaders/streamWrite.js.map +1 -0
  171. package/dist/stats.d.ts +31 -0
  172. package/dist/stats.d.ts.map +1 -0
  173. package/dist/stats.js +67 -0
  174. package/dist/stats.js.map +1 -0
  175. package/dist/suite.d.ts +25 -0
  176. package/dist/suite.d.ts.map +1 -0
  177. package/dist/suite.js +196 -0
  178. package/dist/suite.js.map +1 -0
  179. package/dist/types.d.ts +171 -0
  180. package/dist/types.d.ts.map +1 -0
  181. package/dist/types.js +2 -0
  182. package/dist/types.js.map +1 -0
  183. package/package.json +45 -0
@@ -0,0 +1,98 @@
1
+ import type { TimingMethod } from '../types.ts';
2
+ /** Knobs controlling how one timed measurement of a kernel is taken. */
3
+ export interface MeasurementConfig {
4
+ /**
5
+ * Target duration of a single measurement (one submitted command buffer),
6
+ * in ms; sets how many dispatches get batched. Default 100.
7
+ */
8
+ targetMs?: number;
9
+ /**
10
+ * Target duration of a single *dispatch*, in ms. A dispatch can't be
11
+ * preempted, so a long one freezes the display; kernels that expose a
12
+ * work knob get it calibrated so one dispatch lands near this. Default 10.
13
+ */
14
+ targetDispatchMs?: number;
15
+ /** Discarded measurements taken after calibration and before timing starts. Default 1. */
16
+ warmups?: number;
17
+ /** Hard cap on how many dispatches get batched into one measurement (guards against runaway calibration). */
18
+ maxIterations?: number;
19
+ }
20
+ export declare const DEFAULT_MEASUREMENT: Required<MeasurementConfig>;
21
+ /**
22
+ * A kernel's tunable per-dispatch work (for the raw-FLOPS kernels: the
23
+ * in-shader loop trip count). Lets the sampler size a single dispatch to
24
+ * `targetDispatchMs` on whatever GPU it finds itself on, instead of a fixed
25
+ * count that's a few ms on a desktop and a second on a phone.
26
+ */
27
+ export interface WorkKnob {
28
+ /** Smallest sensible work per dispatch (also the first calibration probe, so keep it cheap). */
29
+ min: number;
30
+ /** Largest work per dispatch (the kernel's own default; bounds numerical range and per-thread setup amortisation). */
31
+ max: number;
32
+ /** Make subsequent dispatches use this much work (e.g. rewrite the params uniform). */
33
+ apply(work: number): void;
34
+ }
35
+ export interface KernelHarness extends MeasurementConfig {
36
+ device: GPUDevice;
37
+ /** Records `iterations` back-to-back dispatches (same pipeline/bind group) into the pass. */
38
+ encode: (pass: GPUComputePassEncoder, iterations: number) => void;
39
+ useTimestamps: boolean;
40
+ /** Present for kernels whose per-dispatch work can be resized at runtime. */
41
+ work?: WorkKnob;
42
+ }
43
+ /**
44
+ * Takes individual timed measurements of one kernel on demand, so a
45
+ * scheduler can interleave many kernels round-robin (see `runSampling`)
46
+ * instead of hammering one kernel until it converges. Holds the GPU timer
47
+ * and the calibrated batch size between calls.
48
+ *
49
+ * Lifecycle: `calibrate()` once (sizes the dispatch and the batch, runs the
50
+ * warmups), then `sample()` as often as wanted, then `destroy()`.
51
+ */
52
+ export declare class KernelSampler {
53
+ private readonly h;
54
+ private readonly timer;
55
+ private iterations;
56
+ private currentWork;
57
+ /** Cleared once the GPU timestamps have disagreed with wall clock `TIMESTAMP_STRIKES_TO_DEMOTE` times running. */
58
+ private trustTimestamps;
59
+ private timestampStrikes;
60
+ /** Wall time of an empty submit (min of `OVERHEAD_PROBES`): submit, scheduling and readback, no GPU work. */
61
+ private overheadMs;
62
+ constructor(h: KernelHarness);
63
+ get timingMethod(): TimingMethod;
64
+ /** Number of dispatches batched into each measurement; 0 until calibrated. */
65
+ get innerIterations(): number;
66
+ /** Per-dispatch work the kernel was calibrated to; undefined if it has no work knob. */
67
+ get work(): number | undefined;
68
+ /**
69
+ * Sizes the kernel so one dispatch takes about `targetDispatchMs` (when it
70
+ * has a work knob: start from the cheapest probe and ramp up, never more
71
+ * than 4x per step, so even a very slow GPU never gets handed a long
72
+ * dispatch), then batches dispatches to fill `targetMs`, then runs the
73
+ * discarded warmups. The probes double as pipeline warm-up.
74
+ *
75
+ * Batch sizing uses *wall-clock* time, never the GPU timestamps: wall
76
+ * clock includes submit/readback overhead so it can only over-estimate,
77
+ * which errs toward smaller batches — whereas a broken timestamp (see
78
+ * `TIMESTAMP_MAX_UNDERREPORT`) would size a batch tens of times too large
79
+ * and hang the browser. The work ramp does use the GPU time while it's
80
+ * trusted (a single dispatch's wall time is mostly readback overhead, so
81
+ * sizing from it leaves dispatches far too small), which is safe there
82
+ * because growth is capped at 4x per step: a bogus reading can at worst
83
+ * overshoot one step before the wall-clock cross-check demotes it.
84
+ */
85
+ calibrate(): Promise<void>;
86
+ /** One timed measurement: per-op time in ms. Requires `calibrate()` first. */
87
+ sample(): Promise<number>;
88
+ destroy(): void;
89
+ /**
90
+ * Submits `iterations` dispatches as one command buffer and waits for
91
+ * them. Always returns the wall-clock time; returns the GPU-timestamp
92
+ * time too while the timestamps are trusted. An implausibly small reading
93
+ * (see `TIMESTAMP_MAX_UNDERREPORT`) is replaced by wall clock, and the
94
+ * sampler is demoted to wall-clock for good on the second in a row.
95
+ */
96
+ private measureRaw;
97
+ }
98
+ //# sourceMappingURL=benchmarkRunner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"benchmarkRunner.d.ts","sourceRoot":"","sources":["../../src/gpu/benchmarkRunner.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,wEAAwE;AACxE,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6GAA6G;IAC7G,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,iBAAiB,CAK3D,CAAC;AAEF;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,gGAAgG;IAChG,GAAG,EAAE,MAAM,CAAC;IACZ,sHAAsH;IACtH,GAAG,EAAE,MAAM,CAAC;IACZ,uFAAuF;IACvF,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,aAAc,SAAQ,iBAAiB;IACtD,MAAM,EAAE,SAAS,CAAC;IAClB,6FAA6F;IAC7F,MAAM,EAAE,CAAC,IAAI,EAAE,qBAAqB,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAClE,aAAa,EAAE,OAAO,CAAC;IACvB,6EAA6E;IAC7E,IAAI,CAAC,EAAE,QAAQ,CAAC;CACjB;AAsBD;;;;;;;;GAQG;AACH,qBAAa,aAAa;IAUZ,OAAO,CAAC,QAAQ,CAAC,CAAC;IAT9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAW;IACjC,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,WAAW,CAAqB;IACxC,kHAAkH;IAClH,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,gBAAgB,CAAK;IAC7B,6GAA6G;IAC7G,OAAO,CAAC,UAAU,CAAK;gBAEM,CAAC,EAAE,aAAa;IAK7C,IAAI,YAAY,IAAI,YAAY,CAE/B;IAED,8EAA8E;IAC9E,IAAI,eAAe,IAAI,MAAM,CAE5B;IAED,wFAAwF;IACxF,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAE7B;IAED;;;;;;;;;;;;;;;;OAgBG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAsDhC,8EAA8E;IACxE,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAQ/B,OAAO,IAAI,IAAI;IAIf;;;;;;OAMG;YACW,UAAU;CAgCzB"}
@@ -0,0 +1,178 @@
1
+ import { GpuTimer } from "./timing.js";
2
+ export const DEFAULT_MEASUREMENT = {
3
+ targetMs: 100,
4
+ targetDispatchMs: 10,
5
+ warmups: 1,
6
+ maxIterations: 200_000,
7
+ };
8
+ /** Never grow a calibration probe by more than this factor per step, so no probe can run away on a slow GPU. */
9
+ const MAX_PROBE_GROWTH = 4;
10
+ /**
11
+ * GPU timestamps are cross-checked against wall clock on every measurement.
12
+ * Wall clock minus the measured fixed submit/readback overhead is what the
13
+ * GPU actually spent, so a GPU reading under half of that is a broken timer.
14
+ * Safari's `timestamp-query` does exactly this — reporting ~1ms for a ~70ms
15
+ * batch — and trusting it makes calibration batch ~70x too much work into
16
+ * one command buffer, which hangs the browser. Two consecutive failures are
17
+ * required before demoting for good, so a one-off main-thread stall that
18
+ * inflates wall time (GC, a compositor frame) can't cost a kernel its
19
+ * accurate timer.
20
+ */
21
+ const TIMESTAMP_CHECK_MIN_GPU_MS = 4;
22
+ const TIMESTAMP_MAX_UNDERREPORT = 2;
23
+ const TIMESTAMP_STRIKES_TO_DEMOTE = 2;
24
+ /** Empty submits measured at calibration to estimate the fixed per-measurement overhead. */
25
+ const OVERHEAD_PROBES = 3;
26
+ /**
27
+ * Takes individual timed measurements of one kernel on demand, so a
28
+ * scheduler can interleave many kernels round-robin (see `runSampling`)
29
+ * instead of hammering one kernel until it converges. Holds the GPU timer
30
+ * and the calibrated batch size between calls.
31
+ *
32
+ * Lifecycle: `calibrate()` once (sizes the dispatch and the batch, runs the
33
+ * warmups), then `sample()` as often as wanted, then `destroy()`.
34
+ */
35
+ export class KernelSampler {
36
+ h;
37
+ timer;
38
+ iterations = 0;
39
+ currentWork;
40
+ /** Cleared once the GPU timestamps have disagreed with wall clock `TIMESTAMP_STRIKES_TO_DEMOTE` times running. */
41
+ trustTimestamps;
42
+ timestampStrikes = 0;
43
+ /** Wall time of an empty submit (min of `OVERHEAD_PROBES`): submit, scheduling and readback, no GPU work. */
44
+ overheadMs = 0;
45
+ constructor(h) {
46
+ this.h = h;
47
+ this.timer = new GpuTimer(h.device, h.useTimestamps);
48
+ this.trustTimestamps = this.timer.supported;
49
+ }
50
+ get timingMethod() {
51
+ return this.trustTimestamps ? 'gpu-timestamp' : 'cpu-wallclock';
52
+ }
53
+ /** Number of dispatches batched into each measurement; 0 until calibrated. */
54
+ get innerIterations() {
55
+ return this.iterations;
56
+ }
57
+ /** Per-dispatch work the kernel was calibrated to; undefined if it has no work knob. */
58
+ get work() {
59
+ return this.currentWork;
60
+ }
61
+ /**
62
+ * Sizes the kernel so one dispatch takes about `targetDispatchMs` (when it
63
+ * has a work knob: start from the cheapest probe and ramp up, never more
64
+ * than 4x per step, so even a very slow GPU never gets handed a long
65
+ * dispatch), then batches dispatches to fill `targetMs`, then runs the
66
+ * discarded warmups. The probes double as pipeline warm-up.
67
+ *
68
+ * Batch sizing uses *wall-clock* time, never the GPU timestamps: wall
69
+ * clock includes submit/readback overhead so it can only over-estimate,
70
+ * which errs toward smaller batches — whereas a broken timestamp (see
71
+ * `TIMESTAMP_MAX_UNDERREPORT`) would size a batch tens of times too large
72
+ * and hang the browser. The work ramp does use the GPU time while it's
73
+ * trusted (a single dispatch's wall time is mostly readback overhead, so
74
+ * sizing from it leaves dispatches far too small), which is safe there
75
+ * because growth is capped at 4x per step: a bogus reading can at worst
76
+ * overshoot one step before the wall-clock cross-check demotes it.
77
+ */
78
+ async calibrate() {
79
+ const targetMs = this.h.targetMs ?? DEFAULT_MEASUREMENT.targetMs;
80
+ const targetDispatchMs = this.h.targetDispatchMs ?? DEFAULT_MEASUREMENT.targetDispatchMs;
81
+ const warmups = this.h.warmups ?? DEFAULT_MEASUREMENT.warmups;
82
+ const maxIterations = this.h.maxIterations ?? DEFAULT_MEASUREMENT.maxIterations;
83
+ this.overheadMs = Number.POSITIVE_INFINITY;
84
+ for (let i = 0; i < OVERHEAD_PROBES; i++) {
85
+ this.overheadMs = Math.min(this.overheadMs, (await this.measureRaw(0)).wallMs);
86
+ }
87
+ const knob = this.h.work;
88
+ if (knob) {
89
+ let work = Math.max(1, Math.floor(knob.min));
90
+ knob.apply(work);
91
+ const dispatchTime = async () => {
92
+ const { gpuMs, wallMs } = await this.measureRaw(1);
93
+ return gpuMs ?? wallMs;
94
+ };
95
+ let dispatchMs = await dispatchTime();
96
+ // Ramp: the dispatch time is ~linear in work, so extrapolate straight
97
+ // to the target, but cap the growth per step and re-measure.
98
+ while (work < knob.max && dispatchMs < targetDispatchMs) {
99
+ const wanted = (work * targetDispatchMs) / Math.max(dispatchMs, 1e-6);
100
+ const next = Math.min(knob.max, Math.floor(Math.min(wanted, work * MAX_PROBE_GROWTH)));
101
+ if (next <= work)
102
+ break;
103
+ work = next;
104
+ knob.apply(work);
105
+ dispatchMs = await dispatchTime();
106
+ }
107
+ this.currentWork = work;
108
+ }
109
+ // Batch sizing: grow from a single dispatch until one measurement's wall
110
+ // time is near the target. Wall clock over-estimates a tiny dispatch
111
+ // (fixed submit/readback overhead dominates), so the first extrapolation
112
+ // under-shoots and a couple of refinement steps home in from below. The
113
+ // very first measurement never ends the search: it can absorb a one-off
114
+ // stall (lazy shader compile, GC) that would leave the batch at 1.
115
+ let iterations = 1;
116
+ for (let step = 0; step < 4; step++) {
117
+ const { wallMs } = await this.measureRaw(iterations);
118
+ if ((step > 0 && wallMs >= targetMs / 2) || iterations >= maxIterations)
119
+ break;
120
+ const next = Math.min(maxIterations, Math.floor((iterations * targetMs) / Math.max(wallMs, 1e-6)));
121
+ if (next <= iterations)
122
+ break;
123
+ iterations = next;
124
+ }
125
+ this.iterations = iterations;
126
+ for (let i = 0; i < warmups; i++) {
127
+ await this.measureRaw(this.iterations);
128
+ }
129
+ }
130
+ /** One timed measurement: per-op time in ms. Requires `calibrate()` first. */
131
+ async sample() {
132
+ if (this.iterations === 0) {
133
+ throw new Error('KernelSampler.sample() called before calibrate()');
134
+ }
135
+ const { gpuMs, wallMs } = await this.measureRaw(this.iterations);
136
+ return (gpuMs ?? wallMs) / this.iterations;
137
+ }
138
+ destroy() {
139
+ this.timer.destroy();
140
+ }
141
+ /**
142
+ * Submits `iterations` dispatches as one command buffer and waits for
143
+ * them. Always returns the wall-clock time; returns the GPU-timestamp
144
+ * time too while the timestamps are trusted. An implausibly small reading
145
+ * (see `TIMESTAMP_MAX_UNDERREPORT`) is replaced by wall clock, and the
146
+ * sampler is demoted to wall-clock for good on the second in a row.
147
+ */
148
+ async measureRaw(iterations) {
149
+ const { h, timer } = this;
150
+ const useTimestamps = this.trustTimestamps;
151
+ const encoder = h.device.createCommandEncoder();
152
+ const pass = encoder.beginComputePass({ timestampWrites: useTimestamps ? timer.timestampWrites : undefined });
153
+ h.encode(pass, iterations);
154
+ pass.end();
155
+ if (useTimestamps)
156
+ timer.resolve(encoder);
157
+ const cpuStart = performance.now();
158
+ h.device.queue.submit([encoder.finish()]);
159
+ if (!useTimestamps) {
160
+ await h.device.queue.onSubmittedWorkDone();
161
+ return { gpuMs: null, wallMs: performance.now() - cpuStart };
162
+ }
163
+ const gpuMs = await timer.readElapsedMs();
164
+ const wallMs = performance.now() - cpuStart;
165
+ const gpuWallMs = wallMs - this.overheadMs;
166
+ if (iterations > 0 &&
167
+ gpuWallMs >= TIMESTAMP_CHECK_MIN_GPU_MS &&
168
+ !(gpuMs * TIMESTAMP_MAX_UNDERREPORT >= gpuWallMs)) {
169
+ this.timestampStrikes += 1;
170
+ if (this.timestampStrikes >= TIMESTAMP_STRIKES_TO_DEMOTE)
171
+ this.trustTimestamps = false;
172
+ return { gpuMs: null, wallMs };
173
+ }
174
+ this.timestampStrikes = 0;
175
+ return { gpuMs, wallMs };
176
+ }
177
+ }
178
+ //# sourceMappingURL=benchmarkRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"benchmarkRunner.js","sourceRoot":"","sources":["../../src/gpu/benchmarkRunner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ /** Creates a GPU buffer, uploads `data` into it, and returns the buffer. */
2
+ export declare function createUploadedBuffer(device: GPUDevice, data: ArrayBufferView, usage: GPUBufferUsageFlags, label?: string): GPUBuffer;
3
+ export declare function createStorageBuffer(device: GPUDevice, data: ArrayBufferView, label?: string): GPUBuffer;
4
+ export declare function createUniformBuffer(device: GPUDevice, data: ArrayBufferView, label?: string): GPUBuffer;
5
+ export declare function createEmptyStorageBuffer(device: GPUDevice, byteLength: number, label?: string): GPUBuffer;
6
+ /** Reads a storage buffer back to the CPU as a Float32Array (used only for correctness spot-checks, not timing). */
7
+ export declare function readFloat32(device: GPUDevice, buffer: GPUBuffer, count: number): Promise<Float32Array>;
8
+ //# sourceMappingURL=buffers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffers.d.ts","sourceRoot":"","sources":["../../src/gpu/buffers.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,eAAe,EACrB,KAAK,EAAE,mBAAmB,EAC1B,KAAK,CAAC,EAAE,MAAM,GACb,SAAS,CAUX;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAOvG;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAEvG;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAMzG;AAED,oHAAoH;AACpH,wBAAsB,WAAW,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAa5G"}
@@ -0,0 +1,41 @@
1
+ /** Creates a GPU buffer, uploads `data` into it, and returns the buffer. */
2
+ export function createUploadedBuffer(device, data, usage, label) {
3
+ const buffer = device.createBuffer({
4
+ label,
5
+ size: Math.max(4, Math.ceil(data.byteLength / 4) * 4),
6
+ usage,
7
+ mappedAtCreation: true,
8
+ });
9
+ new Uint8Array(buffer.getMappedRange()).set(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
10
+ buffer.unmap();
11
+ return buffer;
12
+ }
13
+ export function createStorageBuffer(device, data, label) {
14
+ return createUploadedBuffer(device, data, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST, label);
15
+ }
16
+ export function createUniformBuffer(device, data, label) {
17
+ return createUploadedBuffer(device, data, GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, label);
18
+ }
19
+ export function createEmptyStorageBuffer(device, byteLength, label) {
20
+ return device.createBuffer({
21
+ label,
22
+ size: Math.max(4, Math.ceil(byteLength / 4) * 4),
23
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
24
+ });
25
+ }
26
+ /** Reads a storage buffer back to the CPU as a Float32Array (used only for correctness spot-checks, not timing). */
27
+ export async function readFloat32(device, buffer, count) {
28
+ const staging = device.createBuffer({
29
+ size: count * 4,
30
+ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
31
+ });
32
+ const encoder = device.createCommandEncoder();
33
+ encoder.copyBufferToBuffer(buffer, 0, staging, 0, count * 4);
34
+ device.queue.submit([encoder.finish()]);
35
+ await staging.mapAsync(GPUMapMode.READ);
36
+ const result = new Float32Array(staging.getMappedRange().slice(0));
37
+ staging.unmap();
38
+ staging.destroy();
39
+ return result;
40
+ }
41
+ //# sourceMappingURL=buffers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buffers.js","sourceRoot":"","sources":["../../src/gpu/buffers.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,MAAM,UAAU,oBAAoB,CAClC,MAAiB,EACjB,IAAqB,EACrB,KAA0B,EAC1B,KAAc;IAEd,MAAM,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC;QACjC,KAAK;QACL,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QACrD,KAAK;QACL,gBAAgB,EAAE,IAAI;KACvB,CAAC,CAAC;IACH,IAAI,UAAU,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAC3G,MAAM,CAAC,KAAK,EAAE,CAAC;IACf,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,IAAqB,EAAE,KAAc;IAC1F,OAAO,oBAAoB,CACzB,MAAM,EACN,IAAI,EACJ,cAAc,CAAC,OAAO,GAAG,cAAc,CAAC,QAAQ,GAAG,cAAc,CAAC,QAAQ,EAC1E,KAAK,CACN,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,IAAqB,EAAE,KAAc;IAC1F,OAAO,oBAAoB,CAAC,MAAM,EAAE,IAAI,EAAE,cAAc,CAAC,OAAO,GAAG,cAAc,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AACrG,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,MAAiB,EAAE,UAAkB,EAAE,KAAc;IAC5F,OAAO,MAAM,CAAC,YAAY,CAAC;QACzB,KAAK;QACL,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;QAChD,KAAK,EAAE,cAAc,CAAC,OAAO,GAAG,cAAc,CAAC,QAAQ,GAAG,cAAc,CAAC,QAAQ;KAClF,CAAC,CAAC;AACL,CAAC;AAED,oHAAoH;AACpH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAiB,EAAE,MAAiB,EAAE,KAAa;IACnF,MAAM,OAAO,GAAG,MAAM,CAAC,YAAY,CAAC;QAClC,IAAI,EAAE,KAAK,GAAG,CAAC;QACf,KAAK,EAAE,cAAc,CAAC,QAAQ,GAAG,cAAc,CAAC,QAAQ;KACzD,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,CAAC,oBAAoB,EAAE,CAAC;IAC9C,OAAO,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;IAC7D,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACxC,MAAM,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IACxC,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACnE,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,OAAO,CAAC,OAAO,EAAE,CAAC;IAClB,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { DeviceInfo } from '../types.ts';
2
+ export interface GpuContext {
3
+ adapter: GPUAdapter;
4
+ device: GPUDevice;
5
+ info: DeviceInfo;
6
+ }
7
+ /**
8
+ * Acquires a GPUAdapter/GPUDevice directly from the browser's `navigator.gpu`
9
+ * (high-performance power preference), requesting every optional device
10
+ * feature this suite can make use of — f16 shaders and GPU timestamp
11
+ * queries — without failing if the device lacks some of them. Each benchmark
12
+ * checks `info.supports*` and reports itself as "skipped" rather than
13
+ * crashing the suite when a feature is missing.
14
+ */
15
+ export declare function acquireGpuContext(): Promise<GpuContext>;
16
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/gpu/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,UAAU,CAAC;IACpB,MAAM,EAAE,SAAS,CAAC;IAClB,IAAI,EAAE,UAAU,CAAC;CAClB;AAWD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,UAAU,CAAC,CA4D7D"}
@@ -0,0 +1,71 @@
1
+ const OPTIONAL_FEATURES = ['shader-f16', 'timestamp-query'];
2
+ // `packed_4x8_integer_dot_product` is a WGSL *language* extension (enabled in
3
+ // shader source via `enable packed_4x8_integer_dot_product;`), not a
4
+ // GPUFeatureName — it's never granted via requestDevice()'s requiredFeatures
5
+ // and never appears in adapter.features / device.features. Support is
6
+ // reported separately through navigator.gpu.wgslLanguageFeatures.
7
+ const WGSL_I8_DOT_EXTENSION = 'packed_4x8_integer_dot_product';
8
+ /**
9
+ * Acquires a GPUAdapter/GPUDevice directly from the browser's `navigator.gpu`
10
+ * (high-performance power preference), requesting every optional device
11
+ * feature this suite can make use of — f16 shaders and GPU timestamp
12
+ * queries — without failing if the device lacks some of them. Each benchmark
13
+ * checks `info.supports*` and reports itself as "skipped" rather than
14
+ * crashing the suite when a feature is missing.
15
+ */
16
+ export async function acquireGpuContext() {
17
+ if (!('gpu' in navigator) || !navigator.gpu) {
18
+ throw new Error('WebGPU is not available in this browser (navigator.gpu is undefined).');
19
+ }
20
+ const adapter = await navigator.gpu.requestAdapter({ powerPreference: 'high-performance' });
21
+ if (!adapter) {
22
+ throw new Error('No suitable WebGPU adapter was found.');
23
+ }
24
+ const requiredFeatures = OPTIONAL_FEATURES.filter((f) => adapter.features.has(f));
25
+ const requiredLimits = {};
26
+ // Ask for the largest storage-buffer binding & workgroup budgets the adapter allows,
27
+ // so large matrices and tuned workgroup sizes aren't capped by conservative defaults.
28
+ for (const key of [
29
+ 'maxStorageBufferBindingSize',
30
+ 'maxBufferSize',
31
+ 'maxComputeWorkgroupSizeX',
32
+ 'maxComputeInvocationsPerWorkgroup',
33
+ 'maxComputeWorkgroupStorageSize',
34
+ ]) {
35
+ const value = adapter.limits[key];
36
+ if (typeof value === 'number')
37
+ requiredLimits[key] = value;
38
+ }
39
+ const device = await adapter.requestDevice({ requiredFeatures, requiredLimits });
40
+ const limits = {};
41
+ for (const key of Object.keys(device.limits)) {
42
+ const value = device.limits[key];
43
+ if (typeof value === 'number')
44
+ limits[key] = value;
45
+ }
46
+ let adapterInfoDescription;
47
+ let vendor;
48
+ let architecture;
49
+ const anyAdapter = adapter;
50
+ if (anyAdapter.info) {
51
+ vendor = anyAdapter.info.vendor || undefined;
52
+ architecture = anyAdapter.info.architecture || undefined;
53
+ adapterInfoDescription = anyAdapter.info.description || undefined;
54
+ }
55
+ const info = {
56
+ vendor,
57
+ architecture,
58
+ description: adapterInfoDescription,
59
+ features: [...device.features].toSorted(),
60
+ limits,
61
+ supportsF16: device.features.has('shader-f16'),
62
+ supportsI8Dot: Boolean(navigator.gpu.wgslLanguageFeatures?.has(WGSL_I8_DOT_EXTENSION)),
63
+ supportsTimestampQuery: device.features.has('timestamp-query'),
64
+ };
65
+ device.addEventListener('uncapturederror', (event) => {
66
+ // eslint-disable-next-line no-console
67
+ console.error('WebGPU uncaptured error:', event.error);
68
+ });
69
+ return { adapter, device, info };
70
+ }
71
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/gpu/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Wraps a single compute pass in GPU timestamp queries when the device
3
+ * supports `timestamp-query`, giving pure device-side elapsed time (no CPU
4
+ * dispatch/driver overhead in the number). Falls back to CPU wall-clock
5
+ * around `queue.onSubmittedWorkDone()` otherwise — still a fair comparison
6
+ * across kernels, just with a little more noise.
7
+ */
8
+ export declare class GpuTimer {
9
+ readonly supported: boolean;
10
+ private readonly querySet;
11
+ private readonly resolveBuffer;
12
+ private readonly resultBuffer;
13
+ constructor(device: GPUDevice, supported: boolean);
14
+ get timestampWrites(): GPUComputePassTimestampWrites | undefined;
15
+ resolve(encoder: GPUCommandEncoder): void;
16
+ /** Reads back the two timestamps written by the most recently submitted pass and returns elapsed ms. */
17
+ readElapsedMs(): Promise<number>;
18
+ destroy(): void;
19
+ }
20
+ //# sourceMappingURL=timing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timing.d.ts","sourceRoot":"","sources":["../../src/gpu/timing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,qBAAa,QAAQ;IAOjB,QAAQ,CAAC,SAAS,EAAE,OAAO;IAN7B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA4B;IACrD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0B;IACxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA0B;gBAGrD,MAAM,EAAE,SAAS,EACR,SAAS,EAAE,OAAO;IAe7B,IAAI,eAAe,IAAI,6BAA6B,GAAG,SAAS,CAG/D;IAED,OAAO,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI;IAMzC,wGAAwG;IAClG,aAAa,IAAI,OAAO,CAAC,MAAM,CAAC;IAUtC,OAAO,IAAI,IAAI;CAKhB"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Wraps a single compute pass in GPU timestamp queries when the device
3
+ * supports `timestamp-query`, giving pure device-side elapsed time (no CPU
4
+ * dispatch/driver overhead in the number). Falls back to CPU wall-clock
5
+ * around `queue.onSubmittedWorkDone()` otherwise — still a fair comparison
6
+ * across kernels, just with a little more noise.
7
+ */
8
+ export class GpuTimer {
9
+ supported;
10
+ querySet = null;
11
+ resolveBuffer = null;
12
+ resultBuffer = null;
13
+ constructor(device, supported) {
14
+ this.supported = supported;
15
+ if (supported) {
16
+ this.querySet = device.createQuerySet({ type: 'timestamp', count: 2 });
17
+ this.resolveBuffer = device.createBuffer({
18
+ size: 16,
19
+ usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC,
20
+ });
21
+ this.resultBuffer = device.createBuffer({
22
+ size: 16,
23
+ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
24
+ });
25
+ }
26
+ }
27
+ get timestampWrites() {
28
+ if (!this.supported || !this.querySet)
29
+ return undefined;
30
+ return { querySet: this.querySet, beginningOfPassWriteIndex: 0, endOfPassWriteIndex: 1 };
31
+ }
32
+ resolve(encoder) {
33
+ if (!this.supported || !this.querySet || !this.resolveBuffer || !this.resultBuffer)
34
+ return;
35
+ encoder.resolveQuerySet(this.querySet, 0, 2, this.resolveBuffer, 0);
36
+ encoder.copyBufferToBuffer(this.resolveBuffer, 0, this.resultBuffer, 0, 16);
37
+ }
38
+ /** Reads back the two timestamps written by the most recently submitted pass and returns elapsed ms. */
39
+ async readElapsedMs() {
40
+ if (!this.supported || !this.resultBuffer)
41
+ return Number.NaN;
42
+ await this.resultBuffer.mapAsync(GPUMapMode.READ);
43
+ const times = new BigInt64Array(this.resultBuffer.getMappedRange().slice(0));
44
+ this.resultBuffer.unmap();
45
+ const start = times[0];
46
+ const end = times[1];
47
+ return Number(end - start) / 1e6; // nanoseconds -> milliseconds
48
+ }
49
+ destroy() {
50
+ this.querySet?.destroy();
51
+ this.resolveBuffer?.destroy();
52
+ this.resultBuffer?.destroy();
53
+ }
54
+ }
55
+ //# sourceMappingURL=timing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timing.js","sourceRoot":"","sources":["../../src/gpu/timing.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,OAAO,QAAQ;IAOR;IANM,QAAQ,GAAuB,IAAI,CAAC;IACpC,aAAa,GAAqB,IAAI,CAAC;IACvC,YAAY,GAAqB,IAAI,CAAC;IAEvD,YACE,MAAiB,EACR,SAAkB;QAAlB,cAAS,GAAT,SAAS,CAAS;QAE3B,IAAI,SAAS,EAAE,CAAC;YACd,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YACvE,IAAI,CAAC,aAAa,GAAG,MAAM,CAAC,YAAY,CAAC;gBACvC,IAAI,EAAE,EAAE;gBACR,KAAK,EAAE,cAAc,CAAC,aAAa,GAAG,cAAc,CAAC,QAAQ;aAC9D,CAAC,CAAC;YACH,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC;gBACtC,IAAI,EAAE,EAAE;gBACR,KAAK,EAAE,cAAc,CAAC,QAAQ,GAAG,cAAc,CAAC,QAAQ;aACzD,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,IAAI,eAAe;QACjB,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ;YAAE,OAAO,SAAS,CAAC;QACxD,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,yBAAyB,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,CAAC;IAC3F,CAAC;IAED,OAAO,CAAC,OAA0B;QAChC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,QAAQ,IAAI,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC3F,OAAO,CAAC,eAAe,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;QACpE,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,wGAAwG;IACxG,KAAK,CAAC,aAAa;QACjB,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO,MAAM,CAAC,GAAG,CAAC;QAC7D,MAAM,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7E,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACxB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACtB,OAAO,MAAM,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,8BAA8B;IAClE,CAAC;IAED,OAAO;QACL,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC;QACzB,IAAI,CAAC,aAAa,EAAE,OAAO,EAAE,CAAC;QAC9B,IAAI,CAAC,YAAY,EAAE,OAAO,EAAE,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,12 @@
1
+ export { runSuite } from './suite.ts';
2
+ export type { BenchmarkResult, SuiteOptions, SuiteProgressEvent, DeviceInfo, Stats, BenchmarkCategory, BenchmarkStatus, TimingMethod, SamplingStopReason, } from './types.ts';
3
+ export { computeStats, isBestStable, isThrottled, tQuantile975 } from './stats.ts';
4
+ export type { BestStableOptions } from './stats.ts';
5
+ export { DEFAULT_SAMPLING, runSampling, recordSample, roundIsThrottled, resolveSamplingConfig } from './sampling.ts';
6
+ export type { SamplingConfig, Sampleable, SampleState, SampleStateSnapshot, RunSamplingOptions } from './sampling.ts';
7
+ export { DEFAULT_MEASUREMENT, KernelSampler } from './gpu/benchmarkRunner.ts';
8
+ export type { MeasurementConfig, KernelHarness, WorkKnob } from './gpu/benchmarkRunner.ts';
9
+ export { generateMatVecData, padToMultipleOf4, mulberry32 } from './data/generate.ts';
10
+ export { acquireGpuContext } from './gpu/context.ts';
11
+ export type { GpuContext } from './gpu/context.ts';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,YAAY,EACV,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,UAAU,EACV,KAAK,EACL,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,kBAAkB,GACnB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AACnF,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACrH,YAAY,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AACtH,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC9E,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { runSuite } from "./suite.js";
2
+ export { computeStats, isBestStable, isThrottled, tQuantile975 } from "./stats.js";
3
+ export { DEFAULT_SAMPLING, runSampling, recordSample, roundIsThrottled, resolveSamplingConfig } from "./sampling.js";
4
+ export { DEFAULT_MEASUREMENT, KernelSampler } from "./gpu/benchmarkRunner.js";
5
+ export { generateMatVecData, padToMultipleOf4, mulberry32 } from "./data/generate.js";
6
+ export { acquireGpuContext } from "./gpu/context.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAYtC,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEnF,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAErH,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9E,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC"}