917e5cdWebGPU toggle: single-precision GPU integration (displacement-based, multi-dispatch phases, frames read back), linear modes behind a toggle (off by default), shared prepare()Jeremy Magland 1// Development check: run an example on the CPU and on the GPU and compare.
2// From the browser console: (await import('/src/devcompare.ts')).compare('drum', 0.1)
4import { relDiff } from "./sim/analysis";
5import { simulateGPU } from "./sim/gpu";
6import { runScript } from "./sim/runScript";
7import { simulate } from "./sim/solver";
9const helperSources = import.meta.glob("../matlab/helpers/*.m", { query: "?raw", import: "default", eager: true }) as Record<string, string>;
10const exampleSources = import.meta.glob("../matlab/examples/*.m", { query: "?raw", import: "default", eager: true }) as Record<string, string>;
11const helpers = Object.entries(helperSources).map(([path, source]) => ({ name: path.split("/").pop()!, source }));
13export async function compare(name: string, duration: number, edit: (s: string) => string = s => s) {
14 const src = edit(exampleSources[`../matlab/examples/${name}.m`]);
15 const { sys } = runScript(src, helpers, () => {});
16 sys.duration = duration;
17 const cpu = simulate(sys);
18 const gpu = await simulateGPU(sys);
19 const fs = cpu.sampleRate;
20 const peak = (a: Float32Array) => a.reduce((m, x) => Math.max(m, Math.abs(x)), 0);
21 return {
22 n: sys.n,
23 substeps: cpu.substeps,
24 cpuRealTime: cpu.elapsedMs / 1000 / duration,
25 gpuRealTime: gpu.elapsedMs / 1000 / duration,
26 aborted: gpu.aborted,
27 diff: [0.001, 0.003, 0.01, 0.03, 0.1, duration].filter(t => t <= duration).map(t => [t, relDiff(cpu.audio, gpu.audio, Math.round(t * fs))]),
28 peakCpu: peak(cpu.audio),
29 peakGpu: peak(gpu.audio),
30 driftCpu: cpu.energyDrift,
31 driftGpu: gpu.energyDrift,
32 energyEnd: [cpu.energy[cpu.energy.length - 1], gpu.energy[gpu.energy.length - 1]],
33 dissEnd: [cpu.dissipated[cpu.dissipated.length - 1], gpu.dissipated[gpu.dissipated.length - 1]],
34 };
35}