feat(glm52): pegaflow host-tier KV offload — shared DP8 pool, warm TTFT ~34x#600
Conversation
One PegaEngine host pool can now back N rank-level engines: OffloadHost owns the pinned pool, the driving runtime, and the P2P lifecycle; OffloadEngine keeps only per-rank registration state. with_arenas_on() registers an extra rank instance onto an existing host — the DP8 shared-namespace path (MLA KV is byte-identical across DP ranks). use_hugepages is now a config knob instead of a hardcoded false. Also repair tests/cpu_roundtrip.rs, broken since #522 changed query() to return QueryOutcome (GPU-gated test, never compiled in CI). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wire the in-process pegaflow bridge into the DP8 engine, M1 of the P/D-disaggregation plan (docs/models/glm52/pegaflow-offload-pd.md): - One shared OffloadHost (one pinned pool, optionally hugepage-backed) with each rank's arenas registered as its own instance under a single namespace — MLA KV is byte-identical across DP ranks, so any rank restores what any rank saved. - Per rank, 99 arenas register in one instance: 78 MLA fp8_ds_mla arenas (64-token pages x 656 B) plus the 21 full-indexer layers' index-K sidecars (64 x 132 B), all indexed by the same pool block ids, so a block's save/load moves both caches atomically. - Restore leg at admission (a step boundary): probe -> query -> load into reserved pool pages -> commit, then the existing prefix match reports the union as cached_tokens. Save leg on request release, fire-and-forget with block guards pinning pages through the D2H copy. Both legs degrade to a full prefill on failure — the host tier is a cache, never a correctness dependency. - Launch rejects --kv-offload with --no-prefix-cache or the DSpark drafter (offload extends the prefix cache; a config that disables matching while allocating a multi-GiB pool is contradictory). - New --kv-offload-hugepages flag, plumbed to qwen3 as well. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 59b5fec415
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| Err(err) => { | ||
| log::warn!("GLM5.2 host-tier load submit failed (prefill from scratch): {err}"); |
There was a problem hiding this comment.
Release leases when GLM host loads fail to submit
When engine.load returns Err, the query lease created above may still be pinning the host-tier blocks because the load did not get far enough to consume it; the Qwen prefetch path explicitly releases the lease on this same submit-failure path. Under transient CUDA/pegaflow validation or submission errors, repeated GLM restores will leave blocks unevictable until the lease TTL, shrinking the effective host pool and causing later restores to miss even though the request correctly falls back to prefill.
Useful? React with 👍 / 👎.
| .then(|| openinfer_glm52::Glm52KvOffloadOptions { | ||
| pinned_pool_bytes: (args.kv_offload_host_gib * f64::from(1u32 << 30)) | ||
| as usize, | ||
| use_hugepages: args.kv_offload_hugepages, | ||
| }), |
There was a problem hiding this comment.
Reject GLM P2P flags instead of ignoring them
For GLM5.2, --kv-offload --kv-p2p-metaserver-addr ... is accepted by the shared CLI, but this branch constructs Glm52KvOffloadOptions with only the host pool settings and silently drops all kv_p2p_* values. In a P/D or cross-instance experiment the server will start as host-only offload while appearing to have P2P configured, so either reject those flags for GLM until M2 is wired or plumb them through explicitly.
Useful? React with 👍 / 👎.
…nting + teardown order Toxic-review findings, all three hand-verified: - Launch-ahead leases are off while offload is on: a leased replay keeps writing KV on the rank stream after the coordinator joined its argmax D2H, unordered against the restore leg's H2D on pegaflow's stream — a replay row landing after the restore would silently poison a content-addressed block for every later match. Without leases the joined D2H is the last thing on the rank stream, so admission truly is a quiet boundary. Costs ~0.7 ms/step, offload deployments only. - Release-save guards pin freed pages in the active pool until the D2H lands; admission's full-lifetime math now subtracts the pinned count (RankOffload) instead of promising pages schedule_prefill cannot get (which would fail_step the engine under a tight pool). - Coordinator teardown flushes and drops the offload engines BEFORE the workers drop the models — the registered arenas must outlive every in-flight D2H copy (the with_arenas contract). Also: restore is gated on prefix_cache_enabled at the use point, and the cross-rank sharing comments state the actual tolerance (FP reduction order may differ by batch shape; same as rank-local prefix reuse), not byte identity. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…kv-p2p-* flags Codex review P2s: a submit error can leave the lease pinning host blocks until the TTL (same fix as the qwen3 path), and the shared --kv-p2p-* flags were silently dropped by the GLM5.2 arm — fail loud until M2 wires P2P. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Review findings addressed in 0858c8e + f1297c5: Internal adversarial review (3 findings, all reproduced by hand before fixing):
Codex P2s: lease released on load-submit failure (mirrors the qwen3 path); Re-running the jz-38 gate suite on the fixed branch; will post updated numbers. |
|
Gate suite re-run on the fixed branch (jz-38, run 3): ALL PASS — byte parity holds cold → warm-restored → no-offload, warm TTFT 140.5 ms (cold 5239/5064 ms), 15 full-prefix restores under 16-way mixed load, zero errors, hugepage pool verified again. Numbers in the PR body updated. |
GLM5.2 gains the pegaflow host tier behind
--kv-offload— M1 of the P/D-disaggregation plan (docs/models/glm52/pegaflow-offload-pd.md). Sealed KV blocks flow to one shared pinned pool on request release; a prompt whose prefix fell out of HBM restores from it at admission and reports ascached_tokens.Design
openinfer-kv-offloadsplitsOffloadHost(onePegaEnginepool + runtime + P2P lifecycle) from the per-rankOffloadEngine;with_arenas_on()registers each rank as one more pegaflow instance over the same pool. MLA KV is byte-identical across DP ranks (no TP sharding in the latent, replicated non-expert weights), so any rank restores what any rank saved — the host tier has no per-rank placement problem.--kv-offload+--no-prefix-cache/DSpark rejected at launch (offload extends the prefix cache). New--kv-offload-hugepagesbacks the pool with 2 MiB hugepages (plumbed to qwen3 too, previously hardcoded off).tests/cpu_roundtrip.rs, broken since feat(qwen3): P/D disaggregation with cross-instance KV via pegaflow metaserver P2P #522 (GPU-gated, never compiled in CI).vLLM layout alignment
Verified at source level against vLLM
cdab28319: the device-side layouts are already byte-identical (our kernels are ports of vLLM's) — 656 B/token field order, ÷448 scales, index-K block-split packing, page 64, layer-outermost arenas. The only cross-engine gap for M2 is block hashing (SHA-256-cbor vs xxh3 lineage), which is the #540 pattern's job. Evidence table in the design doc.Measured (jz-38, 8×H200,
--max-model-len 4096, host pool 32 GiB hugepages)Second column re-measured after the review fixes (leases disabled under offload) — every gate re-passed on the fixed branch. The warm run restored all 22 cacheable prefix blocks from the host tier after 160 diverse ~2700-token prompts (c8) had evicted the GPU prefix (per-rank pool 521 pages, churn ≈ 840 pages/rank).
HugePages_Freedropped 17408 → 1024 at launch: the pool really is hugepage-backed.Gates (all pass,
ALL-GATES-PASS)cargo test -p openinfer-glm52 -p openinfer-kv-offload --libgreen; clippy clean on touched crates.🤖 Generated with Claude Code