/// // The compute worker: runs solves off the main thread. One request at a // time; requests queue in the message queue while a sweep runs. numbl // solvers run synchronously here; a WebGPU solver runs on the worker's own // device, which is why the handler is asynchronous. import { getInstance } from "../problems/laplace2d/spec"; import { getSolver } from "../solvers"; import { runSweep } from "../harness/sweep"; import { runPoint, type RunPoint } from "../harness/runner"; import { runPointGpu, runSweepGpu } from "../harness/webgpuRun"; import { toResultPoint, type ResultPoint } from "../harness/resultSchema"; import { DEFAULT_TIMING, type TimingPolicy } from "../harness/timing"; import { matlabBase, solverSource } from "./matlabSources"; export interface SweepRequest { type: "sweep"; id: number; instanceId: string; solverId: string; timing: TimingPolicy; } export interface SolutionRequest { type: "solution"; id: number; instanceId: string; solverId: string; n: number; } export type WorkerRequest = SweepRequest | SolutionRequest; export type WorkerResponse = | { type: "point"; id: number; point: ResultPoint; index: number; total: number } | { type: "sweepDone"; id: number; points: ResultPoint[] } | { type: "solutionDone"; id: number; point: ResultPoint; uGrid: Float64Array; } | { type: "error"; id: number; message: string }; self.onmessage = async (e: MessageEvent) => { const msg = e.data; try { if (msg.type === "sweep") { const solver = getSolver(msg.solverId); const instance = getInstance(msg.instanceId); const onPoint = (p: RunPoint, index: number, total: number) => { const resp: WorkerResponse = { type: "point", id: msg.id, point: toResultPoint(p), index, total, }; postMessage(resp); }; const points = solver.runtime === "webgpu" ? await runSweepGpu({ instance, solver, timing: msg.timing, onPoint }) : runSweep({ instance, solver, sources: { ...matlabBase(), solver: solverSource(msg.solverId) }, timing: msg.timing, onPoint, }); const resp: WorkerResponse = { type: "sweepDone", id: msg.id, points: points.map(toResultPoint), }; postMessage(resp); } else if (msg.type === "solution") { const solver = getSolver(msg.solverId); const timing = { ...DEFAULT_TIMING, minTimedRuns: 1, timeBudgetSeconds: 0 }; const p = solver.runtime === "webgpu" ? await runPointGpu({ instance: getInstance(msg.instanceId), solverId: msg.solverId, n: msg.n, timing, wantGrid: true, }) : runPoint({ instance: getInstance(msg.instanceId), n: msg.n, timing, wantGrid: true, sources: { ...matlabBase(), solver: solverSource(msg.solverId) }, }); if (!p.uGrid) throw new Error("solver returned no grid values"); const resp: WorkerResponse = { type: "solutionDone", id: msg.id, point: toResultPoint(p), uGrid: p.uGrid, }; postMessage(resp, { transfer: [p.uGrid.buffer] }); } } catch (err) { const resp: WorkerResponse = { type: "error", id: msg.id, message: err instanceof Error ? err.message : String(err), }; postMessage(resp); } };