Skip to content

fix: synchronize self-benchmark capacity across DP ranks - #12021

Merged
liyuanzhe1991 merged 5 commits into
ai-dynamo:mainfrom
liyuanzhe1991:fpm-dp-capacity-sync
Aug 6, 2026
Merged

fix: synchronize self-benchmark capacity across DP ranks#12021
liyuanzhe1991 merged 5 commits into
ai-dynamo:mainfrom
liyuanzhe1991:fpm-dp-capacity-sync

Conversation

@liyuanzhe1991

@liyuanzhe1991 liyuanzhe1991 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Overview:

Self-benchmarking with attention-DP > 1 intermittently deadlocks at startup: each DP rank probes its local KV-cache capacity independently, and any run-to-run variation (block-pool rounding, allocator state) makes ranks generate different benchmark grids. The lockstep synchronization protocol then waits forever on points that only a subset of ranks generated. In our GLM-5.2-NVFP4 / 4×B200 campaigns, decode benchmarks with dp=4 failed 3 out of 4 attempts before this fix.

Details:

  • Each rank builds a local capacity envelope (_bench_make_local_capacity: max_model_len, max_num_running_reqs, max_num_scheduled_tokens, usable KV blocks) and exchanges it through the existing benchmark synchronizer before grid generation.
  • Grid construction reads capacity exclusively through _bench_capacity_limit() / _bench_grid_usable_blocks(), which return the minimum across ranks — every rank derives byte-identical grids by construction.
  • _bench_decode_feasible_max_batch_size() now computes from the synchronized envelope, so both call sites (the native decode grid and explicit benchmark points) agree across ranks.
  • Single-rank (dp=1) behavior is unchanged: the synchronized envelope degenerates to the local one.

Validated on 4-rank and 8-rank attention-DP topologies (GLM-5.2-NVFP4, B200, vLLM 0.25.1): previously flaky decode cells pass deterministically; full prefill+decode campaigns (5 466 and 6 508 grid points) completed with zero lockstep timeouts.

Where should the reviewer start?

  • components/src/dynamo/vllm/instrumented_scheduler.py:
    • _BenchmarkCapacityEnvelope, _bench_make_local_capacity, _bench_capacity_limit, _bench_grid_usable_blocks
    • the capacity exchange in the _BenchmarkSynchronizer handshake
    • _bench_decode_feasible_max_batch_size (now envelope-based)
  • components/src/dynamo/vllm/tests/test_vllm_instrumented_scheduler.py — capacity-divergence regression tests

Related Issues

🚫 This PR is NOT linked to an issue:

  • Confirmed — no related issue

Summary by CodeRabbit

  • New Features

    • Improved distributed benchmark setup by negotiating shared capacity across ranks.
    • Benchmark grids now adapt to the common capacity available across participating ranks.
    • Benchmark results include the negotiated common capacity when available.
  • Bug Fixes

    • Added validation to detect capacity and benchmark-grid mismatches before warmup.
    • Improved KV-cache capacity accounting for prefill and decode benchmark scenarios.
  • Tests

    • Added regression coverage for capacity negotiation, grid synchronization, and mismatch handling.

@liyuanzhe1991
liyuanzhe1991 requested review from a team as code owners July 22, 2026 17:07
@copy-pr-bot

copy-pr-bot Bot commented Jul 22, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@liyuanzhe1991
liyuanzhe1991 temporarily deployed to external_collaborator July 22, 2026 17:07 — with GitHub Actions Inactive
@liyuanzhe1991
liyuanzhe1991 temporarily deployed to external_collaborator July 22, 2026 17:07 — with GitHub Actions Inactive
@github-actions

Copy link
Copy Markdown
Contributor

👋 Hi liyuanzhe1991! Thank you for contributing to ai-dynamo/dynamo.

Just a reminder: The NVIDIA Test Github Validation CI runs an essential subset of the testing framework to quickly catch errors.Your PR reviewers may elect to test the changes comprehensively before approving your changes.

🚀

@github-actions github-actions Bot added external-contribution Pull request is from an external contributor fix backend::vllm Relates to the vllm backend labels Jul 22, 2026
@datadog-official

This comment has been minimized.

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

Benchmark capacity coordination

Layer / File(s) Summary
Capacity envelope and rank synchronization
components/src/dynamo/vllm/instrumented_scheduler.py, components/src/dynamo/vllm/tests/test_vllm_instrumented_scheduler.py
Capacity reports are validated and reduced to common minimum limits across attention-DP ranks. Grid digests, expected point counts, and missing phases are synchronized, with regression tests for mismatch errors.
Benchmark grid construction and lifecycle state
components/src/dynamo/vllm/instrumented_scheduler.py, components/src/dynamo/vllm/tests/test_vllm_instrumented_scheduler.py
Benchmark state tracks local and negotiated capacity, grid construction performs synchronization, results include common capacity, and existing grid tests install capacity preflight stubs.
Capacity-aware prefill and decode feasibility
components/src/dynamo/vllm/instrumented_scheduler.py, components/src/dynamo/vllm/tests/test_vllm_instrumented_scheduler.py
Prefill and decode generation use negotiated limits and grid-aware usable-block accounting, with regression tests verifying identical grids across differing rank capacities.

Estimated code review effort: 4 (Complex) | ~60 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: synchronizing self-benchmark capacity across DP ranks.
Description check ✅ Passed The description follows the template with Overview, Details, reviewer guidance, and a completed Related Issues section.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
components/src/dynamo/vllm/tests/test_vllm_instrumented_scheduler.py (1)

552-699: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a @pytest.mark.timeout(...) to the threaded synchronizer tests.

These three tests spawn a follower thread and rely on ZMQ socket polling/waits between ranks. If coordination ever wedges, follower.join(timeout=2) returns while the socket-blocked thread lingers; a bounded per-test timeout keeps CI from hanging on regressions. As per path instructions: "Add @pytest.mark.timeout(...) for tests that may exceed 30s or contain polling/sleeps/waits."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@components/src/dynamo/vllm/tests/test_vllm_instrumented_scheduler.py` around
lines 552 - 699, Add an appropriate `@pytest.mark.timeout`(...) decorator to each
threaded synchronizer test:
test_benchmark_synchronizer_negotiates_minimum_capacity_and_grid,
test_benchmark_synchronizer_rejects_capacity_invariant_mismatch, and
test_benchmark_synchronizer_rejects_grid_mismatch_before_warmup. Keep the
existing thread joins and test behavior unchanged.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@components/src/dynamo/vllm/tests/test_vllm_instrumented_scheduler.py`:
- Around line 552-699: Add an appropriate `@pytest.mark.timeout`(...) decorator to
each threaded synchronizer test:
test_benchmark_synchronizer_negotiates_minimum_capacity_and_grid,
test_benchmark_synchronizer_rejects_capacity_invariant_mismatch, and
test_benchmark_synchronizer_rejects_grid_mismatch_before_warmup. Keep the
existing thread joins and test behavior unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 75d54ebb-7b81-43c1-b341-42f7548b71af

📥 Commits

Reviewing files that changed from the base of the PR and between 116a1cb and 06ab021.

📒 Files selected for processing (2)
  • components/src/dynamo/vllm/instrumented_scheduler.py
  • components/src/dynamo/vllm/tests/test_vllm_instrumented_scheduler.py

@tedzhouhk tedzhouhk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Three blocking findings from the agentic review are noted inline.

Comment thread components/src/dynamo/vllm/instrumented_scheduler.py Outdated
Comment thread components/src/dynamo/vllm/instrumented_scheduler.py
Comment thread components/src/dynamo/vllm/instrumented_scheduler.py Outdated
@liyuanzhe1991
liyuanzhe1991 temporarily deployed to external_collaborator July 23, 2026 06:53 — with GitHub Actions Inactive
@liyuanzhe1991
liyuanzhe1991 temporarily deployed to external_collaborator July 23, 2026 10:07 — with GitHub Actions Inactive
@liyuanzhe1991
liyuanzhe1991 force-pushed the fpm-dp-capacity-sync branch from e7d5768 to 79717ca Compare July 23, 2026 12:51
@liyuanzhe1991
liyuanzhe1991 temporarily deployed to external_collaborator July 23, 2026 12:51 — with GitHub Actions Inactive
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test 79717ca

@liyuanzhe1991
liyuanzhe1991 temporarily deployed to external_collaborator July 23, 2026 13:14 — with GitHub Actions Inactive
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test 077a2c5

@liyuanzhe1991
liyuanzhe1991 temporarily deployed to external_collaborator August 2, 2026 03:38 — with GitHub Actions Inactive
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test 1f16d7e

liyuanzhe1991 and others added 5 commits August 4, 2026 08:45
Signed-off-by: YZLi <yuanli@nvidia.com>
- Hash the unfiltered cudagraph capture configuration in the grid
  invariants digest and re-filter decode capture sizes with the
  negotiated max_num_running_reqs, so ranks that differ only in
  request limits negotiate the minimum instead of failing the
  invariant check before negotiation starts.
- Use the negotiated max_num_scheduled_tokens when materializing
  explicit prefill points so cudagraph sample_reasons (engine_limit
  vs geometric_tail) and per-point digests match across ranks.
- Drop the unused capacity locals in _bench_generate_decode_grid
  (ruff F841).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: YZLi <yuanli@nvidia.com>
_bench_build_grid now negotiates capacity and re-filters the decode capture
list on entry, so every stub that reaches it needs the preflight installed
and a _bench_decode_capture_sizes attribute. The scheduled-token-limit test
moves its constraint into the negotiated envelope, which is where
_bench_capacity_limit reads it from now.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: YZLi <yuanli@nvidia.com>
mypy: asdict() rejects _BenchmarkCapacityEnvelope | None; bind the
attribute to a local via walrus so the None-check narrows it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: YZLi <yuanli@nvidia.com>
…ization

Steady-coordinate normalization (ai-dynamo#12358) merges each batch's sub-2B
decode presets into a single point, shrinking the synthetic negotiation
grid from 1368 to 1266 points and moving batch=1's feasibility boundary
from index 19 to 18.

Signed-off-by: YZLi <yuanli@nvidia.com>
@liyuanzhe1991
liyuanzhe1991 temporarily deployed to external_collaborator August 4, 2026 00:52 — with GitHub Actions Inactive
@dynamo-ops

Copy link
Copy Markdown
Contributor

/ok to test bc00233

@tedzhouhk tedzhouhk left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified the three previously raised P1 concerns against the current head: decode capture invariants are negotiated correctly, explicit prefill metadata uses the common limit, and the unused locals are removed. The added regression coverage matches the fixes.

@liyuanzhe1991
liyuanzhe1991 merged commit e07fa63 into ai-dynamo:main Aug 6, 2026
98 checks passed
hhzhang16 added a commit that referenced this pull request Aug 6, 2026
dyn-3691-extract-shared-target-pid-cuda-customstorage-operation-layer

* 'main' of https://github.com/ai-dynamo/dynamo: (65 commits)
  fix(frontend): emit SGLang stream role once (#12741)
  docs(fern): promote v1.3.1 to current release (#12752)
  fix(docs): remove duplicate unscoped community-rail CSS rules (#12615)
  feat(operator): migrate CRD storage to v1beta1 (#11904)
  fix: synchronize self-benchmark capacity across DP ranks (#12021)
  chore(deps): bump dynamo-tokenizers to 1.8.0 (#12707)
  fix(frontend): preserve split UTF-8 characters (#12688)
  docs: align Kubernetes build selector with CLI (#12729)
  fix(frontend): preserve completion backend error status (#12706)
  fix(operator): replace snapshot pods after GMS restart (#11286)
  refactor(media): rename installer module, drop --packages per review
  fix(media): harden installer against three pre-redesign review findings
  fix(media): verify installs in a fresh interpreter; teach --pip-args= form
  test(serve): install test-time decoders at the validated bounds
  feat(media): explicit installer for additional media decoders
  docs(spica): correct kv_load_ratio support guidance (#12714)
  feat(operator): add experimental grove.forceScalingGroup for single-node components (#11772)
  fix(vllm): declare entry-stage engine_input_source in GLM-Image NIXL config (#12709)
  chore: bump trtllm to v1.3.0rc23 (#12532)
  perf: remove trtllm postprocessing workers from the args as post processing workers are not effective in dynamo (#12592)
  ...

Signed-off-by: Hannah Zhang <hannahz@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend::vllm Relates to the vllm backend external-contribution Pull request is from an external contributor fix size/XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants