Skip to content

[https://nvbugs/6438586][fix] Make gen-only benchmark insufficient-KV fail-fast ADP-safe - #16253

Closed
Tabrizian wants to merge 1 commit into
NVIDIA:mainfrom
Tabrizian:fix/nvbugs6438586-benchmark-disagg-stuck-gate
Closed

[https://nvbugs/6438586][fix] Make gen-only benchmark insufficient-KV fail-fast ADP-safe#16253
Tabrizian wants to merge 1 commit into
NVIDIA:mainfrom
Tabrizian:fix/nvbugs6438586-benchmark-disagg-stuck-gate

Conversation

@Tabrizian

@Tabrizian Tabrizian commented Jul 10, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Bug Fixes

    • Improved benchmark fill-phase failure detection to avoid premature failures while transfer activity is still progressing.
    • Synchronized failure handling across distributed attention-processing ranks.
    • Ensured all ranks remain coordinated during fatal error handling, including when no responses are queued.
  • Tests

    • Added coverage for healthy and stuck distributed fill scenarios.
    • Strengthened assertions for cross-rank health checks and synchronized shutdown behavior.

Description

Fixes https://nvbugs/6438586 (and the crash mode of https://nvbugs/6438658).

In gen-only benchmark mode, the "Insufficient KV cache" fail-fast in _prepare_and_schedule_batch fired on rank-local conditions (fitting_disagg_gen_init_requests / stuck INIT requests). Under attention DP, a subset of ranks could enter _handle_errors (which runs a collective response gather) while the remaining ranks sat in the fill gate's tp_allgather. The mismatched collectives desync the TP group: peer ranks crash with TypeError: '<' not supported between instances of 'list' and 'int' in _is_benchmark_disagg_fill_complete (nvbug 6438586), or hang until the HangDetector hard-kills all ranks via MPI_Abort.

The check also mistook requests deferred by the disagg transfer admission controller (#15356) for stuck requests: deferred requests are waiting on in-flight KV transfers, not on KV capacity, so the fail-fast could kill benchmarks whose fill was still making progress (nvbug 6438658).

Changes:

  • Skip the fail-fast when the admission controller is deferring requests behind active transfers (wait_for_disagg_gen_transfer_progress).
  • Reach an ADP consensus (any over a tp_allgather, run on every iteration regardless of local state) before failing, so all ranks enter _handle_errors together and stay collective-aligned.
  • In _handle_errors' fatal path, enter the waiting-queue response gather on every ADP rank (it was rank-0 only — same desync class).

Note: feat/deepseek_v4 fixed the same desync in 95245c9 ("[TRTLLM-12403][fix] Fix deepseekv4 stall") but the fix was never ported to main, which is why 1.3.0rc15.post1 (dsv4) is unaffected while rc21 (main) regressed.

Verified on Lyris (4x GB200, DeepSeek-V4-Flash ctx tp8 / gen dep8 ADP, gen-only benchmark, concurrency 512, TensorRT-LLM 1.3.0rc21 container):

  • Unfixed + per-rank divergence: ranks 1-7 fire the fail-fast alone, rank 0 blocks in the fill-gate collective, HangDetector MPI_Aborts all GEN ranks at benchmark start.
  • Fixed + same divergence: all 8 ranks fail together at the same timestamp with the real error message; no TypeError, no hang.
  • Fixed + healthy KV config: benchmark runs to completion with zero error signatures.

Test Coverage

  • tests/unittest/_torch/executor/test_benchmark_disagg.py:
    • New test_admission_deferral_does_not_kill — deferral by the admission controller must not trigger the fail-fast.
    • New test_adp_consensus_runs_allgather_even_when_healthy — the consensus collective runs every iteration to keep ranks aligned.
    • New test_adp_consensus_kills_all_ranks_when_peer_is_stuck / test_adp_consensus_local_stuck_reported — consensus semantics.
    • Updated TestFillPhaseEndToEnd::test_full_lifecycle for the new consensus collective.
    • Full file passes (59 passed) against the fixed executor in the rc21 SBSA container.

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

… fail-fast ADP-safe

In gen-only benchmark mode, the "Insufficient KV cache" fail-fast in
_prepare_and_schedule_batch fired on rank-local conditions
(fitting_disagg_gen_init_requests / stuck INIT requests). Under
attention DP, a subset of ranks could enter _handle_errors (which runs
a collective response gather) while the remaining ranks sat in the
fill gate's tp_allgather. The mismatched collectives desync the TP
group: peers crash with
"TypeError: '<' not supported between instances of 'list' and 'int'"
in _is_benchmark_disagg_fill_complete, or hang until the HangDetector
hard-kills all ranks via MPI_Abort.

The check also mistook requests deferred by the disagg transfer
admission controller (added in NVIDIA#15356) for stuck requests: deferred
requests are waiting on in-flight KV transfers, not on KV capacity, so
the fail-fast killed benchmarks whose fill was making progress.

Fixes:
- Skip the fail-fast when the admission controller is deferring
  requests behind active transfers
  (wait_for_disagg_gen_transfer_progress).
- Reach an ADP consensus (any-rank allgather, run on every iteration
  regardless of local state) before failing, so all ranks enter
  _handle_errors together and stay collective-aligned.
- In _handle_errors' fatal path, enter the waiting-queue response
  gather on every ADP rank (it was rank-0 only, same desync class).

The feat/deepseek_v4 branch fixed the same desync in 95245c9 but
the fix was never ported to main.

Verified on Lyris (4x GB200, DeepSeek-V4-Flash ctx tp8 / gen dep8,
gen-only benchmark, concurrency 512): with per-rank divergence the old
code hangs and MPI_Aborts at benchmark start; with the fix all ranks
fail together with the real error message, and a healthy config runs
the benchmark to completion.

Signed-off-by: Iman Tabrizian <10105175+tabrizian@users.noreply.github.com>
@Tabrizian
Tabrizian requested a review from a team as a code owner July 10, 2026 20:21
@Tabrizian
Tabrizian requested a review from dongxuy04 July 10, 2026 20:21
@Tabrizian

Copy link
Copy Markdown
Member Author

/bot run --disable-fail-fast

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Benchmark disaggregated generation now defers fail-fast until transfer progress stops and the request queue is saturated, coordinates stuck decisions across Attention-DP ranks, and preserves collective response-enqueue participation during fatal errors. Tests cover healthy, peer-stuck, and locally-stuck scenarios.

Changes

Attention-DP fail-fast synchronization

Layer / File(s) Summary
Collective stuck-request detection
tensorrt_llm/_torch/pyexecutor/py_executor.py, tests/unittest/_torch/executor/test_benchmark_disagg.py
Stuck INIT detection now considers transfer progress, fetched-request saturation, and TP allgather consensus; tests cover admission deferral and synchronized healthy or failing rank outcomes.
Collective-safe fatal response handling
tensorrt_llm/_torch/pyexecutor/py_executor.py
Fatal handling invokes _enqueue_responses for Attention-DP collective participation even when local waiting responses are empty.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Scheduler
  participant TPAllgather
  participant ErrorHandler
  participant ResponseQueue
  Scheduler->>TPAllgather: Gather local stuck status
  TPAllgather-->>Scheduler: Return rank consensus
  Scheduler->>ErrorHandler: Handle synchronized failure
  ErrorHandler->>ResponseQueue: Enqueue responses collectively
Loading

Suggested reviewers: JunyiXu-nv, joyang-nv, suyoggupta, pcastonguay, taylor-yb-lee, chienchunhung

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title follows the required ticket/type format and clearly summarizes the main fix to gen-only benchmark fail-fast behavior.
Description check ✅ Passed The description includes the issue, solution, test coverage, and checklist items, and it is detailed enough for this PR.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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)
tests/unittest/_torch/executor/test_benchmark_disagg.py (1)

1068-1141: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Coverage verdict: sufficient for the consensus decision, one follow-up gap.

The new tests cover the local_stuck predicate and the any(tp_allgather(...)) consensus well (healthy no-op, peer-stuck kill-together, local-stuck vote). Since _handle_errors is mocked here, the companion collective-safe change in _handle_errors (the ADP _enqueue_responses(waiting_responses) on an empty local list) is never exercised — no test asserts every rank enters that gather in lockstep. Recommend a follow-up test in this file that drives the fatal _handle_errors path under ADP with an empty waiting_responses on the non-rank-0 stub and asserts _enqueue_responses participation, to lock in the fix against regressions.

As per path instructions ("suggest concrete list file names and whether coverage is sufficient, insufficient, or needs follow-up outside the PR").

🤖 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 `@tests/unittest/_torch/executor/test_benchmark_disagg.py` around lines 1068 -
1141, Coverage for the ADP consensus decision is sufficient, but add a follow-up
test in this file for the fatal _handle_errors path: configure a non-rank-0 ADP
executor with empty waiting_responses, invoke the error handling flow, and
assert _enqueue_responses is called with the empty list so every rank
participates in the response gather.

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 `@tests/unittest/_torch/executor/test_benchmark_disagg.py`:
- Around line 1068-1141: Coverage for the ADP consensus decision is sufficient,
but add a follow-up test in this file for the fatal _handle_errors path:
configure a non-rank-0 ADP executor with empty waiting_responses, invoke the
error handling flow, and assert _enqueue_responses is called with the empty list
so every rank participates in the response gather.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 2acfdbc2-f16d-4e04-9598-ffa51a8ce926

📥 Commits

Reviewing files that changed from the base of the PR and between e523b43 and f898524.

📒 Files selected for processing (2)
  • tensorrt_llm/_torch/pyexecutor/py_executor.py
  • tests/unittest/_torch/executor/test_benchmark_disagg.py

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58700 [ run ] triggered by Bot. Commit: f898524 Link to invocation

@Tabrizian

Copy link
Copy Markdown
Member Author

/bot kill

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58704 [ kill ] triggered by Bot. Commit: f898524 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58700 [ run ] completed with state ABORTED. Commit: f898524

Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #58704 [ kill ] completed with state SUCCESS. Commit: f898524
Successfully killed previous jobs for commit f898524

Link to invocation

@Tabrizian Tabrizian closed this Jul 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants