Repository navigation
feat(agentx): allow multi-replica and shared G2 for AgentX replay [AISIM-1893, AISIM-1894] #688
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,7 +22,7 @@ is a separate [performance-model question](../perf-model/support-matrix.md). | |
| | Prefix reuse | Native backend cache | G1 with prefix caching enabled | Actual reuse differs from Router overlap; complete block and backend admission rules apply | | ||
| | Grouped FPM cache | vLLM | Cold aggregated, PP1/CP1 | HBM only, no speculation, prefix caching off, no scalar block capacity, no P/D | | ||
| | G2 host offload | vLLM | Aggregated and token-only P/D, any attention-DP size | Prefix caching, no native MTP/Belady/state-cache offload; local or layout-compatible shared pool | | ||
| | Agentic G2 | vLLM | One aggregated worker or 1P1D, attention DP1 on every role | Static pools, no speculation/G3; each role may omit G2 or use local/shared scope | | ||
| | Agentic G2 | vLLM | Aggregated or P/D with any worker count, attention DP1 on every role | Static pools, no speculation/G3; each role may omit G2 or use local/shared scope | | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. State the valid worker-count boundary.
Replace it with “any positive integer worker count” in all copies. As per path instructions, public claims must match executable behavior.
|
||
| | G3 offload | vLLM | Aggregated, attention DP1; fixed or scaled pools | Requires G2; no speculation, AgentX, P/D, recommendation or hardware integration | | ||
| | KVCR peer fetch | vLLM | Aggregated with any attention-DP size, or P/D prefill ranks; fixed or scaled pools | Requires private G2 and hints from a placement policy or ReplaySpec requests (CLI traffic has none); no G3, decode-role KVCR or recommendation; idle under AgentX | | ||
| | Best-effort Belady | All three native backends | Fixed aggregated, DP1, complete open-loop input trace | Native descriptor; prefix caching required; rejects closed-loop/generated/agentic/delta inputs, scaling and offload | | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -135,6 +135,43 @@ def test_weka_g2_restore_has_causal_bandwidth_and_capacity_controls(name) -> Non | |
| assert fast["committed_prefill_tokens"] < hbm["committed_prefill_tokens"] | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("name", ["agentx-g2-local.yaml", "agentx-g2-shared-pd.yaml"]) | ||
| def test_weka_g2_runs_on_multiple_replicas(name) -> None: | ||
| config = _config(name) | ||
| single = _run(config) | ||
| for worker in config["engine"]["workers"].values(): | ||
| worker["parallelism"] = {**worker["parallelism"], "replicas": 2} | ||
| report = _run(config) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| assert report["completed_requests"] == single["completed_requests"] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Assert G2 reuse in the multi-replica runs. Completion and domain equality can pass even if no request restores a host block. Add a case that forces eviction and asserts As per path instructions: “Require coverage of the changed behavior and its negative or boundary cases.”
|
||
| assert len({route["logical_worker_id"] for row in report["per_request"] for route in row["routing_history"]}) == 2 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check routing separately for each P/D pool. Prefill and decode assign worker IDs independently. This union can contain two IDs even if only one pool uses its second worker. Assert two distinct IDs per pool. (raw.githubusercontent.com) As per path instructions: “Require coverage of the changed behavior and its negative or boundary cases.”
|
||
| # One cluster-shared pool, counted once whatever the replica count. | ||
| assert report.get("g2_domains", []) == single.get("g2_domains", []) | ||
|
|
||
|
|
||
| def test_weka_shared_g2_contract_across_replicas() -> None: | ||
| config = _config("agentx-g2-shared-pd.yaml") | ||
| for worker in config["engine"]["workers"].values(): | ||
| worker["parallelism"] = {**worker["parallelism"], "replicas": 2} | ||
| shared = _run(config) | ||
| # Four participants join one deployment-owned pool, counted once. | ||
| assert [domain["capacity_blocks"] for domain in shared["g2_domains"]] == [8] | ||
| assert shared["completed_requests"] == _run(_config("agentx-g2-shared-pd.yaml"))["completed_requests"] | ||
|
|
||
| disabled, private = copy.deepcopy(config), copy.deepcopy(config) | ||
| for worker in disabled["engine"]["workers"].values(): | ||
| worker["kv_cache"]["host_offload"] = {**worker["kv_cache"]["host_offload"], "scope": "dp_rank_local"} | ||
| for worker in private["engine"]["workers"].values(): | ||
| offload = dict(worker["kv_cache"]["host_offload"], scope="dp_rank_local") | ||
| for field in ("shared_d2h_bandwidth_gbps", "shared_h2d_bandwidth_gbps"): | ||
| offload.pop(field, None) | ||
| worker["kv_cache"]["host_offload"] = offload | ||
| disabled_report, private_report = _run(disabled), _run(private) | ||
| # Disabling sharing reproduces private G2 even with shared-only fields left set. | ||
| assert "g2_domains" not in disabled_report or not disabled_report["g2_domains"] | ||
| assert disabled_report["per_request"] == private_report["per_request"] | ||
| assert disabled_report["committed_prefill_tokens"] == private_report["committed_prefill_tokens"] | ||
|
|
||
|
|
||
| @pytest.mark.parametrize("field,value", [("num_host_blocks", 16), ("shared_h2d_bandwidth_gbps", 2)]) | ||
| def test_weka_g2_rejects_inconsistent_shared_pool(field, value) -> None: | ||
| config = _config("agentx-g2-shared-pd.yaml") | ||
|
|
@@ -156,7 +193,6 @@ def test_weka_g2_rejects_incompatible_shared_layout() -> None: | |
| @pytest.mark.parametrize( | ||
| "fault,message", | ||
| [ | ||
| ("workers", "agentic host offload requires one aggregated worker or one prefill and one decode worker"), | ||
| ("dp", "agentic host offload requires attention DP=1 on every role"), | ||
| ("backend", "agentic host offload requires backend=vllm on every role"), | ||
| ("aic_nextn", "agentic replay requires speculative decoding disabled"), | ||
|
|
@@ -183,11 +219,7 @@ def test_agentic_invalid_configuration_matrix_rejects_python_and_native(role, fa | |
| args = getattr(spec.backend_deployment, args_field) | ||
| engine = payload["spec"]["engine"] if aggregated else payload["spec"]["engine"][role] | ||
| rank = engine["rank"] | ||
| if fault == "workers": | ||
| workers_field = "num_workers" if aggregated else f"num_{role}_workers" | ||
| spec = replace(spec, backend_deployment=replace(spec.backend_deployment, **{workers_field: 2})) | ||
| payload["spec"]["topology"]["workers" if aggregated else role]["initial_workers"] = 2 | ||
| elif fault == "dp": | ||
| if fault == "dp": | ||
| args["aic_attention_dp_size"] = 2 | ||
| engine["dp_size"] = 2 | ||
| if not aggregated: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
State the positive worker-count boundary.
“Pools of any size” also suggests zero or non-integer worker counts. The AgentX G2 contract rejects both. Document that each pool supports any positive integer number of workers.
Source: Path instructions