Add OpProf campaign: protocols, results, patches, run evidence (P0-P6)
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>
This commit is contained in:
47
runs/opprof-phase3/phase3/access-blocker-20260712.json
Normal file
47
runs/opprof-phase3/phase3/access-blocker-20260712.json
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"status": "external_access_blocked",
|
||||
"host": "dash0",
|
||||
"last_reachability_probe_local": "2026-07-12T16:16:39+08:00",
|
||||
"failure": "SSH connection timed out during banner exchange before any remote command executed",
|
||||
"last_durable_remote_state": {
|
||||
"observed_before_outage": true,
|
||||
"controller_pid": 2237019,
|
||||
"controller_status": "running",
|
||||
"active_stage": "primary-02-saturation",
|
||||
"active_stage_phase": "starting_servers",
|
||||
"completed_measured_runs": 8,
|
||||
"drain_quarantined_runs": 0,
|
||||
"clean_window_failures": 0,
|
||||
"missing_trace_files": 8,
|
||||
"gpu_hours_total": 6.8156048206885655
|
||||
},
|
||||
"resume": {
|
||||
"state": "/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/controller-state.json",
|
||||
"log": "/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/phase3-matrix-controller.log",
|
||||
"command": "cd /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712 && /tmp/wjh-opprof-phase2-dash0-20260711/.venv/bin/python scripts/opprof_phase3_matrix.py run --resume",
|
||||
"rule": "inspect state/PID/GPU ownership first; do not relaunch a live controller"
|
||||
},
|
||||
"profile_control_repair": {
|
||||
"reason": "P03/C01 saturated all data-plane connector slots, so /start_profile timed out before reaching the server",
|
||||
"change": "dedicated aiohttp TCPConnector(limit=2) and ClientSession for profile control calls",
|
||||
"old_client_sha256": "a87d92efecd5a8765b51067800b6382f9b174a2ede65f8933fcc9f846ff03d84",
|
||||
"new_client_sha256": "ab937a5f28252559c2fd97e848a500f1094cef232823ce4b90da8c0ece7554a0",
|
||||
"remote_record": "/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/repairs/repair-004-profile-control-connector.json",
|
||||
"tests": "13/13 unittest PASS; ruff PASS; py_compile PASS"
|
||||
},
|
||||
"analysis_ready": {
|
||||
"script_sha256": "205d9012d9462d84403a0f1435c8a449389aa4bef448d8d6dbced707a11559b0",
|
||||
"test_sha256": "eac6f55042865c9a24811eef9c1a13c23a26dd1504b54348513d8e6a7ba2b939",
|
||||
"tests": "4/4 unittest PASS; ruff PASS; py_compile PASS",
|
||||
"executed_on_matrix": false
|
||||
},
|
||||
"not_claimed": [
|
||||
"matrix completion",
|
||||
"final quarantine count",
|
||||
"H1a verdict",
|
||||
"H1b verdict",
|
||||
"final GPU hours",
|
||||
"final GPU cleanup"
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
1
runs/opprof-phase3/phase3/analysis/analyze-ap37.log
Normal file
1
runs/opprof-phase3/phase3/analysis/analyze-ap37.log
Normal file
File diff suppressed because one or more lines are too long
1
runs/opprof-phase3/phase3/analysis/launch-ap37.log
Normal file
1
runs/opprof-phase3/phase3/analysis/launch-ap37.log
Normal file
@@ -0,0 +1 @@
|
||||
CPU_ANALYSIS A-P3-7: accepted_runs=40, run_root=/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3, private_manifests=/home/admin/cpfs/wjh/opprof-phase3-private/manifests, bootstrap=100000 seed=20260714, output=runs/phase3/analysis/metrics-ap37.json, expected=10-30m CPU-only, GPU_cost=0
|
||||
737
runs/opprof-phase3/phase3/controller-state-stop-ap36.json
Normal file
737
runs/opprof-phase3/phase3/controller-state-stop-ap36.json
Normal file
@@ -0,0 +1,737 @@
|
||||
{
|
||||
"clean_window_failures": 0,
|
||||
"completed_burnins": 5,
|
||||
"completed_measured_runs": 40,
|
||||
"controller_pid": 2438791,
|
||||
"created_at": 1783833885.960389,
|
||||
"drain_quarantined_runs": 0,
|
||||
"fingerprint": {
|
||||
"cells": [
|
||||
"P08-C00",
|
||||
"P03-C10",
|
||||
"P07-C00",
|
||||
"P10-C01",
|
||||
"P01-C10",
|
||||
"P01-C01",
|
||||
"P10-C10",
|
||||
"P03-C01",
|
||||
"P09-C00",
|
||||
"P06-C01",
|
||||
"P10-C11",
|
||||
"P01-C00",
|
||||
"P01-C11",
|
||||
"P10-C00",
|
||||
"P04-C00",
|
||||
"P03-C00",
|
||||
"P06-C10",
|
||||
"P02-C00",
|
||||
"P06-C00",
|
||||
"P06-C11",
|
||||
"P11-C00",
|
||||
"P10-C00-TP2",
|
||||
"P03-C11",
|
||||
"P05-C00"
|
||||
],
|
||||
"client_sha256": "ab937a5f28252559c2fd97e848a500f1094cef232823ce4b90da8c0ece7554a0",
|
||||
"common_controller_sha256": "95f7169a1771e385aab40fcaecd967dc5cff0c21ea67bdd139382774ba43f01f",
|
||||
"controller_sha256": "6ac565ff35ead305f7b2e39e6a754389d03c27ea6511b2c9e8ebc0c868c9519f",
|
||||
"cpu_map": {
|
||||
"0": "0-19",
|
||||
"1": "20-39",
|
||||
"2": "40-59",
|
||||
"3": "60-79",
|
||||
"4": "80-99",
|
||||
"5": "100-119",
|
||||
"6": "120-139",
|
||||
"7": "140-159"
|
||||
},
|
||||
"manifests": {
|
||||
"P01": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P01.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "13ffb226c83373f54c4a7afea6c78cb7cd29720f1858d56728826fc1367b31a4"
|
||||
},
|
||||
"P02": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P02.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "0138ada3fccc98298daee66c26bd1952c987cb42ed8d5341d66b698a597417f9"
|
||||
},
|
||||
"P03": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P03.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "432cfbc26d36f105c179c83f3bb0f3b24b8b3f205788263b4171797f0a4d6fa1"
|
||||
},
|
||||
"P04": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P04.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "caf8d0941b093956a81e1413adc4a4ea9d92460f1b2ed0f6a9b118d0119d6247"
|
||||
},
|
||||
"P05": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P05.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "192e213109f8cb429b99d9eb0f227bb4390fc03f63b02d5456569369bff5a3d7"
|
||||
},
|
||||
"P06": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P06.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "65954bc6e47de9e7be07b8975f97f0bc4639979ef6d33e8c664557ded34b9f96"
|
||||
},
|
||||
"P07": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P07.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "74df66e21a705cd583493199a875e226e93d2da7cfede9bca81dfd9bcb8c9cc6"
|
||||
},
|
||||
"P08": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P08.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "0c4f835aae099265c3eb596d06c6c2fa7070dd280558eb289c602e8c3434dfe9"
|
||||
},
|
||||
"P09": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P09.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "7af92ee3c27dc7d2cf895d6ff3a6e737ec4b6da13d6841ca59e1166f28a0ae1e"
|
||||
},
|
||||
"P10": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P10.jsonl",
|
||||
"rows": 4011,
|
||||
"sha256": "f51b7a1cc657d62b9ea81823c754408732326b06e03439452433cd8ed481bf33"
|
||||
},
|
||||
"P11": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P11.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "7d196df38963528ff181cf72ce39c8ad913c8f61d40b1425410d3c6c30b6be18"
|
||||
}
|
||||
},
|
||||
"model": "/home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B",
|
||||
"source_commit": "4b253fd8619764b6971a7f2e3a3aa7545f6ace05",
|
||||
"source_tree": "a3d536b287a724e60abbec68b45eed7e088a15d1"
|
||||
},
|
||||
"gpu_hours_this_stage": 0.7173924536837472,
|
||||
"gpu_hours_total": 14.025875418755744,
|
||||
"missing_trace_files": 8,
|
||||
"repairs": [
|
||||
{
|
||||
"change": "dedicated aiohttp TCPConnector(limit=2) for profile endpoint session; request stream unchanged",
|
||||
"evidence": "/start_profile connection acquisition timed out before server receipt while 256 data-plane connections were occupied",
|
||||
"failed_run": "P03-C01-saturation",
|
||||
"failed_stage": "primary-02-saturation",
|
||||
"new_client_sha256": "ab937a5f28252559c2fd97e848a500f1094cef232823ce4b90da8c0ece7554a0",
|
||||
"old_client_sha256": "a87d92efecd5a8765b51067800b6382f9b174a2ede65f8933fcc9f846ff03d84",
|
||||
"repair": "profile-control-connector-isolation",
|
||||
"retry": "one exact whole-wave retry; failed directories retained as .interrupted-*",
|
||||
"schema": 1,
|
||||
"tests": {
|
||||
"py_compile": "PASS",
|
||||
"ruff": "PASS",
|
||||
"unittest": "13/13 PASS"
|
||||
},
|
||||
"timestamp": 1783837763.431071
|
||||
},
|
||||
{
|
||||
"budget": {
|
||||
"hard_cap": 16.0,
|
||||
"projected_remaining_h20_hours": 6.3857560787267165,
|
||||
"projected_total_h20_hours": 14.513826778670154,
|
||||
"projected_total_with_15pct_remaining_contingency": 15.471690190479162,
|
||||
"used_h20_hours": 8.128070699943438
|
||||
},
|
||||
"cause": "controller required failed_records==0 across excluded profile/recovery time although the registered hard gate is zero clean-window failures",
|
||||
"change": "replace all_failures_zero with clean-window boundary validation plus failed-record accounting; excluded failures remain reported",
|
||||
"evidence": {
|
||||
"clean_completed": 5828,
|
||||
"clean_failed": 0,
|
||||
"error_kind": "ServerDisconnectedError",
|
||||
"excluded_window_failures": 2,
|
||||
"failure_completion_s": [
|
||||
373.1505718010012,
|
||||
373.9740898209857
|
||||
],
|
||||
"run": "P01-C01-moderate"
|
||||
},
|
||||
"failed_stage": "primary-02-moderate",
|
||||
"gpu_rerun": false,
|
||||
"new_controller_sha256": "becfe00889274b51023016b1e7edb866d10e477249504f2032859a4d621f295f",
|
||||
"old_controller_sha256": "167e48f98f307e16ee44b321068a82a13813b3bf9a4d76882f774f15fe85e595",
|
||||
"repair": "clean-window-failure-scope",
|
||||
"schema": 1,
|
||||
"tests": {
|
||||
"py_compile": "PASS",
|
||||
"ruff": "PASS",
|
||||
"unittest": "14/14 PASS"
|
||||
},
|
||||
"timestamp": 1783847092.6920242
|
||||
},
|
||||
{
|
||||
"cause": "single preflight NVML sample observed 4 MiB on GPU0-3 with 0% utilization and no compute apps immediately after a verified cleanup",
|
||||
"change": "bounded 60s preflight requiring three consecutive samples with zero memory, zero utilization, and no compute apps; no nonzero-memory tolerance",
|
||||
"failed_stage": "primary-06-saturation",
|
||||
"gpu_hours_total_unchanged": 11.920448313262728,
|
||||
"gpu_launch_before_failure": false,
|
||||
"new_common_controller_sha256": "95f7169a1771e385aab40fcaecd967dc5cff0c21ea67bdd139382774ba43f01f",
|
||||
"old_common_controller_sha256": "15ad254298a38c4a9318468db89ab32707b6196bb38d5e2a007f2267529397a5",
|
||||
"repair": "stable-zero-preflight",
|
||||
"schema": 1,
|
||||
"tests": {
|
||||
"py_compile": "PASS",
|
||||
"ruff": "PASS",
|
||||
"unittest": "15/15 PASS"
|
||||
},
|
||||
"timestamp": 1783850898.1496143
|
||||
},
|
||||
{
|
||||
"code_change": false,
|
||||
"gpu_hours_used": 12.606695837948058,
|
||||
"hard_cap": 16.0,
|
||||
"projected_remaining_h20_hours": 2.1455133807990285,
|
||||
"projected_total_with_15pct_contingency": 15.07403622586694,
|
||||
"protocol_action": "single exact whole-wave infrastructure retry under identical 4-way placement; gate unchanged",
|
||||
"reason": "first TP2 P10 inference-shape cold start/autotune after readiness yielded 15 successful warmup completions against required 32; clean window and artifacts otherwise valid",
|
||||
"repair": "tp2-warmup-exact-retry",
|
||||
"run": "P10-C00-TP2-saturation",
|
||||
"schema": 1,
|
||||
"stage": "primary-06-saturation",
|
||||
"timestamp": 1783851710.3100822,
|
||||
"warmup_required": 32,
|
||||
"warmup_success": 15
|
||||
},
|
||||
{
|
||||
"accepted_runs_preserved": 40,
|
||||
"amendment": "A-P3-6",
|
||||
"changed_fingerprint_keys": [
|
||||
"controller_sha256"
|
||||
],
|
||||
"created_at": 1783853258.3098204,
|
||||
"failed_stage_preserved": "primary-06-saturation",
|
||||
"new_controller_sha256": "6ac565ff35ead305f7b2e39e6a754389d03c27ea6511b2c9e8ebc0c868c9519f",
|
||||
"old_controller_sha256": "becfe00889274b51023016b1e7edb866d10e477249504f2032859a4d621f295f",
|
||||
"projected_remaining_h20_hours": 2.1,
|
||||
"projected_total_h20_hours": 15.408482965071997,
|
||||
"repair_id": "repair-008-ap36",
|
||||
"retained_attempt_re_adjudicated": false,
|
||||
"retained_attempt_reason": "21 completions but A-P3-6 normalized drift 2.3385345997286295 and bin step counts 13/9/44",
|
||||
"schema": 1
|
||||
}
|
||||
],
|
||||
"schema": 1,
|
||||
"stages": {
|
||||
"burnin-01": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P06-C00",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C10",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C01",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C11",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": true,
|
||||
"clients": {},
|
||||
"completed_at": 1783834288.1238313,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.30808498481909435,
|
||||
"load_point": "saturation",
|
||||
"profile": false,
|
||||
"servers": {},
|
||||
"started_at": 1783833886.4448946,
|
||||
"status": "complete",
|
||||
"validation_attempt1_failure": "RuntimeError(\"server config/backend failure: /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/burnins/C01: {'triton_moe': True, 'chunked_mbt': False, 'tp_effective': True, 'drain_shutdown': True, 'mns_effective': True}\")"
|
||||
},
|
||||
"burnin-02": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P06-C00-TP2",
|
||||
"gpus": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": true,
|
||||
"clients": {},
|
||||
"completed_at": 1783834671.921921,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.19903395679261948,
|
||||
"load_point": "saturation",
|
||||
"profile": false,
|
||||
"servers": {},
|
||||
"started_at": 1783834301.7813473,
|
||||
"status": "complete"
|
||||
},
|
||||
"primary-01-moderate": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P08-C00",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P03-C10",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P07-C00",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P10-C01",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {},
|
||||
"completed_at": 1783836723.3639715,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.5195140059126748,
|
||||
"load_point": "moderate",
|
||||
"profile": true,
|
||||
"servers": {},
|
||||
"started_at": 1783836150.2169476,
|
||||
"status": "complete",
|
||||
"validation_attempt1_failure": "RuntimeError(\"client invariant failure: /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P10-C01/moderate: {'client_sanity': True, 'clean_duration': True, 'clean_failures_zero': True, 'all_failures_zero': True, 'manifest_no_wrap': True, 'warmup_completions': False, 'profile_count': True, 'profile_after_clean': True, 'drain_re_adjudicated': True}; failed=[]\")",
|
||||
"warmup_feasibility": "P10 target=min(32,floor(0.445*60))=26; observed=27"
|
||||
},
|
||||
"primary-01-saturation": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P08-C00",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P03-C10",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P07-C00",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P10-C01",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {},
|
||||
"completed_at": 1783836130.8498049,
|
||||
"confirmation": false,
|
||||
"drain_readjudication": "P10/C01 288.619107924s <= 600s",
|
||||
"gpu_hours": 0.8836704309119119,
|
||||
"load_point": "saturation",
|
||||
"missing_trace_files": 8,
|
||||
"profile": true,
|
||||
"servers": {},
|
||||
"started_at": 1783834671.9563339,
|
||||
"status": "complete",
|
||||
"validation_attempt1_failure": "RuntimeError(\"client failures: {'P10-C01-saturation': 1}\")"
|
||||
},
|
||||
"primary-02-moderate": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P01-C10",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P01-C01",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P10-C10",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P03-C01",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {},
|
||||
"completed_at": 1783847092.7229948,
|
||||
"confirmation": false,
|
||||
"failure": "RuntimeError(\"client invariant failure: /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P01-C01/moderate: {'client_sanity': True, 'clean_duration': True, 'clean_failures_zero': True, 'all_failures_zero': False, 'manifest_no_wrap': True, 'warmup_completions': True, 'profile_count': True, 'profile_after_clean': True, 'drain_re_adjudicated': True}; failed=[]\")",
|
||||
"gpu_hours": 0.5151156750652525,
|
||||
"load_point": "moderate",
|
||||
"profile": true,
|
||||
"readjudicated_without_gpu": true,
|
||||
"servers": {},
|
||||
"started_at": 1783838513.4472992,
|
||||
"status": "complete",
|
||||
"validation_attempt1_failure": "RuntimeError(\"client invariant failure: /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P01-C01/moderate: {'client_sanity': True, 'clean_duration': True, 'clean_failures_zero': True, 'all_failures_zero': False, 'manifest_no_wrap': True, 'warmup_completions': True, 'profile_count': True, 'profile_after_clean': True, 'drain_re_adjudicated': True}; failed=[]\")"
|
||||
},
|
||||
"primary-02-saturation": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P01-C10",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P01-C01",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P10-C10",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P03-C01",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {},
|
||||
"completed_at": 1783838513.4027848,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.7973502041896184,
|
||||
"load_point": "saturation",
|
||||
"profile": true,
|
||||
"servers": {},
|
||||
"started_at": 1783837773.6088765,
|
||||
"status": "complete"
|
||||
},
|
||||
"primary-03-moderate": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P09-C00",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C01",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P10-C11",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P01-C00",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {},
|
||||
"completed_at": 1783848369.3507695,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.5205460974905226,
|
||||
"load_point": "moderate",
|
||||
"profile": true,
|
||||
"servers": {},
|
||||
"started_at": 1783847881.06146,
|
||||
"status": "complete"
|
||||
},
|
||||
"primary-03-saturation": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P09-C00",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C01",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P10-C11",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P01-C00",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {},
|
||||
"completed_at": 1783847881.0197804,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.8273645816908942,
|
||||
"load_point": "saturation",
|
||||
"profile": true,
|
||||
"servers": {},
|
||||
"started_at": 1783847109.5683346,
|
||||
"status": "complete"
|
||||
},
|
||||
"primary-04-moderate": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P01-C11",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P10-C00",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P04-C00",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P03-C00",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {},
|
||||
"completed_at": 1783849583.5228572,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.5205216948853598,
|
||||
"load_point": "moderate",
|
||||
"profile": true,
|
||||
"servers": {},
|
||||
"started_at": 1783849096.4363403,
|
||||
"status": "complete"
|
||||
},
|
||||
"primary-04-saturation": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P01-C11",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P10-C00",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P04-C00",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P03-C00",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {},
|
||||
"completed_at": 1783849096.3948114,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.7872003297011058,
|
||||
"load_point": "saturation",
|
||||
"profile": true,
|
||||
"servers": {},
|
||||
"started_at": 1783848369.390857,
|
||||
"status": "complete"
|
||||
},
|
||||
"primary-05-moderate": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P06-C10",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P02-C00",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C00",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C11",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {},
|
||||
"completed_at": 1783850641.6781306,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.5138198028008143,
|
||||
"load_point": "moderate",
|
||||
"profile": true,
|
||||
"servers": {},
|
||||
"started_at": 1783850163.1211865,
|
||||
"status": "complete"
|
||||
},
|
||||
"primary-05-saturation": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P06-C10",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P02-C00",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C00",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C11",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {},
|
||||
"completed_at": 1783850163.0472832,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.6229251067505942,
|
||||
"load_point": "saturation",
|
||||
"profile": true,
|
||||
"servers": {},
|
||||
"started_at": 1783849583.5652869,
|
||||
"status": "complete"
|
||||
},
|
||||
"primary-06-saturation": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P11-C00",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P10-C00-TP2",
|
||||
"gpus": [
|
||||
1,
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P03-C11",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {
|
||||
"P03-C11-saturation": {
|
||||
"pgid": 2440965,
|
||||
"pid": 2440965
|
||||
},
|
||||
"P10-C00-TP2-saturation": {
|
||||
"pgid": 2440964,
|
||||
"pid": 2440964
|
||||
},
|
||||
"P11-C00-saturation": {
|
||||
"pgid": 2440962,
|
||||
"pid": 2440962
|
||||
}
|
||||
},
|
||||
"confirmation": false,
|
||||
"failure": "RuntimeError(\"client invariant failure: /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P10-C00-TP2/saturation: {'client_sanity': True, 'clean_duration': True, 'clean_failures_zero': True, 'failed_records_accounted': True, 'manifest_no_wrap': True, 'warmup_completions': False, 'profile_count': True, 'profile_after_clean': True, 'drain_re_adjudicated': True}; failed=[]; warmup_completions=17; warmup_gate_branch=failed; warmup_stability={'passed': False, 'reason': 'A-P3-6 stabilization criterion not met', 'window_seconds': [45.0, 60.0], 'bin_seconds': 5.0, 'step_counts': [11, 10, 16], 'scheduled_tokens': [90112, 81920, 70313], 'scheduled_token_throughput': [18022.4, 16384.0, 14062.6], 'mean_scheduled_token_throughput': 16156.333333333334, 'slope_tokens_per_second_squared': -395.98000000000013, 'normalized_drift': 0.367639109533929, 'normalized_drift_limit': 0.1, 'step_indices_continuous': True}\")",
|
||||
"gpu_hours": 0.7173924536837472,
|
||||
"load_point": "saturation",
|
||||
"profile": true,
|
||||
"servers": {
|
||||
"P03-C11-saturation": {
|
||||
"gpus": [
|
||||
3
|
||||
],
|
||||
"pgid": 2438868,
|
||||
"pid": 2438868
|
||||
},
|
||||
"P10-C00-TP2-saturation": {
|
||||
"gpus": [
|
||||
1,
|
||||
2
|
||||
],
|
||||
"pgid": 2438867,
|
||||
"pid": 2438867
|
||||
},
|
||||
"P11-C00-saturation": {
|
||||
"gpus": [
|
||||
0
|
||||
],
|
||||
"pgid": 2438866,
|
||||
"pid": 2438866
|
||||
}
|
||||
},
|
||||
"started_at": 1783853279.9695158,
|
||||
"status": "failed"
|
||||
}
|
||||
},
|
||||
"status": "failed",
|
||||
"updated_at": 1783853946.066117
|
||||
}
|
||||
39015
runs/opprof-phase3/phase3/metrics.json
Normal file
39015
runs/opprof-phase3/phase3/metrics.json
Normal file
File diff suppressed because it is too large
Load Diff
103
runs/opprof-phase3/phase3/remote-evidence/P03-C10/result.json
Normal file
103
runs/opprof-phase3/phase3/remote-evidence/P03-C10/result.json
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"admission_stop_s": 417.3262625900097,
|
||||
"arrival": "steady",
|
||||
"clean": {
|
||||
"admitted": 559,
|
||||
"completed": 559,
|
||||
"completed_throughput_rps": 2.3291666666666666,
|
||||
"duration_s": 240.0,
|
||||
"end_s": 300.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 3429894,
|
||||
"offered_rps": 2.3291666666666666,
|
||||
"output_tokens": 35776,
|
||||
"start_s": 60.0
|
||||
},
|
||||
"clean_segment_seconds": 80.0,
|
||||
"drain_seconds": 91.29178713698639,
|
||||
"elapsed_seconds": 508.6180497269961,
|
||||
"failed_records": 0,
|
||||
"load_point": "saturation",
|
||||
"manifest_admitted": 1094,
|
||||
"manifest_exhausted": false,
|
||||
"manifest_rows": 32768,
|
||||
"manifest_sha256": "432cfbc26d36f105c179c83f3bb0f3b24b8b3f205788263b4171797f0a4d6fa1",
|
||||
"manifest_wrapped": false,
|
||||
"max_in_flight": 256,
|
||||
"num_clean_segments": 3,
|
||||
"profiles": [
|
||||
{
|
||||
"start_call_s": 300.0043962339987,
|
||||
"start_return_s": 301.3819164079905,
|
||||
"start_status": 200,
|
||||
"stop_call_s": 321.8697677869932,
|
||||
"stop_return_s": 326.31530767300865,
|
||||
"stop_status": 200,
|
||||
"trace_file": "dp0_pp0_tp0_dcp0_ep0_rank0.1783835059474707213.pt.trace.json.gz",
|
||||
"trace_ready_s": 321.86976291501196,
|
||||
"trace_sha256": "527ddb81b1d54a12a463508bc163d85a2c443d94c8a897959a39735e030b90a2",
|
||||
"window": 1
|
||||
},
|
||||
{
|
||||
"start_call_s": 356.32926020701416,
|
||||
"start_return_s": 361.34978177401354,
|
||||
"start_status": 200,
|
||||
"stop_call_s": 381.577829301008,
|
||||
"stop_return_s": 387.31277802900877,
|
||||
"stop_status": 200,
|
||||
"trace_file": "dp0_pp0_tp0_dcp0_ep0_rank0.1783835119198018909.pt.trace.json.gz",
|
||||
"trace_ready_s": 381.57782580400817,
|
||||
"trace_sha256": "0882d9705f1208580d5e693f94ba64d89ab12ef0aae2731a82d460a46a3e4cb1",
|
||||
"window": 2
|
||||
}
|
||||
],
|
||||
"rate_fraction": null,
|
||||
"records": 1094,
|
||||
"request_rate": "inf",
|
||||
"schema": 1,
|
||||
"segments": [
|
||||
{
|
||||
"admitted": 191,
|
||||
"completed": 191,
|
||||
"completed_throughput_rps": 2.3875,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 140.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 1154628,
|
||||
"name": "A",
|
||||
"offered_rps": 2.3875,
|
||||
"output_tokens": 12224,
|
||||
"start_s": 60.0
|
||||
},
|
||||
{
|
||||
"admitted": 184,
|
||||
"completed": 184,
|
||||
"completed_throughput_rps": 2.3,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 220.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 1135217,
|
||||
"name": "B",
|
||||
"offered_rps": 2.3,
|
||||
"output_tokens": 11776,
|
||||
"start_s": 140.0
|
||||
},
|
||||
{
|
||||
"admitted": 184,
|
||||
"completed": 184,
|
||||
"completed_throughput_rps": 2.3,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 300.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 1140049,
|
||||
"name": "C",
|
||||
"offered_rps": 2.3,
|
||||
"output_tokens": 11776,
|
||||
"start_s": 220.0
|
||||
}
|
||||
],
|
||||
"successful_records": 1094,
|
||||
"t0_mono_ns": 166323993366724,
|
||||
"t0_wall_ns": 1783834751119796663,
|
||||
"warmup_seconds": 60.0
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"invariants": {
|
||||
"clean_duration_exact": true,
|
||||
"clean_failures_zero": true,
|
||||
"concurrency_bounded": true,
|
||||
"drain_within_timeout": true,
|
||||
"manifest_no_wrap": true,
|
||||
"manifest_not_exhausted": true,
|
||||
"output_tokens_exact": true,
|
||||
"profile_count_exact": true,
|
||||
"profile_status_ok": true,
|
||||
"segment_count_exact": true
|
||||
},
|
||||
"numeric": {
|
||||
"actual_output_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 1094,
|
||||
"max": 64.0,
|
||||
"min": 64.0,
|
||||
"missing_n": 0,
|
||||
"n": 1094
|
||||
},
|
||||
"admitted_s": {
|
||||
"distinct_n": 1094,
|
||||
"finite_n": 1094,
|
||||
"max": 416.7779763180006,
|
||||
"min": 0.0008771540015004575,
|
||||
"missing_n": 0,
|
||||
"n": 1094
|
||||
},
|
||||
"completed_s": {
|
||||
"distinct_n": 1094,
|
||||
"finite_n": 1094,
|
||||
"max": 508.61568894199445,
|
||||
"min": 22.18080371801625,
|
||||
"missing_n": 0,
|
||||
"n": 1094
|
||||
},
|
||||
"input_tokens": {
|
||||
"distinct_n": 964,
|
||||
"finite_n": 1094,
|
||||
"max": 8190.0,
|
||||
"min": 4097.0,
|
||||
"missing_n": 0,
|
||||
"n": 1094
|
||||
},
|
||||
"requested_output_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 1094,
|
||||
"max": 64.0,
|
||||
"min": 64.0,
|
||||
"missing_n": 0,
|
||||
"n": 1094
|
||||
},
|
||||
"scheduled_s": {
|
||||
"distinct_n": 1094,
|
||||
"finite_n": 1094,
|
||||
"max": 416.7779758319957,
|
||||
"min": 0.0008756940078455955,
|
||||
"missing_n": 0,
|
||||
"n": 1094
|
||||
}
|
||||
},
|
||||
"schema": 1
|
||||
}
|
||||
103
runs/opprof-phase3/phase3/remote-evidence/P07-C00/result.json
Normal file
103
runs/opprof-phase3/phase3/remote-evidence/P07-C00/result.json
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"admission_stop_s": 417.66287675101194,
|
||||
"arrival": "burst:8",
|
||||
"clean": {
|
||||
"admitted": 1226,
|
||||
"completed": 1226,
|
||||
"completed_throughput_rps": 5.108333333333333,
|
||||
"duration_s": 240.0,
|
||||
"end_s": 300.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 1569280,
|
||||
"offered_rps": 5.108333333333333,
|
||||
"output_tokens": 627712,
|
||||
"start_s": 60.0
|
||||
},
|
||||
"clean_segment_seconds": 80.0,
|
||||
"drain_seconds": 26.098238860984566,
|
||||
"elapsed_seconds": 443.7611156119965,
|
||||
"failed_records": 0,
|
||||
"load_point": "saturation",
|
||||
"manifest_admitted": 2078,
|
||||
"manifest_exhausted": false,
|
||||
"manifest_rows": 32768,
|
||||
"manifest_sha256": "74df66e21a705cd583493199a875e226e93d2da7cfede9bca81dfd9bcb8c9cc6",
|
||||
"manifest_wrapped": false,
|
||||
"max_in_flight": 256,
|
||||
"num_clean_segments": 3,
|
||||
"profiles": [
|
||||
{
|
||||
"start_call_s": 300.0039349270228,
|
||||
"start_return_s": 300.9924320260179,
|
||||
"start_status": 200,
|
||||
"stop_call_s": 323.90002606701455,
|
||||
"stop_return_s": 328.078528626007,
|
||||
"stop_status": 200,
|
||||
"trace_file": "dp0_pp0_tp0_dcp0_ep0_rank0.1783835058771060551.pt.trace.json.gz",
|
||||
"trace_ready_s": 323.9000201699964,
|
||||
"trace_sha256": "2d12038b03c6f9c28d1a488abd880ff2763e1f3c0ab502cfdd2507b649de2af7",
|
||||
"window": 1
|
||||
},
|
||||
{
|
||||
"start_call_s": 358.0940292410087,
|
||||
"start_return_s": 358.8905565890018,
|
||||
"start_status": 200,
|
||||
"stop_call_s": 382.04741394601297,
|
||||
"stop_return_s": 387.64796055300394,
|
||||
"stop_status": 200,
|
||||
"trace_file": "dp0_pp0_tp0_dcp0_ep0_rank0.1783835116964699401.pt.trace.json.gz",
|
||||
"trace_ready_s": 382.04741024502437,
|
||||
"trace_sha256": "2184d4f83ea22c0e5455dd3914922548ce8d3d5eba34f89562df69326e3832b5",
|
||||
"window": 2
|
||||
}
|
||||
],
|
||||
"rate_fraction": null,
|
||||
"records": 2078,
|
||||
"request_rate": "inf",
|
||||
"schema": 1,
|
||||
"segments": [
|
||||
{
|
||||
"admitted": 394,
|
||||
"completed": 394,
|
||||
"completed_throughput_rps": 4.925,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 140.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 504320,
|
||||
"name": "A",
|
||||
"offered_rps": 4.925,
|
||||
"output_tokens": 201728,
|
||||
"start_s": 60.0
|
||||
},
|
||||
{
|
||||
"admitted": 397,
|
||||
"completed": 397,
|
||||
"completed_throughput_rps": 4.9625,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 220.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 508160,
|
||||
"name": "B",
|
||||
"offered_rps": 4.9625,
|
||||
"output_tokens": 203264,
|
||||
"start_s": 140.0
|
||||
},
|
||||
{
|
||||
"admitted": 435,
|
||||
"completed": 435,
|
||||
"completed_throughput_rps": 5.4375,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 300.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 556800,
|
||||
"name": "C",
|
||||
"offered_rps": 5.4375,
|
||||
"output_tokens": 222720,
|
||||
"start_s": 220.0
|
||||
}
|
||||
],
|
||||
"successful_records": 2078,
|
||||
"t0_mono_ns": 166323999932716,
|
||||
"t0_wall_ns": 1783834751126361482,
|
||||
"warmup_seconds": 60.0
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"invariants": {
|
||||
"clean_duration_exact": true,
|
||||
"clean_failures_zero": true,
|
||||
"concurrency_bounded": true,
|
||||
"drain_within_timeout": true,
|
||||
"manifest_no_wrap": true,
|
||||
"manifest_not_exhausted": true,
|
||||
"output_tokens_exact": true,
|
||||
"profile_count_exact": true,
|
||||
"profile_status_ok": true,
|
||||
"segment_count_exact": true
|
||||
},
|
||||
"numeric": {
|
||||
"actual_output_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 2078,
|
||||
"max": 512.0,
|
||||
"min": 512.0,
|
||||
"missing_n": 0,
|
||||
"n": 2078
|
||||
},
|
||||
"admitted_s": {
|
||||
"distinct_n": 2078,
|
||||
"finite_n": 2078,
|
||||
"max": 417.40899016702315,
|
||||
"min": 0.0008179180149454623,
|
||||
"missing_n": 0,
|
||||
"n": 2078
|
||||
},
|
||||
"completed_s": {
|
||||
"distinct_n": 2078,
|
||||
"finite_n": 2078,
|
||||
"max": 443.75592052700813,
|
||||
"min": 35.15151289102505,
|
||||
"missing_n": 0,
|
||||
"n": 2078
|
||||
},
|
||||
"input_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 2078,
|
||||
"max": 1280.0,
|
||||
"min": 1280.0,
|
||||
"missing_n": 0,
|
||||
"n": 2078
|
||||
},
|
||||
"requested_output_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 2078,
|
||||
"max": 512.0,
|
||||
"min": 512.0,
|
||||
"missing_n": 0,
|
||||
"n": 2078
|
||||
},
|
||||
"scheduled_s": {
|
||||
"distinct_n": 2078,
|
||||
"finite_n": 2078,
|
||||
"max": 417.4089898300008,
|
||||
"min": 0.0008165129984263331,
|
||||
"missing_n": 0,
|
||||
"n": 2078
|
||||
}
|
||||
},
|
||||
"schema": 1
|
||||
}
|
||||
103
runs/opprof-phase3/phase3/remote-evidence/P08-C00/result.json
Normal file
103
runs/opprof-phase3/phase3/remote-evidence/P08-C00/result.json
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"admission_stop_s": 493.2576180040196,
|
||||
"arrival": "burst:8",
|
||||
"clean": {
|
||||
"admitted": 2233,
|
||||
"completed": 2233,
|
||||
"completed_throughput_rps": 9.304166666666667,
|
||||
"duration_s": 240.0,
|
||||
"end_s": 300.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 2858240,
|
||||
"offered_rps": 9.304166666666667,
|
||||
"output_tokens": 1143296,
|
||||
"start_s": 60.0
|
||||
},
|
||||
"clean_segment_seconds": 80.0,
|
||||
"drain_seconds": 14.923095890000695,
|
||||
"elapsed_seconds": 508.1807138940203,
|
||||
"failed_records": 0,
|
||||
"load_point": "saturation",
|
||||
"manifest_admitted": 3941,
|
||||
"manifest_exhausted": false,
|
||||
"manifest_rows": 32768,
|
||||
"manifest_sha256": "0c4f835aae099265c3eb596d06c6c2fa7070dd280558eb289c602e8c3434dfe9",
|
||||
"manifest_wrapped": false,
|
||||
"max_in_flight": 256,
|
||||
"num_clean_segments": 3,
|
||||
"profiles": [
|
||||
{
|
||||
"start_call_s": 300.0054247789958,
|
||||
"start_return_s": 323.45228312400286,
|
||||
"start_status": 200,
|
||||
"stop_call_s": 354.6066670610162,
|
||||
"stop_return_s": 381.28106322701205,
|
||||
"stop_status": 200,
|
||||
"trace_file": "dp0_pp0_tp0_dcp0_ep0_rank0.1783835082061801278.pt.trace.json.gz",
|
||||
"trace_ready_s": 354.6066622030048,
|
||||
"trace_sha256": "53d36238e82e5d031d8ed7841094c56d715b7cd5009368b64e380bf89a0f0dec",
|
||||
"window": 1
|
||||
},
|
||||
{
|
||||
"start_call_s": 411.30330635100836,
|
||||
"start_return_s": 411.4401313569979,
|
||||
"start_status": 200,
|
||||
"stop_call_s": 436.0742275560042,
|
||||
"stop_return_s": 463.23921855099616,
|
||||
"stop_status": 200,
|
||||
"trace_file": "dp0_pp0_tp0_dcp0_ep0_rank0.1783835169024306574.pt.trace.json.gz",
|
||||
"trace_ready_s": 436.0742245099973,
|
||||
"trace_sha256": "e088bd800a4e43446effbbcd4fce7d9ba1defaceb378a6e0db04d64780e1d09a",
|
||||
"window": 2
|
||||
}
|
||||
],
|
||||
"rate_fraction": null,
|
||||
"records": 3941,
|
||||
"request_rate": "inf",
|
||||
"schema": 1,
|
||||
"segments": [
|
||||
{
|
||||
"admitted": 697,
|
||||
"completed": 697,
|
||||
"completed_throughput_rps": 8.7125,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 140.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 892160,
|
||||
"name": "A",
|
||||
"offered_rps": 8.7125,
|
||||
"output_tokens": 356864,
|
||||
"start_s": 60.0
|
||||
},
|
||||
{
|
||||
"admitted": 768,
|
||||
"completed": 768,
|
||||
"completed_throughput_rps": 9.6,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 220.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 983040,
|
||||
"name": "B",
|
||||
"offered_rps": 9.6,
|
||||
"output_tokens": 393216,
|
||||
"start_s": 140.0
|
||||
},
|
||||
{
|
||||
"admitted": 768,
|
||||
"completed": 768,
|
||||
"completed_throughput_rps": 9.6,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 300.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 983040,
|
||||
"name": "C",
|
||||
"offered_rps": 9.6,
|
||||
"output_tokens": 393216,
|
||||
"start_s": 220.0
|
||||
}
|
||||
],
|
||||
"successful_records": 3941,
|
||||
"t0_mono_ns": 166324009670273,
|
||||
"t0_wall_ns": 1783834751136099481,
|
||||
"warmup_seconds": 60.0
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"invariants": {
|
||||
"clean_duration_exact": true,
|
||||
"clean_failures_zero": true,
|
||||
"concurrency_bounded": true,
|
||||
"drain_within_timeout": true,
|
||||
"manifest_no_wrap": true,
|
||||
"manifest_not_exhausted": true,
|
||||
"output_tokens_exact": true,
|
||||
"profile_count_exact": true,
|
||||
"profile_status_ok": true,
|
||||
"segment_count_exact": true
|
||||
},
|
||||
"numeric": {
|
||||
"actual_output_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 3941,
|
||||
"max": 512.0,
|
||||
"min": 512.0,
|
||||
"missing_n": 0,
|
||||
"n": 3941
|
||||
},
|
||||
"admitted_s": {
|
||||
"distinct_n": 3941,
|
||||
"finite_n": 3941,
|
||||
"max": 493.25117621201207,
|
||||
"min": 0.0009094980196096003,
|
||||
"missing_n": 0,
|
||||
"n": 3941
|
||||
},
|
||||
"completed_s": {
|
||||
"distinct_n": 3941,
|
||||
"finite_n": 3941,
|
||||
"max": 508.1755032700021,
|
||||
"min": 30.030000179016497,
|
||||
"missing_n": 0,
|
||||
"n": 3941
|
||||
},
|
||||
"input_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 3941,
|
||||
"max": 1280.0,
|
||||
"min": 1280.0,
|
||||
"missing_n": 0,
|
||||
"n": 3941
|
||||
},
|
||||
"requested_output_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 3941,
|
||||
"max": 512.0,
|
||||
"min": 512.0,
|
||||
"missing_n": 0,
|
||||
"n": 3941
|
||||
},
|
||||
"scheduled_s": {
|
||||
"distinct_n": 3941,
|
||||
"finite_n": 3941,
|
||||
"max": 493.25117589501315,
|
||||
"min": 0.000907983019715175,
|
||||
"missing_n": 0,
|
||||
"n": 3941
|
||||
}
|
||||
},
|
||||
"schema": 1
|
||||
}
|
||||
103
runs/opprof-phase3/phase3/remote-evidence/P10-C01/result.json
Normal file
103
runs/opprof-phase3/phase3/remote-evidence/P10-C01/result.json
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"admission_stop_s": 420.6437278209778,
|
||||
"arrival": "steady",
|
||||
"clean": {
|
||||
"admitted": 178,
|
||||
"completed": 178,
|
||||
"completed_throughput_rps": 0.7416666666666667,
|
||||
"duration_s": 240.0,
|
||||
"end_s": 300.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 1755158,
|
||||
"offered_rps": 0.7416666666666667,
|
||||
"output_tokens": 40658,
|
||||
"start_s": 60.0
|
||||
},
|
||||
"clean_segment_seconds": 80.0,
|
||||
"drain_seconds": 288.6191079240234,
|
||||
"elapsed_seconds": 709.2628357450012,
|
||||
"failed_records": 0,
|
||||
"load_point": "saturation",
|
||||
"manifest_admitted": 558,
|
||||
"manifest_exhausted": false,
|
||||
"manifest_rows": 4011,
|
||||
"manifest_sha256": "f51b7a1cc657d62b9ea81823c754408732326b06e03439452433cd8ed481bf33",
|
||||
"manifest_wrapped": false,
|
||||
"max_in_flight": 256,
|
||||
"num_clean_segments": 3,
|
||||
"profiles": [
|
||||
{
|
||||
"start_call_s": 300.0035294489935,
|
||||
"start_return_s": 310.3520467719936,
|
||||
"start_status": 200,
|
||||
"stop_call_s": 325.0655262139917,
|
||||
"stop_return_s": 338.54296391498065,
|
||||
"stop_status": 200,
|
||||
"trace_file": "dp0_pp0_tp0_dcp0_ep0_rank0.1783835066783986388.pt.trace.json.gz",
|
||||
"trace_ready_s": 325.0655210709956,
|
||||
"trace_sha256": "d457af416fa91f44e617c7259167fca467bea8466a3e4c4b916f811fb5899c73",
|
||||
"window": 1
|
||||
},
|
||||
{
|
||||
"start_call_s": 368.55468072599615,
|
||||
"start_return_s": 372.31818850699347,
|
||||
"start_status": 200,
|
||||
"stop_call_s": 386.0271748309897,
|
||||
"stop_return_s": 390.6334540609969,
|
||||
"stop_status": 200,
|
||||
"trace_file": "dp0_pp0_tp0_dcp0_ep0_rank0.1783835128341345321.pt.trace.json.gz",
|
||||
"trace_ready_s": 386.02717122397735,
|
||||
"trace_sha256": "41e8b34a0464cfd92d16b21c6242113b23594081697f5d1e88cdc3647542a96a",
|
||||
"window": 2
|
||||
}
|
||||
],
|
||||
"rate_fraction": null,
|
||||
"records": 558,
|
||||
"request_rate": "inf",
|
||||
"schema": 1,
|
||||
"segments": [
|
||||
{
|
||||
"admitted": 48,
|
||||
"completed": 48,
|
||||
"completed_throughput_rps": 0.6,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 140.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 548329,
|
||||
"name": "A",
|
||||
"offered_rps": 0.6,
|
||||
"output_tokens": 11027,
|
||||
"start_s": 60.0
|
||||
},
|
||||
{
|
||||
"admitted": 70,
|
||||
"completed": 70,
|
||||
"completed_throughput_rps": 0.875,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 220.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 574251,
|
||||
"name": "B",
|
||||
"offered_rps": 0.875,
|
||||
"output_tokens": 16298,
|
||||
"start_s": 140.0
|
||||
},
|
||||
{
|
||||
"admitted": 60,
|
||||
"completed": 60,
|
||||
"completed_throughput_rps": 0.75,
|
||||
"duration_s": 80.0,
|
||||
"end_s": 300.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 632578,
|
||||
"name": "C",
|
||||
"offered_rps": 0.75,
|
||||
"output_tokens": 13333,
|
||||
"start_s": 220.0
|
||||
}
|
||||
],
|
||||
"successful_records": 558,
|
||||
"t0_mono_ns": 166325149689000,
|
||||
"t0_wall_ns": 1783834752276118250,
|
||||
"warmup_seconds": 60.0
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"invariants": {
|
||||
"clean_duration_exact": true,
|
||||
"clean_failures_zero": true,
|
||||
"concurrency_bounded": true,
|
||||
"drain_within_timeout": false,
|
||||
"manifest_no_wrap": true,
|
||||
"manifest_not_exhausted": true,
|
||||
"output_tokens_exact": true,
|
||||
"profile_count_exact": true,
|
||||
"profile_status_ok": true,
|
||||
"segment_count_exact": true
|
||||
},
|
||||
"numeric": {
|
||||
"actual_output_tokens": {
|
||||
"distinct_n": 92,
|
||||
"finite_n": 558,
|
||||
"max": 256.0,
|
||||
"min": 6.0,
|
||||
"missing_n": 0,
|
||||
"n": 558
|
||||
},
|
||||
"admitted_s": {
|
||||
"distinct_n": 558,
|
||||
"finite_n": 558,
|
||||
"max": 420.08466253298684,
|
||||
"min": 0.000850101001560688,
|
||||
"missing_n": 0,
|
||||
"n": 558
|
||||
},
|
||||
"completed_s": {
|
||||
"distinct_n": 558,
|
||||
"finite_n": 558,
|
||||
"max": 709.2613093179825,
|
||||
"min": 14.001143716974184,
|
||||
"missing_n": 0,
|
||||
"n": 558
|
||||
},
|
||||
"input_tokens": {
|
||||
"distinct_n": 535,
|
||||
"finite_n": 558,
|
||||
"max": 32527.0,
|
||||
"min": 70.0,
|
||||
"missing_n": 0,
|
||||
"n": 558
|
||||
},
|
||||
"requested_output_tokens": {
|
||||
"distinct_n": 92,
|
||||
"finite_n": 558,
|
||||
"max": 256.0,
|
||||
"min": 6.0,
|
||||
"missing_n": 0,
|
||||
"n": 558
|
||||
},
|
||||
"scheduled_s": {
|
||||
"distinct_n": 558,
|
||||
"finite_n": 558,
|
||||
"max": 420.08466206499725,
|
||||
"min": 0.0008485929865855724,
|
||||
"missing_n": 0,
|
||||
"n": 558
|
||||
}
|
||||
},
|
||||
"schema": 1
|
||||
}
|
||||
258
runs/opprof-phase3/phase3/remote-evidence/controller-state.json
Normal file
258
runs/opprof-phase3/phase3/remote-evidence/controller-state.json
Normal file
@@ -0,0 +1,258 @@
|
||||
{
|
||||
"completed_burnins": 5,
|
||||
"completed_measured_runs": 0,
|
||||
"controller_pid": 2187729,
|
||||
"created_at": 1783833885.960389,
|
||||
"fingerprint": {
|
||||
"cells": [
|
||||
"P08-C00",
|
||||
"P03-C10",
|
||||
"P07-C00",
|
||||
"P10-C01",
|
||||
"P01-C10",
|
||||
"P01-C01",
|
||||
"P10-C10",
|
||||
"P03-C01",
|
||||
"P09-C00",
|
||||
"P06-C01",
|
||||
"P10-C11",
|
||||
"P01-C00",
|
||||
"P01-C11",
|
||||
"P10-C00",
|
||||
"P04-C00",
|
||||
"P03-C00",
|
||||
"P06-C10",
|
||||
"P02-C00",
|
||||
"P06-C00",
|
||||
"P06-C11",
|
||||
"P11-C00",
|
||||
"P10-C00-TP2",
|
||||
"P03-C11",
|
||||
"P05-C00"
|
||||
],
|
||||
"client_sha256": "a87d92efecd5a8765b51067800b6382f9b174a2ede65f8933fcc9f846ff03d84",
|
||||
"common_controller_sha256": "15ad254298a38c4a9318468db89ab32707b6196bb38d5e2a007f2267529397a5",
|
||||
"controller_sha256": "c2d3232fb99c66cea55e30e6cb1aa6a84d3a816434ed8155a309f41df2837f73",
|
||||
"cpu_map": {
|
||||
"0": "0-19",
|
||||
"1": "20-39",
|
||||
"2": "40-59",
|
||||
"3": "60-79",
|
||||
"4": "80-99",
|
||||
"5": "100-119",
|
||||
"6": "120-139",
|
||||
"7": "140-159"
|
||||
},
|
||||
"manifests": {
|
||||
"P01": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P01.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "13ffb226c83373f54c4a7afea6c78cb7cd29720f1858d56728826fc1367b31a4"
|
||||
},
|
||||
"P02": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P02.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "0138ada3fccc98298daee66c26bd1952c987cb42ed8d5341d66b698a597417f9"
|
||||
},
|
||||
"P03": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P03.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "432cfbc26d36f105c179c83f3bb0f3b24b8b3f205788263b4171797f0a4d6fa1"
|
||||
},
|
||||
"P04": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P04.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "caf8d0941b093956a81e1413adc4a4ea9d92460f1b2ed0f6a9b118d0119d6247"
|
||||
},
|
||||
"P05": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P05.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "192e213109f8cb429b99d9eb0f227bb4390fc03f63b02d5456569369bff5a3d7"
|
||||
},
|
||||
"P06": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P06.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "65954bc6e47de9e7be07b8975f97f0bc4639979ef6d33e8c664557ded34b9f96"
|
||||
},
|
||||
"P07": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P07.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "74df66e21a705cd583493199a875e226e93d2da7cfede9bca81dfd9bcb8c9cc6"
|
||||
},
|
||||
"P08": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P08.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "0c4f835aae099265c3eb596d06c6c2fa7070dd280558eb289c602e8c3434dfe9"
|
||||
},
|
||||
"P09": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P09.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "7af92ee3c27dc7d2cf895d6ff3a6e737ec4b6da13d6841ca59e1166f28a0ae1e"
|
||||
},
|
||||
"P10": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P10.jsonl",
|
||||
"rows": 4011,
|
||||
"sha256": "f51b7a1cc657d62b9ea81823c754408732326b06e03439452433cd8ed481bf33"
|
||||
},
|
||||
"P11": {
|
||||
"path": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P11.jsonl",
|
||||
"rows": 32768,
|
||||
"sha256": "7d196df38963528ff181cf72ce39c8ad913c8f61d40b1425410d3c6c30b6be18"
|
||||
}
|
||||
},
|
||||
"model": "/home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B",
|
||||
"source_commit": "4b253fd8619764b6971a7f2e3a3aa7545f6ace05",
|
||||
"source_tree": "a3d536b287a724e60abbec68b45eed7e088a15d1"
|
||||
},
|
||||
"gpu_hours_this_stage": 0.8836704309119119,
|
||||
"gpu_hours_total": 5.473521912336349,
|
||||
"schema": 1,
|
||||
"stages": {
|
||||
"burnin-01": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P06-C00",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C10",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C01",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P06-C11",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": true,
|
||||
"clients": {},
|
||||
"completed_at": 1783834288.1238313,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.30808498481909435,
|
||||
"load_point": "saturation",
|
||||
"profile": false,
|
||||
"servers": {},
|
||||
"started_at": 1783833886.4448946,
|
||||
"status": "complete",
|
||||
"validation_attempt1_failure": "RuntimeError(\"server config/backend failure: /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/burnins/C01: {'triton_moe': True, 'chunked_mbt': False, 'tp_effective': True, 'drain_shutdown': True, 'mns_effective': True}\")"
|
||||
},
|
||||
"burnin-02": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P06-C00-TP2",
|
||||
"gpus": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": true,
|
||||
"clients": {},
|
||||
"completed_at": 1783834671.921921,
|
||||
"confirmation": false,
|
||||
"gpu_hours": 0.19903395679261948,
|
||||
"load_point": "saturation",
|
||||
"profile": false,
|
||||
"servers": {},
|
||||
"started_at": 1783834301.7813473,
|
||||
"status": "complete"
|
||||
},
|
||||
"primary-01-saturation": {
|
||||
"assignments": [
|
||||
{
|
||||
"cell": "P08-C00",
|
||||
"gpus": [
|
||||
0
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P03-C10",
|
||||
"gpus": [
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P07-C00",
|
||||
"gpus": [
|
||||
2
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell": "P10-C01",
|
||||
"gpus": [
|
||||
3
|
||||
]
|
||||
}
|
||||
],
|
||||
"burnin": false,
|
||||
"clients": {
|
||||
"P03-C10-saturation": {
|
||||
"pgid": 2195599,
|
||||
"pid": 2195599
|
||||
},
|
||||
"P07-C00-saturation": {
|
||||
"pgid": 2195600,
|
||||
"pid": 2195600
|
||||
},
|
||||
"P08-C00-saturation": {
|
||||
"pgid": 2195597,
|
||||
"pid": 2195597
|
||||
},
|
||||
"P10-C01-saturation": {
|
||||
"pgid": 2195601,
|
||||
"pid": 2195601
|
||||
}
|
||||
},
|
||||
"confirmation": false,
|
||||
"failure": "RuntimeError(\"client failures: {'P10-C01-saturation': 1}\")",
|
||||
"gpu_hours": 0.8836704309119119,
|
||||
"load_point": "saturation",
|
||||
"profile": true,
|
||||
"servers": {
|
||||
"P03-C10-saturation": {
|
||||
"gpus": [
|
||||
1
|
||||
],
|
||||
"pgid": 2193680,
|
||||
"pid": 2193680
|
||||
},
|
||||
"P07-C00-saturation": {
|
||||
"gpus": [
|
||||
2
|
||||
],
|
||||
"pgid": 2193681,
|
||||
"pid": 2193681
|
||||
},
|
||||
"P08-C00-saturation": {
|
||||
"gpus": [
|
||||
0
|
||||
],
|
||||
"pgid": 2193679,
|
||||
"pid": 2193679
|
||||
},
|
||||
"P10-C01-saturation": {
|
||||
"gpus": [
|
||||
3
|
||||
],
|
||||
"pgid": 2193682,
|
||||
"pid": 2193682
|
||||
}
|
||||
},
|
||||
"started_at": 1783834671.9563339,
|
||||
"status": "failed"
|
||||
}
|
||||
},
|
||||
"status": "failed",
|
||||
"updated_at": 1783835479.1651883
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"at": 1783834288.13871,
|
||||
"finding": "Explicit MBT=2048 is logged in non-default args; scheduler.py emits the separate Chunked-prefill line only for default MBT.",
|
||||
"gpu_rerun": false,
|
||||
"kind": "validator-only",
|
||||
"new_controller_sha256": "c2d3232fb99c66cea55e30e6cb1aa6a84d3a816434ed8155a309f41df2837f73",
|
||||
"old_controller_sha256": "74859614a8da3341bf827bb75b667db7d219f059d1d29c1182b9a77c2ee59e92",
|
||||
"protocol_or_workload_changed": false,
|
||||
"revalidated_runs": [
|
||||
"P06-C00-burnin",
|
||||
"P06-C10-burnin",
|
||||
"P06-C01-burnin",
|
||||
"P06-C11-burnin"
|
||||
],
|
||||
"schema": 1
|
||||
}
|
||||
@@ -0,0 +1,355 @@
|
||||
{
|
||||
"gpu_seconds": 427.43714332580566,
|
||||
"results": {
|
||||
"graceful": {
|
||||
"accounting": {
|
||||
"bytes": 1462585,
|
||||
"checkpoint_age_seconds": -0.382308841,
|
||||
"counters": {
|
||||
"dropped_records": 0,
|
||||
"encoded_records": 1598,
|
||||
"written_records": 1598
|
||||
},
|
||||
"footer_count": 1,
|
||||
"invariants": {
|
||||
"all_schema_1": true,
|
||||
"encoded_balanced": true,
|
||||
"final_sidecar": true,
|
||||
"footer_sidecar_agree": true,
|
||||
"last_step_matches": true,
|
||||
"one_footer_last": true,
|
||||
"steps_contiguous": true,
|
||||
"written_matches_records": true,
|
||||
"zero_drops": true
|
||||
},
|
||||
"last_step_index": 1597,
|
||||
"records": 1598,
|
||||
"sidecar": "/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/e-b-sidecar-verification/graceful/opprof/opprof-v1-dp0-pid2163417-1783832631507578426.jsonl.footer.json",
|
||||
"stream": "/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/e-b-sidecar-verification/graceful/opprof/opprof-v1-dp0-pid2163417-1783832631507578426.jsonl"
|
||||
},
|
||||
"clean": {
|
||||
"admitted": 5202,
|
||||
"completed": 5202,
|
||||
"completed_throughput_rps": 43.35,
|
||||
"duration_s": 120.0,
|
||||
"end_s": 140.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 1662118,
|
||||
"offered_rps": 43.35,
|
||||
"output_tokens": 332928,
|
||||
"start_s": 20.0
|
||||
},
|
||||
"failed_records": 0,
|
||||
"gpu_seconds": 219.92383646965027,
|
||||
"gpu_zero_samples": [
|
||||
[
|
||||
{
|
||||
"index": 0,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"index": 0,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"index": 0,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
}
|
||||
]
|
||||
],
|
||||
"mode": "graceful",
|
||||
"schema": 1,
|
||||
"server_returncode": 0,
|
||||
"status": "pass",
|
||||
"termination_wall_ns": 1783832775735239240
|
||||
},
|
||||
"hard-kill": {
|
||||
"accounting": {
|
||||
"bytes": 1460860,
|
||||
"checkpoint_age_seconds": 0.02436319,
|
||||
"counters": {
|
||||
"dropped_records": 0,
|
||||
"encoded_records": 1596,
|
||||
"written_records": 1596
|
||||
},
|
||||
"footer_count": 0,
|
||||
"invariants": {
|
||||
"all_schema_1": true,
|
||||
"checkpoint_sidecar": true,
|
||||
"checkpoint_within_bound": true,
|
||||
"encoded_balanced": true,
|
||||
"last_step_matches": true,
|
||||
"no_in_stream_footer": true,
|
||||
"steps_contiguous": true,
|
||||
"written_matches_records": true,
|
||||
"zero_drops": true
|
||||
},
|
||||
"last_step_index": 1595,
|
||||
"records": 1596,
|
||||
"sidecar": "/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/e-b-sidecar-verification/hard-kill/opprof/opprof-v1-dp0-pid2166360-1783832841962667333.jsonl.footer.json",
|
||||
"stream": "/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/e-b-sidecar-verification/hard-kill/opprof/opprof-v1-dp0-pid2166360-1783832841962667333.jsonl"
|
||||
},
|
||||
"clean": {
|
||||
"admitted": 5179,
|
||||
"completed": 5179,
|
||||
"completed_throughput_rps": 43.15833333333333,
|
||||
"duration_s": 120.0,
|
||||
"end_s": 140.0,
|
||||
"failed": 0,
|
||||
"input_tokens": 1655384,
|
||||
"offered_rps": 43.15833333333333,
|
||||
"output_tokens": 331456,
|
||||
"start_s": 20.0
|
||||
},
|
||||
"failed_records": 0,
|
||||
"gpu_seconds": 207.5133068561554,
|
||||
"gpu_zero_samples": [
|
||||
[
|
||||
{
|
||||
"index": 0,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 1
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"index": 0,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"index": 0,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 1,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 2,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 3,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 4,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 5,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 6,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
},
|
||||
{
|
||||
"index": 7,
|
||||
"memory_mib": 0,
|
||||
"utilization_pct": 0
|
||||
}
|
||||
]
|
||||
],
|
||||
"mode": "hard-kill",
|
||||
"schema": 1,
|
||||
"server_returncode": -9,
|
||||
"status": "pass",
|
||||
"termination_wall_ns": 1783832986410202706
|
||||
}
|
||||
},
|
||||
"schema": 1,
|
||||
"status": "complete"
|
||||
}
|
||||
17
runs/opprof-phase3/phase3/repair-008-ap36.json
Normal file
17
runs/opprof-phase3/phase3/repair-008-ap36.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"accepted_runs_preserved": 40,
|
||||
"amendment": "A-P3-6",
|
||||
"changed_fingerprint_keys": [
|
||||
"controller_sha256"
|
||||
],
|
||||
"created_at": 1783853258.3098204,
|
||||
"failed_stage_preserved": "primary-06-saturation",
|
||||
"new_controller_sha256": "6ac565ff35ead305f7b2e39e6a754389d03c27ea6511b2c9e8ebc0c868c9519f",
|
||||
"old_controller_sha256": "becfe00889274b51023016b1e7edb866d10e477249504f2032859a4d621f295f",
|
||||
"projected_remaining_h20_hours": 2.1,
|
||||
"projected_total_h20_hours": 15.408482965071997,
|
||||
"repair_id": "repair-008-ap36",
|
||||
"retained_attempt_re_adjudicated": false,
|
||||
"retained_attempt_reason": "21 completions but A-P3-6 normalized drift 2.3385345997286295 and bin step counts 13/9/44",
|
||||
"schema": 1
|
||||
}
|
||||
469
runs/opprof-phase3/phase4/capture-p09/controller-state.json
Normal file
469
runs/opprof-phase3/phase4/capture-p09/controller-state.json
Normal file
@@ -0,0 +1,469 @@
|
||||
{
|
||||
"arms": {
|
||||
"OFF": {
|
||||
"client_pid": 2487398,
|
||||
"server_pid": 2486295,
|
||||
"started_at": 1783856664.5207698,
|
||||
"status": "complete",
|
||||
"summary": {
|
||||
"arm": "OFF",
|
||||
"bucket_tokens": 237911,
|
||||
"capture_sizes": "default",
|
||||
"clean_completed": 1184,
|
||||
"clean_completed_throughput_rps": 4.933333333333334,
|
||||
"clean_failed": 0,
|
||||
"clean_offered_rps": 4.920833333333333,
|
||||
"drain_seconds": 0.7853007119847462,
|
||||
"e2e_latency_mean_s": 1.681152764688729,
|
||||
"e2e_latency_p95_s": 3.8763178953449815,
|
||||
"gpu_hours": 0.13751606033907995,
|
||||
"graph_hit_steps": 12252,
|
||||
"graph_miss_rate": 0.045199501246882795,
|
||||
"layer1_invariants": {
|
||||
"cudagraph_identity": true,
|
||||
"footer_balanced": true,
|
||||
"footer_written_matches": true,
|
||||
"schema_1": true,
|
||||
"sidecar_agrees": true,
|
||||
"sidecar_final": true,
|
||||
"steps_unique_contiguous": true,
|
||||
"token_composition": true,
|
||||
"zero_drops": true
|
||||
},
|
||||
"layer1_records": 16491,
|
||||
"model_step_duration_ms": 479367.749483,
|
||||
"model_steps": 12832,
|
||||
"padding_fraction": 0.08545632610514016,
|
||||
"padding_tokens": 20331,
|
||||
"schema": 1,
|
||||
"token_efficiency_per_ms": 4.5540506267984115,
|
||||
"useful_tokens": 2183065
|
||||
}
|
||||
},
|
||||
"ON": {
|
||||
"client_pid": 2479800,
|
||||
"server_pid": 2477652,
|
||||
"started_at": 1783856086.549906,
|
||||
"status": "complete",
|
||||
"summary": {
|
||||
"arm": "ON",
|
||||
"bucket_tokens": 227714,
|
||||
"capture_sizes": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
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
|
||||
],
|
||||
"clean_completed": 1190,
|
||||
"clean_completed_throughput_rps": 4.958333333333333,
|
||||
"clean_failed": 0,
|
||||
"clean_offered_rps": 4.920833333333333,
|
||||
"drain_seconds": 0.7876331160077825,
|
||||
"e2e_latency_mean_s": 1.612280680370388,
|
||||
"e2e_latency_p95_s": 3.9930475192406423,
|
||||
"gpu_hours": 0.15887338949574364,
|
||||
"graph_hit_steps": 14253,
|
||||
"graph_miss_rate": 0.0389724226282786,
|
||||
"layer1_invariants": {
|
||||
"cudagraph_identity": true,
|
||||
"footer_balanced": true,
|
||||
"footer_written_matches": true,
|
||||
"schema_1": true,
|
||||
"sidecar_agrees": true,
|
||||
"sidecar_final": true,
|
||||
"steps_unique_contiguous": true,
|
||||
"token_composition": true,
|
||||
"zero_drops": true
|
||||
},
|
||||
"layer1_records": 17579,
|
||||
"model_step_duration_ms": 478655.543996,
|
||||
"model_steps": 14831,
|
||||
"padding_fraction": 0.035658764941988635,
|
||||
"padding_tokens": 8120,
|
||||
"schema": 1,
|
||||
"token_efficiency_per_ms": 4.562222306607711,
|
||||
"useful_tokens": 2183733
|
||||
}
|
||||
}
|
||||
},
|
||||
"controller_pid": 2477456,
|
||||
"created_at": 1783856081.3481774,
|
||||
"gpu_hours_increment": 0.2963894498348236,
|
||||
"plan": {
|
||||
"added_capture_sizes": [
|
||||
3,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
9
|
||||
],
|
||||
"clean_seconds": 240,
|
||||
"gpu": 0,
|
||||
"gpu_hour_limit": 16.0,
|
||||
"load": "moderate",
|
||||
"manifest": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P09.jsonl",
|
||||
"measured_padding_recovery_bound": 0.049776380388728225,
|
||||
"on_capture_sizes": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
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
|
||||
],
|
||||
"order": [
|
||||
"ON",
|
||||
"OFF"
|
||||
],
|
||||
"pattern": "P09",
|
||||
"primary_metric": "clean graph-hit padding_fraction",
|
||||
"prior_gpu_hours": 14.025875418755744,
|
||||
"profile": false,
|
||||
"projected_increment_gpu_hours": 0.5,
|
||||
"projected_total_gpu_hours": 14.525875418755744,
|
||||
"rate_fraction": 0.6,
|
||||
"saturation_result": "/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P09-C00/saturation/client/result.json",
|
||||
"schema": 1,
|
||||
"secondary_metrics": [
|
||||
"Layer-1 useful scheduled tokens/model-step millisecond",
|
||||
"clean completed request throughput",
|
||||
"clean request latency"
|
||||
],
|
||||
"warmup_seconds": 60
|
||||
},
|
||||
"result": {
|
||||
"delta": {
|
||||
"completed_throughput_relative": 0.0050675675675675436,
|
||||
"e2e_mean_latency_relative": -0.04096717785851722,
|
||||
"e2e_p95_latency_relative": 0.03011353223527924,
|
||||
"padding_fraction_points": -0.049797561163151524,
|
||||
"padding_reduction_fraction": 0.5827252753866776,
|
||||
"token_efficiency_relative": 0.0017943761453185214
|
||||
},
|
||||
"gpu_hours_increment": 0.2963894498348236,
|
||||
"gpu_hours_total": 14.322264868590567,
|
||||
"off": {
|
||||
"arm": "OFF",
|
||||
"bucket_tokens": 237911,
|
||||
"capture_sizes": "default",
|
||||
"clean_completed": 1184,
|
||||
"clean_completed_throughput_rps": 4.933333333333334,
|
||||
"clean_failed": 0,
|
||||
"clean_offered_rps": 4.920833333333333,
|
||||
"drain_seconds": 0.7853007119847462,
|
||||
"e2e_latency_mean_s": 1.681152764688729,
|
||||
"e2e_latency_p95_s": 3.8763178953449815,
|
||||
"gpu_hours": 0.13751606033907995,
|
||||
"graph_hit_steps": 12252,
|
||||
"graph_miss_rate": 0.045199501246882795,
|
||||
"layer1_invariants": {
|
||||
"cudagraph_identity": true,
|
||||
"footer_balanced": true,
|
||||
"footer_written_matches": true,
|
||||
"schema_1": true,
|
||||
"sidecar_agrees": true,
|
||||
"sidecar_final": true,
|
||||
"steps_unique_contiguous": true,
|
||||
"token_composition": true,
|
||||
"zero_drops": true
|
||||
},
|
||||
"layer1_records": 16491,
|
||||
"model_step_duration_ms": 479367.749483,
|
||||
"model_steps": 12832,
|
||||
"padding_fraction": 0.08545632610514016,
|
||||
"padding_tokens": 20331,
|
||||
"schema": 1,
|
||||
"token_efficiency_per_ms": 4.5540506267984115,
|
||||
"useful_tokens": 2183065
|
||||
},
|
||||
"on": {
|
||||
"arm": "ON",
|
||||
"bucket_tokens": 227714,
|
||||
"capture_sizes": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
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
|
||||
],
|
||||
"clean_completed": 1190,
|
||||
"clean_completed_throughput_rps": 4.958333333333333,
|
||||
"clean_failed": 0,
|
||||
"clean_offered_rps": 4.920833333333333,
|
||||
"drain_seconds": 0.7876331160077825,
|
||||
"e2e_latency_mean_s": 1.612280680370388,
|
||||
"e2e_latency_p95_s": 3.9930475192406423,
|
||||
"gpu_hours": 0.15887338949574364,
|
||||
"graph_hit_steps": 14253,
|
||||
"graph_miss_rate": 0.0389724226282786,
|
||||
"layer1_invariants": {
|
||||
"cudagraph_identity": true,
|
||||
"footer_balanced": true,
|
||||
"footer_written_matches": true,
|
||||
"schema_1": true,
|
||||
"sidecar_agrees": true,
|
||||
"sidecar_final": true,
|
||||
"steps_unique_contiguous": true,
|
||||
"token_composition": true,
|
||||
"zero_drops": true
|
||||
},
|
||||
"layer1_records": 17579,
|
||||
"model_step_duration_ms": 478655.543996,
|
||||
"model_steps": 14831,
|
||||
"padding_fraction": 0.035658764941988635,
|
||||
"padding_tokens": 8120,
|
||||
"schema": 1,
|
||||
"token_efficiency_per_ms": 4.562222306607711,
|
||||
"useful_tokens": 2183733
|
||||
},
|
||||
"plan": {
|
||||
"added_capture_sizes": [
|
||||
3,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
9
|
||||
],
|
||||
"clean_seconds": 240,
|
||||
"gpu": 0,
|
||||
"gpu_hour_limit": 16.0,
|
||||
"load": "moderate",
|
||||
"manifest": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P09.jsonl",
|
||||
"measured_padding_recovery_bound": 0.049776380388728225,
|
||||
"on_capture_sizes": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
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
|
||||
],
|
||||
"order": [
|
||||
"ON",
|
||||
"OFF"
|
||||
],
|
||||
"pattern": "P09",
|
||||
"primary_metric": "clean graph-hit padding_fraction",
|
||||
"prior_gpu_hours": 14.025875418755744,
|
||||
"profile": false,
|
||||
"projected_increment_gpu_hours": 0.5,
|
||||
"projected_total_gpu_hours": 14.525875418755744,
|
||||
"rate_fraction": 0.6,
|
||||
"saturation_result": "/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P09-C00/saturation/client/result.json",
|
||||
"schema": 1,
|
||||
"secondary_metrics": [
|
||||
"Layer-1 useful scheduled tokens/model-step millisecond",
|
||||
"clean completed request throughput",
|
||||
"clean request latency"
|
||||
],
|
||||
"warmup_seconds": 60
|
||||
},
|
||||
"schema": 1
|
||||
},
|
||||
"schema": 1,
|
||||
"status": "complete",
|
||||
"updated_at": 1783857160.3890784
|
||||
}
|
||||
5
runs/opprof-phase3/phase4/capture-p09/controller.log
Normal file
5
runs/opprof-phase3/phase4/capture-p09/controller.log
Normal file
@@ -0,0 +1,5 @@
|
||||
GPU_COMMAND P09-capture-ON-server: taskset -c 0-19 /tmp/wjh-opprof-phase2-dash0-20260711/.venv/bin/vllm serve /home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B --host 127.0.0.1 --port 8200 --tensor-parallel-size 1 --enable-chunked-prefill --enable-prefix-caching --shutdown-timeout 120 --cudagraph-capture-sizes 1 2 3 4 5 6 7 8 9 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; expected=6-9m
|
||||
GPU_COMMAND P09-capture-ON-client: taskset -c 0-19 /tmp/wjh-opprof-phase2-dash0-20260711/.venv/bin/python /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/scripts/opprof_phase3_client.py run --manifest /home/admin/cpfs/wjh/opprof-phase3-private/manifests/P09.jsonl --base-url http://127.0.0.1:8200 --model /home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B --load-point moderate --saturation-result /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P09-C00/saturation/client/result.json --rate-fraction 0.60 --max-concurrency 256 --ignore-eos --temperature 0 --warmup-seconds 60 --clean-segment-seconds 80 --num-clean-segments 3 --recovery-seconds 30 --drain-timeout-seconds 120 --workload-seed 20260712 --server-seed 20260712 --result-dir /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase4-capture-p09/on/client; expected=5-7m
|
||||
GPU_COMMAND P09-capture-OFF-server: taskset -c 0-19 /tmp/wjh-opprof-phase2-dash0-20260711/.venv/bin/vllm serve /home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B --host 127.0.0.1 --port 8200 --tensor-parallel-size 1 --enable-chunked-prefill --enable-prefix-caching --shutdown-timeout 120; expected=6-9m
|
||||
GPU_COMMAND P09-capture-OFF-client: taskset -c 0-19 /tmp/wjh-opprof-phase2-dash0-20260711/.venv/bin/python /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/scripts/opprof_phase3_client.py run --manifest /home/admin/cpfs/wjh/opprof-phase3-private/manifests/P09.jsonl --base-url http://127.0.0.1:8200 --model /home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B --load-point moderate --saturation-result /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P09-C00/saturation/client/result.json --rate-fraction 0.60 --max-concurrency 256 --ignore-eos --temperature 0 --warmup-seconds 60 --clean-segment-seconds 80 --num-clean-segments 3 --recovery-seconds 30 --drain-timeout-seconds 120 --workload-seed 20260712 --server-seed 20260712 --result-dir /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase4-capture-p09/off/client; expected=5-7m
|
||||
{"delta": {"completed_throughput_relative": 0.0050675675675675436, "e2e_mean_latency_relative": -0.04096717785851722, "e2e_p95_latency_relative": 0.03011353223527924, "padding_fraction_points": -0.049797561163151524, "padding_reduction_fraction": 0.5827252753866776, "token_efficiency_relative": 0.0017943761453185214}, "gpu_hours_increment": 0.2963894498348236, "gpu_hours_total": 14.322264868590567, "off": {"arm": "OFF", "bucket_tokens": 237911, "capture_sizes": "default", "clean_completed": 1184, "clean_completed_throughput_rps": 4.933333333333334, "clean_failed": 0, "clean_offered_rps": 4.920833333333333, "drain_seconds": 0.7853007119847462, "e2e_latency_mean_s": 1.681152764688729, "e2e_latency_p95_s": 3.8763178953449815, "gpu_hours": 0.13751606033907995, "graph_hit_steps": 12252, "graph_miss_rate": 0.045199501246882795, "layer1_invariants": {"cudagraph_identity": true, "footer_balanced": true, "footer_written_matches": true, "schema_1": true, "sidecar_agrees": true, "sidecar_final": true, "steps_unique_contiguous": true, "token_composition": true, "zero_drops": true}, "layer1_records": 16491, "model_step_duration_ms": 479367.749483, "model_steps": 12832, "padding_fraction": 0.08545632610514016, "padding_tokens": 20331, "schema": 1, "token_efficiency_per_ms": 4.5540506267984115, "useful_tokens": 2183065}, "on": {"arm": "ON", "bucket_tokens": 227714, "capture_sizes": [1, 2, 3, 4, 5, 6, 7, 8, 9, 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], "clean_completed": 1190, "clean_completed_throughput_rps": 4.958333333333333, "clean_failed": 0, "clean_offered_rps": 4.920833333333333, "drain_seconds": 0.7876331160077825, "e2e_latency_mean_s": 1.612280680370388, "e2e_latency_p95_s": 3.9930475192406423, "gpu_hours": 0.15887338949574364, "graph_hit_steps": 14253, "graph_miss_rate": 0.0389724226282786, "layer1_invariants": {"cudagraph_identity": true, "footer_balanced": true, "footer_written_matches": true, "schema_1": true, "sidecar_agrees": true, "sidecar_final": true, "steps_unique_contiguous": true, "token_composition": true, "zero_drops": true}, "layer1_records": 17579, "model_step_duration_ms": 478655.543996, "model_steps": 14831, "padding_fraction": 0.035658764941988635, "padding_tokens": 8120, "schema": 1, "token_efficiency_per_ms": 4.562222306607711, "useful_tokens": 2183733}, "plan": {"added_capture_sizes": [3, 5, 6, 7, 9], "clean_seconds": 240, "gpu": 0, "gpu_hour_limit": 16.0, "load": "moderate", "manifest": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P09.jsonl", "measured_padding_recovery_bound": 0.049776380388728225, "on_capture_sizes": [1, 2, 3, 4, 5, 6, 7, 8, 9, 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], "order": ["ON", "OFF"], "pattern": "P09", "primary_metric": "clean graph-hit padding_fraction", "prior_gpu_hours": 14.025875418755744, "profile": false, "projected_increment_gpu_hours": 0.5, "projected_total_gpu_hours": 14.525875418755744, "rate_fraction": 0.6, "saturation_result": "/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P09-C00/saturation/client/result.json", "schema": 1, "secondary_metrics": ["Layer-1 useful scheduled tokens/model-step millisecond", "clean completed request throughput", "clean request latency"], "warmup_seconds": 60}, "schema": 1}
|
||||
1
runs/opprof-phase3/phase4/capture-p09/launch.log
Normal file
1
runs/opprof-phase3/phase4/capture-p09/launch.log
Normal file
@@ -0,0 +1 @@
|
||||
GPU_VALIDATION Phase4 P09 capture sizes: order=ON,OFF, GPU0 TP1, manifest=/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P09.jsonl, saturation_source=/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P09-C00/saturation/client/result.json, added_sizes=3,5,6,7,9, warmup=60s, clean=240s/arm, projected=0.50 H20-hours, cumulative_projection=14.525875/16, expected_wall=15-22m
|
||||
66
runs/opprof-phase3/phase4/capture-p09/off/client-sanity.json
Normal file
66
runs/opprof-phase3/phase4/capture-p09/off/client-sanity.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"invariants": {
|
||||
"clean_duration_exact": true,
|
||||
"clean_failures_zero": true,
|
||||
"concurrency_bounded": true,
|
||||
"drain_within_timeout": true,
|
||||
"manifest_no_wrap": true,
|
||||
"manifest_not_exhausted": true,
|
||||
"moderate_offered_within_5pct": true,
|
||||
"output_tokens_exact": true,
|
||||
"profile_count_exact": true,
|
||||
"profile_status_ok": true,
|
||||
"segment_count_exact": true
|
||||
},
|
||||
"numeric": {
|
||||
"actual_output_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 1477,
|
||||
"max": 64.0,
|
||||
"min": 64.0,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
},
|
||||
"admitted_s": {
|
||||
"distinct_n": 1477,
|
||||
"finite_n": 1477,
|
||||
"max": 299.8483776419889,
|
||||
"min": 0.00022695399820804596,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
},
|
||||
"completed_s": {
|
||||
"distinct_n": 1477,
|
||||
"finite_n": 1477,
|
||||
"max": 300.78334441498737,
|
||||
"min": 0.6682249770092312,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
},
|
||||
"input_tokens": {
|
||||
"distinct_n": 944,
|
||||
"finite_n": 1477,
|
||||
"max": 8161.0,
|
||||
"min": 128.0,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
},
|
||||
"requested_output_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 1477,
|
||||
"max": 64.0,
|
||||
"min": 64.0,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
},
|
||||
"scheduled_s": {
|
||||
"distinct_n": 1477,
|
||||
"finite_n": 1477,
|
||||
"max": 299.84763839512016,
|
||||
"min": 0.0,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
}
|
||||
},
|
||||
"schema": 1
|
||||
}
|
||||
2
runs/opprof-phase3/phase4/capture-p09/off/commands.log
Normal file
2
runs/opprof-phase3/phase4/capture-p09/off/commands.log
Normal file
@@ -0,0 +1,2 @@
|
||||
GPU_COMMAND P09-capture-OFF-server: taskset -c 0-19 /tmp/wjh-opprof-phase2-dash0-20260711/.venv/bin/vllm serve /home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B --host 127.0.0.1 --port 8200 --tensor-parallel-size 1 --enable-chunked-prefill --enable-prefix-caching --shutdown-timeout 120 ; expected=6-9m
|
||||
GPU_COMMAND P09-capture-OFF-client: taskset -c 0-19 /tmp/wjh-opprof-phase2-dash0-20260711/.venv/bin/python /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/scripts/opprof_phase3_client.py run --manifest /home/admin/cpfs/wjh/opprof-phase3-private/manifests/P09.jsonl --base-url http://127.0.0.1:8200 --model /home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B --load-point moderate --saturation-result /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P09-C00/saturation/client/result.json --rate-fraction 0.60 --max-concurrency 256 --ignore-eos --temperature 0 --warmup-seconds 60 --clean-segment-seconds 80 --num-clean-segments 3 --recovery-seconds 30 --drain-timeout-seconds 120 --workload-seed 20260712 --server-seed 20260712 --result-dir /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase4-capture-p09/off/client ; expected=5-7m
|
||||
34
runs/opprof-phase3/phase4/capture-p09/off/summary.json
Normal file
34
runs/opprof-phase3/phase4/capture-p09/off/summary.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"arm": "OFF",
|
||||
"bucket_tokens": 237911,
|
||||
"capture_sizes": "default",
|
||||
"clean_completed": 1184,
|
||||
"clean_completed_throughput_rps": 4.933333333333334,
|
||||
"clean_failed": 0,
|
||||
"clean_offered_rps": 4.920833333333333,
|
||||
"drain_seconds": 0.7853007119847462,
|
||||
"e2e_latency_mean_s": 1.681152764688729,
|
||||
"e2e_latency_p95_s": 3.8763178953449815,
|
||||
"gpu_hours": 0.13751606033907995,
|
||||
"graph_hit_steps": 12252,
|
||||
"graph_miss_rate": 0.045199501246882795,
|
||||
"layer1_invariants": {
|
||||
"cudagraph_identity": true,
|
||||
"footer_balanced": true,
|
||||
"footer_written_matches": true,
|
||||
"schema_1": true,
|
||||
"sidecar_agrees": true,
|
||||
"sidecar_final": true,
|
||||
"steps_unique_contiguous": true,
|
||||
"token_composition": true,
|
||||
"zero_drops": true
|
||||
},
|
||||
"layer1_records": 16491,
|
||||
"model_step_duration_ms": 479367.749483,
|
||||
"model_steps": 12832,
|
||||
"padding_fraction": 0.08545632610514016,
|
||||
"padding_tokens": 20331,
|
||||
"schema": 1,
|
||||
"token_efficiency_per_ms": 4.5540506267984115,
|
||||
"useful_tokens": 2183065
|
||||
}
|
||||
66
runs/opprof-phase3/phase4/capture-p09/on/client-sanity.json
Normal file
66
runs/opprof-phase3/phase4/capture-p09/on/client-sanity.json
Normal file
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"invariants": {
|
||||
"clean_duration_exact": true,
|
||||
"clean_failures_zero": true,
|
||||
"concurrency_bounded": true,
|
||||
"drain_within_timeout": true,
|
||||
"manifest_no_wrap": true,
|
||||
"manifest_not_exhausted": true,
|
||||
"moderate_offered_within_5pct": true,
|
||||
"output_tokens_exact": true,
|
||||
"profile_count_exact": true,
|
||||
"profile_status_ok": true,
|
||||
"segment_count_exact": true
|
||||
},
|
||||
"numeric": {
|
||||
"actual_output_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 1477,
|
||||
"max": 64.0,
|
||||
"min": 64.0,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
},
|
||||
"admitted_s": {
|
||||
"distinct_n": 1477,
|
||||
"finite_n": 1477,
|
||||
"max": 299.8487557930057,
|
||||
"min": 0.00024887899053283036,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
},
|
||||
"completed_s": {
|
||||
"distinct_n": 1477,
|
||||
"finite_n": 1477,
|
||||
"max": 300.78616064199014,
|
||||
"min": 15.648636110010557,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
},
|
||||
"input_tokens": {
|
||||
"distinct_n": 944,
|
||||
"finite_n": 1477,
|
||||
"max": 8161.0,
|
||||
"min": 128.0,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
},
|
||||
"requested_output_tokens": {
|
||||
"distinct_n": 1,
|
||||
"finite_n": 1477,
|
||||
"max": 64.0,
|
||||
"min": 64.0,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
},
|
||||
"scheduled_s": {
|
||||
"distinct_n": 1477,
|
||||
"finite_n": 1477,
|
||||
"max": 299.84763839512016,
|
||||
"min": 0.0,
|
||||
"missing_n": 0,
|
||||
"n": 1477
|
||||
}
|
||||
},
|
||||
"schema": 1
|
||||
}
|
||||
2
runs/opprof-phase3/phase4/capture-p09/on/commands.log
Normal file
2
runs/opprof-phase3/phase4/capture-p09/on/commands.log
Normal file
@@ -0,0 +1,2 @@
|
||||
GPU_COMMAND P09-capture-ON-server: taskset -c 0-19 /tmp/wjh-opprof-phase2-dash0-20260711/.venv/bin/vllm serve /home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B --host 127.0.0.1 --port 8200 --tensor-parallel-size 1 --enable-chunked-prefill --enable-prefix-caching --shutdown-timeout 120 --cudagraph-capture-sizes 1 2 3 4 5 6 7 8 9 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 ; expected=6-9m
|
||||
GPU_COMMAND P09-capture-ON-client: taskset -c 0-19 /tmp/wjh-opprof-phase2-dash0-20260711/.venv/bin/python /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/scripts/opprof_phase3_client.py run --manifest /home/admin/cpfs/wjh/opprof-phase3-private/manifests/P09.jsonl --base-url http://127.0.0.1:8200 --model /home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B --load-point moderate --saturation-result /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P09-C00/saturation/client/result.json --rate-fraction 0.60 --max-concurrency 256 --ignore-eos --temperature 0 --warmup-seconds 60 --clean-segment-seconds 80 --num-clean-segments 3 --recovery-seconds 30 --drain-timeout-seconds 120 --workload-seed 20260712 --server-seed 20260712 --result-dir /home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase4-capture-p09/on/client ; expected=5-7m
|
||||
91
runs/opprof-phase3/phase4/capture-p09/on/summary.json
Normal file
91
runs/opprof-phase3/phase4/capture-p09/on/summary.json
Normal file
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"arm": "ON",
|
||||
"bucket_tokens": 227714,
|
||||
"capture_sizes": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
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
|
||||
],
|
||||
"clean_completed": 1190,
|
||||
"clean_completed_throughput_rps": 4.958333333333333,
|
||||
"clean_failed": 0,
|
||||
"clean_offered_rps": 4.920833333333333,
|
||||
"drain_seconds": 0.7876331160077825,
|
||||
"e2e_latency_mean_s": 1.612280680370388,
|
||||
"e2e_latency_p95_s": 3.9930475192406423,
|
||||
"gpu_hours": 0.15887338949574364,
|
||||
"graph_hit_steps": 14253,
|
||||
"graph_miss_rate": 0.0389724226282786,
|
||||
"layer1_invariants": {
|
||||
"cudagraph_identity": true,
|
||||
"footer_balanced": true,
|
||||
"footer_written_matches": true,
|
||||
"schema_1": true,
|
||||
"sidecar_agrees": true,
|
||||
"sidecar_final": true,
|
||||
"steps_unique_contiguous": true,
|
||||
"token_composition": true,
|
||||
"zero_drops": true
|
||||
},
|
||||
"layer1_records": 17579,
|
||||
"model_step_duration_ms": 478655.543996,
|
||||
"model_steps": 14831,
|
||||
"padding_fraction": 0.035658764941988635,
|
||||
"padding_tokens": 8120,
|
||||
"schema": 1,
|
||||
"token_efficiency_per_ms": 4.562222306607711,
|
||||
"useful_tokens": 2183733
|
||||
}
|
||||
230
runs/opprof-phase3/phase4/capture-p09/result.json
Normal file
230
runs/opprof-phase3/phase4/capture-p09/result.json
Normal file
@@ -0,0 +1,230 @@
|
||||
{
|
||||
"delta": {
|
||||
"completed_throughput_relative": 0.0050675675675675436,
|
||||
"e2e_mean_latency_relative": -0.04096717785851722,
|
||||
"e2e_p95_latency_relative": 0.03011353223527924,
|
||||
"padding_fraction_points": -0.049797561163151524,
|
||||
"padding_reduction_fraction": 0.5827252753866776,
|
||||
"token_efficiency_relative": 0.0017943761453185214
|
||||
},
|
||||
"gpu_hours_increment": 0.2963894498348236,
|
||||
"gpu_hours_total": 14.322264868590567,
|
||||
"off": {
|
||||
"arm": "OFF",
|
||||
"bucket_tokens": 237911,
|
||||
"capture_sizes": "default",
|
||||
"clean_completed": 1184,
|
||||
"clean_completed_throughput_rps": 4.933333333333334,
|
||||
"clean_failed": 0,
|
||||
"clean_offered_rps": 4.920833333333333,
|
||||
"drain_seconds": 0.7853007119847462,
|
||||
"e2e_latency_mean_s": 1.681152764688729,
|
||||
"e2e_latency_p95_s": 3.8763178953449815,
|
||||
"gpu_hours": 0.13751606033907995,
|
||||
"graph_hit_steps": 12252,
|
||||
"graph_miss_rate": 0.045199501246882795,
|
||||
"layer1_invariants": {
|
||||
"cudagraph_identity": true,
|
||||
"footer_balanced": true,
|
||||
"footer_written_matches": true,
|
||||
"schema_1": true,
|
||||
"sidecar_agrees": true,
|
||||
"sidecar_final": true,
|
||||
"steps_unique_contiguous": true,
|
||||
"token_composition": true,
|
||||
"zero_drops": true
|
||||
},
|
||||
"layer1_records": 16491,
|
||||
"model_step_duration_ms": 479367.749483,
|
||||
"model_steps": 12832,
|
||||
"padding_fraction": 0.08545632610514016,
|
||||
"padding_tokens": 20331,
|
||||
"schema": 1,
|
||||
"token_efficiency_per_ms": 4.5540506267984115,
|
||||
"useful_tokens": 2183065
|
||||
},
|
||||
"on": {
|
||||
"arm": "ON",
|
||||
"bucket_tokens": 227714,
|
||||
"capture_sizes": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
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
|
||||
],
|
||||
"clean_completed": 1190,
|
||||
"clean_completed_throughput_rps": 4.958333333333333,
|
||||
"clean_failed": 0,
|
||||
"clean_offered_rps": 4.920833333333333,
|
||||
"drain_seconds": 0.7876331160077825,
|
||||
"e2e_latency_mean_s": 1.612280680370388,
|
||||
"e2e_latency_p95_s": 3.9930475192406423,
|
||||
"gpu_hours": 0.15887338949574364,
|
||||
"graph_hit_steps": 14253,
|
||||
"graph_miss_rate": 0.0389724226282786,
|
||||
"layer1_invariants": {
|
||||
"cudagraph_identity": true,
|
||||
"footer_balanced": true,
|
||||
"footer_written_matches": true,
|
||||
"schema_1": true,
|
||||
"sidecar_agrees": true,
|
||||
"sidecar_final": true,
|
||||
"steps_unique_contiguous": true,
|
||||
"token_composition": true,
|
||||
"zero_drops": true
|
||||
},
|
||||
"layer1_records": 17579,
|
||||
"model_step_duration_ms": 478655.543996,
|
||||
"model_steps": 14831,
|
||||
"padding_fraction": 0.035658764941988635,
|
||||
"padding_tokens": 8120,
|
||||
"schema": 1,
|
||||
"token_efficiency_per_ms": 4.562222306607711,
|
||||
"useful_tokens": 2183733
|
||||
},
|
||||
"plan": {
|
||||
"added_capture_sizes": [
|
||||
3,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
9
|
||||
],
|
||||
"clean_seconds": 240,
|
||||
"gpu": 0,
|
||||
"gpu_hour_limit": 16.0,
|
||||
"load": "moderate",
|
||||
"manifest": "/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P09.jsonl",
|
||||
"measured_padding_recovery_bound": 0.049776380388728225,
|
||||
"on_capture_sizes": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5,
|
||||
6,
|
||||
7,
|
||||
8,
|
||||
9,
|
||||
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
|
||||
],
|
||||
"order": [
|
||||
"ON",
|
||||
"OFF"
|
||||
],
|
||||
"pattern": "P09",
|
||||
"primary_metric": "clean graph-hit padding_fraction",
|
||||
"prior_gpu_hours": 14.025875418755744,
|
||||
"profile": false,
|
||||
"projected_increment_gpu_hours": 0.5,
|
||||
"projected_total_gpu_hours": 14.525875418755744,
|
||||
"rate_fraction": 0.6,
|
||||
"saturation_result": "/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712/runs/phase3/primary/P09-C00/saturation/client/result.json",
|
||||
"schema": 1,
|
||||
"secondary_metrics": [
|
||||
"Layer-1 useful scheduled tokens/model-step millisecond",
|
||||
"clean completed request throughput",
|
||||
"clean request latency"
|
||||
],
|
||||
"warmup_seconds": 60
|
||||
},
|
||||
"schema": 1
|
||||
}
|
||||
373
runs/opprof-phase3/phase4/capture_validation.py
Normal file
373
runs/opprof-phase3/phase4/capture_validation.py
Normal file
@@ -0,0 +1,373 @@
|
||||
#!/usr/bin/env python3
|
||||
"""One-pair P09 CUDAGraph capture-size validation for OpProf Phase 4."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import shlex
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import numpy as np
|
||||
|
||||
import opprof_phase3_controller as common
|
||||
import opprof_phase3_matrix as matrix
|
||||
|
||||
|
||||
WORKDIR = Path("/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712")
|
||||
ROOT = WORKDIR / "runs/phase4-capture-p09"
|
||||
PHASE3 = WORKDIR / "runs/phase3"
|
||||
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_phase3_client.py"
|
||||
STATE = ROOT / "controller-state.json"
|
||||
GPU = 0
|
||||
PORT = 8200
|
||||
PRIOR_GPU_HOURS = 14.025875418755744
|
||||
GPU_HOUR_LIMIT = 16.0
|
||||
EXPECTED_INCREMENT_HOURS = 0.5
|
||||
ADDED_CAPTURE_SIZES = (3, 5, 6, 7, 9)
|
||||
DEFAULT_CAPTURE_SIZES = (
|
||||
1, 2, 4, 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,
|
||||
)
|
||||
ON_CAPTURE_SIZES = tuple(sorted(set(DEFAULT_CAPTURE_SIZES + ADDED_CAPTURE_SIZES)))
|
||||
|
||||
|
||||
def plan() -> dict[str, Any]:
|
||||
return {
|
||||
"schema": 1,
|
||||
"pattern": "P09",
|
||||
"load": "moderate",
|
||||
"order": ["ON", "OFF"],
|
||||
"gpu": GPU,
|
||||
"warmup_seconds": 60,
|
||||
"clean_seconds": 240,
|
||||
"profile": False,
|
||||
"manifest": str(PRIVATE / "P09.jsonl"),
|
||||
"saturation_result": str(
|
||||
PHASE3 / "primary/P09-C00/saturation/client/result.json"
|
||||
),
|
||||
"rate_fraction": 0.60,
|
||||
"added_capture_sizes": list(ADDED_CAPTURE_SIZES),
|
||||
"on_capture_sizes": list(ON_CAPTURE_SIZES),
|
||||
"measured_padding_recovery_bound": 0.049776380388728225,
|
||||
"primary_metric": "clean graph-hit padding_fraction",
|
||||
"secondary_metrics": [
|
||||
"Layer-1 useful scheduled tokens/model-step millisecond",
|
||||
"clean completed request throughput",
|
||||
"clean request latency",
|
||||
],
|
||||
"prior_gpu_hours": PRIOR_GPU_HOURS,
|
||||
"projected_increment_gpu_hours": EXPECTED_INCREMENT_HOURS,
|
||||
"projected_total_gpu_hours": PRIOR_GPU_HOURS + EXPECTED_INCREMENT_HOURS,
|
||||
"gpu_hour_limit": GPU_HOUR_LIMIT,
|
||||
}
|
||||
|
||||
|
||||
def save_state(state: dict[str, Any]) -> None:
|
||||
state["updated_at"] = time.time()
|
||||
state["controller_pid"] = os.getpid()
|
||||
common.atomic_json(STATE, state)
|
||||
|
||||
|
||||
def wait_ready(server: subprocess.Popen[Any]) -> None:
|
||||
deadline = time.monotonic() + 300
|
||||
while time.monotonic() < deadline:
|
||||
if server.poll() is not None:
|
||||
raise RuntimeError("server exited before readiness")
|
||||
try:
|
||||
with urllib.request.urlopen(
|
||||
f"http://127.0.0.1:{PORT}/health", timeout=1
|
||||
) as response:
|
||||
if response.status == 200:
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(1)
|
||||
raise TimeoutError("server readiness timeout")
|
||||
|
||||
|
||||
def server_command(arm: str) -> list[str]:
|
||||
command = [
|
||||
"taskset", "-c", "0-19", str(VENV / "bin/vllm"), "serve", str(MODEL),
|
||||
"--host", "127.0.0.1", "--port", str(PORT),
|
||||
"--tensor-parallel-size", "1", "--enable-chunked-prefill",
|
||||
"--enable-prefix-caching", "--shutdown-timeout", "120",
|
||||
]
|
||||
if arm == "ON":
|
||||
command.extend(("--cudagraph-capture-sizes", *map(str, ON_CAPTURE_SIZES)))
|
||||
return command
|
||||
|
||||
|
||||
def client_command(run_dir: Path) -> list[str]:
|
||||
return [
|
||||
"taskset", "-c", "0-19", str(VENV / "bin/python"), str(CLIENT), "run",
|
||||
"--manifest", str(PRIVATE / "P09.jsonl"),
|
||||
"--base-url", f"http://127.0.0.1:{PORT}", "--model", str(MODEL),
|
||||
"--load-point", "moderate", "--saturation-result",
|
||||
str(PHASE3 / "primary/P09-C00/saturation/client/result.json"),
|
||||
"--rate-fraction", "0.60", "--max-concurrency", "256", "--ignore-eos",
|
||||
"--temperature", "0", "--warmup-seconds", "60",
|
||||
"--clean-segment-seconds", "80", "--num-clean-segments", "3",
|
||||
"--recovery-seconds", "30", "--drain-timeout-seconds", "120",
|
||||
"--workload-seed", "20260712", "--server-seed", "20260712",
|
||||
"--result-dir", str(run_dir / "client"),
|
||||
]
|
||||
|
||||
|
||||
def summarize(run_dir: Path, arm: str) -> 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()
|
||||
]
|
||||
t0 = int(result["t0_mono_ns"])
|
||||
start, end = t0 + int(60e9), t0 + int(300e9)
|
||||
stream = next((run_dir / "opprof").glob("*.jsonl"))
|
||||
records = []
|
||||
for line in stream.read_text().splitlines():
|
||||
record = json.loads(line)
|
||||
if (
|
||||
"step_index" in record
|
||||
and start <= int(record["submit_mono_ns"]) < end
|
||||
):
|
||||
records.append(record)
|
||||
model = [record for record in records if record["model_executed"]]
|
||||
hits = [
|
||||
record
|
||||
for record in model
|
||||
if record["cudagraph"]["hit"]
|
||||
and int(record["cudagraph"]["bucket_tokens"]) > 0
|
||||
]
|
||||
pad = sum(int(record["cudagraph"]["padding_tokens"]) for record in hits)
|
||||
bucket = sum(int(record["cudagraph"]["bucket_tokens"]) for record in hits)
|
||||
useful = sum(
|
||||
int(record["prefill_tokens"]) + int(record["decode_tokens"])
|
||||
for record in records
|
||||
)
|
||||
duration_ms = sum(
|
||||
(int(record["complete_mono_ns"]) - int(record["submit_mono_ns"])) / 1e6
|
||||
for record in records
|
||||
)
|
||||
completed = [
|
||||
request
|
||||
for request in requests
|
||||
if request["success"] and 60 <= float(request["completed_s"]) < 300
|
||||
]
|
||||
e2e = np.asarray(
|
||||
[float(request["completed_s"] - request["admitted_s"]) for request in completed]
|
||||
)
|
||||
layer1 = matrix.validate_layer1(run_dir)
|
||||
return {
|
||||
"schema": 1,
|
||||
"arm": arm,
|
||||
"capture_sizes": list(ON_CAPTURE_SIZES) if arm == "ON" else "default",
|
||||
"clean_completed": len(completed),
|
||||
"clean_failed": int(result["clean"]["failed"]),
|
||||
"clean_completed_throughput_rps": float(
|
||||
result["clean"]["completed_throughput_rps"]
|
||||
),
|
||||
"clean_offered_rps": float(result["clean"]["offered_rps"]),
|
||||
"e2e_latency_mean_s": float(e2e.mean()),
|
||||
"e2e_latency_p95_s": float(np.quantile(e2e, 0.95)),
|
||||
"model_steps": len(model),
|
||||
"graph_hit_steps": len(hits),
|
||||
"padding_tokens": pad,
|
||||
"bucket_tokens": bucket,
|
||||
"padding_fraction": pad / bucket,
|
||||
"graph_miss_rate": sum(not record["cudagraph"]["hit"] for record in model)
|
||||
/ len(model),
|
||||
"useful_tokens": useful,
|
||||
"model_step_duration_ms": duration_ms,
|
||||
"token_efficiency_per_ms": useful / duration_ms,
|
||||
"layer1_records": layer1["records"],
|
||||
"layer1_invariants": layer1["invariants"],
|
||||
"drain_seconds": float(result["drain_seconds"]),
|
||||
}
|
||||
|
||||
|
||||
def run_arm(state: dict[str, Any], arm: str) -> None:
|
||||
if state["arms"].get(arm, {}).get("status") == "complete":
|
||||
return
|
||||
run_dir = ROOT / arm.lower()
|
||||
if run_dir.exists():
|
||||
run_dir.rename(run_dir.with_name(f"{run_dir.name}.interrupted-{int(time.time())}"))
|
||||
run_dir.mkdir(parents=True)
|
||||
common.preflight([GPU], run_dir)
|
||||
server_cmd = server_command(arm)
|
||||
client_cmd = client_command(run_dir)
|
||||
commands_path = run_dir / "commands.log"
|
||||
common.command_log(commands_path, f"P09-capture-{arm}-server", server_cmd, "6-9m")
|
||||
common.command_log(commands_path, f"P09-capture-{arm}-client", client_cmd, "5-7m")
|
||||
print(
|
||||
f"GPU_COMMAND P09-capture-{arm}-server: {shlex.join(server_cmd)}; "
|
||||
"expected=6-9m",
|
||||
flush=True,
|
||||
)
|
||||
print(
|
||||
f"GPU_COMMAND P09-capture-{arm}-client: {shlex.join(client_cmd)}; "
|
||||
"expected=5-7m",
|
||||
flush=True,
|
||||
)
|
||||
environment = os.environ.copy()
|
||||
environment.update(
|
||||
{
|
||||
"CUDA_VISIBLE_DEVICES": str(GPU),
|
||||
"VLLM_OPPROF_DIR": str(run_dir / "opprof"),
|
||||
"HF_HUB_OFFLINE": "1",
|
||||
"TRANSFORMERS_OFFLINE": "1",
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
}
|
||||
)
|
||||
server_log = (run_dir / "server.log").open("ab", buffering=0)
|
||||
server_started = time.time()
|
||||
server = subprocess.Popen(
|
||||
server_cmd,
|
||||
cwd=SOURCE,
|
||||
env=environment,
|
||||
stdout=server_log,
|
||||
stderr=subprocess.STDOUT,
|
||||
start_new_session=True,
|
||||
)
|
||||
client = None
|
||||
client_log = None
|
||||
monitor = None
|
||||
owned = {server.pid}
|
||||
state["arms"][arm] = {
|
||||
"status": "starting",
|
||||
"server_pid": server.pid,
|
||||
"started_at": server_started,
|
||||
}
|
||||
save_state(state)
|
||||
failure = None
|
||||
try:
|
||||
wait_ready(server)
|
||||
monitor = common.Monitor(run_dir / "monitor.jsonl", owned)
|
||||
monitor.start()
|
||||
client_log = (run_dir / "client.log").open("ab", buffering=0)
|
||||
client = subprocess.Popen(
|
||||
client_cmd,
|
||||
cwd=WORKDIR,
|
||||
stdout=client_log,
|
||||
stderr=subprocess.STDOUT,
|
||||
start_new_session=True,
|
||||
)
|
||||
owned.add(client.pid)
|
||||
state["arms"][arm].update(status="running", client_pid=client.pid)
|
||||
save_state(state)
|
||||
deadline = time.monotonic() + 900
|
||||
while client.poll() is None and time.monotonic() < deadline:
|
||||
if server.poll() is not None:
|
||||
raise RuntimeError("server exited during client load")
|
||||
if monitor.other_apps:
|
||||
raise RuntimeError(f"other GPU process appeared: {monitor.other_apps}")
|
||||
time.sleep(2)
|
||||
if client.poll() is None:
|
||||
raise TimeoutError("client exceeded 900 seconds")
|
||||
if client.returncode:
|
||||
raise RuntimeError(f"client failed with {client.returncode}")
|
||||
except Exception as error:
|
||||
failure = error
|
||||
finally:
|
||||
if client is not None and client.poll() is None:
|
||||
try:
|
||||
os.killpg(client.pid, signal.SIGKILL)
|
||||
except ProcessLookupError:
|
||||
pass
|
||||
common.stop_servers([server])
|
||||
server_log.close()
|
||||
if client_log is not None:
|
||||
client_log.close()
|
||||
if monitor is not None:
|
||||
monitor.stop()
|
||||
common.verify_idle([GPU], run_dir)
|
||||
gpu_hours = (time.time() - server_started) / 3600
|
||||
state["gpu_hours_increment"] += gpu_hours
|
||||
if PRIOR_GPU_HOURS + state["gpu_hours_increment"] >= GPU_HOUR_LIMIT:
|
||||
failure = failure or RuntimeError("GPU-hour limit reached")
|
||||
if failure is not None:
|
||||
state["arms"][arm].update(status="failed", failure=repr(failure))
|
||||
state["status"] = "failed"
|
||||
save_state(state)
|
||||
raise failure
|
||||
summary = summarize(run_dir, arm)
|
||||
summary["gpu_hours"] = gpu_hours
|
||||
common.atomic_json(run_dir / "summary.json", summary)
|
||||
state["arms"][arm].update(status="complete", summary=summary)
|
||||
save_state(state)
|
||||
|
||||
|
||||
def run() -> None:
|
||||
ROOT.mkdir(parents=True, exist_ok=True)
|
||||
if PRIOR_GPU_HOURS + EXPECTED_INCREMENT_HOURS >= GPU_HOUR_LIMIT:
|
||||
raise RuntimeError("projected validation exceeds GPU-hour budget")
|
||||
if STATE.exists():
|
||||
state = json.loads(STATE.read_text())
|
||||
else:
|
||||
state = {
|
||||
"schema": 1,
|
||||
"status": "running",
|
||||
"created_at": time.time(),
|
||||
"plan": plan(),
|
||||
"arms": {},
|
||||
"gpu_hours_increment": 0.0,
|
||||
}
|
||||
for arm in ("ON", "OFF"):
|
||||
run_arm(state, arm)
|
||||
on, off = state["arms"]["ON"]["summary"], state["arms"]["OFF"]["summary"]
|
||||
result = {
|
||||
"schema": 1,
|
||||
"plan": plan(),
|
||||
"on": on,
|
||||
"off": off,
|
||||
"delta": {
|
||||
"padding_fraction_points": on["padding_fraction"] - off["padding_fraction"],
|
||||
"padding_reduction_fraction": 1 - on["padding_fraction"] / off["padding_fraction"],
|
||||
"token_efficiency_relative": on["token_efficiency_per_ms"]
|
||||
/ off["token_efficiency_per_ms"]
|
||||
- 1,
|
||||
"completed_throughput_relative": on["clean_completed_throughput_rps"]
|
||||
/ off["clean_completed_throughput_rps"]
|
||||
- 1,
|
||||
"e2e_mean_latency_relative": on["e2e_latency_mean_s"]
|
||||
/ off["e2e_latency_mean_s"]
|
||||
- 1,
|
||||
"e2e_p95_latency_relative": on["e2e_latency_p95_s"]
|
||||
/ off["e2e_latency_p95_s"]
|
||||
- 1,
|
||||
},
|
||||
"gpu_hours_increment": state["gpu_hours_increment"],
|
||||
"gpu_hours_total": PRIOR_GPU_HOURS + state["gpu_hours_increment"],
|
||||
}
|
||||
common.atomic_json(ROOT / "result.json", result)
|
||||
state["status"] = "complete"
|
||||
state["result"] = result
|
||||
save_state(state)
|
||||
print(json.dumps(result, sort_keys=True))
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("command", choices=("plan", "run"))
|
||||
args = parser.parse_args()
|
||||
if args.command == "plan":
|
||||
print(json.dumps(plan(), indent=2, sort_keys=True))
|
||||
else:
|
||||
run()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1611
runs/opprof-phase3/provenance/analyze_phase3.py
Normal file
1611
runs/opprof-phase3/provenance/analyze_phase3.py
Normal file
File diff suppressed because it is too large
Load Diff
794
runs/opprof-phase3/provenance/opprof_phase3_client.py
Normal file
794
runs/opprof-phase3/provenance/opprof_phase3_client.py
Normal file
@@ -0,0 +1,794 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Token-exact fixed-duration client for the OpProf Phase-3 protocol."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import gzip
|
||||
import hashlib
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import aiohttp
|
||||
|
||||
SCHEMA = 1
|
||||
TOKEN_BASE = 1000
|
||||
TOKEN_SPAN = 100000
|
||||
|
||||
|
||||
class ManifestExhausted(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def sha256_file(path: Path) -> str:
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as f:
|
||||
for chunk in iter(lambda: f.read(1024 * 1024), b""):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def atomic_json(path: Path, value: Any, mode: int = 0o640) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
tmp = path.with_name(path.name + f".tmp.{os.getpid()}")
|
||||
fd = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_EXCL, mode)
|
||||
with os.fdopen(fd, "w", encoding="utf-8") as f:
|
||||
json.dump(value, f, sort_keys=True, indent=2)
|
||||
f.write("\n")
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
os.replace(tmp, path)
|
||||
|
||||
|
||||
def atomic_jsonl(path: Path, rows: list[dict[str, Any]], mode: int = 0o640) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
tmp = path.with_name(path.name + f".tmp.{os.getpid()}")
|
||||
fd = os.open(tmp, os.O_WRONLY | os.O_CREAT | os.O_EXCL, mode)
|
||||
with os.fdopen(fd, "w", encoding="utf-8") as f:
|
||||
for row in rows:
|
||||
f.write(json.dumps(row, sort_keys=True, separators=(",", ":")) + "\n")
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
os.replace(tmp, path)
|
||||
|
||||
|
||||
def parse_range(value: str) -> tuple[int, int]:
|
||||
lo_text, hi_text = value.split(":", 1)
|
||||
lo, hi = int(lo_text), int(hi_text)
|
||||
if lo <= 0 or hi < lo:
|
||||
raise argparse.ArgumentTypeError(f"invalid positive range: {value}")
|
||||
return lo, hi
|
||||
|
||||
|
||||
def _integer_counts(weights: list[float], total: int) -> list[int]:
|
||||
raw = [w * total for w in weights]
|
||||
counts = [math.floor(x) for x in raw]
|
||||
order = sorted(
|
||||
range(len(raw)), key=lambda i: raw[i] - counts[i], reverse=True
|
||||
)
|
||||
for idx in order[: total - sum(counts)]:
|
||||
counts[idx] += 1
|
||||
return counts
|
||||
|
||||
|
||||
def numeric_sanity(values: list[float | int]) -> dict[str, Any]:
|
||||
finite = [float(x) for x in values if math.isfinite(float(x))]
|
||||
return {
|
||||
"n": len(values),
|
||||
"finite_n": len(finite),
|
||||
"missing_n": len(values) - len(finite),
|
||||
"min": min(finite) if finite else None,
|
||||
"max": max(finite) if finite else None,
|
||||
"distinct_n": len(set(finite)),
|
||||
}
|
||||
|
||||
|
||||
def manifest_summary(rows: list[dict[str, Any]]) -> dict[str, Any]:
|
||||
return {
|
||||
"schema": SCHEMA,
|
||||
"rows": len(rows),
|
||||
"input_tokens": numeric_sanity([int(r["input_tokens"]) for r in rows]),
|
||||
"output_tokens": numeric_sanity([int(r["output_tokens"]) for r in rows]),
|
||||
"arrival_values": sorted({str(r["arrival"]) for r in rows}),
|
||||
"pattern_values": sorted({str(r["pattern_id"]) for r in rows}),
|
||||
}
|
||||
|
||||
|
||||
def materialize(args: argparse.Namespace) -> dict[str, Any]:
|
||||
import numpy as np
|
||||
|
||||
rng = np.random.default_rng(args.workload_seed)
|
||||
n = args.num_requests
|
||||
if args.kind == "prefix-pool":
|
||||
if args.num_prefixes <= 0 or args.prefix_len <= 0 or args.suffix_fixed <= 0:
|
||||
raise ValueError("prefix-pool requires positive pool/prefix/suffix")
|
||||
lengths = np.full(n, args.prefix_len + args.suffix_fixed, dtype=np.int64)
|
||||
prefix_ids = np.arange(n, dtype=np.int64) % args.num_prefixes
|
||||
rng.shuffle(prefix_ids)
|
||||
else:
|
||||
prefix_ids = np.full(n, -1, dtype=np.int64)
|
||||
if args.input_uniform:
|
||||
lo, hi = parse_range(args.input_uniform)
|
||||
lengths = rng.integers(lo, hi + 1, n, dtype=np.int64)
|
||||
elif args.input_fixed:
|
||||
lengths = np.full(n, args.input_fixed, dtype=np.int64)
|
||||
elif args.input_mixture:
|
||||
spec = json.loads(args.input_mixture)
|
||||
if not isinstance(spec, dict) or not spec:
|
||||
raise ValueError("input mixture must be a non-empty JSON object")
|
||||
keys = list(spec)
|
||||
weights = [float(spec[key]) for key in keys]
|
||||
if any(w < 0 for w in weights) or not math.isclose(sum(weights), 1.0):
|
||||
raise ValueError("mixture weights must be non-negative and sum to 1")
|
||||
pieces = []
|
||||
for key, count in zip(
|
||||
keys, _integer_counts(weights, n), strict=True
|
||||
):
|
||||
kind, lo_text, hi_text = key.split(":")
|
||||
if kind != "uniform":
|
||||
raise ValueError(f"unsupported mixture component: {key}")
|
||||
pieces.append(
|
||||
rng.integers(
|
||||
int(lo_text), int(hi_text) + 1, count, dtype=np.int64
|
||||
)
|
||||
)
|
||||
lengths = np.concatenate(pieces)
|
||||
rng.shuffle(lengths)
|
||||
else:
|
||||
raise ValueError("exactly one input distribution is required")
|
||||
if args.output_fixed <= 0 or args.arrival not in {"steady", "burst:8"}:
|
||||
raise ValueError("invalid output length or arrival class")
|
||||
|
||||
rows = []
|
||||
for i in range(n):
|
||||
row = {
|
||||
"schema": SCHEMA,
|
||||
"request_id": f"{args.id}-{i:05d}",
|
||||
"pattern_id": args.id,
|
||||
"kind": args.kind,
|
||||
"input_tokens": int(lengths[i]),
|
||||
"output_tokens": args.output_fixed,
|
||||
"arrival": args.arrival,
|
||||
"token_seed": int(args.workload_seed * 1000003 + i),
|
||||
}
|
||||
if args.kind == "prefix-pool":
|
||||
row.update(
|
||||
{
|
||||
"prefix_id": int(prefix_ids[i]),
|
||||
"num_prefixes": args.num_prefixes,
|
||||
"prefix_tokens": args.prefix_len,
|
||||
}
|
||||
)
|
||||
rows.append(row)
|
||||
|
||||
out = Path(args.out)
|
||||
atomic_jsonl(out, rows, mode=0o600)
|
||||
summary = manifest_summary(rows)
|
||||
summary.update({"sha256": sha256_file(out), "path": str(out)})
|
||||
atomic_json(out.with_suffix(out.suffix + ".summary.json"), summary, mode=0o600)
|
||||
print(json.dumps(summary, sort_keys=True))
|
||||
return summary
|
||||
|
||||
|
||||
def materialize_private(args: argparse.Namespace) -> dict[str, Any]:
|
||||
from transformers import AutoTokenizer
|
||||
|
||||
source = Path(args.source)
|
||||
selected: list[dict[str, Any]] = []
|
||||
with source.open(encoding="utf-8") as f:
|
||||
for source_index, line in enumerate(f):
|
||||
row = json.loads(line)
|
||||
if (
|
||||
float(row["sampling_u"]) <= args.sampling_u_max
|
||||
and int(row["input_length"]) <= args.max_input_tokens
|
||||
):
|
||||
selected.append(
|
||||
{
|
||||
"schema": SCHEMA,
|
||||
"request_id": f"{args.id}-{len(selected):05d}",
|
||||
"pattern_id": args.id,
|
||||
"kind": "private-trace",
|
||||
"input_tokens": int(row["input_length"]),
|
||||
"output_tokens": min(
|
||||
int(row["output_length"]), args.output_cap
|
||||
),
|
||||
"arrival": args.arrival,
|
||||
"source_index": source_index,
|
||||
"prompt": row["prompt"],
|
||||
}
|
||||
)
|
||||
|
||||
tokenizer = AutoTokenizer.from_pretrained(args.model, trust_remote_code=True)
|
||||
diffs = [
|
||||
len(tokenizer.encode(row["prompt"], add_special_tokens=False))
|
||||
- row["input_tokens"]
|
||||
for row in selected
|
||||
]
|
||||
exact = sum(diff == 0 for diff in diffs)
|
||||
exact_fraction = exact / len(diffs) if diffs else 0.0
|
||||
max_abs = max((abs(diff) for diff in diffs), default=-1)
|
||||
if exact_fraction < 0.99 or max_abs > 1:
|
||||
raise RuntimeError(
|
||||
"tokenizer parity gate failed: "
|
||||
f"exact_fraction={exact_fraction:.6f} max_abs_error={max_abs}"
|
||||
)
|
||||
|
||||
out = Path(args.out)
|
||||
atomic_jsonl(out, selected, mode=0o600)
|
||||
summary = manifest_summary(selected)
|
||||
summary.update(
|
||||
{
|
||||
"sha256": sha256_file(out),
|
||||
"source_sha256": sha256_file(source),
|
||||
"tokenizer_exact_n": exact,
|
||||
"tokenizer_exact_fraction": exact_fraction,
|
||||
"tokenizer_max_abs_error": max_abs,
|
||||
"path": str(out),
|
||||
}
|
||||
)
|
||||
atomic_json(out.with_suffix(out.suffix + ".summary.json"), summary, mode=0o600)
|
||||
print(json.dumps(summary, sort_keys=True))
|
||||
return summary
|
||||
|
||||
|
||||
def load_manifest(path: Path) -> list[dict[str, Any]]:
|
||||
rows = [json.loads(line) for line in path.read_text().splitlines() if line]
|
||||
required = {
|
||||
"request_id",
|
||||
"pattern_id",
|
||||
"input_tokens",
|
||||
"output_tokens",
|
||||
"arrival",
|
||||
}
|
||||
if not rows:
|
||||
raise ValueError("empty manifest")
|
||||
for row in rows:
|
||||
if not required.issubset(row):
|
||||
raise ValueError(f"manifest row lacks {sorted(required - set(row))}")
|
||||
if len({row["request_id"] for row in rows}) != len(rows):
|
||||
raise ValueError("duplicate request_id")
|
||||
return rows
|
||||
|
||||
|
||||
def _token_stream(seed: int, count: int) -> list[int]:
|
||||
state = seed & 0xFFFFFFFF
|
||||
out = []
|
||||
for _ in range(count):
|
||||
state = (1664525 * state + 1013904223) & 0xFFFFFFFF
|
||||
out.append(TOKEN_BASE + state % TOKEN_SPAN)
|
||||
return out
|
||||
|
||||
|
||||
def synthetic_prompt(row: dict[str, Any]) -> list[int]:
|
||||
length = int(row["input_tokens"])
|
||||
seed = int(row.get("token_seed", 0))
|
||||
if row.get("kind") == "prefix-pool":
|
||||
prefix_n = int(row["prefix_tokens"])
|
||||
tokens = _token_stream(0xA5A50000 + int(row["prefix_id"]), prefix_n)
|
||||
tokens += _token_stream(seed, length - prefix_n)
|
||||
offset = prefix_n
|
||||
else:
|
||||
tokens = _token_stream(seed, length)
|
||||
offset = 0
|
||||
if length - offset >= 3:
|
||||
index = int(row["request_id"].rsplit("-", 1)[1])
|
||||
tokens[offset : offset + 3] = [
|
||||
TOKEN_BASE + index % 100,
|
||||
TOKEN_BASE + (index // 100) % 100,
|
||||
TOKEN_BASE + (index // 10000) % 100,
|
||||
]
|
||||
return tokens
|
||||
|
||||
|
||||
@dataclass
|
||||
class RunContext:
|
||||
args: argparse.Namespace
|
||||
rows: list[dict[str, Any]]
|
||||
t0: float
|
||||
clean_end: float
|
||||
stop_event: asyncio.Event
|
||||
lock: asyncio.Lock
|
||||
next_index: int = 0
|
||||
in_flight: int = 0
|
||||
max_in_flight: int = 0
|
||||
exhausted: bool = False
|
||||
admission_stop_s: float | None = None
|
||||
|
||||
async def next_row(self) -> dict[str, Any]:
|
||||
async with self.lock:
|
||||
if self.next_index >= len(self.rows):
|
||||
self.exhausted = True
|
||||
raise ManifestExhausted(
|
||||
f"manifest exhausted after {self.next_index} admissions"
|
||||
)
|
||||
row = self.rows[self.next_index]
|
||||
self.next_index += 1
|
||||
return row
|
||||
|
||||
|
||||
async def request_one(
|
||||
ctx: RunContext,
|
||||
session: aiohttp.ClientSession,
|
||||
row: dict[str, Any],
|
||||
scheduled: float,
|
||||
) -> dict[str, Any]:
|
||||
loop = asyncio.get_running_loop()
|
||||
admitted = loop.time()
|
||||
ctx.in_flight += 1
|
||||
ctx.max_in_flight = max(ctx.max_in_flight, ctx.in_flight)
|
||||
status = 0
|
||||
actual_output: int | None = None
|
||||
first_token: float | None = None
|
||||
error_kind: str | None = None
|
||||
try:
|
||||
prompt: str | list[int] = (
|
||||
row["prompt"]
|
||||
if row.get("kind") == "private-trace"
|
||||
else synthetic_prompt(row)
|
||||
)
|
||||
if not isinstance(prompt, str) and len(prompt) != int(row["input_tokens"]):
|
||||
raise AssertionError("synthetic prompt length drift")
|
||||
payload = {
|
||||
"model": ctx.args.model,
|
||||
"prompt": prompt,
|
||||
"max_tokens": int(row["output_tokens"]),
|
||||
"temperature": ctx.args.temperature,
|
||||
"ignore_eos": ctx.args.ignore_eos,
|
||||
"stream": True,
|
||||
"stream_options": {"include_usage": True},
|
||||
"add_special_tokens": False,
|
||||
"seed": ctx.args.server_seed,
|
||||
}
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"x-request-id": str(row["request_id"]),
|
||||
}
|
||||
async with session.post(
|
||||
ctx.args.base_url.rstrip("/") + "/v1/completions",
|
||||
json=payload,
|
||||
headers=headers,
|
||||
) as response:
|
||||
status = response.status
|
||||
if status != 200:
|
||||
error_kind = f"http_{status}"
|
||||
else:
|
||||
buf = b""
|
||||
async for chunk in response.content.iter_any():
|
||||
buf += chunk
|
||||
while b"\n" in buf:
|
||||
line, buf = buf.split(b"\n", 1)
|
||||
line = line.strip()
|
||||
if not line.startswith(b"data:"):
|
||||
continue
|
||||
data = line[5:].strip()
|
||||
if data == b"[DONE]":
|
||||
continue
|
||||
event = json.loads(data)
|
||||
if event.get("choices") and first_token is None:
|
||||
first_token = loop.time()
|
||||
if event.get("usage") is not None:
|
||||
actual_output = int(event["usage"]["completion_tokens"])
|
||||
if actual_output is None:
|
||||
error_kind = "missing_usage"
|
||||
except (aiohttp.ClientError, asyncio.TimeoutError) as exc:
|
||||
error_kind = type(exc).__name__
|
||||
except Exception as exc:
|
||||
error_kind = type(exc).__name__
|
||||
finally:
|
||||
completed = loop.time()
|
||||
ctx.in_flight -= 1
|
||||
success = (
|
||||
status == 200
|
||||
and error_kind is None
|
||||
and actual_output == int(row["output_tokens"])
|
||||
)
|
||||
if status == 200 and actual_output is not None and not success:
|
||||
error_kind = "output_token_mismatch"
|
||||
return {
|
||||
"schema": SCHEMA,
|
||||
"request_id": row["request_id"],
|
||||
"scheduled_s": scheduled - ctx.t0,
|
||||
"admitted_s": admitted - ctx.t0,
|
||||
"first_token_s": None if first_token is None else first_token - ctx.t0,
|
||||
"completed_s": completed - ctx.t0,
|
||||
"input_tokens": int(row["input_tokens"]),
|
||||
"requested_output_tokens": int(row["output_tokens"]),
|
||||
"actual_output_tokens": actual_output,
|
||||
"http_status": status,
|
||||
"success": success,
|
||||
"error_kind": error_kind,
|
||||
}
|
||||
|
||||
|
||||
async def saturation_load(
|
||||
ctx: RunContext, session: aiohttp.ClientSession
|
||||
) -> list[dict[str, Any]]:
|
||||
results: list[dict[str, Any]] = []
|
||||
|
||||
async def worker() -> None:
|
||||
while not ctx.stop_event.is_set():
|
||||
try:
|
||||
row = await ctx.next_row()
|
||||
except ManifestExhausted:
|
||||
ctx.stop_event.set()
|
||||
return
|
||||
results.append(
|
||||
await request_one(ctx, session, row, asyncio.get_running_loop().time())
|
||||
)
|
||||
|
||||
tasks = [
|
||||
asyncio.create_task(worker()) for _ in range(ctx.args.max_concurrency)
|
||||
]
|
||||
await asyncio.gather(*tasks)
|
||||
return results
|
||||
|
||||
|
||||
async def finite_load(
|
||||
ctx: RunContext, session: aiohttp.ClientSession, rate: float
|
||||
) -> list[dict[str, Any]]:
|
||||
sem = asyncio.Semaphore(ctx.args.max_concurrency)
|
||||
tasks: list[asyncio.Task[dict[str, Any]]] = []
|
||||
batch = 8 if str(ctx.rows[0]["arrival"]) == "burst:8" else 1
|
||||
period = batch / rate
|
||||
event_index = 0
|
||||
|
||||
async def limited(row: dict[str, Any], scheduled: float) -> dict[str, Any]:
|
||||
async with sem:
|
||||
return await request_one(ctx, session, row, scheduled)
|
||||
|
||||
while not ctx.stop_event.is_set():
|
||||
scheduled = ctx.t0 + event_index * period
|
||||
delay = scheduled - asyncio.get_running_loop().time()
|
||||
if delay > 0:
|
||||
try:
|
||||
await asyncio.wait_for(ctx.stop_event.wait(), timeout=delay)
|
||||
break
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
if ctx.stop_event.is_set():
|
||||
break
|
||||
try:
|
||||
for _ in range(batch):
|
||||
tasks.append(
|
||||
asyncio.create_task(limited(await ctx.next_row(), scheduled))
|
||||
)
|
||||
except ManifestExhausted:
|
||||
ctx.stop_event.set()
|
||||
break
|
||||
event_index += 1
|
||||
return await asyncio.gather(*tasks) if tasks else []
|
||||
|
||||
|
||||
async def post_profile(
|
||||
session: aiohttp.ClientSession, base_url: str, endpoint: str
|
||||
) -> tuple[float, float, int]:
|
||||
loop = asyncio.get_running_loop()
|
||||
before = loop.time()
|
||||
async with session.post(base_url.rstrip("/") + endpoint) as response:
|
||||
status = response.status
|
||||
await response.read()
|
||||
return before, loop.time(), status
|
||||
|
||||
|
||||
def _trace_loadable(path: Path) -> bool:
|
||||
try:
|
||||
opener = gzip.open if path.suffix == ".gz" else open
|
||||
with opener(path, "rt", encoding="utf-8") as f:
|
||||
parsed = json.load(f)
|
||||
return isinstance(parsed, dict) and isinstance(parsed.get("traceEvents"), list)
|
||||
except (OSError, EOFError, json.JSONDecodeError):
|
||||
return False
|
||||
|
||||
|
||||
async def wait_new_trace(
|
||||
trace_dir: Path, before: set[Path], timeout: float
|
||||
) -> Path:
|
||||
deadline = asyncio.get_running_loop().time() + timeout
|
||||
while asyncio.get_running_loop().time() < deadline:
|
||||
for path in sorted(set(trace_dir.glob("*.pt.trace.json*")) - before):
|
||||
if _trace_loadable(path):
|
||||
return path
|
||||
await asyncio.sleep(0.25)
|
||||
raise TimeoutError(f"no new loadable trace within {timeout}s")
|
||||
|
||||
|
||||
async def timeline(
|
||||
ctx: RunContext, session: aiohttp.ClientSession
|
||||
) -> list[dict[str, Any]]:
|
||||
args = ctx.args
|
||||
profiles: list[dict[str, Any]] = []
|
||||
await asyncio.sleep(max(0, ctx.clean_end - asyncio.get_running_loop().time()))
|
||||
if args.profile_after_clean:
|
||||
trace_dir = Path(args.profile_trace_dir)
|
||||
for window in range(args.num_profile_windows):
|
||||
prior = set(trace_dir.glob("*.pt.trace.json*"))
|
||||
start_before, start_after, start_status = await post_profile(
|
||||
session, args.base_url, "/start_profile"
|
||||
)
|
||||
trace = await wait_new_trace(
|
||||
trace_dir, prior, args.profile_timeout_seconds
|
||||
)
|
||||
trace_ready = asyncio.get_running_loop().time()
|
||||
stop_before, stop_after, stop_status = await post_profile(
|
||||
session, args.base_url, "/stop_profile"
|
||||
)
|
||||
profiles.append(
|
||||
{
|
||||
"window": window + 1,
|
||||
"start_call_s": start_before - ctx.t0,
|
||||
"start_return_s": start_after - ctx.t0,
|
||||
"trace_ready_s": trace_ready - ctx.t0,
|
||||
"stop_call_s": stop_before - ctx.t0,
|
||||
"stop_return_s": stop_after - ctx.t0,
|
||||
"start_status": start_status,
|
||||
"stop_status": stop_status,
|
||||
"trace_file": trace.name,
|
||||
"trace_sha256": sha256_file(trace),
|
||||
}
|
||||
)
|
||||
if start_status != 200 or stop_status != 200:
|
||||
raise RuntimeError("profile endpoint returned non-200")
|
||||
await asyncio.sleep(args.recovery_seconds)
|
||||
else:
|
||||
await asyncio.sleep(args.post_clean_seconds)
|
||||
ctx.admission_stop_s = asyncio.get_running_loop().time() - ctx.t0
|
||||
ctx.stop_event.set()
|
||||
return profiles
|
||||
|
||||
|
||||
def segment_summary(
|
||||
records: list[dict[str, Any]], start: float, end: float
|
||||
) -> dict[str, Any]:
|
||||
admitted = [r for r in records if start <= r["admitted_s"] < end]
|
||||
completed = [r for r in records if start <= r["completed_s"] < end]
|
||||
successes = [r for r in completed if r["success"]]
|
||||
duration = end - start
|
||||
return {
|
||||
"start_s": start,
|
||||
"end_s": end,
|
||||
"duration_s": duration,
|
||||
"admitted": len(admitted),
|
||||
"completed": len(successes),
|
||||
"failed": len(completed) - len(successes),
|
||||
"offered_rps": len(admitted) / duration,
|
||||
"completed_throughput_rps": len(successes) / duration,
|
||||
"input_tokens": sum(r["input_tokens"] for r in successes),
|
||||
"output_tokens": sum(r["actual_output_tokens"] or 0 for r in successes),
|
||||
}
|
||||
|
||||
|
||||
async def run_load(args: argparse.Namespace) -> dict[str, Any]:
|
||||
manifest = Path(args.manifest)
|
||||
rows = load_manifest(manifest)
|
||||
arrivals = {row["arrival"] for row in rows}
|
||||
if len(arrivals) != 1:
|
||||
raise ValueError("a manifest must have one arrival class")
|
||||
if args.load_point == "saturation":
|
||||
if args.request_rate != "inf":
|
||||
raise ValueError("saturation requires --request-rate inf")
|
||||
rate = math.inf
|
||||
else:
|
||||
if not args.saturation_result:
|
||||
raise ValueError("moderate requires --saturation-result")
|
||||
sat = json.loads(Path(args.saturation_result).read_text())
|
||||
rate = args.rate_fraction * float(sat["clean"]["completed_throughput_rps"])
|
||||
if not math.isfinite(rate) or rate <= 0:
|
||||
raise ValueError("derived moderate rate must be positive and finite")
|
||||
|
||||
loop = asyncio.get_running_loop()
|
||||
t0 = loop.time()
|
||||
t0_mono_ns = int(t0 * 1e9)
|
||||
t0_wall_ns = time.time_ns()
|
||||
clean_seconds = args.clean_segment_seconds * args.num_clean_segments
|
||||
ctx = RunContext(
|
||||
args=args,
|
||||
rows=rows,
|
||||
t0=t0,
|
||||
clean_end=t0 + args.warmup_seconds + clean_seconds,
|
||||
stop_event=asyncio.Event(),
|
||||
lock=asyncio.Lock(),
|
||||
)
|
||||
timeout = aiohttp.ClientTimeout(total=None, connect=30, sock_read=600)
|
||||
connector = aiohttp.TCPConnector(limit=args.max_concurrency)
|
||||
control_connector = aiohttp.TCPConnector(limit=2)
|
||||
async with (
|
||||
aiohttp.ClientSession(timeout=timeout, connector=connector) as session,
|
||||
aiohttp.ClientSession(
|
||||
timeout=timeout, connector=control_connector
|
||||
) as control_session,
|
||||
):
|
||||
profile_task = asyncio.create_task(timeline(ctx, control_session))
|
||||
load_task = asyncio.create_task(
|
||||
saturation_load(ctx, session)
|
||||
if math.isinf(rate)
|
||||
else finite_load(ctx, session, rate)
|
||||
)
|
||||
try:
|
||||
profiles = await profile_task
|
||||
except Exception:
|
||||
ctx.stop_event.set()
|
||||
await load_task
|
||||
raise
|
||||
records = await load_task
|
||||
|
||||
clean_start = args.warmup_seconds
|
||||
clean_end = clean_start + clean_seconds
|
||||
clean = segment_summary(records, clean_start, clean_end)
|
||||
segments = []
|
||||
for i in range(args.num_clean_segments):
|
||||
start = clean_start + i * args.clean_segment_seconds
|
||||
segments.append(
|
||||
{
|
||||
"name": chr(ord("A") + i),
|
||||
**segment_summary(
|
||||
records, start, start + args.clean_segment_seconds
|
||||
),
|
||||
}
|
||||
)
|
||||
successful = [r for r in records if r["success"]]
|
||||
elapsed_seconds = loop.time() - t0
|
||||
if ctx.admission_stop_s is None:
|
||||
raise RuntimeError("admission stop timestamp was not recorded")
|
||||
drain_seconds = elapsed_seconds - ctx.admission_stop_s
|
||||
result = {
|
||||
"schema": SCHEMA,
|
||||
"manifest_sha256": sha256_file(manifest),
|
||||
"manifest_rows": len(rows),
|
||||
"manifest_admitted": ctx.next_index,
|
||||
"manifest_wrapped": False,
|
||||
"manifest_exhausted": ctx.exhausted,
|
||||
"load_point": args.load_point,
|
||||
"t0_mono_ns": t0_mono_ns,
|
||||
"t0_wall_ns": t0_wall_ns,
|
||||
"request_rate": "inf" if math.isinf(rate) else rate,
|
||||
"rate_fraction": None if math.isinf(rate) else args.rate_fraction,
|
||||
"arrival": next(iter(arrivals)),
|
||||
"warmup_seconds": args.warmup_seconds,
|
||||
"clean_segment_seconds": args.clean_segment_seconds,
|
||||
"num_clean_segments": args.num_clean_segments,
|
||||
"elapsed_seconds": elapsed_seconds,
|
||||
"admission_stop_s": ctx.admission_stop_s,
|
||||
"drain_seconds": drain_seconds,
|
||||
"max_in_flight": ctx.max_in_flight,
|
||||
"records": len(records),
|
||||
"successful_records": len(successful),
|
||||
"failed_records": len(records) - len(successful),
|
||||
"clean": clean,
|
||||
"segments": segments,
|
||||
"profiles": profiles,
|
||||
}
|
||||
sanity = {
|
||||
"schema": SCHEMA,
|
||||
"numeric": {
|
||||
"input_tokens": numeric_sanity([r["input_tokens"] for r in records]),
|
||||
"requested_output_tokens": numeric_sanity(
|
||||
[r["requested_output_tokens"] for r in records]
|
||||
),
|
||||
"actual_output_tokens": numeric_sanity(
|
||||
[
|
||||
r["actual_output_tokens"]
|
||||
for r in records
|
||||
if r["actual_output_tokens"] is not None
|
||||
]
|
||||
),
|
||||
"scheduled_s": numeric_sanity([r["scheduled_s"] for r in records]),
|
||||
"admitted_s": numeric_sanity([r["admitted_s"] for r in records]),
|
||||
"completed_s": numeric_sanity([r["completed_s"] for r in records]),
|
||||
},
|
||||
"invariants": {
|
||||
"clean_duration_exact": math.isclose(clean["duration_s"], clean_seconds),
|
||||
"segment_count_exact": len(segments) == args.num_clean_segments,
|
||||
"manifest_no_wrap": ctx.next_index <= len(rows),
|
||||
"manifest_not_exhausted": not ctx.exhausted,
|
||||
"concurrency_bounded": ctx.max_in_flight <= args.max_concurrency,
|
||||
"drain_within_timeout": drain_seconds <= args.drain_timeout_seconds,
|
||||
"output_tokens_exact": all(
|
||||
r["actual_output_tokens"] == r["requested_output_tokens"]
|
||||
for r in successful
|
||||
),
|
||||
"clean_failures_zero": clean["failed"] == 0,
|
||||
"profile_count_exact": len(profiles)
|
||||
== (args.num_profile_windows if args.profile_after_clean else 0),
|
||||
"profile_status_ok": all(
|
||||
p["start_status"] == 200 and p["stop_status"] == 200
|
||||
for p in profiles
|
||||
),
|
||||
},
|
||||
}
|
||||
if not math.isinf(rate):
|
||||
sanity["invariants"]["moderate_offered_within_5pct"] = (
|
||||
abs(clean["offered_rps"] / rate - 1) <= 0.05
|
||||
)
|
||||
out = Path(args.result_dir)
|
||||
out.mkdir(parents=True, exist_ok=True)
|
||||
atomic_jsonl(out / "requests.jsonl", sorted(records, key=lambda r: r["admitted_s"]))
|
||||
atomic_jsonl(out / "segments.jsonl", segments)
|
||||
atomic_json(out / "result.json", result)
|
||||
atomic_json(out / "sanity.json", sanity)
|
||||
if ctx.exhausted:
|
||||
raise ManifestExhausted("manifest exhausted; result retained for diagnosis")
|
||||
failed = [name for name, ok in sanity["invariants"].items() if not ok]
|
||||
if failed:
|
||||
raise RuntimeError(f"client sanity failure: {failed}")
|
||||
return result
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser()
|
||||
sub = parser.add_subparsers(dest="command", required=True)
|
||||
mat = sub.add_parser("materialize")
|
||||
mat.add_argument("--id", required=True)
|
||||
mat.add_argument("--kind", choices=("synthetic", "prefix-pool"), required=True)
|
||||
group = mat.add_mutually_exclusive_group()
|
||||
group.add_argument("--input-uniform")
|
||||
group.add_argument("--input-fixed", type=int)
|
||||
group.add_argument("--input-mixture")
|
||||
mat.add_argument("--output-fixed", type=int, required=True)
|
||||
mat.add_argument("--prefix", default="none")
|
||||
mat.add_argument("--arrival", required=True)
|
||||
mat.add_argument("--num-requests", type=int, required=True)
|
||||
mat.add_argument("--workload-seed", type=int, required=True)
|
||||
mat.add_argument("--num-prefixes", type=int, default=0)
|
||||
mat.add_argument("--prefix-len", type=int, default=0)
|
||||
mat.add_argument("--suffix-fixed", type=int, default=0)
|
||||
mat.add_argument("--out", required=True)
|
||||
private = sub.add_parser("materialize-private")
|
||||
private.add_argument("--id", required=True)
|
||||
private.add_argument("--source", required=True)
|
||||
private.add_argument("--sampling-u-max", type=float, required=True)
|
||||
private.add_argument("--max-input-tokens", type=int, required=True)
|
||||
private.add_argument("--output-cap", type=int, required=True)
|
||||
private.add_argument("--preserve-prompts", action="store_true", required=True)
|
||||
private.add_argument("--disable-shuffle", action="store_true", required=True)
|
||||
private.add_argument("--arrival", required=True)
|
||||
private.add_argument("--model", required=True)
|
||||
private.add_argument("--out", required=True)
|
||||
run = sub.add_parser("run")
|
||||
run.add_argument("--manifest", required=True)
|
||||
run.add_argument("--base-url", required=True)
|
||||
run.add_argument("--model", required=True)
|
||||
run.add_argument("--load-point", choices=("saturation", "moderate"), required=True)
|
||||
run.add_argument("--request-rate")
|
||||
run.add_argument("--saturation-result")
|
||||
run.add_argument("--rate-fraction", type=float, default=0.60)
|
||||
run.add_argument("--max-concurrency", type=int, default=256)
|
||||
run.add_argument("--ignore-eos", action="store_true")
|
||||
run.add_argument("--temperature", type=float, default=0.0)
|
||||
run.add_argument("--warmup-seconds", type=float, default=60)
|
||||
run.add_argument("--clean-segment-seconds", type=float, default=80)
|
||||
run.add_argument("--num-clean-segments", type=int, default=3)
|
||||
run.add_argument("--profile-after-clean", action="store_true")
|
||||
run.add_argument("--num-profile-windows", type=int, default=0)
|
||||
run.add_argument("--profile-warmup-iterations", type=int, default=2)
|
||||
run.add_argument("--profile-active-iterations", type=int, default=8)
|
||||
run.add_argument("--profile-trace-dir")
|
||||
run.add_argument("--profile-timeout-seconds", type=float, default=120)
|
||||
run.add_argument("--recovery-seconds", type=float, default=30)
|
||||
run.add_argument("--post-clean-seconds", type=float, default=0)
|
||||
run.add_argument("--drain-timeout-seconds", type=float, default=120)
|
||||
run.add_argument("--workload-seed", type=int, default=20260712)
|
||||
run.add_argument("--server-seed", type=int, default=20260712)
|
||||
run.add_argument("--result-dir", required=True)
|
||||
return parser
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = build_parser().parse_args()
|
||||
if args.command == "materialize":
|
||||
materialize(args)
|
||||
elif args.command == "materialize-private":
|
||||
materialize_private(args)
|
||||
else:
|
||||
if args.profile_after_clean and not args.profile_trace_dir:
|
||||
raise ValueError("--profile-after-clean requires --profile-trace-dir")
|
||||
print(json.dumps(asyncio.run(run_load(args)), sort_keys=True))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
1056
runs/opprof-phase3/provenance/opprof_phase3_controller.py
Normal file
1056
runs/opprof-phase3/provenance/opprof_phase3_controller.py
Normal file
File diff suppressed because it is too large
Load Diff
1045
runs/opprof-phase3/provenance/opprof_phase3_controller_ea.py
Normal file
1045
runs/opprof-phase3/provenance/opprof_phase3_controller_ea.py
Normal file
File diff suppressed because it is too large
Load Diff
1252
runs/opprof-phase3/provenance/opprof_phase3_matrix.py
Normal file
1252
runs/opprof-phase3/provenance/opprof_phase3_matrix.py
Normal file
File diff suppressed because it is too large
Load Diff
109
runs/opprof-phase3/provenance/test_phase3_analysis.py
Normal file
109
runs/opprof-phase3/provenance/test_phase3_analysis.py
Normal file
@@ -0,0 +1,109 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
import analyze_phase3 as analysis
|
||||
|
||||
|
||||
class Phase3AnalysisTests(unittest.TestCase):
|
||||
def test_ap36_stability_formula(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
(root / "client").mkdir()
|
||||
(root / "opprof").mkdir()
|
||||
(root / "client/result.json").write_text(
|
||||
json.dumps({"t0_mono_ns": 0, "warmup_seconds": 60})
|
||||
)
|
||||
(root / "client/requests.jsonl").write_text(
|
||||
"".join(
|
||||
json.dumps({"success": True, "completed_s": index + 1}) + "\n"
|
||||
for index in range(16)
|
||||
)
|
||||
)
|
||||
records = []
|
||||
for bin_index in range(3):
|
||||
for step in range(16):
|
||||
records.append(
|
||||
{
|
||||
"step_index": len(records),
|
||||
"model_executed": True,
|
||||
"submit_mono_ns": int(
|
||||
(45 + 5 * bin_index + (step + 0.5) / 16 * 5)
|
||||
* 1e9
|
||||
),
|
||||
"prefill_tokens": 100,
|
||||
"decode_tokens": 0,
|
||||
}
|
||||
)
|
||||
(root / "opprof/test.jsonl").write_text(
|
||||
"".join(json.dumps(item) + "\n" for item in records)
|
||||
)
|
||||
result = analysis.ap36_warmup_stability(root)
|
||||
self.assertTrue(result["passes"])
|
||||
self.assertEqual(result["normalized_drift"], 0)
|
||||
|
||||
def test_ap37_partial_verdict_can_confirm_but_not_refute(self):
|
||||
self.assertEqual(analysis.partial_verdict(True), "PASS")
|
||||
self.assertEqual(analysis.partial_verdict(False), "INCONCLUSIVE")
|
||||
|
||||
def test_accepted_markers_come_only_from_complete_stages(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
complete = root / "stages/primary-01-saturation"
|
||||
complete.mkdir(parents=True)
|
||||
(complete / "stage-complete.json").write_text(
|
||||
json.dumps({"runs": ["P01-C00-saturation"]})
|
||||
)
|
||||
accepted = root / "primary/P01-C00/saturation"
|
||||
accepted.mkdir(parents=True)
|
||||
(accepted / "run-complete.json").write_text(
|
||||
json.dumps({"run_id": "P01-C00-saturation"})
|
||||
)
|
||||
unaccepted = root / "primary/P05-C00/saturation"
|
||||
unaccepted.mkdir(parents=True)
|
||||
(unaccepted / "run-complete.json").write_text(
|
||||
json.dumps({"run_id": "P05-C00-saturation"})
|
||||
)
|
||||
primary, confirmations, stages, excluded = analysis.accepted_marker_paths(
|
||||
root
|
||||
)
|
||||
self.assertEqual(primary, [accepted / "run-complete.json"])
|
||||
self.assertEqual(confirmations, [])
|
||||
self.assertEqual(stages, [complete])
|
||||
self.assertEqual(excluded, ["P05-C00-saturation"])
|
||||
|
||||
def test_r64_is_ratio_of_cohort_sums(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp) / "manifest.jsonl"
|
||||
rows = [{"input_tokens": value} for value in (1, 3, 2, 2)]
|
||||
path.write_text("".join(json.dumps(row) + "\n" for row in rows))
|
||||
value, pieces = analysis.manifest_raggedness(path, 2)
|
||||
self.assertEqual(pieces, [(2.0, 6.0), (0.0, 4.0)])
|
||||
self.assertAlmostEqual(value, 0.2)
|
||||
|
||||
def test_one_percentage_point_ranking_ties(self):
|
||||
shares = dict.fromkeys(analysis.FAMILIES, 0.0)
|
||||
shares.update(attention=0.40, moe_gemm=0.395, moe_router=0.20)
|
||||
ranked = {item["family"]: item["rank"] for item in analysis.ranked_families(shares)}
|
||||
self.assertEqual(ranked["attention"], ranked["moe_gemm"])
|
||||
self.assertGreater(ranked["moe_router"], ranked["attention"])
|
||||
|
||||
def test_holm_uses_declared_total_test_family(self):
|
||||
values = [{"p": 0.001}, {"p": 0.01}]
|
||||
analysis.holm(values, total_tests=10)
|
||||
self.assertAlmostEqual(values[0]["p_holm"], 0.01)
|
||||
self.assertAlmostEqual(values[1]["p_holm"], 0.09)
|
||||
|
||||
def test_robust_spline_prediction_is_nonnegative(self):
|
||||
rows = [(float(x), float(n), float(2 * x + n)) for x in range(1, 20) for n in (1, 4)]
|
||||
predict, hull = analysis.fit_nonnegative_robust(rows)
|
||||
self.assertGreaterEqual(predict(3, 2), 0)
|
||||
self.assertTrue(analysis.inside_convex(hull, (3, 2)))
|
||||
self.assertFalse(analysis.inside_convex(hull, (100, 2)))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
486
runs/opprof-phase3/provenance/test_phase3_tools.py
Normal file
486
runs/opprof-phase3/provenance/test_phase3_tools.py
Normal file
@@ -0,0 +1,486 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import importlib.util
|
||||
import json
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest import mock
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
|
||||
|
||||
def load_module(name: str, filename: str):
|
||||
spec = importlib.util.spec_from_file_location(name, HERE / filename)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[name] = module
|
||||
assert spec.loader is not None
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
client = load_module("phase3_client", "opprof_phase3_client.py")
|
||||
controller = load_module("phase3_controller", "opprof_phase3_controller.py")
|
||||
sys.modules["opprof_phase3_controller"] = controller
|
||||
matrix = load_module("phase3_matrix", "opprof_phase3_matrix.py")
|
||||
|
||||
|
||||
def rows(n: int, arrival: str = "steady") -> list[dict]:
|
||||
return [
|
||||
{
|
||||
"schema": 1,
|
||||
"request_id": f"T-{i:05d}",
|
||||
"pattern_id": "T",
|
||||
"kind": "synthetic",
|
||||
"input_tokens": 8,
|
||||
"output_tokens": 2,
|
||||
"arrival": arrival,
|
||||
"token_seed": i + 1,
|
||||
}
|
||||
for i in range(n)
|
||||
]
|
||||
|
||||
|
||||
class MockServer:
|
||||
def __init__(self, delay: float = 0.01, trace_dir: Path | None = None) -> None:
|
||||
self.active = 0
|
||||
self.max_active = 0
|
||||
self.payloads = []
|
||||
self.runner = None
|
||||
self.port = None
|
||||
self.delay = delay
|
||||
self.trace_dir = trace_dir
|
||||
self.profile_count = 0
|
||||
|
||||
async def completion(self, request):
|
||||
payload = await request.json()
|
||||
self.payloads.append(payload)
|
||||
self.active += 1
|
||||
self.max_active = max(self.max_active, self.active)
|
||||
await asyncio.sleep(self.delay)
|
||||
response = web.StreamResponse(
|
||||
status=200, headers={"Content-Type": "text/event-stream"}
|
||||
)
|
||||
await response.prepare(request)
|
||||
await response.write(
|
||||
b'data: {"choices":[{"text":"x"}],"usage":null}\n\n'
|
||||
)
|
||||
usage = json.dumps(
|
||||
{
|
||||
"choices": [],
|
||||
"usage": {
|
||||
"prompt_tokens": len(payload["prompt"]),
|
||||
"completion_tokens": payload["max_tokens"],
|
||||
},
|
||||
}
|
||||
).encode()
|
||||
await response.write(b"data: " + usage + b"\n\n")
|
||||
await response.write(b"data: [DONE]\n\n")
|
||||
await response.write_eof()
|
||||
self.active -= 1
|
||||
return response
|
||||
|
||||
async def start_profile(self, request):
|
||||
self.profile_count += 1
|
||||
path = self.trace_dir / f"window-{self.profile_count}.pt.trace.json"
|
||||
path.write_text('{"traceEvents": []}')
|
||||
return web.Response(status=200)
|
||||
|
||||
async def stop_profile(self, request):
|
||||
return web.Response(status=200)
|
||||
|
||||
async def start(self):
|
||||
app = web.Application()
|
||||
app.router.add_post("/v1/completions", self.completion)
|
||||
if self.trace_dir is not None:
|
||||
app.router.add_post("/start_profile", self.start_profile)
|
||||
app.router.add_post("/stop_profile", self.stop_profile)
|
||||
self.runner = web.AppRunner(app)
|
||||
await self.runner.setup()
|
||||
site = web.TCPSite(self.runner, "127.0.0.1", 0)
|
||||
await site.start()
|
||||
self.port = site._server.sockets[0].getsockname()[1]
|
||||
|
||||
async def stop(self):
|
||||
await self.runner.cleanup()
|
||||
|
||||
|
||||
def run_args(
|
||||
manifest: Path,
|
||||
result_dir: Path,
|
||||
port: int,
|
||||
load_point: str = "saturation",
|
||||
saturation_result: Path | None = None,
|
||||
):
|
||||
return SimpleNamespace(
|
||||
manifest=str(manifest),
|
||||
base_url=f"http://127.0.0.1:{port}",
|
||||
model="mock",
|
||||
load_point=load_point,
|
||||
request_rate="inf" if load_point == "saturation" else None,
|
||||
saturation_result=None if saturation_result is None else str(saturation_result),
|
||||
rate_fraction=0.60,
|
||||
max_concurrency=3,
|
||||
ignore_eos=True,
|
||||
temperature=0,
|
||||
warmup_seconds=0.04,
|
||||
clean_segment_seconds=0.04,
|
||||
num_clean_segments=3,
|
||||
profile_after_clean=False,
|
||||
num_profile_windows=0,
|
||||
profile_warmup_iterations=2,
|
||||
profile_active_iterations=8,
|
||||
profile_trace_dir=None,
|
||||
profile_timeout_seconds=1,
|
||||
recovery_seconds=0,
|
||||
post_clean_seconds=0,
|
||||
drain_timeout_seconds=1,
|
||||
workload_seed=20260712,
|
||||
server_seed=20260712,
|
||||
result_dir=str(result_dir),
|
||||
)
|
||||
|
||||
|
||||
class Phase3ToolTests(unittest.TestCase):
|
||||
def write_warmup_stream(self, root: Path, tokens: list[int]) -> None:
|
||||
stream_dir = root / "opprof"
|
||||
stream_dir.mkdir()
|
||||
records = []
|
||||
step = 0
|
||||
for bin_index, token_count in enumerate(tokens):
|
||||
per_step, remainder = divmod(token_count, 16)
|
||||
for in_bin in range(16):
|
||||
records.append(
|
||||
{
|
||||
"step_index": step,
|
||||
"model_executed": True,
|
||||
"submit_mono_ns": int(
|
||||
1e9
|
||||
+ (45 + bin_index * 5 + (in_bin + 0.5) / 16 * 5)
|
||||
* 1e9
|
||||
),
|
||||
"prefill_tokens": per_step + (in_bin < remainder),
|
||||
"decode_tokens": 0,
|
||||
}
|
||||
)
|
||||
step += 1
|
||||
(stream_dir / "test.jsonl").write_text(
|
||||
"".join(json.dumps(record) + "\n" for record in records)
|
||||
)
|
||||
|
||||
def test_p10_warmup_stability_accepts_flat_trailing_quartile(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
self.write_warmup_stream(root, [1600, 1600, 1600])
|
||||
result = matrix.p10_warmup_stability(root, int(1e9))
|
||||
self.assertTrue(result["passed"])
|
||||
self.assertEqual(result["step_counts"], [16, 16, 16])
|
||||
self.assertEqual(result["scheduled_token_throughput"], [320, 320, 320])
|
||||
self.assertEqual(result["normalized_drift"], 0)
|
||||
|
||||
def test_p10_warmup_stability_rejects_large_drift(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
self.write_warmup_stream(root, [1600, 3200, 4800])
|
||||
result = matrix.p10_warmup_stability(root, int(1e9))
|
||||
self.assertFalse(result["passed"])
|
||||
self.assertGreater(result["normalized_drift"], 0.10)
|
||||
|
||||
def test_only_clean_window_request_failures_are_hard_failures(self):
|
||||
requests = [
|
||||
{"success": False, "completed_s": 59.9, "error_kind": "warmup"},
|
||||
{"success": False, "completed_s": 60.0, "error_kind": "clean"},
|
||||
{"success": False, "completed_s": 299.9, "error_kind": "clean"},
|
||||
{"success": False, "completed_s": 300.0, "error_kind": "recovery"},
|
||||
{"success": True, "completed_s": 100.0, "error_kind": None},
|
||||
]
|
||||
summary = matrix.summarize_request_failures(requests, 60.0, 300.0)
|
||||
self.assertEqual(summary["failed"], 4)
|
||||
self.assertEqual(summary["clean_failed"], 2)
|
||||
self.assertEqual(summary["excluded"], 2)
|
||||
self.assertEqual(summary["excluded_kinds"], {"warmup": 1, "recovery": 1})
|
||||
|
||||
def test_synthetic_prompt_exact_and_unique_early_prefix(self):
|
||||
generated = [client.synthetic_prompt(row) for row in rows(200)]
|
||||
self.assertTrue(all(len(value) == 8 for value in generated))
|
||||
self.assertEqual(len({tuple(value[:3]) for value in generated}), 200)
|
||||
|
||||
def test_p05_manifest_has_exact_half_modes(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
out = Path(tmp) / "P05.jsonl"
|
||||
args = SimpleNamespace(
|
||||
id="P05",
|
||||
kind="synthetic",
|
||||
input_uniform=None,
|
||||
input_fixed=None,
|
||||
input_mixture='{"uniform:128:512":0.5,"uniform:4096:8192":0.5}',
|
||||
output_fixed=64,
|
||||
prefix="none",
|
||||
arrival="steady",
|
||||
num_requests=100,
|
||||
workload_seed=20260712,
|
||||
num_prefixes=0,
|
||||
prefix_len=0,
|
||||
suffix_fixed=0,
|
||||
out=str(out),
|
||||
)
|
||||
client.materialize(args)
|
||||
manifest = client.load_manifest(out)
|
||||
self.assertEqual(sum(r["input_tokens"] <= 512 for r in manifest), 50)
|
||||
self.assertEqual(sum(r["input_tokens"] >= 4096 for r in manifest), 50)
|
||||
|
||||
def test_prefix_pool_balanced(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
out = Path(tmp) / "P08.jsonl"
|
||||
args = SimpleNamespace(
|
||||
id="P08",
|
||||
kind="prefix-pool",
|
||||
input_uniform=None,
|
||||
input_fixed=None,
|
||||
input_mixture=None,
|
||||
output_fixed=512,
|
||||
prefix="none",
|
||||
arrival="burst:8",
|
||||
num_requests=80,
|
||||
workload_seed=20260712,
|
||||
num_prefixes=8,
|
||||
prefix_len=1024,
|
||||
suffix_fixed=256,
|
||||
out=str(out),
|
||||
)
|
||||
client.materialize(args)
|
||||
manifest = client.load_manifest(out)
|
||||
counts = {i: 0 for i in range(8)}
|
||||
for row in manifest:
|
||||
counts[row["prefix_id"]] += 1
|
||||
self.assertEqual(row["input_tokens"], 1280)
|
||||
self.assertEqual(set(counts.values()), {10})
|
||||
|
||||
def test_fixed_duration_saturation_and_redaction(self):
|
||||
async def case():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
manifest = root / "m.jsonl"
|
||||
client.atomic_jsonl(manifest, rows(1000))
|
||||
mock = MockServer()
|
||||
await mock.start()
|
||||
try:
|
||||
result = await client.run_load(
|
||||
run_args(manifest, root / "result", mock.port)
|
||||
)
|
||||
finally:
|
||||
await mock.stop()
|
||||
self.assertEqual(result["max_in_flight"], 3)
|
||||
self.assertEqual(mock.max_active, 3)
|
||||
self.assertAlmostEqual(result["clean"]["duration_s"], 0.12, places=9)
|
||||
self.assertEqual(len(result["segments"]), 3)
|
||||
self.assertLessEqual(result["drain_seconds"], 1)
|
||||
self.assertTrue(
|
||||
all(p["max_tokens"] == 2 and p["ignore_eos"] for p in mock.payloads)
|
||||
)
|
||||
text = (root / "result/requests.jsonl").read_text()
|
||||
self.assertNotIn('"prompt":', text)
|
||||
self.assertNotIn('"text":', text)
|
||||
|
||||
asyncio.run(case())
|
||||
|
||||
def test_profile_control_plane_is_not_starved_by_data_connector(self):
|
||||
async def case():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
manifest = root / "m.jsonl"
|
||||
trace_dir = root / "traces"
|
||||
trace_dir.mkdir()
|
||||
client.atomic_jsonl(manifest, rows(1000))
|
||||
server = MockServer(delay=0.5, trace_dir=trace_dir)
|
||||
await server.start()
|
||||
args = run_args(manifest, root / "result", server.port)
|
||||
args.max_concurrency = 1
|
||||
args.warmup_seconds = 0.01
|
||||
args.clean_segment_seconds = 0.01
|
||||
args.num_clean_segments = 1
|
||||
args.profile_after_clean = True
|
||||
args.num_profile_windows = 1
|
||||
args.profile_trace_dir = str(trace_dir)
|
||||
args.recovery_seconds = 0
|
||||
try:
|
||||
result = await client.run_load(args)
|
||||
finally:
|
||||
await server.stop()
|
||||
self.assertEqual(server.max_active, 1)
|
||||
self.assertEqual(server.profile_count, 1)
|
||||
self.assertLess(result["profiles"][0]["start_return_s"], 0.25)
|
||||
|
||||
asyncio.run(case())
|
||||
|
||||
def test_drain_timeout_is_a_hard_sanity_failure(self):
|
||||
async def case():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
manifest = root / "m.jsonl"
|
||||
client.atomic_jsonl(manifest, rows(1000))
|
||||
mock = MockServer()
|
||||
await mock.start()
|
||||
try:
|
||||
args = run_args(manifest, root / "result", mock.port)
|
||||
args.drain_timeout_seconds = 0
|
||||
with self.assertRaisesRegex(RuntimeError, "drain_within_timeout"):
|
||||
await client.run_load(args)
|
||||
finally:
|
||||
await mock.stop()
|
||||
sanity = json.loads((root / "result/sanity.json").read_text())
|
||||
self.assertFalse(sanity["invariants"]["drain_within_timeout"])
|
||||
|
||||
asyncio.run(case())
|
||||
|
||||
def test_burst_schedule_is_eight_at_once(self):
|
||||
async def case():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
manifest = root / "m.jsonl"
|
||||
client.atomic_jsonl(manifest, rows(1000, "burst:8"))
|
||||
sat = root / "sat.json"
|
||||
client.atomic_json(
|
||||
sat, {"clean": {"completed_throughput_rps": 100.0}}
|
||||
)
|
||||
mock = MockServer()
|
||||
await mock.start()
|
||||
try:
|
||||
args = run_args(
|
||||
manifest, root / "result", mock.port, "moderate", sat
|
||||
)
|
||||
args.warmup_seconds = 0
|
||||
args.clean_segment_seconds = 0.4 / 3
|
||||
result = await client.run_load(args)
|
||||
finally:
|
||||
await mock.stop()
|
||||
records = [
|
||||
json.loads(line)
|
||||
for line in (root / "result/requests.jsonl").read_text().splitlines()
|
||||
]
|
||||
groups = {}
|
||||
for record in records:
|
||||
groups.setdefault(round(record["scheduled_s"], 6), 0)
|
||||
groups[round(record["scheduled_s"], 6)] += 1
|
||||
self.assertTrue(all(value == 8 for value in groups.values()))
|
||||
starts = sorted(groups)
|
||||
if len(starts) > 1:
|
||||
self.assertAlmostEqual(starts[1] - starts[0], 8 / 60, places=5)
|
||||
self.assertAlmostEqual(result["request_rate"], 60.0)
|
||||
|
||||
asyncio.run(case())
|
||||
|
||||
def test_manifest_exhaustion_stops_instead_of_wrapping(self):
|
||||
async def case():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
manifest = root / "m.jsonl"
|
||||
client.atomic_jsonl(manifest, rows(2))
|
||||
mock = MockServer()
|
||||
await mock.start()
|
||||
try:
|
||||
with self.assertRaises(client.ManifestExhausted):
|
||||
await client.run_load(
|
||||
run_args(manifest, root / "result", mock.port)
|
||||
)
|
||||
finally:
|
||||
await mock.stop()
|
||||
|
||||
asyncio.run(case())
|
||||
|
||||
def test_cpu_affinity_sets_are_disjoint_and_cover_host(self):
|
||||
values = []
|
||||
for spec in controller.CPU_MAP.values():
|
||||
lo, hi = [int(x) for x in spec.split("-")]
|
||||
values.extend(range(lo, hi + 1))
|
||||
self.assertEqual(sorted(values), list(range(160)))
|
||||
self.assertEqual(len(values), len(set(values)))
|
||||
|
||||
def test_preflight_waits_for_three_stable_zero_samples(self):
|
||||
def sample(memory):
|
||||
return [
|
||||
{
|
||||
"index": 0,
|
||||
"uuid": "GPU-test",
|
||||
"memory_used_mib": memory,
|
||||
"utilization_pct": 0,
|
||||
}
|
||||
]
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
with (
|
||||
mock.patch.object(
|
||||
controller,
|
||||
"gpu_query",
|
||||
side_effect=[sample(4), sample(0), sample(0), sample(0)],
|
||||
),
|
||||
mock.patch.object(controller, "compute_apps", return_value=[]),
|
||||
mock.patch.object(controller, "run_text", return_value=""),
|
||||
mock.patch.object(controller.time, "sleep"),
|
||||
):
|
||||
root = Path(tmp)
|
||||
controller.preflight([0], root)
|
||||
samples = json.loads((root / "gpu-before-samples.json").read_text())
|
||||
self.assertEqual(len(samples), 4)
|
||||
self.assertEqual(samples[0]["gpus"][0]["memory_used_mib"], 4)
|
||||
self.assertEqual(samples[-1]["gpus"][0]["memory_used_mib"], 0)
|
||||
|
||||
def test_kernel_mapping_priority(self):
|
||||
cases = {
|
||||
"void vllm::moe::topkGating": "moe_router",
|
||||
"ncclDevKernel_AllReduce": "collective",
|
||||
"flash_fwd_kernel": "attention",
|
||||
"nvjet_sm90_tst": "moe_gemm",
|
||||
"argmax_kernel": "sampler",
|
||||
"cutlass_gemm": "dense_gemm",
|
||||
"triton_red_fused_add_rms_norm": "norm_elementwise",
|
||||
"cache_swap_kernel": "kv_memory",
|
||||
"unknown": "other",
|
||||
}
|
||||
self.assertEqual(
|
||||
{name: controller.classify_kernel(name) for name in cases}, cases
|
||||
)
|
||||
|
||||
def test_atomic_state_replacement(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp) / "state.json"
|
||||
controller.atomic_json(path, {"schema": 1, "value": 1})
|
||||
controller.atomic_json(path, {"schema": 1, "value": 2})
|
||||
self.assertEqual(json.loads(path.read_text())["value"], 2)
|
||||
self.assertFalse(list(path.parent.glob("*.tmp.*")))
|
||||
|
||||
def test_fingerprint_survives_json_roundtrip(self):
|
||||
original_run_text = controller.run_text
|
||||
original_hash = controller.sha256_file
|
||||
try:
|
||||
controller.run_text = lambda *args, **kwargs: "deadbeef\n"
|
||||
controller.sha256_file = lambda path: "a" * 64
|
||||
fingerprint = controller.make_fingerprint()
|
||||
finally:
|
||||
controller.run_text = original_run_text
|
||||
controller.sha256_file = original_hash
|
||||
self.assertEqual(json.loads(json.dumps(fingerprint)), fingerprint)
|
||||
self.assertEqual(set(fingerprint["cpu_map"]), {str(i) for i in range(8)})
|
||||
|
||||
def test_server_shutdown_signals_parent_before_group(self):
|
||||
process = SimpleNamespace(pid=12345, poll=lambda: None)
|
||||
with (
|
||||
mock.patch.object(controller.os, "kill") as kill,
|
||||
mock.patch.object(controller.os, "killpg") as killpg,
|
||||
mock.patch.object(controller, "_process_group_alive", return_value=False),
|
||||
):
|
||||
controller.stop_servers([process])
|
||||
kill.assert_called_once_with(12345, controller.signal.SIGINT)
|
||||
killpg.assert_not_called()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
353
runs/opprof-phase3/provenance/test_phase3_tools_ea.py
Normal file
353
runs/opprof-phase3/provenance/test_phase3_tools_ea.py
Normal file
@@ -0,0 +1,353 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import importlib.util
|
||||
import json
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest import mock
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
from aiohttp import web
|
||||
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
|
||||
|
||||
def load_module(name: str, filename: str):
|
||||
spec = importlib.util.spec_from_file_location(name, HERE / filename)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[name] = module
|
||||
assert spec.loader is not None
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
client = load_module("phase3_client", "opprof_phase3_client.py")
|
||||
controller = load_module("phase3_controller", "opprof_phase3_controller.py")
|
||||
|
||||
|
||||
def rows(n: int, arrival: str = "steady") -> list[dict]:
|
||||
return [
|
||||
{
|
||||
"schema": 1,
|
||||
"request_id": f"T-{i:05d}",
|
||||
"pattern_id": "T",
|
||||
"kind": "synthetic",
|
||||
"input_tokens": 8,
|
||||
"output_tokens": 2,
|
||||
"arrival": arrival,
|
||||
"token_seed": i + 1,
|
||||
}
|
||||
for i in range(n)
|
||||
]
|
||||
|
||||
|
||||
class MockServer:
|
||||
def __init__(self) -> None:
|
||||
self.active = 0
|
||||
self.max_active = 0
|
||||
self.payloads = []
|
||||
self.runner = None
|
||||
self.port = None
|
||||
|
||||
async def completion(self, request):
|
||||
payload = await request.json()
|
||||
self.payloads.append(payload)
|
||||
self.active += 1
|
||||
self.max_active = max(self.max_active, self.active)
|
||||
await asyncio.sleep(0.01)
|
||||
response = web.StreamResponse(
|
||||
status=200, headers={"Content-Type": "text/event-stream"}
|
||||
)
|
||||
await response.prepare(request)
|
||||
await response.write(
|
||||
b'data: {"choices":[{"text":"x"}],"usage":null}\n\n'
|
||||
)
|
||||
usage = json.dumps(
|
||||
{
|
||||
"choices": [],
|
||||
"usage": {
|
||||
"prompt_tokens": len(payload["prompt"]),
|
||||
"completion_tokens": payload["max_tokens"],
|
||||
},
|
||||
}
|
||||
).encode()
|
||||
await response.write(b"data: " + usage + b"\n\n")
|
||||
await response.write(b"data: [DONE]\n\n")
|
||||
await response.write_eof()
|
||||
self.active -= 1
|
||||
return response
|
||||
|
||||
async def start(self):
|
||||
app = web.Application()
|
||||
app.router.add_post("/v1/completions", self.completion)
|
||||
self.runner = web.AppRunner(app)
|
||||
await self.runner.setup()
|
||||
site = web.TCPSite(self.runner, "127.0.0.1", 0)
|
||||
await site.start()
|
||||
self.port = site._server.sockets[0].getsockname()[1]
|
||||
|
||||
async def stop(self):
|
||||
await self.runner.cleanup()
|
||||
|
||||
|
||||
def run_args(
|
||||
manifest: Path,
|
||||
result_dir: Path,
|
||||
port: int,
|
||||
load_point: str = "saturation",
|
||||
saturation_result: Path | None = None,
|
||||
):
|
||||
return SimpleNamespace(
|
||||
manifest=str(manifest),
|
||||
base_url=f"http://127.0.0.1:{port}",
|
||||
model="mock",
|
||||
load_point=load_point,
|
||||
request_rate="inf" if load_point == "saturation" else None,
|
||||
saturation_result=None if saturation_result is None else str(saturation_result),
|
||||
rate_fraction=0.60,
|
||||
max_concurrency=3,
|
||||
ignore_eos=True,
|
||||
temperature=0,
|
||||
warmup_seconds=0.04,
|
||||
clean_segment_seconds=0.04,
|
||||
num_clean_segments=3,
|
||||
profile_after_clean=False,
|
||||
num_profile_windows=0,
|
||||
profile_warmup_iterations=2,
|
||||
profile_active_iterations=8,
|
||||
profile_trace_dir=None,
|
||||
profile_timeout_seconds=1,
|
||||
recovery_seconds=0,
|
||||
post_clean_seconds=0,
|
||||
drain_timeout_seconds=1,
|
||||
workload_seed=20260712,
|
||||
server_seed=20260712,
|
||||
result_dir=str(result_dir),
|
||||
)
|
||||
|
||||
|
||||
class Phase3ToolTests(unittest.TestCase):
|
||||
def test_synthetic_prompt_exact_and_unique_early_prefix(self):
|
||||
generated = [client.synthetic_prompt(row) for row in rows(200)]
|
||||
self.assertTrue(all(len(value) == 8 for value in generated))
|
||||
self.assertEqual(len({tuple(value[:3]) for value in generated}), 200)
|
||||
|
||||
def test_p05_manifest_has_exact_half_modes(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
out = Path(tmp) / "P05.jsonl"
|
||||
args = SimpleNamespace(
|
||||
id="P05",
|
||||
kind="synthetic",
|
||||
input_uniform=None,
|
||||
input_fixed=None,
|
||||
input_mixture='{"uniform:128:512":0.5,"uniform:4096:8192":0.5}',
|
||||
output_fixed=64,
|
||||
prefix="none",
|
||||
arrival="steady",
|
||||
num_requests=100,
|
||||
workload_seed=20260712,
|
||||
num_prefixes=0,
|
||||
prefix_len=0,
|
||||
suffix_fixed=0,
|
||||
out=str(out),
|
||||
)
|
||||
client.materialize(args)
|
||||
manifest = client.load_manifest(out)
|
||||
self.assertEqual(sum(r["input_tokens"] <= 512 for r in manifest), 50)
|
||||
self.assertEqual(sum(r["input_tokens"] >= 4096 for r in manifest), 50)
|
||||
|
||||
def test_prefix_pool_balanced(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
out = Path(tmp) / "P08.jsonl"
|
||||
args = SimpleNamespace(
|
||||
id="P08",
|
||||
kind="prefix-pool",
|
||||
input_uniform=None,
|
||||
input_fixed=None,
|
||||
input_mixture=None,
|
||||
output_fixed=512,
|
||||
prefix="none",
|
||||
arrival="burst:8",
|
||||
num_requests=80,
|
||||
workload_seed=20260712,
|
||||
num_prefixes=8,
|
||||
prefix_len=1024,
|
||||
suffix_fixed=256,
|
||||
out=str(out),
|
||||
)
|
||||
client.materialize(args)
|
||||
manifest = client.load_manifest(out)
|
||||
counts = {i: 0 for i in range(8)}
|
||||
for row in manifest:
|
||||
counts[row["prefix_id"]] += 1
|
||||
self.assertEqual(row["input_tokens"], 1280)
|
||||
self.assertEqual(set(counts.values()), {10})
|
||||
|
||||
def test_fixed_duration_saturation_and_redaction(self):
|
||||
async def case():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
manifest = root / "m.jsonl"
|
||||
client.atomic_jsonl(manifest, rows(1000))
|
||||
mock = MockServer()
|
||||
await mock.start()
|
||||
try:
|
||||
result = await client.run_load(
|
||||
run_args(manifest, root / "result", mock.port)
|
||||
)
|
||||
finally:
|
||||
await mock.stop()
|
||||
self.assertEqual(result["max_in_flight"], 3)
|
||||
self.assertEqual(mock.max_active, 3)
|
||||
self.assertAlmostEqual(result["clean"]["duration_s"], 0.12, places=9)
|
||||
self.assertEqual(len(result["segments"]), 3)
|
||||
self.assertLessEqual(result["drain_seconds"], 1)
|
||||
self.assertTrue(
|
||||
all(p["max_tokens"] == 2 and p["ignore_eos"] for p in mock.payloads)
|
||||
)
|
||||
text = (root / "result/requests.jsonl").read_text()
|
||||
self.assertNotIn('"prompt":', text)
|
||||
self.assertNotIn('"text":', text)
|
||||
|
||||
asyncio.run(case())
|
||||
|
||||
def test_drain_timeout_is_a_hard_sanity_failure(self):
|
||||
async def case():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
manifest = root / "m.jsonl"
|
||||
client.atomic_jsonl(manifest, rows(1000))
|
||||
mock = MockServer()
|
||||
await mock.start()
|
||||
try:
|
||||
args = run_args(manifest, root / "result", mock.port)
|
||||
args.drain_timeout_seconds = 0
|
||||
with self.assertRaisesRegex(RuntimeError, "drain_within_timeout"):
|
||||
await client.run_load(args)
|
||||
finally:
|
||||
await mock.stop()
|
||||
sanity = json.loads((root / "result/sanity.json").read_text())
|
||||
self.assertFalse(sanity["invariants"]["drain_within_timeout"])
|
||||
|
||||
asyncio.run(case())
|
||||
|
||||
def test_burst_schedule_is_eight_at_once(self):
|
||||
async def case():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
manifest = root / "m.jsonl"
|
||||
client.atomic_jsonl(manifest, rows(1000, "burst:8"))
|
||||
sat = root / "sat.json"
|
||||
client.atomic_json(
|
||||
sat, {"clean": {"completed_throughput_rps": 100.0}}
|
||||
)
|
||||
mock = MockServer()
|
||||
await mock.start()
|
||||
try:
|
||||
args = run_args(
|
||||
manifest, root / "result", mock.port, "moderate", sat
|
||||
)
|
||||
args.warmup_seconds = 0
|
||||
args.clean_segment_seconds = 0.4 / 3
|
||||
result = await client.run_load(args)
|
||||
finally:
|
||||
await mock.stop()
|
||||
records = [
|
||||
json.loads(line)
|
||||
for line in (root / "result/requests.jsonl").read_text().splitlines()
|
||||
]
|
||||
groups = {}
|
||||
for record in records:
|
||||
groups.setdefault(round(record["scheduled_s"], 6), 0)
|
||||
groups[round(record["scheduled_s"], 6)] += 1
|
||||
self.assertTrue(all(value == 8 for value in groups.values()))
|
||||
starts = sorted(groups)
|
||||
if len(starts) > 1:
|
||||
self.assertAlmostEqual(starts[1] - starts[0], 8 / 60, places=5)
|
||||
self.assertAlmostEqual(result["request_rate"], 60.0)
|
||||
|
||||
asyncio.run(case())
|
||||
|
||||
def test_manifest_exhaustion_stops_instead_of_wrapping(self):
|
||||
async def case():
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
root = Path(tmp)
|
||||
manifest = root / "m.jsonl"
|
||||
client.atomic_jsonl(manifest, rows(2))
|
||||
mock = MockServer()
|
||||
await mock.start()
|
||||
try:
|
||||
with self.assertRaises(client.ManifestExhausted):
|
||||
await client.run_load(
|
||||
run_args(manifest, root / "result", mock.port)
|
||||
)
|
||||
finally:
|
||||
await mock.stop()
|
||||
|
||||
asyncio.run(case())
|
||||
|
||||
def test_cpu_affinity_sets_are_disjoint_and_cover_host(self):
|
||||
values = []
|
||||
for spec in controller.CPU_MAP.values():
|
||||
lo, hi = [int(x) for x in spec.split("-")]
|
||||
values.extend(range(lo, hi + 1))
|
||||
self.assertEqual(sorted(values), list(range(160)))
|
||||
self.assertEqual(len(values), len(set(values)))
|
||||
|
||||
def test_kernel_mapping_priority(self):
|
||||
cases = {
|
||||
"void vllm::moe::topkGating": "moe_router",
|
||||
"ncclDevKernel_AllReduce": "collective",
|
||||
"flash_fwd_kernel": "attention",
|
||||
"nvjet_sm90_tst": "moe_gemm",
|
||||
"argmax_kernel": "sampler",
|
||||
"cutlass_gemm": "dense_gemm",
|
||||
"triton_red_fused_add_rms_norm": "norm_elementwise",
|
||||
"cache_swap_kernel": "kv_memory",
|
||||
"unknown": "other",
|
||||
}
|
||||
self.assertEqual(
|
||||
{name: controller.classify_kernel(name) for name in cases}, cases
|
||||
)
|
||||
|
||||
def test_atomic_state_replacement(self):
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
path = Path(tmp) / "state.json"
|
||||
controller.atomic_json(path, {"schema": 1, "value": 1})
|
||||
controller.atomic_json(path, {"schema": 1, "value": 2})
|
||||
self.assertEqual(json.loads(path.read_text())["value"], 2)
|
||||
self.assertFalse(list(path.parent.glob("*.tmp.*")))
|
||||
|
||||
def test_fingerprint_survives_json_roundtrip(self):
|
||||
original_run_text = controller.run_text
|
||||
original_hash = controller.sha256_file
|
||||
try:
|
||||
controller.run_text = lambda *args, **kwargs: "deadbeef\n"
|
||||
controller.sha256_file = lambda path: "a" * 64
|
||||
fingerprint = controller.make_fingerprint()
|
||||
finally:
|
||||
controller.run_text = original_run_text
|
||||
controller.sha256_file = original_hash
|
||||
self.assertEqual(json.loads(json.dumps(fingerprint)), fingerprint)
|
||||
self.assertEqual(set(fingerprint["cpu_map"]), {str(i) for i in range(8)})
|
||||
|
||||
def test_server_shutdown_signals_parent_before_group(self):
|
||||
process = SimpleNamespace(pid=12345, poll=lambda: None)
|
||||
with (
|
||||
mock.patch.object(controller.os, "kill") as kill,
|
||||
mock.patch.object(controller.os, "killpg") as killpg,
|
||||
mock.patch.object(controller, "_process_group_alive", return_value=False),
|
||||
):
|
||||
controller.stop_servers([process])
|
||||
kill.assert_called_once_with(12345, controller.signal.SIGINT)
|
||||
killpg.assert_not_called()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(verbosity=2)
|
||||
353
runs/opprof-phase3/provenance/verify_shutdown_footer.py
Normal file
353
runs/opprof-phase3/provenance/verify_shutdown_footer.py
Normal file
@@ -0,0 +1,353 @@
|
||||
#!/usr/bin/env python3
|
||||
"""One-GPU verification of API-parent-first OpProf shutdown."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import shlex
|
||||
import shutil
|
||||
import signal
|
||||
import subprocess
|
||||
import time
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
WORKDIR = Path("/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712")
|
||||
RUN_DIR = WORKDIR / "runs/e-b-shutdown-verification"
|
||||
SOURCE = Path(
|
||||
"/home/admin/cpfs/wjh/opprof-phase2-dash0-20260711/vllm-v0.24.0"
|
||||
)
|
||||
VENV = Path("/tmp/wjh-opprof-phase2-dash0-20260711/.venv")
|
||||
MODEL = Path("/home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B")
|
||||
CLIENT = WORKDIR / "scripts/opprof_phase3_client.py"
|
||||
MANIFEST = Path("/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P01.jsonl")
|
||||
PORT = 8010
|
||||
|
||||
|
||||
def atomic_json(path: Path, value: Any) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
tmp = path.with_name(path.name + f".tmp.{os.getpid()}")
|
||||
with tmp.open("w", encoding="utf-8") as f:
|
||||
json.dump(value, f, sort_keys=True, indent=2)
|
||||
f.write("\n")
|
||||
f.flush()
|
||||
os.fsync(f.fileno())
|
||||
os.replace(tmp, path)
|
||||
|
||||
|
||||
def run_text(command: list[str], check: bool = True) -> str:
|
||||
result = subprocess.run(
|
||||
command, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT
|
||||
)
|
||||
if check and result.returncode:
|
||||
raise RuntimeError(
|
||||
f"command failed ({result.returncode}): {shlex.join(command)}\n"
|
||||
f"{result.stdout}"
|
||||
)
|
||||
return result.stdout
|
||||
|
||||
|
||||
def gpu_rows() -> list[dict[str, int]]:
|
||||
output = run_text(
|
||||
[
|
||||
"nvidia-smi",
|
||||
"--query-gpu=index,memory.used,utilization.gpu",
|
||||
"--format=csv,noheader,nounits",
|
||||
]
|
||||
)
|
||||
rows = []
|
||||
for line in output.strip().splitlines():
|
||||
index, memory, utilization = [int(part.strip()) for part in line.split(",")]
|
||||
rows.append(
|
||||
{"index": index, "memory_mib": memory, "utilization_pct": utilization}
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
def compute_apps() -> str:
|
||||
return run_text(
|
||||
[
|
||||
"nvidia-smi",
|
||||
"--query-compute-apps=gpu_uuid,pid,process_name,used_memory",
|
||||
"--format=csv,noheader,nounits",
|
||||
],
|
||||
check=False,
|
||||
).strip()
|
||||
|
||||
|
||||
def group_alive(pgid: int, process: subprocess.Popen[Any] | None = None) -> bool:
|
||||
if process is not None:
|
||||
process.poll() # reap an exited API parent before probing its group
|
||||
try:
|
||||
os.killpg(pgid, 0)
|
||||
return True
|
||||
except ProcessLookupError:
|
||||
return False
|
||||
|
||||
|
||||
def wait_ready(process: subprocess.Popen[Any], timeout: float = 300) -> None:
|
||||
deadline = time.monotonic() + timeout
|
||||
while time.monotonic() < deadline:
|
||||
if process.poll() is not None:
|
||||
raise RuntimeError("server exited before readiness")
|
||||
try:
|
||||
with urllib.request.urlopen(
|
||||
f"http://127.0.0.1:{PORT}/health", timeout=1
|
||||
) as response:
|
||||
if response.status == 200:
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(1)
|
||||
raise TimeoutError("server readiness timeout")
|
||||
|
||||
|
||||
def shutdown_parent_first(process: subprocess.Popen[Any]) -> dict[str, Any]:
|
||||
called_at = time.time()
|
||||
os.kill(process.pid, signal.SIGINT)
|
||||
deadline = time.monotonic() + 120
|
||||
while time.monotonic() < deadline and group_alive(process.pid, process):
|
||||
time.sleep(1)
|
||||
graceful = not group_alive(process.pid, process)
|
||||
if not graceful:
|
||||
for sig in (signal.SIGTERM, signal.SIGKILL):
|
||||
try:
|
||||
os.killpg(process.pid, sig)
|
||||
except ProcessLookupError:
|
||||
break
|
||||
time.sleep(5)
|
||||
return {
|
||||
"api_parent_pid": process.pid,
|
||||
"sigint_wall_time": called_at,
|
||||
"group_gone_wall_time": time.time(),
|
||||
"graceful": graceful,
|
||||
"returncode": process.poll(),
|
||||
}
|
||||
|
||||
|
||||
def wait_stable_zero() -> list[list[dict[str, int]]]:
|
||||
samples = []
|
||||
consecutive = 0
|
||||
deadline = time.monotonic() + 120
|
||||
while time.monotonic() < deadline and consecutive < 3:
|
||||
rows = gpu_rows()
|
||||
samples.append(rows)
|
||||
zero = rows[0]["memory_mib"] == 0 and not compute_apps()
|
||||
consecutive = consecutive + 1 if zero else 0
|
||||
if consecutive < 3:
|
||||
time.sleep(5)
|
||||
if consecutive < 3:
|
||||
raise RuntimeError("GPU0 did not reach three stable zero samples")
|
||||
return samples
|
||||
|
||||
|
||||
def validate_footer() -> dict[str, Any]:
|
||||
files = sorted((RUN_DIR / "opprof").glob("*.jsonl"))
|
||||
if len(files) != 1:
|
||||
raise RuntimeError(f"expected one OpProf JSONL, found {len(files)}")
|
||||
lines = files[0].read_text().splitlines()
|
||||
decoded = [json.loads(line) for line in lines]
|
||||
if not decoded or decoded[-1].get("record_type") != "footer":
|
||||
raise RuntimeError("Layer-1 footer missing")
|
||||
records, footer = decoded[:-1], decoded[-1]
|
||||
indices = [record["step_index"] for record in records]
|
||||
invariants = {
|
||||
"all_schema_1": all(item.get("schema") == 1 for item in decoded),
|
||||
"one_footer_last": sum(
|
||||
item.get("record_type") == "footer" for item in decoded
|
||||
)
|
||||
== 1,
|
||||
"steps_contiguous": indices == list(range(len(indices))),
|
||||
"written_matches_records": footer["written_records"] == len(records),
|
||||
"encoded_balanced": footer["encoded_records"]
|
||||
== footer["written_records"] + footer["dropped_records"],
|
||||
"zero_drops": footer["dropped_records"] == 0
|
||||
and all(record["dropped_records_before"] == 0 for record in records),
|
||||
}
|
||||
if not all(invariants.values()):
|
||||
raise RuntimeError(f"footer accounting invalid: {invariants}, {footer}")
|
||||
return {
|
||||
"path": str(files[0]),
|
||||
"bytes": files[0].stat().st_size,
|
||||
"records": len(records),
|
||||
"footer": footer,
|
||||
"invariants": invariants,
|
||||
}
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if RUN_DIR.exists():
|
||||
raise RuntimeError(f"refusing to overwrite {RUN_DIR}")
|
||||
RUN_DIR.mkdir(parents=True)
|
||||
state: dict[str, Any] = {
|
||||
"schema": 1,
|
||||
"status": "preflight",
|
||||
"started_at": time.time(),
|
||||
"gpu": 0,
|
||||
}
|
||||
atomic_json(RUN_DIR / "state.json", state)
|
||||
before = gpu_rows()
|
||||
if before[0]["memory_mib"] != 0 or before[0]["utilization_pct"] != 0:
|
||||
raise RuntimeError(f"GPU0 is not idle: {before[0]}")
|
||||
if compute_apps():
|
||||
raise RuntimeError("a compute process exists before verification")
|
||||
(RUN_DIR / "gpu-before.json").write_text(json.dumps(before, indent=2) + "\n")
|
||||
(RUN_DIR / "clocks-before.txt").write_text(
|
||||
run_text(["nvidia-smi", "-q", "-d", "CLOCK"])
|
||||
)
|
||||
profile_config = {
|
||||
"profiler": "torch",
|
||||
"torch_profiler_dir": "/tmp/wjh-opprof-p3-footer-verify",
|
||||
"ignore_frontend": True,
|
||||
"wait_iterations": 0,
|
||||
"warmup_iterations": 2,
|
||||
"active_iterations": 8,
|
||||
}
|
||||
trace_dir = Path(profile_config["torch_profiler_dir"])
|
||||
if trace_dir.exists():
|
||||
shutil.rmtree(trace_dir)
|
||||
trace_dir.mkdir()
|
||||
server_command = [
|
||||
"taskset",
|
||||
"-c",
|
||||
"0-19",
|
||||
str(VENV / "bin/vllm"),
|
||||
"serve",
|
||||
str(MODEL),
|
||||
"--host",
|
||||
"127.0.0.1",
|
||||
"--port",
|
||||
str(PORT),
|
||||
"--tensor-parallel-size",
|
||||
"1",
|
||||
"--enable-chunked-prefill",
|
||||
"--enable-prefix-caching",
|
||||
"--profiler-config",
|
||||
json.dumps(profile_config, separators=(",", ":")),
|
||||
]
|
||||
client_command = [
|
||||
"taskset",
|
||||
"-c",
|
||||
"0-19",
|
||||
str(VENV / "bin/python"),
|
||||
str(CLIENT),
|
||||
"run",
|
||||
"--manifest",
|
||||
str(MANIFEST),
|
||||
"--base-url",
|
||||
f"http://127.0.0.1:{PORT}",
|
||||
"--model",
|
||||
str(MODEL),
|
||||
"--load-point",
|
||||
"saturation",
|
||||
"--request-rate",
|
||||
"inf",
|
||||
"--max-concurrency",
|
||||
"256",
|
||||
"--ignore-eos",
|
||||
"--temperature",
|
||||
"0",
|
||||
"--warmup-seconds",
|
||||
"30",
|
||||
"--clean-segment-seconds",
|
||||
"40",
|
||||
"--num-clean-segments",
|
||||
"3",
|
||||
"--drain-timeout-seconds",
|
||||
"120",
|
||||
"--workload-seed",
|
||||
"20260712",
|
||||
"--result-dir",
|
||||
str(RUN_DIR / "client"),
|
||||
]
|
||||
with (RUN_DIR / "commands.log").open("w") as f:
|
||||
f.write(
|
||||
"GPU_COMMAND shutdown footer server: "
|
||||
+ shlex.join(server_command)
|
||||
+ " ; expected=60-180s startup + 150-180s load\n"
|
||||
)
|
||||
f.write(
|
||||
"GPU_COMMAND shutdown footer client: "
|
||||
+ shlex.join(client_command)
|
||||
+ " ; expected=30s warmup + 120s clean + drain\n"
|
||||
)
|
||||
server_log = (RUN_DIR / "server.log").open("ab", buffering=0)
|
||||
env = os.environ.copy()
|
||||
env.update(
|
||||
{
|
||||
"CUDA_VISIBLE_DEVICES": "0",
|
||||
"VLLM_OPPROF_DIR": str(RUN_DIR / "opprof"),
|
||||
"HF_HUB_OFFLINE": "1",
|
||||
"TRANSFORMERS_OFFLINE": "1",
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
}
|
||||
)
|
||||
server: subprocess.Popen[Any] | None = None
|
||||
try:
|
||||
print(
|
||||
"GPU_COMMAND shutdown-fix verification: P01/C00 GPU0, "
|
||||
"30s warmup + 120s clean, expected 4-6 wall-min",
|
||||
flush=True,
|
||||
)
|
||||
server = subprocess.Popen(
|
||||
server_command,
|
||||
cwd=SOURCE,
|
||||
env=env,
|
||||
stdout=server_log,
|
||||
stderr=subprocess.STDOUT,
|
||||
start_new_session=True,
|
||||
)
|
||||
state.update({"status": "server_starting", "server_pid": server.pid})
|
||||
atomic_json(RUN_DIR / "state.json", state)
|
||||
wait_ready(server)
|
||||
state.update({"status": "client_running", "server_ready_at": time.time()})
|
||||
atomic_json(RUN_DIR / "state.json", state)
|
||||
with (RUN_DIR / "client.log").open("ab", buffering=0) as client_log:
|
||||
result = subprocess.run(
|
||||
client_command,
|
||||
cwd=WORKDIR,
|
||||
stdout=client_log,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
if result.returncode:
|
||||
raise RuntimeError(f"client exited {result.returncode}")
|
||||
state["status"] = "parent_first_shutdown"
|
||||
atomic_json(RUN_DIR / "state.json", state)
|
||||
shutdown = shutdown_parent_first(server)
|
||||
if not shutdown["graceful"]:
|
||||
raise RuntimeError(f"server required escalation: {shutdown}")
|
||||
footer = validate_footer()
|
||||
zero_samples = wait_stable_zero()
|
||||
client_result = json.loads((RUN_DIR / "client/result.json").read_text())
|
||||
result_json = {
|
||||
"schema": 1,
|
||||
"status": "pass",
|
||||
"gpu": 0,
|
||||
"shutdown": shutdown,
|
||||
"footer": footer,
|
||||
"clean": client_result["clean"],
|
||||
"failed_records": client_result["failed_records"],
|
||||
"gpu_zero_samples": zero_samples,
|
||||
"gpu_seconds": zero_samples and time.time() - state["started_at"],
|
||||
}
|
||||
atomic_json(RUN_DIR / "result.json", result_json)
|
||||
state.update({"status": "complete", "completed_at": time.time()})
|
||||
atomic_json(RUN_DIR / "state.json", state)
|
||||
print(json.dumps(result_json, sort_keys=True), flush=True)
|
||||
except Exception as error:
|
||||
state.update({"status": "failed", "failure": repr(error)})
|
||||
atomic_json(RUN_DIR / "state.json", state)
|
||||
if server is not None and group_alive(server.pid, server):
|
||||
try:
|
||||
os.killpg(server.pid, signal.SIGKILL)
|
||||
except ProcessLookupError:
|
||||
pass
|
||||
raise
|
||||
finally:
|
||||
server_log.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
392
runs/opprof-phase3/provenance/verify_sidecar_shutdown.py
Normal file
392
runs/opprof-phase3/provenance/verify_sidecar_shutdown.py
Normal file
@@ -0,0 +1,392 @@
|
||||
#!/usr/bin/env python3
|
||||
"""GPU verification of graceful and hard-kill OpProf accounting."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import shlex
|
||||
import signal
|
||||
import subprocess
|
||||
import time
|
||||
import urllib.request
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
WORKDIR = Path("/home/admin/cpfs/wjh/opprof-phase3-dash0-20260712")
|
||||
RUN_ROOT = WORKDIR / "runs/e-b-sidecar-verification"
|
||||
SOURCE = Path(
|
||||
"/home/admin/cpfs/wjh/opprof-phase2-dash0-20260711/vllm-v0.24.0"
|
||||
)
|
||||
VENV = Path("/tmp/wjh-opprof-phase2-dash0-20260711/.venv")
|
||||
MODEL = Path("/home/admin/cpfs/wjh/models/Qwen/Qwen3-30B-A3B")
|
||||
CLIENT = WORKDIR / "scripts/opprof_phase3_client.py"
|
||||
MANIFEST = Path("/home/admin/cpfs/wjh/opprof-phase3-private/manifests/P01.jsonl")
|
||||
FLUSH_INTERVAL_SECONDS = 1.0
|
||||
CHECKPOINT_TOLERANCE_SECONDS = 0.1
|
||||
|
||||
|
||||
def atomic_json(path: Path, value: Any) -> None:
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
temporary = path.with_name(f"{path.name}.tmp-{os.getpid()}")
|
||||
with temporary.open("w", encoding="utf-8") as output:
|
||||
json.dump(value, output, indent=2, sort_keys=True)
|
||||
output.write("\n")
|
||||
output.flush()
|
||||
os.fsync(output.fileno())
|
||||
os.replace(temporary, path)
|
||||
|
||||
|
||||
def run_text(command: list[str], check: bool = True) -> str:
|
||||
result = subprocess.run(
|
||||
command,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
if check and result.returncode:
|
||||
raise RuntimeError(
|
||||
f"command failed ({result.returncode}): {shlex.join(command)}\n"
|
||||
f"{result.stdout}"
|
||||
)
|
||||
return result.stdout
|
||||
|
||||
|
||||
def gpu_rows() -> list[dict[str, int]]:
|
||||
output = run_text(
|
||||
[
|
||||
"nvidia-smi",
|
||||
"--query-gpu=index,memory.used,utilization.gpu",
|
||||
"--format=csv,noheader,nounits",
|
||||
]
|
||||
)
|
||||
rows = []
|
||||
for line in output.strip().splitlines():
|
||||
index, memory, utilization = (int(value.strip()) for value in line.split(","))
|
||||
rows.append(
|
||||
{
|
||||
"index": index,
|
||||
"memory_mib": memory,
|
||||
"utilization_pct": utilization,
|
||||
}
|
||||
)
|
||||
return rows
|
||||
|
||||
|
||||
def compute_apps() -> str:
|
||||
return run_text(
|
||||
[
|
||||
"nvidia-smi",
|
||||
"--query-compute-apps=gpu_uuid,pid,process_name,used_memory",
|
||||
"--format=csv,noheader,nounits",
|
||||
],
|
||||
check=False,
|
||||
).strip()
|
||||
|
||||
|
||||
def assert_idle() -> list[dict[str, int]]:
|
||||
rows = gpu_rows()
|
||||
if any(row["memory_mib"] or row["utilization_pct"] for row in rows):
|
||||
raise RuntimeError(f"dash0 is not GPU-idle: {rows}")
|
||||
applications = compute_apps()
|
||||
if applications:
|
||||
raise RuntimeError(f"compute applications present: {applications}")
|
||||
return rows
|
||||
|
||||
|
||||
def wait_ready(process: subprocess.Popen[Any], port: int) -> None:
|
||||
deadline = time.monotonic() + 300
|
||||
while time.monotonic() < deadline:
|
||||
if process.poll() is not None:
|
||||
raise RuntimeError("server exited before readiness")
|
||||
try:
|
||||
with urllib.request.urlopen(
|
||||
f"http://127.0.0.1:{port}/health", timeout=1
|
||||
) as response:
|
||||
if response.status == 200:
|
||||
return
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(1)
|
||||
raise TimeoutError("server readiness timeout")
|
||||
|
||||
|
||||
def wait_zero() -> tuple[list[list[dict[str, int]]], float]:
|
||||
samples: list[list[dict[str, int]]] = []
|
||||
consecutive = 0
|
||||
deadline = time.monotonic() + 180
|
||||
while time.monotonic() < deadline and consecutive < 3:
|
||||
rows = gpu_rows()
|
||||
samples.append(rows)
|
||||
zero = all(row["memory_mib"] == 0 for row in rows) and not compute_apps()
|
||||
consecutive = consecutive + 1 if zero else 0
|
||||
if consecutive < 3:
|
||||
time.sleep(2)
|
||||
if consecutive < 3:
|
||||
raise RuntimeError("GPUs did not reach three stable zero samples")
|
||||
return samples, time.time()
|
||||
|
||||
|
||||
def wait_fresh_sidecar(run_dir: Path) -> dict[str, Any]:
|
||||
deadline = time.monotonic() + 10
|
||||
while time.monotonic() < deadline:
|
||||
files = sorted((run_dir / "opprof").glob("*.jsonl.footer.json"))
|
||||
if len(files) == 1:
|
||||
sidecar = json.loads(files[0].read_text())
|
||||
age = time.time_ns() - sidecar["checkpoint_wall_ns"]
|
||||
if 0 <= age <= 250_000_000:
|
||||
return sidecar
|
||||
time.sleep(0.02)
|
||||
raise TimeoutError("could not observe a fresh OpProf sidecar")
|
||||
|
||||
|
||||
def validate_accounting(
|
||||
run_dir: Path, mode: str, termination_wall_ns: int
|
||||
) -> dict[str, Any]:
|
||||
streams = sorted((run_dir / "opprof").glob("*.jsonl"))
|
||||
sidecars = sorted((run_dir / "opprof").glob("*.jsonl.footer.json"))
|
||||
if len(streams) != 1 or len(sidecars) != 1:
|
||||
raise RuntimeError(
|
||||
f"expected one stream/sidecar, got {len(streams)}/{len(sidecars)}"
|
||||
)
|
||||
raw = streams[0].read_bytes()
|
||||
if not raw.endswith(b"\n"):
|
||||
raise RuntimeError("partial final JSONL line")
|
||||
decoded = [json.loads(line) for line in raw.splitlines()]
|
||||
footers = [row for row in decoded if row.get("record_type") == "footer"]
|
||||
records = [row for row in decoded if row.get("record_type") != "footer"]
|
||||
sidecar = json.loads(sidecars[0].read_text())
|
||||
indices = [row["step_index"] for row in records]
|
||||
checkpoint_age = (
|
||||
termination_wall_ns - sidecar["checkpoint_wall_ns"]
|
||||
) / 1e9
|
||||
common = {
|
||||
"all_schema_1": all(row.get("schema") == 1 for row in decoded)
|
||||
and sidecar.get("schema") == 1,
|
||||
"steps_contiguous": indices == list(range(len(indices))),
|
||||
"written_matches_records": sidecar["written_records"] == len(records),
|
||||
"encoded_balanced": sidecar["encoded_records"]
|
||||
== sidecar["written_records"] + sidecar["dropped_records"],
|
||||
"last_step_matches": bool(records)
|
||||
and sidecar["last_step_index"] == records[-1]["step_index"],
|
||||
"zero_drops": sidecar["dropped_records"] == 0
|
||||
and all(row["dropped_records_before"] == 0 for row in records),
|
||||
}
|
||||
if mode == "graceful":
|
||||
footer_ok = len(footers) == 1 and decoded[-1] is footers[0]
|
||||
agreement = footer_ok and all(
|
||||
footers[0][counter] == sidecar[counter]
|
||||
for counter in ("encoded_records", "written_records", "dropped_records")
|
||||
)
|
||||
specific = {
|
||||
"one_footer_last": footer_ok,
|
||||
"final_sidecar": sidecar["final"] is True,
|
||||
"footer_sidecar_agree": agreement,
|
||||
}
|
||||
else:
|
||||
specific = {
|
||||
"no_in_stream_footer": not footers,
|
||||
"checkpoint_sidecar": sidecar["final"] is False,
|
||||
"checkpoint_within_bound": checkpoint_age
|
||||
<= FLUSH_INTERVAL_SECONDS + CHECKPOINT_TOLERANCE_SECONDS,
|
||||
}
|
||||
invariants = {**common, **specific}
|
||||
if not all(invariants.values()):
|
||||
raise RuntimeError(
|
||||
f"{mode} accounting invalid: {invariants}; sidecar={sidecar}"
|
||||
)
|
||||
return {
|
||||
"stream": str(streams[0]),
|
||||
"sidecar": str(sidecars[0]),
|
||||
"bytes": len(raw),
|
||||
"records": len(records),
|
||||
"footer_count": len(footers),
|
||||
"checkpoint_age_seconds": checkpoint_age,
|
||||
"counters": {
|
||||
key: sidecar[key]
|
||||
for key in ("encoded_records", "written_records", "dropped_records")
|
||||
},
|
||||
"last_step_index": sidecar["last_step_index"],
|
||||
"invariants": invariants,
|
||||
}
|
||||
|
||||
|
||||
def run_trial(mode: str, port: int) -> dict[str, Any]:
|
||||
run_dir = RUN_ROOT / mode
|
||||
if run_dir.exists():
|
||||
raise RuntimeError(f"refusing to overwrite {run_dir}")
|
||||
run_dir.mkdir(parents=True)
|
||||
before = assert_idle()
|
||||
atomic_json(run_dir / "gpu-before.json", before)
|
||||
(run_dir / "clocks-before.txt").write_text(
|
||||
run_text(["nvidia-smi", "-q", "-d", "CLOCK"])
|
||||
)
|
||||
server_command = [
|
||||
"taskset",
|
||||
"-c",
|
||||
"0-19",
|
||||
str(VENV / "bin/vllm"),
|
||||
"serve",
|
||||
str(MODEL),
|
||||
"--host",
|
||||
"127.0.0.1",
|
||||
"--port",
|
||||
str(port),
|
||||
"--tensor-parallel-size",
|
||||
"1",
|
||||
"--enable-chunked-prefill",
|
||||
"--enable-prefix-caching",
|
||||
"--shutdown-timeout",
|
||||
"120",
|
||||
]
|
||||
client_command = [
|
||||
"taskset",
|
||||
"-c",
|
||||
"0-19",
|
||||
str(VENV / "bin/python"),
|
||||
str(CLIENT),
|
||||
"run",
|
||||
"--manifest",
|
||||
str(MANIFEST),
|
||||
"--base-url",
|
||||
f"http://127.0.0.1:{port}",
|
||||
"--model",
|
||||
str(MODEL),
|
||||
"--load-point",
|
||||
"saturation",
|
||||
"--request-rate",
|
||||
"inf",
|
||||
"--max-concurrency",
|
||||
"256",
|
||||
"--ignore-eos",
|
||||
"--temperature",
|
||||
"0",
|
||||
"--warmup-seconds",
|
||||
"20",
|
||||
"--clean-segment-seconds",
|
||||
"40",
|
||||
"--num-clean-segments",
|
||||
"3",
|
||||
"--drain-timeout-seconds",
|
||||
"120",
|
||||
"--workload-seed",
|
||||
"20260712",
|
||||
"--result-dir",
|
||||
str(run_dir / "client"),
|
||||
]
|
||||
with (run_dir / "commands.log").open("w", encoding="utf-8") as output:
|
||||
output.write(
|
||||
f"GPU_COMMAND {mode} server: {shlex.join(server_command)}; "
|
||||
"expected=60-180s startup + 140-180s load\n"
|
||||
)
|
||||
output.write(
|
||||
f"GPU_COMMAND {mode} client: {shlex.join(client_command)}; "
|
||||
"expected=20s warmup + 120s clean + drain\n"
|
||||
)
|
||||
environment = os.environ.copy()
|
||||
environment.update(
|
||||
{
|
||||
"CUDA_VISIBLE_DEVICES": "0",
|
||||
"VLLM_OPPROF_DIR": str(run_dir / "opprof"),
|
||||
"HF_HUB_OFFLINE": "1",
|
||||
"TRANSFORMERS_OFFLINE": "1",
|
||||
"PYTHONUNBUFFERED": "1",
|
||||
}
|
||||
)
|
||||
started = time.time()
|
||||
server_log = (run_dir / "server.log").open("ab", buffering=0)
|
||||
server: subprocess.Popen[Any] | None = None
|
||||
try:
|
||||
print(
|
||||
f"GPU_COMMAND sidecar-{mode}: P01/C00 GPU0, 20s warmup + "
|
||||
"120s clean, expected 4-6 wall-min",
|
||||
flush=True,
|
||||
)
|
||||
server = subprocess.Popen(
|
||||
server_command,
|
||||
cwd=SOURCE,
|
||||
env=environment,
|
||||
stdout=server_log,
|
||||
stderr=subprocess.STDOUT,
|
||||
start_new_session=True,
|
||||
)
|
||||
atomic_json(
|
||||
run_dir / "state.json",
|
||||
{"status": "server_starting", "server_pid": server.pid},
|
||||
)
|
||||
wait_ready(server, port)
|
||||
with (run_dir / "client.log").open("ab", buffering=0) as client_log:
|
||||
client = subprocess.run(
|
||||
client_command,
|
||||
cwd=WORKDIR,
|
||||
stdout=client_log,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
if client.returncode:
|
||||
raise RuntimeError(f"client exited {client.returncode}")
|
||||
if mode == "graceful":
|
||||
termination_wall_ns = time.time_ns()
|
||||
os.kill(server.pid, signal.SIGINT)
|
||||
server.wait(timeout=150)
|
||||
log_text = (run_dir / "server.log").read_text(errors="replace")
|
||||
if "mode=drain timeout=120s" not in log_text:
|
||||
raise RuntimeError("official drain-mode log not observed")
|
||||
else:
|
||||
wait_fresh_sidecar(run_dir)
|
||||
termination_wall_ns = time.time_ns()
|
||||
os.killpg(server.pid, signal.SIGKILL)
|
||||
server.wait(timeout=30)
|
||||
zero_samples, zero_at = wait_zero()
|
||||
accounting = validate_accounting(run_dir, mode, termination_wall_ns)
|
||||
client_result = json.loads((run_dir / "client/result.json").read_text())
|
||||
result = {
|
||||
"schema": 1,
|
||||
"status": "pass",
|
||||
"mode": mode,
|
||||
"server_returncode": server.returncode,
|
||||
"termination_wall_ns": termination_wall_ns,
|
||||
"accounting": accounting,
|
||||
"clean": client_result["clean"],
|
||||
"failed_records": client_result["failed_records"],
|
||||
"gpu_zero_samples": zero_samples,
|
||||
"gpu_seconds": zero_at - started,
|
||||
}
|
||||
atomic_json(run_dir / "result.json", result)
|
||||
atomic_json(run_dir / "state.json", {"status": "complete"})
|
||||
return result
|
||||
except Exception as error:
|
||||
atomic_json(
|
||||
run_dir / "state.json",
|
||||
{"status": "failed", "failure": repr(error)},
|
||||
)
|
||||
if server is not None and server.poll() is None:
|
||||
try:
|
||||
os.killpg(server.pid, signal.SIGKILL)
|
||||
except ProcessLookupError:
|
||||
pass
|
||||
wait_zero()
|
||||
raise
|
||||
finally:
|
||||
server_log.close()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
if RUN_ROOT.exists():
|
||||
raise RuntimeError(f"refusing to overwrite {RUN_ROOT}")
|
||||
RUN_ROOT.mkdir(parents=True)
|
||||
state: dict[str, Any] = {"schema": 1, "status": "running", "results": {}}
|
||||
atomic_json(RUN_ROOT / "state.json", state)
|
||||
for offset, mode in enumerate(("graceful", "hard-kill")):
|
||||
result = run_trial(mode, 8010 + offset)
|
||||
state["results"][mode] = result
|
||||
atomic_json(RUN_ROOT / "state.json", state)
|
||||
state["status"] = "complete"
|
||||
state["gpu_seconds"] = sum(
|
||||
result["gpu_seconds"] for result in state["results"].values()
|
||||
)
|
||||
atomic_json(RUN_ROOT / "state.json", state)
|
||||
print(json.dumps(state, sort_keys=True), flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user