Skip to content

Commit 7f8f450

Browse files
committed
Add speculative idle execution for warmInit (Phase 9).
1 parent 090493f commit 7f8f450

3 files changed

Lines changed: 43 additions & 0 deletions

File tree

builder/cpu-worker.mjs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { deriveOfflinePage, deriveOfflinePageCached,
1919
import {
2020
createViews, scanAndClaim, onTaskDone,
2121
READY, F_ON_DEMAND, F_RUN_ON_MAIN,
22+
F_RUN_WHEN_IDLE, F_UNIQUE_PER_WORKER,
2223
MAX_LANES,
2324
} from "./sab-scheduler.mjs";
2425

@@ -191,6 +192,24 @@ parentPort.on("message", (msg) => {
191192
}
192193
});
193194

195+
// ── Idle-task scan (speculative warmup) ─────────────────────────────────────
196+
197+
function findIdleTask(views, lane) {
198+
const count = Atomics.load(views.taskCount, 0);
199+
for (let i = 0; i < count; i++) {
200+
if (!(Atomics.load(views.flags, i) & F_RUN_WHEN_IDLE)) continue;
201+
if (Atomics.load(views.flags, i) & F_UNIQUE_PER_WORKER) {
202+
if (Atomics.load(views.perWorkerDone, i * MAX_LANES + lane) === 0)
203+
return i;
204+
} else {
205+
if (Atomics.load(views.status, i) !== READY) continue;
206+
if (Atomics.compareExchange(views.status, i, READY, CLAIMED) === READY)
207+
return i;
208+
}
209+
}
210+
return -1;
211+
}
212+
194213
// ── Pull loop ───────────────────────────────────────────────────────────────
195214

196215
async function pullLoop() {
@@ -200,6 +219,26 @@ async function pullLoop() {
200219
let taskIdx = scanAndClaim(views, myLane);
201220

202221
if (taskIdx === -1) {
222+
// Speculative: run idle-eligible tasks before sleeping
223+
const idleTask = findIdleTask(views, myLane);
224+
if (idleTask !== -1) {
225+
const idleMeta = taskMeta[idleTask];
226+
const idleStart = Date.now();
227+
try {
228+
await handlers[idleMeta.handler]();
229+
} catch (err) {
230+
parentPort.postMessage({ taskFailed: idleTask, message: err.message, stack: err.stack });
231+
return;
232+
}
233+
Atomics.store(views.perWorkerDone, idleTask * MAX_LANES + myLane, 1);
234+
parentPort.postMessage({
235+
warmInit: true,
236+
timing: { start: idleStart, end: Date.now() },
237+
lane: myLane,
238+
});
239+
continue;
240+
}
241+
203242
const gen = Atomics.load(views.notify, 0);
204243
// Double-check after reading gen (race: a task may have become
205244
// READY between the failed scan and this load).

builder/sab-scheduler.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export const F_ON_DEMAND = 1;
2222
export const F_UNIQUE_PER_WORKER = 2;
2323
export const F_RUN_ON_MAIN = 4;
2424
export const F_PIN_TO_PRED = 8;
25+
export const F_RUN_WHEN_IDLE = 16;
2526

2627
// ── SAB layout ───────────────────────────────────────────────────────────────
2728
//
@@ -142,6 +143,7 @@ export function allocSchedulerSAB(taskDefs, workerCount) {
142143
if (def?.unique_per_worker) f |= F_UNIQUE_PER_WORKER;
143144
if (def?.runOnMain) f |= F_RUN_ON_MAIN;
144145
if (def?.pin_to_predecessor) f |= F_PIN_TO_PRED;
146+
if (def?.run_when_idle) f |= F_RUN_WHEN_IDLE;
145147
views.flags[i] = f;
146148

147149
// successor edges
@@ -364,6 +366,7 @@ export function verifySchedulerSAB(taskDefs, views, idMapping) {
364366
if (def.unique_per_worker) want |= F_UNIQUE_PER_WORKER;
365367
if (def.runOnMain) want |= F_RUN_ON_MAIN;
366368
if (def.pin_to_predecessor) want |= F_PIN_TO_PRED;
369+
if (def.run_when_idle) want |= F_RUN_WHEN_IDLE;
367370
if (views.flags[idx] !== want)
368371
errors.push(`flags "${name}": got ${views.flags[idx]}, want ${want}`);
369372
}

builder/tbdocs.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ const TASKS = {
240240
expected: [],
241241
on_demand: true,
242242
unique_per_worker: true,
243+
run_when_idle: true,
243244
handler: "warmInit",
244245
submit() {},
245246
},

0 commit comments

Comments
 (0)