Repository navigation
perf(router): probe worker availability with an Fx set - #18008
Conversation
|
No actionable comments were generated in the recent review. WalkthroughThe scheduler now represents available workers with ChangesWorker availability scheduling
Estimated code review effort: 3 (Moderate) | ~20 minutes Merge Risk:
|
❌ Dynamo PR CI failed — run 41775881272 (attempt 1) on
|
| Other | Jobs |
|---|---|
| dynamo-runtime | ❌ 2 ✅ 5 |
| planner | ❌ 2 ✅ 3 |
Failure details
4 jobs failed, all with the same 2 planner unit tests in test_live_retune_frontend_config.py: the frontend/worker argparser rejects --router-mode power-of-two (valid choices: round-robin, random, kv, direct, least-loaded, device-aware-weighted). Both architectures fail identically, so this is not an infrastructure problem.
❌ planner / CPU Test cpu, amd64: invalid choice 'power-of-two' for --router-mode
Job: planner / CPU Test cpu, amd64 · Failed step: Run CPU-only tests (parallelized) · Logs: gh run view --job 126400381798 -R ai-dynamo/dynamo --log-failed
_______________ test_effective_argv[command7-args7-power_of_two] _______________
E AssertionError: P4: cannot parse the frontend args: argument --router-mode: invalid choice: 'power-of-two' (choose from 'round-robin', 'random', 'kv', 'direct', 'least-loaded', 'device-aware-weighted')
E assert False
______ test_worker_router_mode_matches_the_real_worker_parser[args3-env3] ______
E argparse.ArgumentError: argument --router-mode: invalid choice: 'power-of-two' (choose from 'round-robin', 'random', 'kv', 'direct', 'least-loaded', 'device-aware-weighted')
E SystemExit: 2
FAILED components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_effective_argv[command7-args7-power_of_two]
FAILED components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_worker_router_mode_matches_the_real_worker_parser[args3-env3]
============ 2 failed, 4170 passed, 30 skipped in 435.37s (0:07:15) ============
Two tests parametrized with router mode power_of_two fail because the real frontend and worker parsers no longer accept power-of-two as a --router-mode choice (failed on 3 auto-retries each). The test cases and the parser's allowed router modes disagree.
❌ planner / CPU Test cpu, arm64: same 2 tests, invalid choice 'power-of-two'
Job: planner / CPU Test cpu, arm64 · Failed step: Run CPU-only tests (parallelized) · Logs: gh run view --job 126400381759 -R ai-dynamo/dynamo --log-failed
FAILED components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_effective_argv[command7-args7-power_of_two] - AssertionError: P4: cannot parse the frontend args: argument --router-mode: invalid choice: 'power-of-two' (...)
FAILED components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_worker_router_mode_matches_the_real_worker_parser[args3-env3] - SystemExit: 2
============ 2 failed, 4170 passed, 30 skipped in 546.18s (0:09:06) ============
Identical to the amd64 job: same 2 tests, same --router-mode parse error.
❌ dynamo-runtime / test / sequential cuda13.0, amd64: same 2 planner tests
Job: dynamo-runtime / test / sequential cuda13.0, amd64 · Failed step: Run CPU-only tests (parallelized) · Logs: gh run view --job 126401606778 -R ai-dynamo/dynamo --log-failed
FAILED components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_effective_argv[command7-args7-power_of_two] - AssertionError: P4: cannot parse the frontend args: argument --router-mode: invalid choice: 'power-of-two' (...)
FAILED components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_worker_router_mode_matches_the_real_worker_parser[args3-env3] - SystemExit: 2
== 2 failed, 7778 passed, 170 skipped, 2854 deselected in 1588.81s (0:26:28) ===
##[error]A pytest stage did not record a passing result. See this step's log for the stage.
The runtime suite picks up the same 2 planner tests and fails on the same --router-mode power-of-two parse error; nothing else failed. The "custom container implementation failed" lines after it just report the non-zero pytest exit.
❌ dynamo-runtime / test / sequential cuda13.0, arm64: same 2 planner tests
Job: dynamo-runtime / test / sequential cuda13.0, arm64 · Failed step: Run CPU-only tests (parallelized) · Logs: gh run view --job 126401606663 -R ai-dynamo/dynamo --log-failed
FAILED components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_effective_argv[command7-args7-power_of_two] - AssertionError: P4: cannot parse the frontend args: argument --router-mode: invalid choice: 'power-of-two' (...)
FAILED components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_worker_router_mode_matches_the_real_worker_parser[args3-env3] - SystemExit: 2
== 2 failed, 7778 passed, 170 skipped, 2854 deselected in 1954.89s (0:32:34) ===
Same 2 tests and error as the amd64 runtime job.
For agents
{"pr": 18008, "run_id": 41775881272, "run_attempt": 1, "head_sha": "147fddc30e1e91c2866a69d9f6f57281691f1330",
"failures": [
{"job": "planner / CPU Test cpu, amd64", "job_id": 126400381798, "failed_step": "Run CPU-only tests (parallelized)", "signature": "argument --router-mode: invalid choice: 'power-of-two'", "tests": ["components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_effective_argv[command7-args7-power_of_two]", "components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_worker_router_mode_matches_the_real_worker_parser[args3-env3]"], "log_cmd": "gh run view --job 126400381798 -R ai-dynamo/dynamo --log-failed"},
{"job": "planner / CPU Test cpu, arm64", "job_id": 126400381759, "failed_step": "Run CPU-only tests (parallelized)", "signature": "argument --router-mode: invalid choice: 'power-of-two'", "tests": ["components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_effective_argv[command7-args7-power_of_two]", "components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_worker_router_mode_matches_the_real_worker_parser[args3-env3]"], "log_cmd": "gh run view --job 126400381759 -R ai-dynamo/dynamo --log-failed"},
{"job": "dynamo-runtime / test / sequential cuda13.0, amd64", "job_id": 126401606778, "failed_step": "Run CPU-only tests (parallelized)", "signature": "argument --router-mode: invalid choice: 'power-of-two'", "tests": ["components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_effective_argv[command7-args7-power_of_two]", "components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_worker_router_mode_matches_the_real_worker_parser[args3-env3]"], "log_cmd": "gh run view --job 126401606778 -R ai-dynamo/dynamo --log-failed"},
{"job": "dynamo-runtime / test / sequential cuda13.0, arm64", "job_id": 126401606663, "failed_step": "Run CPU-only tests (parallelized)", "signature": "argument --router-mode: invalid choice: 'power-of-two'", "tests": ["components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_effective_argv[command7-args7-power_of_two]", "components/src/dynamo/planner/tests/unit/test_live_retune_frontend_config.py::test_worker_router_mode_matches_the_real_worker_parser[args3-env3]"], "log_cmd": "gh run view --job 126401606663 -R ai-dynamo/dynamo --log-failed"}
]}Posted automatically by Devin for run 41775881272. Updated on every full-CI run of this PR.
147fddc to
10bfe10
Compare
|
/ok to test 10bfe10 |
Selection checks the provider's available-worker set once per worker on every admission: candidate preparation, best cached tokens, the queue gate, and the actor's candidate collection. The set is a std HashSet, so each check paid for SipHash. Convert the provider's set to an FxHashSet once per distinct set (the frontend's provider returns the same Arc until membership changes) and probe that instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
…ate policy tests RoutingInstances rebuilt the routable-ID set on every overload update, expiry and reconciliation, even with membership unchanged, so each one made the scheduler convert the available set again and fall back from a pointer compare to a full compare of prepared rows. Share the set across rebuilds that leave the routable IDs unchanged, as the overloaded set already is. Build the builtin policy tests' availability sets as WorkerIdSet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
10bfe10 to
eee5e68
Compare
Signed-off-by: jthomson04 <jwillthomson19@gmail.com>
Third upstream merge for the split v2 PR: the five commits past 53015f9 that landed while the second merge was validated. Four conflicts, each placed in the owner crate, upstream behavior whole, the stack's moves intact, no shims. - ai-dynamo#18008 probe worker availability with an Fx set: WorkerIdSet and the per-set AvailableWorkerIds cache in the kernel's types.rs, the listed- worker walk in the kernel's filter.rs, the actor's cached availability in queue.rs (auto-merged); WorkerIdSet exported to hosts through dynamo_scheduler::host (lib/llm's LoRA availability filter) and to plugins through dynamo_kv_router::plugins::prelude (the builtin default_policy test stays prelude-only). - ai-dynamo#18084 CRTC stale-leaf sweep trigger scaled with tree size: lib/router/kv-indexer concurrent_radix_tree_compressed (auto-merged). - ai-dynamo#17900 shared fixed-lane bench primitive: lib/bench (auto-merged). - ai-dynamo#17947 planner priority pools, ai-dynamo#17625 beam tool-call finalization: outside the router, auto-merged. Signed-off-by: Ishan Dhanani <ishandhanani@gmail.com>
Overview
Selection checks the frontend's available-worker set once per worker on every admission. That happens in candidate preparation,
best_cached_tokens, the queue gate, and the scheduler actor's candidate collection when ranks are full. The set comes fromClient::available_instance_ids()as a stdHashSet, so with 2,048 workers each admission pays for thousands of SipHash probes. This PR converts the provider's set to anFxHashSetonce per distinct set and probes that instead. The runtime hands out the sameArcuntil membership changes, so the conversion runs only when membership changes.selection_replay_bench(AgentX workload, 2,048 workers)run_selectioncallers (kcycles per admission)Setup: Tyche Grace node. Both arms ran at once, one per socket, swapping sockets between the two rounds, replaying the same corpus (equal
corpus_digest). The cycle counts come from window-bracketedperfprofiles. Busy thresholds:--active-decode-blocks-threshold 0.25 --active-prefill-tokens-threshold-frac 1.0. Bench: #17959.Key Changes
AvailableWorkerIds(scheduling/types.rs) wraps theWorkerAvailabilityProviderand caches the last converted set against its sourceArc. Holding the source keeps its address from being reused, so a pointer match means the same set. A per-request set, such as a LoRA filter's, is converted per request, at about the cost of building it.SchedulerQueuewraps the provider once and shares it between the handle and the actor.RoutingEligibilityandPreparedAdmissiontake the Fx set (WorkerIdSet).any_eligible_worker_rankstill walks the smaller of the allowed and available sets when one is sparse. Each set type now has its own branch.RoutingInstances) now keeps its routable-ID set'sArcacross rebuilds that leave membership unchanged (overload updates, expiry, reconciliation), as it already did for the overloaded set. Without this, each overload update forced a new conversion and a full compare in place of a pointer compare.Validation
cargo test -p dynamo-kv-router --lib(1,164 passed, including a new test for the conversion cache).cargo test -p dynamo-router-policies --test default_policy,cargo test -p dynamo-runtime --lib component::client(including a new test that overload updates keep the availability snapshot), and the lib/llm availability test.cargo clippy --all-targets -p dynamo-kv-router -p dynamo-router-policies -p dynamo-worker-selection-policy-catalog -p dynamo-llm -p dynamo-runtime -- -D warnings.Issues and Ongoing Work
selection_replay_bench).🤖 Generated with Claude Code