|
1 | | -# Handoff: state and continuation (written 2026-08-01, branch p2p-findings @ 02d81d8a) |
| 1 | +# Handoff: state and continuation (updated 2026-08-01 after c64 probe PASS) |
2 | 2 |
|
3 | 3 | ## Where the campaign stands |
4 | 4 |
|
5 | 5 | - Cluster: kermit, namespace `nilig-p2p`. Fleet 4/4 Ready on |
6 | 6 | `quay.io/niliguy/vllm-openai:nightly-6f91edf9-pr50302` with the |
7 | 7 | author's prefill settings (util 0.935, ceiling 2048). The vllm #50302 |
8 | | - crash is FIXED under real traffic: warm round 32/32 HTTP 200 through |
9 | | - the EPP, zero decode restarts (previously 3/32 + decode crash). |
| 8 | + crash is FIXED under real traffic (warm round 32/32; sustained c64 |
| 9 | + probe clean). #50302 is merged upstream (`a0cd2b69`), so any |
| 10 | + post-merge nightly is a fallback engine if the baked image ever |
| 11 | + misbehaves. |
10 | 12 | - Active EPP config: armC (precise+P2P). `activate_arm.sh` re-proves |
11 | | - live KV-event subscriptions after every B/C activation. |
12 | | -- Gate 1: PASS (live-subscription evidence, 32/32; |
13 | | - `gates/archives/gate1-20260801181759/`). |
14 | | -- Gate 2: every byte assertion PASSES on the recalibrated window |
15 | | - (control 0.0 MB; engine-inject 1341.5 MB; pd-stock 1341.5 MB = 0.0% |
16 | | - deviation; window 1200-1550 MB around the measured 54.6 KB/token). |
17 | | - The ONLY failing assertion is source-session delta >= 1. |
| 13 | + live KV-event subscriptions after every armB/armC activation |
| 14 | + (`gates/subscriptions/`). |
| 15 | +- Gate 1: PASS - live-subscription evidence, 32/32 |
| 16 | + (`gates/archives/gate1-20260801181759/`). |
| 17 | +- Gate 2: PASS - control 0.0 MB / engine-inject 1341.5 MB / pd-stock |
| 18 | + 1341.5 MB (0.0% deviation, window 1200-1550 MB per the measured |
| 19 | + 54.6 KB/token), session evidence delta>=1 OR live exact-peer |
| 20 | + (`gates/archives/gate2-20260801183650/`). |
| 21 | +- Stage-1 engagement probe at c64: PASS at 10.6% (threshold 5%): |
| 22 | + 3889 requests, 412 distinct organic source directives, 251 new peer |
| 23 | + sessions, 3.9 TB prefill tier restores (loaded-bytes includes LOCAL |
| 24 | + CPU->GPU restores; directives+sessions are the P2P-specific |
| 25 | + evidence). Archive: `gates/probe-c64-20260801185307/`. |
18 | 26 |
|
19 | 27 | ## The one open decision (for codex) |
20 | 28 |
|
21 | | -Session-delta semantics on a warm mesh. P2P sessions persist beyond the |
22 | | -pull that created them: the first Gate 2 run consumed the only |
23 | | -`accepting incoming connection` event; reruns ride the same open |
24 | | -session, so the log delta reads 0 while a live ESTABLISHED connection |
25 | | -on the source's P2P port 7777 from the destination prefill IP is |
26 | | -verifiable in /proc/net/tcp. Proposal on the table: satisfy the session |
27 | | -assertion by EITHER new-session delta >= 1 OR a live ESTABLISHED |
28 | | -source-port-7777 connection whose remote address equals the destination |
29 | | -pod IP, captured at gate end (same live-evidence style as |
30 | | -`wait_precise_subscriptions.sh`). Alternative: declare Gate 2 |
31 | | -single-shot per mesh-cold (conflicts with no-restart reruns). |
| 29 | +The README defers to a "cold-roll policy" whose text never made it into |
| 30 | +the repo (it lived in the original design message). Needed before the |
| 31 | +causal B/C measurements: the cache-state rule between runs. Tension: |
| 32 | +C runs warm persistent CPU tiers and leave peer sessions open, which a |
| 33 | +following B run partially inherits; a full engine roll restores cold |
| 34 | +state but costs ~40 min per roll (24 planned runs) and re-exposes the |
| 35 | +boot to the gpu-pruner. Counterbalanced pairs (B/C then C/B, 3 paired |
| 36 | +seeds) exist to neutralize order effects without rolls, and the blog's |
| 37 | +own ladder ran rungs back-to-back warm. Recommendation on the table: |
| 38 | +no rolls within the ladder, fixed warm-in convention (the scenario's |
| 39 | +900 s steady-state minimum), rolls at most at cell boundaries. Codex to |
| 40 | +rule; write the ruling into README.md so it is declared, then proceed. |
32 | 41 |
|
33 | 42 | ## Continuation sequence after that ruling |
34 | 43 |
|
35 | | -1. Apply the ruled session check to `gates/gate2_p2p_proof.sh`, rerun |
36 | | - Gate 2 (fresh prefixes, no fleet restart), require full PASS. |
37 | | -2. `gates/armC_probe.sh 64` - organic engagement probe (needs >0 |
38 | | - source-header emissions AND >0 prefill loaded-bytes delta; prints |
39 | | - engagement % for the 5% rule). |
40 | | -3. Ladder c16/32/64/128 (the blog's own rungs; 900 s per rung, seed 42 |
41 | | - fixed): stage 1 = one paired B/C run + probe per rung; stage 2 = at |
42 | | - rungs with >=5% engagement, three counterbalanced B/C repetitions |
43 | | - with SEED=42/43/44 via `run_arm.sh <arm> <conc> <tag>`, plus one |
44 | | - armA anchor per rung. B-vs-C is the only causal P2P comparison. |
| 44 | +1. Write the ruled policy into README.md (replace the dangling |
| 45 | + "Cold-roll policy ... per the campaign design" sentence). |
| 46 | +2. Measurements at c64 (already qualified): three counterbalanced |
| 47 | + B/C repetitions with SEED=42/43/44 via |
| 48 | + `run_arm.sh <armB|armC> 64 <tag>`, order alternated (BC/CB/BC), |
| 49 | + plus one armA anchor run. B-vs-C is the only causal P2P |
| 50 | + comparison; A is context. |
| 51 | +3. Remaining rungs c16/c32/c128: `gates/armC_probe.sh <conc> 900` |
| 52 | + first; measure only rungs with >=5% engagement (expect c128 yes; |
| 53 | + c16/c32 likely ties - a tie at <5% engagement is itself the |
| 54 | + reported result, run one paired B/C to confirm if cheap). |
| 55 | +4. Results: per-rung tables (TTFT p50/p99, req/s, tok/s/user from |
| 56 | + `profile_export_aiperf.json`) B vs C with A anchor, plus mechanism |
| 57 | + counters (directives, sessions, loaded bytes) per run. Compare |
| 58 | + shapes against the author's p1w2d1w2 curves in |
| 59 | + `workload/blog-ladder-archive/headline_metrics.csv` (topology |
| 60 | + differs: no absolute claims). |
45 | 61 |
|
46 | | -## Gate 2 invocation (re-resolve pod IPs first - they change on reboot) |
| 62 | +## Run mechanics |
47 | 63 |
|
48 | | -``` |
49 | | -kubectl get pods -n nilig-p2p -l llm-d.ai/inference-serving=true -o wide |
50 | | -cd gates && NS=nilig-p2p \ |
51 | | - SRC_POD=<prefill-0 pod name> \ |
52 | | - SRC_PF_URL=http://<prefill-0 IP>:8000 SRC_PF_SERVING=<prefill-0 IP>:8000 \ |
53 | | - DST_PF_URL=http://<prefill-1 IP>:8000 DST_PF_SERVING=<prefill-1 IP>:8000 \ |
54 | | - DECODE_SIDECAR_URL=http://<decode-0 IP>:8000 \ |
55 | | - OUT=archives/gate2-$(date +%Y%m%d%H%M%S) bash gate2_p2p_proof.sh |
56 | | -``` |
| 64 | +- `run_arm.sh` clones the recovered Job (`workload/ |
| 65 | + blog-campaign-job-c64.json`), changing only URL/metrics/artifact |
| 66 | + volume/concurrency/seed; it aborts on fleet!=4 Ready, foreign ACTIVE |
| 67 | + jobs (ALLOW_FOREIGN=1 to override), config/producer mismatch; snap |
| 68 | + counters before/after (`snap_counters.sh`). |
| 69 | +- A Complete Job is not a valid run - grep the harness log for |
| 70 | + `errors=N` and check `was_cancelled`. |
| 71 | +- The scenario rejects `--benchmark-duration < 900`. |
| 72 | +- Gate 2 invocation template and pod-IP resolution: see the gate's |
| 73 | + header; IPs change on every pod recreation. |
57 | 74 |
|
58 | 75 | ## Operational guards (session-local - they DIE with the operator session) |
59 | 76 |
|
60 | | -Two watchdogs ran from the operator's machine and do not survive it: |
61 | | - |
62 | | -- gpu-pruner guard: the cluster pruner scales idle LWS roles to 0. |
63 | | - Restore with: |
| 77 | +- gpu-pruner scales idle LWS roles to 0 within ~15-20 idle minutes. |
| 78 | + Restore: |
64 | 79 | `kubectl scale lws -n nilig-p2p wide-ep-lws-nvidia-gpu-vllm-glm-5-2-prefill --replicas=2` |
65 | 80 | `kubectl scale lws -n nilig-p2p wide-ep-lws-nvidia-gpu-vllm-glm-5-2-decode --replicas=1` |
66 | | - Reboot ~40 min total (prefill ~15, decode ~25). Nodes have been |
67 | | - retained across reaps so far. |
68 | | -- keep-warm ticker: any Ready engine idles back into the pruner's |
69 | | - sights in ~15-20 min. Ping each Ready engine every ~4 min (decode |
70 | | - pods :8200, prefill pods :8000, `/v1/completions`, max_tokens 8, via |
71 | | - the in-cluster `scenc-loadgen` pod - python3 urllib; the image has no |
72 | | - curl). Real benchmark traffic also counts as warm. |
73 | | - |
74 | | -After any fleet reboot: re-run `activate_arm.sh armC` (it re-proves |
75 | | -subscriptions), then Gate 1, then Gate 2 - pod IPs and the session |
76 | | -state will have changed (a cold mesh makes the session delta valid |
77 | | -again). |
| 81 | + Reboot ~40 min (prefill ~15, decode ~25); nodes retained so far. |
| 82 | +- Keep-warm: ping every Ready engine every ~4 min from the in-cluster |
| 83 | + `scenc-loadgen` pod (decode :8200, prefill :8000, |
| 84 | + `/v1/completions`, max_tokens 8, python3 urllib - image has no |
| 85 | + curl). Benchmark traffic also counts. |
| 86 | +- After any fleet reboot: `activate_arm.sh armC`, Gate 1, Gate 2 |
| 87 | + (cold mesh makes the session delta valid again), and re-check pod |
| 88 | + IPs everywhere. |
78 | 89 |
|
79 | 90 | ## Traps already hit (do not re-diagnose) |
80 | 91 |
|
81 | 92 | - `kubectl exec` heredocs need `-i` or python runs an empty script. |
82 | 93 | - EPP log greps are not evidence at --v=5; use live /proc/net/tcp |
83 | | - checks (`gates/wait_precise_subscriptions.sh`). |
| 94 | + checks (`gates/wait_precise_subscriptions.sh`); stream logs with a |
| 95 | + `grep --line-buffered '"requestID"'` filter (a 3-min unfiltered |
| 96 | + stream was 224 MB). |
84 | 97 | - The approx producer auto-instantiates alongside precise |
85 | | - (RegisterAsDefaultProducer for PrefixCacheMatchInfoDataKey in |
86 | | - runner.go) - its log lines under armB/C are expected, not a config |
87 | | - mismatch. |
88 | | -- `accepting incoming connection` = session, not pull; sessions persist |
89 | | - across runs and arms. |
| 98 | + (RegisterAsDefaultProducer in runner.go) - its log lines under |
| 99 | + armB/C are expected, not a config mismatch. |
| 100 | +- `accepting incoming connection` = session, not pull; sessions |
| 101 | + persist across runs and arms (Gate 2's warm-mesh rule exists for |
| 102 | + this). |
90 | 103 | - Stuck-LWS template: after any LWS spec change, delete pods; STS |
91 | | - ordinal revision lag can recreate pod-0 on the old revision until |
92 | | - pod-1 is Ready. |
93 | | -- KV footprint on this engine is 54.6 KB/token (FP8 KV); the old |
94 | | - 92.6 KB/token expectation is stale. |
95 | | -- A Complete benchmark Job is not a valid arm - grep the harness log |
96 | | - for `errors=N`; abort rungs with foreign ACTIVE jobs (run_arm.sh |
97 | | - enforces both). |
| 104 | + ordinal revision lag can recreate pod-0 on the old revision. |
| 105 | +- KV footprint on this engine: 54.6 KB/token (FP8 KV). The 92.6 |
| 106 | + KB/token figure is stale. |
| 107 | +- `kv_offload_load_bytes` counts LOCAL CPU->GPU restores, not just |
| 108 | + P2P pulls - never present loaded-bytes alone as pull evidence. |
0 commit comments