p4_plan_sweep: drive the shipped plan() at each candidate rate to settle the session shape before D-018
Browse files- kernels/p4_plan_sweep.py +63 -0
kernels/p4_plan_sweep.py
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Session-shape sweep on free CPU: what the shipped planner actually does at each candidate rate.
|
| 2 |
+
|
| 3 |
+
The D-018 decision is not only "12,977 tok/s or 9,696 tok/s" -- it is how many billed sessions the run
|
| 4 |
+
becomes and whether the remaining weekly quota covers them. Both are computed by the launcher's own `plan()`,
|
| 5 |
+
so this runs that function rather than re-deriving the arithmetic in prose: import the pinned launcher, walk
|
| 6 |
+
the schedule leg by leg at each rate, and print the legs, the session count, the stepping hours and the
|
| 7 |
+
hours the week still owes.
|
| 8 |
+
|
| 9 |
+
It mutates the module globals between walks, which is exactly what the environment variables do at launch,
|
| 10 |
+
so nothing here is a model of the planner -- it is the planner.
|
| 11 |
+
"""
|
| 12 |
+
import hashlib
|
| 13 |
+
import importlib.util
|
| 14 |
+
import json
|
| 15 |
+
import os
|
| 16 |
+
import subprocess
|
| 17 |
+
import sys
|
| 18 |
+
|
| 19 |
+
REV = "add04ae7a24bd9925115773a93e870fc1dd01f59"
|
| 20 |
+
SHA = "5f506471141683b710f41813cc0f19fc02442f7442d395d95dd9cba73a1b760f"
|
| 21 |
+
os.chdir("/kaggle/working")
|
| 22 |
+
url = f"https://huggingface.co/Cion-lab/ounce100m-code/resolve/{REV}/kernels/phase4_session.py"
|
| 23 |
+
assert subprocess.run(["curl", "-sfL", url, "-o", "phase4_session.py"]).returncode == 0, "fetch launcher"
|
| 24 |
+
got = hashlib.sha256(open("phase4_session.py", "rb").read()).hexdigest()
|
| 25 |
+
assert got == SHA, ("LAUNCHER SHA MISMATCH", got[:16], SHA[:16])
|
| 26 |
+
print("pinned launcher", got[:12], flush=True)
|
| 27 |
+
|
| 28 |
+
spec = importlib.util.spec_from_file_location("phase4_session", "phase4_session.py")
|
| 29 |
+
S = importlib.util.module_from_spec(spec)
|
| 30 |
+
spec.loader.exec_module(S)
|
| 31 |
+
|
| 32 |
+
RATES = [(9358.0, "checkpointed, the Gate 3 P3 measurement"),
|
| 33 |
+
(12792.0, "no checkpointing, the Gate 3 opts cell"),
|
| 34 |
+
(12977.0, "no checkpointing, measured again by probe v8")]
|
| 35 |
+
QUOTAS = [26.3, 24.5, 22.0]
|
| 36 |
+
|
| 37 |
+
for rate, why in RATES:
|
| 38 |
+
S.PLANNING_TOK_PER_S = rate
|
| 39 |
+
sec_per_step = S.TOKENS_PER_STEP / rate
|
| 40 |
+
for quota in QUOTAS:
|
| 41 |
+
S.QUOTA_LEFT_HOURS = quota
|
| 42 |
+
legs, start, guard = [], 0, 0
|
| 43 |
+
while start < S.HORIZON_STEPS and guard < 30:
|
| 44 |
+
guard += 1
|
| 45 |
+
pl = S.plan(start, 19.5)
|
| 46 |
+
n = pl["planned_steps"]
|
| 47 |
+
if not n:
|
| 48 |
+
legs.append((start, "REFUSED", pl["usable_hours"]))
|
| 49 |
+
break
|
| 50 |
+
end = S.HORIZON_STEPS if pl["stop_after_steps"] == 0 else pl["stop_after_steps"]
|
| 51 |
+
legs.append((start, end, end - start))
|
| 52 |
+
start = end
|
| 53 |
+
trained = sum(l[1] - l[0] for l in legs if isinstance(l[1], int))
|
| 54 |
+
hours = trained * sec_per_step / 3600.0
|
| 55 |
+
sessions = len(legs)
|
| 56 |
+
print("RATE %6.0f (%s) QUOTA %5.1f h -> %d sessions, %d/%d steps, %.2f h stepping; %s" % (
|
| 57 |
+
rate, why, quota, sessions, trained, S.HORIZON_STEPS, hours,
|
| 58 |
+
"FITS" if trained == S.HORIZON_STEPS and hours <= quota else "DOES NOT FIT"), flush=True)
|
| 59 |
+
print(" legs", json.dumps(legs), flush=True)
|
| 60 |
+
if trained != S.HORIZON_STEPS:
|
| 61 |
+
print(" shortfall %d steps = %.2f h at this rate" % (
|
| 62 |
+
S.HORIZON_STEPS - trained, (S.HORIZON_STEPS - trained) * sec_per_step / 3600.0), flush=True)
|
| 63 |
+
print("PLAN_SWEEP_DONE", flush=True)
|