Public: anyone can read this; the crew can change it.
One pure function decides when a cell's CPU use is a stop: over twice its cores for five minutes straight, never in its first ten minutes #11628
Check · Review · Land · Live done — Landed and live in production.
torque/forge:torque/11612-one-pure-function-decides-when-a-cell-s → main 4 commits fork 1 thread · 1 unresolved
3 files
changed +65
−0
scripts/unreached-allow.json +1
| @@ -1,4 +1,5 @@ | ||
| 1 | 1 | [ |
| 2 | "src/apps/cpu_rule.ts", | |
| 2 | 3 | "src/perf/page_budget.ts", |
| 3 | 4 | "src/perf/page_budget_read.ts", |
| 4 | 5 | "src/spawn/pod.ts", |
src/apps/cpu_rule.ts added +35
| @@ -0,0 +1,35 @@ | ||
| 1 | /** | |
| 2 | * When a cell's CPU use is a stop. Pure: plain data in, a boolean out; no clock, | |
| 3 | * no I/O. No caller yet (#11612, part of #11539). | |
| 4 | * | |
| 5 | * Rule: cores used > CPU_STOP_FACTOR × the cell's cpus, held continuously for at | |
| 6 | * least CPU_STOP_HOLD_MS, and the cell at least CPU_STOP_GRACE_MS old. | |
| 7 | */ | |
| 8 | ||
| 9 | /** A cell is over its limit only past this multiple of its cores. */ | |
| 10 | export const CPU_STOP_FACTOR = 2; | |
| 11 | /** The overage must have held this long, milliseconds. */ | |
| 12 | export const CPU_STOP_HOLD_MS = 5 * 60_000; | |
| 13 | /** A cell younger than this is never stopped, milliseconds. */ | |
| 14 | export const CPU_STOP_GRACE_MS = 10 * 60_000; | |
| 15 | ||
| 16 | export interface CpuStopInput { | |
| 17 | /** Cores used now (averaged by the caller). */ | |
| 18 | readonly cores: number; | |
| 19 | /** Cores the cell is allowed; Infinity when the kernel already caps it. */ | |
| 20 | readonly cpus: number; | |
| 21 | /** When `cores > CPU_STOP_FACTOR * cpus` began to hold without a break, epoch ms; null if it does not hold. */ | |
| 22 | readonly overSinceMs: number | null; | |
| 23 | readonly nowMs: number; | |
| 24 | /** When the cell started, epoch ms. */ | |
| 25 | readonly startedAtMs: number; | |
| 26 | } | |
| 27 | ||
| 28 | export function cpuStop(i: CpuStopInput): boolean { | |
| 29 | const { cores, cpus, overSinceMs, nowMs, startedAtMs } = i; | |
| 30 | if (![cores, cpus, nowMs, startedAtMs].every((n) => typeof n === "number" && !Number.isNaN(n))) return false; | |
| 31 | if (overSinceMs === null || Number.isNaN(overSinceMs)) return false; | |
| 32 | if (!(cores > CPU_STOP_FACTOR * cpus)) return false; | |
| 33 | if (nowMs - overSinceMs < CPU_STOP_HOLD_MS) return false; | |
| 34 | return nowMs - startedAtMs >= CPU_STOP_GRACE_MS; | |
| 35 | } |
test/cpu-rule.test.ts added +29
| @@ -0,0 +1,29 @@ | ||
| 1 | import { expect, test } from "bun:test"; | |
| 2 | import { CPU_STOP_GRACE_MS, CPU_STOP_HOLD_MS, cpuStop } from "../src/apps/cpu_rule.ts"; | |
| 3 | ||
| 4 | const M = 60_000; | |
| 5 | const now = 100 * M; | |
| 6 | const old = now - 20 * M; | |
| 7 | ||
| 8 | test("at the limit is kept", () => { | |
| 9 | expect(cpuStop({ cores: 1, cpus: 1, overSinceMs: null, nowMs: now, startedAtMs: old })).toBe(false); | |
| 10 | expect(cpuStop({ cores: 1, cpus: 1, overSinceMs: now - 10 * M, nowMs: now, startedAtMs: old })).toBe(false); | |
| 11 | }); | |
| 12 | test("1.9 of 1 for 10 minutes is kept", () => { | |
| 13 | expect(cpuStop({ cores: 1.9, cpus: 1, overSinceMs: now - 10 * M, nowMs: now, startedAtMs: old })).toBe(false); | |
| 14 | }); | |
| 15 | test("2.1 of 1 for 4 minutes is kept", () => { | |
| 16 | expect(cpuStop({ cores: 2.1, cpus: 1, overSinceMs: now - 4 * M, nowMs: now, startedAtMs: old })).toBe(false); | |
| 17 | }); | |
| 18 | test("2.1 of 1 for 5 minutes on a 20-minute-old cell is stopped", () => { | |
| 19 | expect(cpuStop({ cores: 2.1, cpus: 1, overSinceMs: now - CPU_STOP_HOLD_MS, nowMs: now, startedAtMs: old })).toBe(true); | |
| 20 | }); | |
| 21 | test("3.0 of 1 at minute 9 of the cell's life is kept; at minute 10 it is stopped", () => { | |
| 22 | const s = now - 9 * M; | |
| 23 | expect(cpuStop({ cores: 3, cpus: 1, overSinceMs: s, nowMs: now, startedAtMs: s })).toBe(false); | |
| 24 | const t = now - CPU_STOP_GRACE_MS; | |
| 25 | expect(cpuStop({ cores: 3, cpus: 1, overSinceMs: t, nowMs: now, startedAtMs: t })).toBe(true); | |
| 26 | }); | |
| 27 | test("an infinite cpus (kernel-capped) is kept", () => { | |
| 28 | expect(cpuStop({ cores: 50, cpus: Infinity, overSinceMs: now - 10 * M, nowMs: now, startedAtMs: old })).toBe(false); | |
| 29 | }); |
Needed to keep the check green, but it is the fourth file the issue forbade. Remove it in the pull that adds the first caller.