E2 finished 1h33min wall. Headline contrast on the matched Inferact 50-session subset: E1 (naive 1P3D + kv-aware + RDMA): 1200/1285 succ, lat p50=93s p99=219s, TTFT p50=89s p99=207s E2 (KVC v2 + RDMA): 231/1285 succ, lat p50= 7.4s p99=65s, TTFT p50=0.43s p99=8.7s E2 is 12.4× worse on failure rate but 20× better on TTFT p50 among the requests that did complete. Both runs leave D2 entirely unused for the same structural reason: Inferact's shared "permissions instructions" boilerplate makes overlap dominate the kv-aware lex score, and v2's migration mechanism only fires on capacity rejects which never reach D2. The 1054 E2 timeouts are downstream of that imbalance, not a v2 bug per se. The doc closes with five concrete follow-ups for the next agent — cold-D bonus, router-mode admission, default-policy control arm, TCP-loopback comparison, failure mode forensics. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
179 lines
12 KiB
Markdown
179 lines
12 KiB
Markdown
# E1 vs E2 Experiment Results — H200 + Driver 570
|
||
|
||
**Status**: E1 ✅ complete (2026-05-12 01:48 UTC, wall 1h29min). E2 ✅ complete (2026-05-12 03:22 UTC, wall 1h33min).
|
||
**Branch**: `h200-cu130`.
|
||
**Trace**: `outputs/inferact_50sess.jsonl` (deterministic head-cut of Inferact `codex_swebenchpro` to first 50 trials, md5 `7bb263a32600ef5a6ef5099ba340a487`, 1285 requests, mean input_length 67,631 tokens).
|
||
**Hardware**: 4× H200 80GB, driver 570.86.15 (cu12.8 API), Mellanox mlx5_60 RoCE 400 Gb/s NDR.
|
||
**Model**: Qwen3-30B-A3B-Instruct-2507 (TP1).
|
||
**Toolchain**: vendored SGLang 0.5.10 + cu12.8 nvcc local install (`~/cuda-12.8`) — see `docs/H200_DRIVER570_SETUP_ZH.md`.
|
||
|
||
---
|
||
|
||
## 1. Hypotheses being tested
|
||
|
||
From `docs/ONBOARDING_NEXT_AGENT_ZH.md` §3.1:
|
||
|
||
- **H1**: KVC v2's wins are not just from "1P3D topology + kv-aware policy" — the KVC layer (admission / migration / direct-to-D) contributes meaningfully on top. Pairing E1 (no KVC layer) against E2 (full KVC v2) on the **same subset** isolates the marginal contribution.
|
||
- **H2/H3**: Enabling real RDMA pushes TTFT p99 down from the reported 1.28s (TCP loopback) toward ~0.7s. Independent of H1, this is measured inside E2 alone (comparing against the historical TCP-loopback v2 reference).
|
||
|
||
---
|
||
|
||
## 2. E1 results — naive 1P3D + kv-aware + RDMA
|
||
|
||
**Configuration**: `mechanism=pd-disaggregation`, `policy=kv-aware`, 1P3D (GPU0=P, GPU1/2/3=D), `--force-rdma --ib-device mlx5_60`, `--concurrency-limit 32`, ts=1.
|
||
|
||
| Metric | E1 |
|
||
|---|---:|
|
||
| request_count | 1285 |
|
||
| success | 1200 |
|
||
| **error_count** | **85** |
|
||
| **failure_count** | **85** |
|
||
| abort_count | 0 |
|
||
| latency mean | 96.34 s |
|
||
| latency p50 | 93.21 s |
|
||
| latency p90 | 180.69 s |
|
||
| latency p99 | 219.46 s |
|
||
| ttft mean | 90.48 s |
|
||
| ttft p50 | 88.62 s |
|
||
| ttft p90 | 175.13 s |
|
||
| **ttft p99** | **207.39 s** |
|
||
| execution_modes | `pd-disaggregation-router: 1200`, `pd-disaggregation: 85` (errors) |
|
||
| per_decode_load | **D0:575, D1:710, D2:0** |
|
||
| per_prefill_load | P0:1285 |
|
||
| cache_hit_request_count | 1199 / 1200 (99.9%) |
|
||
|
||
### Key observations on E1
|
||
|
||
1. **D2 was never bound to a single session**. All 50 sessions got pinned to D0 or D1 by `kv-aware` policy's (overlap + sticky + inflight + assigned) lex-score, and naive pd-disaggregation has no migration mechanism to rebalance. Effective topology was **1P2D**, not 1P3D.
|
||
2. **Massive queueing**. TTFT p50 ≈ 89 s and p99 > 200 s indicate sessions waited tens of seconds in router/prefill queue. With `--concurrency-limit 32` and D0/D1 saturated, the inflight cap forced ~1250 reqs to serialize through only two decode workers.
|
||
3. **85 failures (6.6%)** — all `execution_mode == pd-disaggregation` (which the metrics module classifies as `error` when the agentic-pd-hybrid replay sees an unsuccessful upstream response). Most likely caused by `--request-timeout-s 300` firing on the longest queued requests.
|
||
4. **Cache hit 99.9%** — the kv-aware policy did successfully concentrate sessions on their prior D worker; the Inferact converter's prefix-shared 24-token-block hash_ids gave near-perfect prefix overlap across turns of the same session.
|
||
|
||
### What E1 establishes
|
||
|
||
For the same hardware, same trace, same model, **naive 1P3D + kv-aware policy is unusable for multi-session agentic workloads**:
|
||
- session-stickiness without migration leaves a third of compute capacity (1 of 3 decode GPUs) entirely unused
|
||
- queueing dominates user-facing latency
|
||
- failure rate is 6.6% even with 5 minutes per-request timeout
|
||
|
||
This is *the baseline H1 needs* — it shows the KVC layer (E2) has something concrete to improve over.
|
||
|
||
---
|
||
|
||
## 3. E2 results — KVC v2 + RDMA
|
||
|
||
**Configuration**: `mechanism=kvcache-centric`, `policy=kv-aware`, 1P3D, `--force-rdma --ib-device mlx5_60`, `--kvcache-admission-mode worker`, `--kvcache-direct-max-uncached-tokens 8192`, `--kvcache-migration-reject-threshold 3`, `--kvcache-prefill-backup-policy release-after-transfer`, `--kvcache-prefill-priority-eviction`, ts=1.
|
||
|
||
| Metric | E2 |
|
||
|---|---:|
|
||
| request_count | 1285 |
|
||
| success | 231 |
|
||
| **error_count** | **1054** |
|
||
| **failure_count** | **1054** |
|
||
| abort_count | 0 |
|
||
| latency mean (successful only) | 10.94 s |
|
||
| latency p50 | 7.44 s |
|
||
| latency p90 | 20.68 s |
|
||
| latency p99 | 64.73 s |
|
||
| ttft mean (successful only) | 1.76 s |
|
||
| ttft p50 | 0.43 s |
|
||
| ttft p90 | 6.56 s |
|
||
| **ttft p99** | **8.74 s** |
|
||
| execution_modes (succ.) | direct-to-D: 87; turn1-seed: 50; reseed: 12; large-append-reseed: 11; seed-filter-early-turn: 50; large-append-cap: 21 |
|
||
| per_decode_load | **D0:600, D1:685, D2:0** |
|
||
| per_prefill_load | P0:1285 |
|
||
| cache_hit_request_count | 230 / 231 (99.6 %) |
|
||
|
||
### Key observations on E2
|
||
|
||
1. **D2 still has zero bindings** — same root cause as E1. The kv-aware policy's overlap term dominates and Inferact's identical "permissions instructions" boilerplate creates overlap on D0/D1 for every new session. KVC v2's `migration_reject_threshold=3` never trips because D0/D1 do not *reject* admission until they are completely saturated.
|
||
2. **80 % failure rate, 1054 / 1285**. The 1054 reqs classified as bare `kvcache-centric` execution_mode are upstream timeouts / failures: they exceeded `--request-timeout-s 300` while waiting for admission. v2's stricter admission path (direct-to-D requires both `session resident on D` and `append_len ≤ τ_append` AND capacity) rejects more often than E1's vanilla pd-disagg; the rejects don't trigger migration (see §3 root cause), they cause the request to fall through to `fallback-seed` / `fallback-no-d-capacity` which queue on already-saturated D0/D1, hit timeout, and fail.
|
||
3. **Among the 231 that succeeded, the latency profile is sharply better**: TTFT p50 = **0.43 s** vs E1's 88.62 s (E2/E1 = 0.5 %), latency p50 = **7.44 s** vs E1's 93.21 s (8 %). This is the "if it gets through, it's fast" regime — direct-to-D fast path eliminates P→D mooncake transfer for resident sessions.
|
||
4. **Direct-to-D fast path engaged 87 / 231 = 37.7 %** of successful requests. Lower than historical v2's 91.6 % on SWE-Bench, because most Inferact reqs fell into seed (50) / reseed (12) / fallback paths due to the D0/D1 capacity-vs-admission contention.
|
||
|
||
---
|
||
|
||
## 4. Comparison table — E1 vs E2
|
||
|
||
Numbers below are over **all 1285 requests** for E1 (since failure rate is small) but **only the 231 successful** for E2 (since the bulk timed out before producing latency datapoints). This is **not a fair head-to-head**, see §6.
|
||
|
||
| Metric | E1 | E2 (succ only) | E2 / E1 |
|
||
|---|---:|---:|---:|
|
||
| Total reqs | 1285 | 1285 | – |
|
||
| Successful | 1200 | **231** | 0.19× |
|
||
| **error_count** | 85 (6.6 %) | **1054 (82 %)** | **12.4× worse** |
|
||
| lat mean | 96.34 s | 10.94 s | 0.114 |
|
||
| lat p50 | 93.21 s | **7.44 s** | **0.080** |
|
||
| lat p90 | 180.69 s | 20.68 s | 0.114 |
|
||
| lat p99 | 219.46 s | 64.73 s | 0.295 |
|
||
| ttft mean | 90.48 s | 1.76 s | 0.019 |
|
||
| **ttft p50** | 88.62 s | **0.43 s** | **0.005** |
|
||
| ttft p90 | 175.13 s | 6.56 s | 0.037 |
|
||
| ttft p99 | 207.39 s | 8.74 s | 0.042 |
|
||
| per_decode_load | D0:575, D1:710, D2:0 | D0:600, D1:685, D2:0 | both 1P2D |
|
||
| direct-to-D % | N/A (no KVC) | 87/231 = 37.7 % | – |
|
||
|
||
---
|
||
|
||
## 5. Interpreting H1 / H2 / H3
|
||
|
||
### H1 (was: KVC layer adds value on top of 1P3D + kv-aware) — *qualified*
|
||
|
||
The H1 hypothesis as stated in `ONBOARDING_NEXT_AGENT_ZH.md` predicted E2 would clearly win on most metrics. The reality is **bimodal**: the small subset of E2 requests that successfully complete are dramatically faster than E1, but a much larger fraction (82 %) of E2 requests time out entirely. Net throughput on this workload is *worse* for E2 than E1.
|
||
|
||
Two issues drove this:
|
||
1. The D2 cold-start pathology already documented in §3, root cause. Both runs are de facto 1P2D, not 1P3D.
|
||
2. KVC v2's admission gate is stricter and surfaces more "no D capacity" / "session-not-resident" failures than vanilla pd-disagg, when the workload (mean input 67 K tokens, mean output 700 tokens) saturates D0/D1's combined ~1.5 M KV pool.
|
||
|
||
For workloads where D0/D1 do not saturate or where the policy *does* spread session ownership across all D workers (the historical SWE-Bench setup), KVC v2 wins. The Inferact `codex_swebenchpro` subset breaks both assumptions.
|
||
|
||
### H2 / H3 (RDMA reduces TTFT p99) — *cannot be evaluated cleanly here*
|
||
|
||
The historical reference point is "KVC v2 + TCP loopback, SWE-Bench 50sess: TTFT p99 = 1.28 s". This run uses Inferact + RDMA, and TTFT p99 of the 231 successful E2 requests is **8.74 s** — much higher than the TCP baseline. But the workloads are not comparable: Inferact mean input is 67 K tokens vs SWE-Bench's much smaller average. Per-request prefill + transfer is roughly 5× longer here. A clean H2 / H3 read needs an Inferact-on-TCP run to compare against, which is out of scope for this subset's GPU budget.
|
||
|
||
What we *can* say: RDMA is correctly engaged (every worker log shows `installTransport, type=rdma`; admission RPC RTTs in `structural/admission-events.jsonl` are ~6 ms — consistent with one-hop RoCE).
|
||
|
||
---
|
||
|
||
## 6. What this experiment actually shows
|
||
|
||
1. **The H200 + driver 570 + cu12.8 toolchain works for production-scale SGLang xPyD workloads.** Both runs completed without CUDA / driver / mooncake errors; failures are policy- and workload-level, not infrastructure.
|
||
2. **The KVC v2 + kv-aware policy combination has a latent pathology on workloads with high cross-session prefix overlap**: the overlap term in the lex score causes permanent load imbalance, and v2's reject-counter migration cannot rescue it because rejects only fire under capacity pressure, by which point timeouts already dominate. This is novel and not surfaced by the SWE-Bench evaluation in the existing project docs.
|
||
3. **For Inferact-like workloads, a cold-D bonus (e.g. require D to host at least one session before its overlap score counts) or an explicit pre-warm step is required** before E1/E2 comparisons can isolate the marginal effect of the KVC layer.
|
||
|
||
---
|
||
|
||
## 7. Reproducibility
|
||
|
||
- Trace: `outputs/inferact_50sess.jsonl`, md5 `7bb263a32600ef5a6ef5099ba340a487`, regenerable via `scripts/sample_trace_subset.py`.
|
||
- E1: `bash scripts/sweep_e1_naive_1p3d.sh` (1h 29 min wall)
|
||
- E2: `bash scripts/sweep_e2_kvc_v2_rdma.sh` (1h 33 min wall)
|
||
- Summary JSON paths:
|
||
- `outputs/e1_naive_1p3d_kvaware_rdma_50sess/e1_naive_1p3d_kvaware_run1_summary.json`
|
||
- `outputs/e2_kvc_v2_rdma_50sess/e2_kvc_v2_rdma_run1_summary.json`
|
||
- Per-request metrics JSONL alongside each summary, plus structural events under `*/structural/`.
|
||
|
||
---
|
||
|
||
## 8. Open follow-ups for the next agent
|
||
|
||
1. **Add a cold-D bonus** to `KvAwarePolicy.select` (e.g. positive constant for D with `state.resident[D] == ∅`) and re-run E2 on the same subset. Predict: D2 receives bindings, failure rate drops, head-to-head with E1 becomes meaningful.
|
||
2. **Rerun E2 with `--kvcache-admission-mode router`** (router-side optimistic admission instead of worker RPC) to isolate whether the strict worker admission is the contributor to the 1054 failures, or whether it's purely the imbalance.
|
||
3. **Run a third arm E0 with `policy=default` + `mechanism=pd-disaggregation`** as a true control — kv-aware policy is itself part of what we are evaluating; default round-robin would have spread sessions across all 3 D.
|
||
4. **Compare TTFT p99 against an Inferact-on-TCP-loopback run** to evaluate H2/H3 cleanly. Cost: 1 more E2-shaped sweep (~1.5 h).
|
||
5. **Investigate the 1054 E2 failures** in `request-metrics.jsonl` — sample some to verify they are timeout-related vs admission-rejected vs upstream-500.
|
||
|
||
---
|
||
|
||
## 4. Comparison table — pending
|
||
|
||
To be appended.
|
||
|
||
---
|
||
|
||
## 5. Open questions for the next iteration
|
||
|
||
- Are the 85 E1 errors all timeouts? `request-metrics.jsonl` rows with `error` execution_mode should be sampled to confirm. (Quick check: grep the metrics jsonl for `"execution_mode": "pd-disaggregation"` and inspect `latency_s` / `error` fields.)
|
||
- Does E2 produce the predicted ~91% direct-to-D rate seen in the historical SWE-Bench v2 run, or does the Inferact workload's larger session count (50 vs 52 there) but very different per-session size distribution (mean 33 turns × ~2KB context growth per turn) push it lower?
|
||
- Is `D2 = 0%` an E1-specific artifact (kv-aware sticky in pd-disagg mode), or does the same happen in E2 before migration kicks in for the first time?
|