1/**
2 * The optional CPU comparison: run the very same script through numbl's
3 * normal engine (interpreter + its own JIT) in a worker numbl manages.
4 *
5 * tic/toc, fprintf and disp behave natively there, so the output — including
6 * the "Elapsed time is ..." lines — is directly comparable to the GPU pane
7 * and to real MATLAB. numbl computes in f64, which is also a useful
8 * cross-check on the GPU's f32 results.
9 *
10 * A fresh session per run keeps workspace state from leaking between runs.
11 * mip is disabled: sandbox scripts are self-contained MATLAB, and skipping
12 * the bootstrap keeps first-run latency down.
13 */
14import { createNumblSession } from 'numbl/browser';
16export interface CpuRunResult {
17 output: string;
18 /** Wall time of the whole script, as seen from the host. */
19 totalSeconds: number;
20 error?: string;
21 aborted?: boolean;
22}
24export interface CpuRunHandle {
25 result: Promise<CpuRunResult>;
26 /** Cooperative stop (needs cross-origin isolation to preempt loops). */
27 cancel: () => void;
28}
30export function runOnCpu(
31 source: string,
32 onOutput?: (text: string) => void,
33): CpuRunHandle {
34 let disposed = false;
35 let sessionRef: { dispose(): void; interrupt(): void } | null = null;
37 const result = (async (): Promise<CpuRunResult> => {
38 let output = '';
39 const session = await createNumblSession({
40 mip: false,
41 persistSystem: false,
42 displayResults: true,
43 onOutput: (text: string) => {
44 output += text;
45 onOutput?.(text);
46 },
47 });
48 sessionRef = session;
49 if (disposed) {
50 session.dispose();
51 return { output: '', totalSeconds: 0, aborted: true };
52 }
53 const t0 = performance.now();
54 try {
55 const res = await session.execute(source);
56 const totalSeconds = (performance.now() - t0) / 1000;
57 return {
58 output,
59 totalSeconds,
60 error: res.ok ? undefined : (res.error ?? 'numbl error'),
61 aborted: res.aborted === true,
62 };
63 } finally {
64 session.dispose();
65 }
66 })();
68 return {
69 result,
70 cancel: () => {
71 disposed = true;
72 sessionRef?.interrupt();
73 sessionRef?.dispose();
74 },
75 };
76}