Workload-conditioned operator profiling on patched vLLM 0.24.0 + Qwen3-30B-A3B/H20. H1b PASS (irregular patterns carry +23-45pp R64 raggedness, 8-45% token-efficiency loss vs rectangular controls); mechanism decomposition kills the padding narrative and finds the arrival-uniformization artifact (-12.9%); cross-version churn surface shows TP2/MNS64 -29.4% across vLLM 0.20->0.24 while the argmax held. Raw Layer-1 JSONL streams (507 MB) stay on disk, git-ignored; footer sidecars and metrics are tracked. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
671 lines
24 KiB
Python
671 lines
24 KiB
Python
#!/usr/bin/env python3
|
|
"""Detached, resumable Phase-5 four-way primary/control controller."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import datetime as dt
|
|
import hashlib
|
|
import json
|
|
import math
|
|
import os
|
|
import re
|
|
import shlex
|
|
import shutil
|
|
import subprocess
|
|
import time
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import opprof_phase3_matrix as m
|
|
|
|
|
|
WORKDIR = Path("/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712")
|
|
RUN_ROOT = WORKDIR / "runs/phase5"
|
|
PRIVATE = Path("/home/admin/cpfs/wjh/opprof-phase5-private/manifests")
|
|
P3_PRIVATE = Path("/home/admin/cpfs/wjh/opprof-phase3-private/manifests")
|
|
MODEL = Path("/home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B")
|
|
SOURCE = Path("/home/admin/cpfs/wjh/opprof-phase2-dash0-20260711/vllm-v0.24.0")
|
|
VENV = Path("/tmp/wjh-opprof-phase2-dash0-20260711/.venv")
|
|
CLIENT = WORKDIR / "scripts/opprof_phase5_client.py"
|
|
P3_CLIENT = WORKDIR / "scripts/opprof_phase3_client.py"
|
|
STATE = RUN_ROOT / "controller-state.json"
|
|
RATE = 0.4725
|
|
CAPTURE_SIZES = (
|
|
1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88,
|
|
96, 104, 112, 120, 128, 136, 144, 152, 160, 168, 176, 184, 192,
|
|
200, 208, 216, 224, 232, 240, 248, 256, 272, 288, 304, 320, 336,
|
|
352, 368, 384, 400, 416, 432, 448, 464, 480, 496, 512,
|
|
)
|
|
|
|
|
|
m.WORKDIR = WORKDIR
|
|
m.RUN_ROOT = RUN_ROOT
|
|
m.PRIVATE = PRIVATE
|
|
m.MODEL = MODEL
|
|
m.SOURCE = SOURCE
|
|
m.VENV = VENV
|
|
m.CLIENT = CLIENT
|
|
m.STATE = STATE
|
|
m.GPU_HOUR_LIMIT = 6.0
|
|
m.PRIOR_GPU_HOURS = 0.0
|
|
m.CONFIGS = {
|
|
"C00": {"tp": 1, "mns": 1024, "mbt": 8192, "flags": []},
|
|
"A2": {"tp": 1, "mns": 1024, "mbt": 8192, "flags": []},
|
|
"A4": {"tp": 1, "mns": 1024, "mbt": 8192, "flags": []},
|
|
}
|
|
|
|
|
|
def sha256_file(path: Path) -> str:
|
|
return m.sha256_file(path)
|
|
|
|
|
|
def arm_name(pattern: str) -> str:
|
|
return pattern.split("-r", 1)[0]
|
|
|
|
|
|
def manifest_for(pattern: str, burnin: bool) -> Path:
|
|
if burnin or pattern.startswith("background"):
|
|
return P3_PRIVATE / "P06.jsonl"
|
|
if pattern.startswith("control-P03"):
|
|
return P3_PRIVATE / "P03.jsonl"
|
|
if pattern.startswith("control-P04"):
|
|
return P3_PRIVATE / "P04.jsonl"
|
|
arm = arm_name(pattern)
|
|
return PRIVATE / ("P10-base.jsonl" if arm in {"base", "A2", "A4"} else f"P10-{arm}.jsonl")
|
|
|
|
|
|
def saturation_result_for(pattern: str) -> Path:
|
|
if pattern.startswith("control-P03"):
|
|
cell = "P03-C00"
|
|
elif pattern.startswith("control-P04"):
|
|
cell = "P04-C00"
|
|
else:
|
|
cell = "P10-C00"
|
|
return WORKDIR / f"runs/phase3/primary/{cell}/saturation/client/result.json"
|
|
|
|
|
|
def drain_budget(_pattern: str) -> int:
|
|
return 600
|
|
|
|
|
|
m.drain_budget = drain_budget
|
|
|
|
|
|
def server_command(assignment: m.Assignment, port: int, _trace_dir: Path) -> list[str]:
|
|
arm = arm_name(assignment.cell.pattern)
|
|
command = [
|
|
"taskset", "-c", m.cpu_mask(assignment.gpus), str(VENV / "bin/vllm"),
|
|
"serve", str(MODEL), "--host", "127.0.0.1", "--port", str(port),
|
|
"--tensor-parallel-size", "1", "--enable-chunked-prefill",
|
|
]
|
|
if arm != "A4" and assignment.cell.config != "A4":
|
|
command.append("--enable-prefix-caching")
|
|
command.extend(("--shutdown-timeout", "600"))
|
|
if arm == "A2" or assignment.cell.config == "A2":
|
|
command.extend(("--cudagraph-capture-sizes", *map(str, CAPTURE_SIZES)))
|
|
return command
|
|
|
|
|
|
def client_command(
|
|
assignment: m.Assignment,
|
|
port: int,
|
|
run_dir: Path,
|
|
_load_point: str,
|
|
_profile: bool,
|
|
burnin: bool,
|
|
_saturation_result: Path | None,
|
|
) -> list[str]:
|
|
pattern = assignment.cell.pattern
|
|
common = [
|
|
"taskset", "-c", m.cpu_mask(assignment.gpus), str(VENV / "bin/python"),
|
|
str(CLIENT), "run", "--manifest", str(manifest_for(pattern, burnin)),
|
|
"--base-url", f"http://127.0.0.1:{port}", "--model", str(MODEL),
|
|
"--max-concurrency", "256", "--ignore-eos", "--temperature", "0",
|
|
"--workload-seed", "20260712", "--server-seed", "20260712",
|
|
"--result-dir", str(run_dir / "client"),
|
|
]
|
|
if burnin:
|
|
return common + [
|
|
"--load-point", "saturation", "--request-rate", "inf",
|
|
"--warmup-seconds", "0", "--clean-segment-seconds", "20",
|
|
"--num-clean-segments", "3", "--post-clean-seconds", "0",
|
|
"--drain-timeout-seconds", "600",
|
|
]
|
|
if pattern.startswith("background"):
|
|
return common + [
|
|
"--load-point", "saturation", "--request-rate", "inf",
|
|
"--warmup-seconds", "60", "--clean-segment-seconds", "80",
|
|
"--num-clean-segments", "3", "--post-clean-seconds", "0",
|
|
"--drain-timeout-seconds", "600",
|
|
]
|
|
if pattern.startswith("control-"):
|
|
return common + [
|
|
"--load-point", "moderate", "--saturation-result",
|
|
str(saturation_result_for(pattern)), "--rate-fraction", "0.60",
|
|
"--warmup-seconds", "60", "--clean-segment-seconds", "80",
|
|
"--num-clean-segments", "3", "--post-clean-seconds", "0",
|
|
"--drain-timeout-seconds", "600",
|
|
]
|
|
return common + [
|
|
"--load-point", "moderate", "--fixed-request-rate", str(RATE),
|
|
"--warmup-seconds", "60", "--clean-segment-seconds", "80",
|
|
"--num-clean-segments", "3", "--post-clean-seconds", "0",
|
|
"--drain-timeout-seconds", "600",
|
|
]
|
|
|
|
|
|
m.server_command = server_command
|
|
m.client_command = client_command
|
|
|
|
|
|
_ORIGINAL_VALIDATE_CLIENT = m.validate_client
|
|
|
|
|
|
def _log_event_time(line: str, t0_wall_ns: int) -> float | None:
|
|
match = re.search(r"INFO\s+(\d{2})-(\d{2})\s+(\d{2}):(\d{2}):(\d{2})", line)
|
|
if match is None:
|
|
return None
|
|
month, day, hour, minute, second = map(int, match.groups())
|
|
year = dt.datetime.fromtimestamp(t0_wall_ns / 1e9, tz=dt.timezone.utc).year
|
|
stamp = dt.datetime(year, month, day, hour, minute, second, tzinfo=dt.timezone.utc)
|
|
return stamp.timestamp()
|
|
|
|
|
|
def cold_start_gate(run_dir: Path) -> dict[str, Any]:
|
|
result = json.loads((run_dir / "client/result.json").read_text())
|
|
requests = [
|
|
json.loads(line)
|
|
for line in (run_dir / "client/requests.jsonl").read_text().splitlines()
|
|
]
|
|
warm = [
|
|
request for request in requests
|
|
if request["success"] and 0 <= float(request["completed_s"]) < 60
|
|
]
|
|
warm_long = [request for request in warm if int(request["input_tokens"]) >= 8192]
|
|
t0_mono_ns = int(result["t0_mono_ns"])
|
|
stream = next((run_dir / "opprof").glob("*.jsonl"))
|
|
warm_descriptors: set[tuple[str, int]] = set()
|
|
clean_descriptors: set[tuple[str, int]] = set()
|
|
for line in stream.read_text().splitlines():
|
|
item = json.loads(line)
|
|
if "step_index" not in item or not item.get("model_executed"):
|
|
continue
|
|
graph = item["cudagraph"]
|
|
if not graph.get("hit"):
|
|
continue
|
|
relative_s = (int(item["submit_mono_ns"]) - t0_mono_ns) / 1e9
|
|
descriptor = (str(graph["runtime_mode"]), int(graph["bucket_tokens"]))
|
|
if 0 <= relative_s < 60:
|
|
warm_descriptors.add(descriptor)
|
|
elif 60 <= relative_s < 300:
|
|
clean_descriptors.add(descriptor)
|
|
|
|
log_lines = (run_dir / "server.log").read_text(errors="replace").splitlines()
|
|
ready_indices = [
|
|
index for index, line in enumerate(log_lines)
|
|
if "Application startup complete" in line
|
|
]
|
|
if len(ready_indices) != 1:
|
|
raise RuntimeError(f"expected one server ready marker: {run_dir}: {ready_indices}")
|
|
ready_index = ready_indices[0]
|
|
event_pattern = re.compile(
|
|
r"torch\.compile took|Directly load AOT compilation|\bCompiling\b|Capturing CUDA graphs",
|
|
re.IGNORECASE,
|
|
)
|
|
events = []
|
|
clean_boundary_wall_s = int(result["t0_wall_ns"]) / 1e9 + 60
|
|
clean_end_wall_s = int(result["t0_wall_ns"]) / 1e9 + 300
|
|
event_gate = True
|
|
clean_events = 0
|
|
for index, line in enumerate(log_lines):
|
|
if not event_pattern.search(line):
|
|
continue
|
|
timestamp = _log_event_time(line, int(result["t0_wall_ns"]))
|
|
phase = "pre-ready" if index < ready_index else "post-ready"
|
|
if index >= ready_index:
|
|
if timestamp is None:
|
|
event_gate = False
|
|
phase = "post-ready-unparseable"
|
|
elif timestamp >= clean_boundary_wall_s:
|
|
event_gate = False
|
|
phase = "clean" if timestamp < clean_end_wall_s else "post-clean"
|
|
if timestamp < clean_end_wall_s:
|
|
clean_events += 1
|
|
else:
|
|
phase = "warmup"
|
|
events.append(
|
|
{
|
|
"line": index + 1,
|
|
"phase": phase,
|
|
"timestamp_s": timestamp,
|
|
"message_prefix": line[:200],
|
|
}
|
|
)
|
|
|
|
config_match = re.search(
|
|
r"cudagraph_capture_sizes['\"]?:\s*\[([^\]]+)\]",
|
|
"\n".join(log_lines[:ready_index]),
|
|
)
|
|
startup_sizes = (
|
|
{int(value.strip()) for value in config_match.group(1).split(",")}
|
|
if config_match else set()
|
|
)
|
|
startup_modes = set()
|
|
for line in log_lines[:ready_index]:
|
|
if "Capturing CUDA graphs" not in line:
|
|
continue
|
|
if "PIECEWISE" in line:
|
|
startup_modes.add("PIECEWISE")
|
|
if "FULL" in line:
|
|
startup_modes.add("FULL")
|
|
uncovered = sorted(
|
|
descriptor for descriptor in clean_descriptors
|
|
if descriptor[0] not in startup_modes or descriptor[1] not in startup_sizes
|
|
)
|
|
passed = (
|
|
event_gate
|
|
and len(warm) >= 16
|
|
and len(warm_long) >= 1
|
|
and startup_modes == {"FULL", "PIECEWISE"}
|
|
and bool(startup_sizes)
|
|
and not uncovered
|
|
and clean_events == 0
|
|
)
|
|
return {
|
|
"amendment": "A-P5-1",
|
|
"passed": passed,
|
|
"warmup_completions": len(warm),
|
|
"warmup_long_completions": len(warm_long),
|
|
"warmup_long_min_tokens": min(
|
|
(int(request["input_tokens"]) for request in warm_long), default=None
|
|
),
|
|
"server_ready_line": ready_index + 1,
|
|
"compile_capture_events": events,
|
|
"event_gate_passed": event_gate,
|
|
"clean_capture_events": clean_events,
|
|
"startup_capture_sizes": sorted(startup_sizes),
|
|
"startup_capture_modes": sorted(startup_modes),
|
|
"warmup_descriptors": [list(item) for item in sorted(warm_descriptors)],
|
|
"clean_descriptors": [list(item) for item in sorted(clean_descriptors)],
|
|
"uncovered_clean_descriptors": [list(item) for item in uncovered],
|
|
"invariants": {
|
|
"events_preclean": event_gate,
|
|
"warmup_completions_ge_16": len(warm) >= 16,
|
|
"warmup_long_completion": len(warm_long) >= 1,
|
|
"startup_modes_complete": startup_modes == {"FULL", "PIECEWISE"},
|
|
"startup_sizes_present": bool(startup_sizes),
|
|
"clean_descriptors_covered": not uncovered,
|
|
"zero_clean_capture_events": clean_events == 0,
|
|
},
|
|
}
|
|
|
|
|
|
def validate_rate_client(run_dir: Path) -> dict[str, Any]:
|
|
result = json.loads((run_dir / "client/result.json").read_text())
|
|
sanity = json.loads((run_dir / "client/sanity.json").read_text())
|
|
requests = [
|
|
json.loads(line)
|
|
for line in (run_dir / "client/requests.jsonl").read_text().splitlines()
|
|
]
|
|
failed_sanity = [
|
|
key for key, value in sanity["invariants"].items()
|
|
if not value and key != "drain_within_timeout"
|
|
]
|
|
failure_summary = m.summarize_request_failures(
|
|
requests, float(result["clean"]["start_s"]), float(result["clean"]["end_s"])
|
|
)
|
|
cold = cold_start_gate(run_dir)
|
|
quarantined = float(result["drain_seconds"]) > 600
|
|
invariants = {
|
|
"client_sanity": not failed_sanity,
|
|
"clean_duration": math.isclose(float(result["clean"]["duration_s"]), 240.0),
|
|
"clean_failures_zero": result["clean"]["failed"] == 0
|
|
and failure_summary["clean_failed"] == 0,
|
|
"failed_records_accounted": result["failed_records"] == failure_summary["failed"],
|
|
"manifest_no_wrap": not result["manifest_wrapped"]
|
|
and not result["manifest_exhausted"],
|
|
"warmup_cold_start_gate": cold["passed"],
|
|
"profile_count": len(result["profiles"]) == 0,
|
|
"drain_re_adjudicated": not quarantined,
|
|
}
|
|
non_drain = {key: value for key, value in invariants.items() if key != "drain_re_adjudicated"}
|
|
if not all(non_drain.values()):
|
|
raise RuntimeError(
|
|
f"A-P5-1 rate-client invariant failure: {run_dir}: "
|
|
f"invariants={invariants}; failed_sanity={failed_sanity}; cold={cold}"
|
|
)
|
|
return {
|
|
"result": result,
|
|
"sanity": sanity,
|
|
"request_count": len(requests),
|
|
"warmup_completions": cold["warmup_completions"],
|
|
"warmup_required": 16,
|
|
"warmup_gate_branch": "A-P5-1-cold-start",
|
|
"warmup_stability": None,
|
|
"cold_start_gate": cold,
|
|
"drain_budget_seconds": 600,
|
|
"drain_quarantined": quarantined,
|
|
"excluded_window_failures": failure_summary["excluded"],
|
|
"excluded_window_failure_kinds": failure_summary["excluded_kinds"],
|
|
"invariants": invariants,
|
|
}
|
|
|
|
|
|
def validate_run(
|
|
entry: dict[str, Any], profile: bool, burnin: bool, allow_missing_traces: bool = False
|
|
) -> dict[str, Any]:
|
|
del profile, allow_missing_traces
|
|
pattern = entry["assignment"].cell.pattern
|
|
if burnin or pattern.startswith("background"):
|
|
validation_pattern = "P06"
|
|
elif pattern.startswith("control-P03"):
|
|
validation_pattern = "P03"
|
|
elif pattern.startswith("control-P04"):
|
|
validation_pattern = "P04"
|
|
else:
|
|
validation_pattern = "P10"
|
|
if burnin or pattern.startswith("background"):
|
|
client = _ORIGINAL_VALIDATE_CLIENT(
|
|
entry["run_dir"], validation_pattern, False, burnin
|
|
)
|
|
else:
|
|
client = validate_rate_client(entry["run_dir"])
|
|
layer1 = m.validate_layer1(entry["run_dir"])
|
|
log = (entry["run_dir"] / "server.log").read_text(errors="replace")
|
|
invariants = {
|
|
"triton_moe": "Using TRITON Unquantized MoE backend" in log,
|
|
"chunked_mbt": "Chunked prefill is enabled with max_num_batched_tokens=8192" in log,
|
|
"tp1": "tensor_parallel_size=1" in log,
|
|
"drain_shutdown": "mode=drain timeout=600s" in log,
|
|
"a2_sizes": entry["assignment"].cell.config != "A2"
|
|
or all(str(size) in log for size in (3, 5, 6, 7)),
|
|
}
|
|
if not all(invariants.values()):
|
|
raise RuntimeError(f"server invariant failure: {entry['run_id']}: {invariants}")
|
|
forbidden = re.compile(r'"(?:prompt|messages|content|text)"\s*:')
|
|
for path in (
|
|
entry["run_dir"] / "client/requests.jsonl",
|
|
entry["run_dir"] / "client/result.json",
|
|
Path(layer1["stream"]),
|
|
):
|
|
if forbidden.search(path.read_text(errors="replace")):
|
|
raise RuntimeError(f"private text leaked: {path}")
|
|
summary = {
|
|
"schema": 1,
|
|
"run_id": entry["run_id"],
|
|
"pattern": pattern,
|
|
"config": entry["assignment"].cell.config,
|
|
"gpus": entry["assignment"].gpus,
|
|
"client": client,
|
|
"layer1": layer1,
|
|
"traces": [],
|
|
"missing_trace_files": 0,
|
|
"layer2_missing_after_controller_cleanup": False,
|
|
"drain_quarantined": client["drain_quarantined"],
|
|
"server_invariants": invariants,
|
|
}
|
|
m.atomic_json(entry["run_dir"] / "run-complete.json", summary)
|
|
return summary
|
|
|
|
|
|
m.validate_run = validate_run
|
|
|
|
|
|
def manifests() -> dict[str, Any]:
|
|
result = {}
|
|
for name in ("base", "A1", "A3"):
|
|
path = PRIVATE / f"P10-{name}.jsonl"
|
|
summary = json.loads(path.with_suffix(path.suffix + ".summary.json").read_text())
|
|
if summary["rows"] != 142 or summary["sha256"] != sha256_file(path):
|
|
raise RuntimeError(f"manifest verification failed: {name}")
|
|
result[name] = {"path": str(path), "sha256": summary["sha256"]}
|
|
return result
|
|
|
|
|
|
def fingerprint() -> dict[str, Any]:
|
|
return {
|
|
"source_commit": subprocess.check_output(
|
|
["git", "-C", str(SOURCE), "rev-parse", "HEAD"], text=True
|
|
).strip(),
|
|
"source_tree": subprocess.check_output(
|
|
["git", "-C", str(SOURCE), "rev-parse", "HEAD^{tree}"], text=True
|
|
).strip(),
|
|
"client_sha256": sha256_file(CLIENT),
|
|
"controller_sha256": sha256_file(Path(__file__)),
|
|
"p3_client_sha256": sha256_file(P3_CLIENT),
|
|
"p3_matrix_sha256": sha256_file(Path(m.__file__).resolve()),
|
|
"manifests": manifests(),
|
|
"capture_sizes": list(CAPTURE_SIZES),
|
|
"rate": RATE,
|
|
}
|
|
|
|
|
|
def load_state(resume: bool) -> dict[str, Any]:
|
|
if STATE.exists():
|
|
if not resume:
|
|
raise RuntimeError("controller state exists; use --resume")
|
|
return json.loads(STATE.read_text())
|
|
return {
|
|
"schema": 1,
|
|
"status": "created",
|
|
"created_at": time.time(),
|
|
"controller_pid": os.getpid(),
|
|
"gpu_hours_total": 0.0,
|
|
"gpu_hours_this_stage": 0.0,
|
|
"completed_measured_runs": 0,
|
|
"completed_burnins": 0,
|
|
"drain_quarantined_runs": 0,
|
|
"clean_window_failures": 0,
|
|
"missing_trace_files": 0,
|
|
"stages": {},
|
|
"fingerprint": {},
|
|
}
|
|
|
|
|
|
def save_state(state: dict[str, Any]) -> None:
|
|
state["controller_pid"] = os.getpid()
|
|
state["updated_at"] = time.time()
|
|
m.atomic_json(STATE, state)
|
|
|
|
|
|
m.save_state = save_state
|
|
|
|
|
|
def ensure_provenance() -> None:
|
|
destination = RUN_ROOT / "provenance"
|
|
destination.mkdir(parents=True, exist_ok=True)
|
|
sources = [CLIENT, Path(__file__).resolve(), Path(m.__file__).resolve(), Path(m.common.__file__).resolve()]
|
|
hashes = {}
|
|
for source in sources:
|
|
target = destination / source.name
|
|
digest = sha256_file(source)
|
|
if target.exists() and sha256_file(target) != digest:
|
|
target = destination / f"{source.stem}.{digest[:12]}{source.suffix}"
|
|
if target.exists() and sha256_file(target) != digest:
|
|
raise RuntimeError(f"content-addressed provenance mismatch: {target}")
|
|
if not target.exists():
|
|
shutil.copy2(source, target)
|
|
hashes[target.name] = digest
|
|
m.atomic_json(destination / "sha256.json", hashes)
|
|
|
|
|
|
def primary_cells() -> list[m.Cell]:
|
|
config = {"base": "C00", "A1": "C00", "A2": "A2", "A3": "C00", "A4": "A4"}
|
|
items = [m.Cell(f"{arm}-r{replicate}", config[arm]) for arm in config for replicate in range(1, 4)]
|
|
return sorted(
|
|
items,
|
|
key=lambda cell: hashlib.sha256(
|
|
f"20260715:{cell.pattern.rsplit('-r',1)[1]}:{arm_name(cell.pattern)}".encode()
|
|
).hexdigest(),
|
|
)
|
|
|
|
|
|
def pack_unique(items: list[m.Cell], prefix: str) -> list[list[m.Assignment]]:
|
|
remaining = list(items)
|
|
waves: list[list[m.Assignment]] = []
|
|
wave_index = 0
|
|
while remaining:
|
|
selected: list[m.Cell] = []
|
|
used: set[str] = set()
|
|
for cell in list(remaining):
|
|
key = arm_name(cell.pattern)
|
|
if key in used:
|
|
continue
|
|
selected.append(cell)
|
|
used.add(key)
|
|
remaining.remove(cell)
|
|
if len(selected) == 4:
|
|
break
|
|
while len(selected) < 4:
|
|
selected.append(m.Cell(f"background-{prefix}-{wave_index}-{len(selected)}", "C00"))
|
|
assignments = []
|
|
for slot, cell in enumerate(selected):
|
|
gpu = (slot + wave_index) % 4
|
|
assignments.append(m.Assignment(cell, (gpu,)))
|
|
waves.append(assignments)
|
|
wave_index += 1
|
|
return waves
|
|
|
|
|
|
def pack_primary(items: list[m.Cell]) -> list[list[m.Assignment]]:
|
|
"""Pack SHA-ordered cells as 4/4/4/3 without duplicate arms per wave."""
|
|
capacities = (4, 4, 4, 3)
|
|
waves: list[list[m.Cell]] = [[] for _ in capacities]
|
|
|
|
def place(index: int) -> bool:
|
|
if index == len(items):
|
|
return all(len(wave) == capacity for wave, capacity in zip(waves, capacities, strict=True))
|
|
cell = items[index]
|
|
arm = arm_name(cell.pattern)
|
|
for wave_index, capacity in enumerate(capacities):
|
|
if len(waves[wave_index]) >= capacity:
|
|
continue
|
|
if any(arm_name(existing.pattern) == arm for existing in waves[wave_index]):
|
|
continue
|
|
waves[wave_index].append(cell)
|
|
if place(index + 1):
|
|
return True
|
|
waves[wave_index].pop()
|
|
return False
|
|
|
|
if not place(0):
|
|
raise RuntimeError("cannot pack frozen primary assignments into 4/4/4/3")
|
|
result: list[list[m.Assignment]] = []
|
|
for wave_index, cells in enumerate(waves):
|
|
if len(cells) == 3:
|
|
cells.append(m.Cell("background-primary-final", "C00"))
|
|
result.append(
|
|
[
|
|
m.Assignment(cell, ((slot + wave_index) % 4,))
|
|
for slot, cell in enumerate(cells)
|
|
]
|
|
)
|
|
return result
|
|
|
|
|
|
def execute_primary(resume: bool, amendment_a_p5_1: bool = False) -> None:
|
|
RUN_ROOT.mkdir(parents=True, exist_ok=True)
|
|
state = load_state(resume)
|
|
if resume:
|
|
m.cleanup_recorded(state)
|
|
current = fingerprint()
|
|
if state["fingerprint"] and state["fingerprint"] != current:
|
|
failure = str(state.get("stages", {}).get("primary-01", {}).get("failure", ""))
|
|
if not (
|
|
amendment_a_p5_1
|
|
and state.get("status") == "failed"
|
|
and "warmup" in failure.lower()
|
|
):
|
|
raise RuntimeError("resume fingerprint differs from frozen Phase-5 plan")
|
|
state.setdefault("amendments", {})["A-P5-1"] = {
|
|
"approved": True,
|
|
"applied_at": time.time(),
|
|
"reason": "replace rate-following drift gate with cold-start gates",
|
|
"prior_fingerprint": state["fingerprint"],
|
|
"replacement_fingerprint": current,
|
|
"retained_gpu_hours": state["gpu_hours_total"],
|
|
"burnins_reused": state["completed_burnins"],
|
|
}
|
|
state["fingerprint"] = current
|
|
state["status"] = "amended_resume_A-P5-1"
|
|
save_state(state)
|
|
state["fingerprint"] = current
|
|
state["status"] = "running_primary"
|
|
save_state(state)
|
|
ensure_provenance()
|
|
burnins = [
|
|
m.Assignment(m.Cell("burnin-C00", "C00"), (0,)),
|
|
m.Assignment(m.Cell("burnin-A2", "A2"), (1,)),
|
|
m.Assignment(m.Cell("burnin-A4", "A4"), (2,)),
|
|
]
|
|
m.run_stage(state, "burnins", burnins, "saturation", profile=False, burnin=True)
|
|
waves = pack_primary(primary_cells())
|
|
for index, wave in enumerate(waves, 1):
|
|
m.run_stage(state, f"primary-{index:02d}", wave, "moderate", profile=False)
|
|
primary = [
|
|
path for path in (RUN_ROOT / "primary").glob("*-r*-*/moderate/run-complete.json")
|
|
if "background" not in str(path)
|
|
]
|
|
if len(primary) != 15:
|
|
raise RuntimeError(f"primary completion mismatch: {len(primary)} != 15")
|
|
state["primary_runs"] = 15
|
|
state["background_runs"] = state["completed_measured_runs"] - 15
|
|
state["status"] = "primary_complete"
|
|
state["completed_at"] = time.time()
|
|
save_state(state)
|
|
|
|
|
|
def execute_controls(resume: bool) -> None:
|
|
state = load_state(resume)
|
|
m.cleanup_recorded(state)
|
|
if state.get("fingerprint") != fingerprint():
|
|
raise RuntimeError("control resume fingerprint mismatch")
|
|
cells = [
|
|
m.Cell(f"control-{pattern}-r{replicate}", "C00")
|
|
for pattern in ("P03", "P04") for replicate in range(1, 4)
|
|
]
|
|
for index, wave in enumerate(pack_unique(cells, "controls"), 1):
|
|
m.run_stage(state, f"controls-{index:02d}", wave, "moderate", profile=False)
|
|
state["status"] = "controls_complete"
|
|
state["controls_completed_at"] = time.time()
|
|
save_state(state)
|
|
|
|
|
|
def plan() -> dict[str, Any]:
|
|
return {
|
|
"schema": 1,
|
|
"primary_runs": 15,
|
|
"burnins": 3,
|
|
"waves": [[{"cell": a.cell.cell_id, "gpus": a.gpus} for a in wave] for wave in pack_primary(primary_cells())],
|
|
"rate": RATE,
|
|
"clean_seconds": 240,
|
|
"drain_seconds": 600,
|
|
"gpu_hour_limit": 6.0,
|
|
}
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser()
|
|
sub = parser.add_subparsers(dest="command", required=True)
|
|
for name in ("primary", "controls"):
|
|
item = sub.add_parser(name)
|
|
item.add_argument("--resume", action="store_true")
|
|
if name == "primary":
|
|
item.add_argument("--amendment-a-p5-1", action="store_true")
|
|
sub.add_parser("plan")
|
|
sub.add_parser("status")
|
|
args = parser.parse_args()
|
|
if args.command == "primary":
|
|
execute_primary(args.resume, args.amendment_a_p5_1)
|
|
elif args.command == "controls":
|
|
execute_controls(args.resume)
|
|
elif args.command == "plan":
|
|
print(json.dumps(plan(), sort_keys=True, indent=2))
|
|
else:
|
|
print(STATE.read_text() if STATE.exists() else '{"status":"absent"}')
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|