Skip to content

[https://nvbugs/6480621][test] Revert to 60-second KV transfer timeout for GB300 DeepSeek V4 Pro disaggregated perf-sanity - #17137

Open
chienchunhung wants to merge 6 commits into
NVIDIA:mainfrom
chienchunhung:codex/nvbug-6480621-timeout-60s-ci
Open

[https://nvbugs/6480621][test] Revert to 60-second KV transfer timeout for GB300 DeepSeek V4 Pro disaggregated perf-sanity#17137
chienchunhung wants to merge 6 commits into
NVIDIA:mainfrom
chienchunhung:codex/nvbug-6480621-timeout-60s-ci

Conversation

@chienchunhung

@chienchunhung chienchunhung commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

Stacked on #17223. This PR changes only the targeted GB300 DeepSeek V4 Pro perf-sanity YAML:

  • set GEN and CTX kv_transfer_timeout_ms from 600000 ms to 60000 ms;
  • explicitly enable cache_transceiver_precheck for this target while the gate is globally opt-in.

The explicit opt-in ensures the targeted stage exercises #17223's ownership/deadline path before running the real 60-second workload.

Stack and merge order

Validation

Exact stage:

GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-2

Exact test:

perf/test_perf_sanity.py::test_e2e[disagg_upload-gen_only-gb300_deepseek-v4-pro-fp4_8k1k_con180_ctx3_dep4_gen1_dep32_eplb384_mtp3_ccb-NIXL]

A prior revision passed this stage with test reuse disabled (L0 #51530), including all six precheck peer/request-length combinations and 180/180 benchmark requests. That run is useful historical evidence but does not validate the current restacked SHA; a fresh targeted run is being triggered.

This CI proxy is 3 CTX servers and concurrency 180. It does not replace rerunning the original 8-CTX, concurrency-1760 NVBug workload.

Dev Engineer Review

  • Reduced kv_transfer_timeout_ms from 600000 to 60000 for GEN and CTX in the targeted configuration.
  • Added transfer deadlines, bounded waits, cancellation handling, and failure propagation.
  • Preserved KV pages until transfer ownership and CUDA quiescence are confirmed.
  • Added model-root propagation and shell-safe LLM_MODELS_ROOT export.
  • Added fail-fast KV-cache-manager resolution checks.
  • Limited verification to transferred prompt blocks.
  • Updated related documentation and example timeout handling.
  • No test-list files were modified.
  • The parent PR must land before restacking and final merge-gate validation.

QA Engineer Review

Test-code changes include:

  • Added exact-block-boundary coverage with MTP draft-token reservations.
  • Added bounded-polling coverage for retries, deadlines, cancellation, task failures, auxiliary-task failures, and timeout retention.
  • Added configuration-resolution and shell-quoting tests.
  • Added precheck tests for speculative-page exclusion and transfer ownership.
  • Added transfer failure-path, cleanup, quiescence, and timeout-propagation tests.
  • Added extract_pytest_command_env tests for quoted values, spaces, = characters, missing assignments, and malformed exports.
  • Removed test_tx_session_wait_complete_defaults_to_blocking.
  • No corresponding test-db/ or qa/ entries were added or modified.
  • Targeted CI passed with test reuse disabled. The precheck passed all six combinations, and the GEN benchmark completed 180/180 requests.
  • The validation covers the CI proxy, not the original concurrency-1760, 8-CTX-worker NVBug workload.
  • Verdict: needs follow-up before merge-gate approval.

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-2"

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-2"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63105 [ run ] triggered by Bot. Commit: 38ca970 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63106 [ run ] triggered by Bot. Commit: 38ca970 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63105 [ run ] completed with state ABORTED. Commit: 38ca970

Link to invocation

@chienchunhung chienchunhung changed the title [https://nvbugs/6480621][test] Validate 60-second KV transfer timeout [https://nvbugs/6480621][test] Revert to 60-second KV transfer timeout for GB300 DeepSeek V4 Pro disaggregated perf-sanity Jul 31, 2026
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63106 [ run ] completed with state SUCCESS. Commit: 38ca970
/LLM/main/L0_MergeRequest_PR pipeline #51197 (Partly Tested) completed with status: 'SUCCESS'

CI Report

Link to invocation

@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63144 [ run ] triggered by Bot. Commit: 38ca970 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63144 [ run ] completed with state FAILURE. Commit: 38ca970
/LLM/main/L0_MergeRequest_PR pipeline #51231 (Partly Tested) completed with status: 'ABORTED'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

Link to invocation

@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63150 [ run ] triggered by Bot. Commit: 38ca970 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63150 [ run ] completed with state FAILURE. Commit: 38ca970
/LLM/main/L0_MergeRequest_PR pipeline #51234 (Partly Tested) completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63165 [ run ] triggered by Bot. Commit: 38ca970 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63165 [ run ] completed with state FAILURE. Commit: 38ca970
/LLM/main/L0_MergeRequest_PR pipeline #51249 (Partly Tested) completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-1"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63555 [ run ] triggered by Bot. Commit: 3e6c120 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63555 [ run ] completed with state SUCCESS. Commit: 3e6c120
/LLM/main/L0_MergeRequest_PR pipeline #51521 (Partly Tested) completed with status: 'FAILURE'

CI Report

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@chienchunhung
chienchunhung force-pushed the codex/nvbug-6480621-timeout-60s-ci branch from 3e6c120 to b7bd98a Compare August 3, 2026 21:40
@chienchunhung

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-2"

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63564 [ run ] triggered by Bot. Commit: b7bd98a Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63564 [ run ] completed with state SUCCESS. Commit: b7bd98a
/LLM/main/L0_MergeRequest_PR pipeline #51530 (Partly Tested) completed with status: 'SUCCESS'

CI Report

Link to invocation

@chienchunhung
chienchunhung marked this pull request as ready for review August 3, 2026 23:41
@chienchunhung
chienchunhung requested review from a team as code owners August 3, 2026 23:41
@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@chienchunhung
chienchunhung force-pushed the codex/nvbug-6480621-timeout-60s-ci branch from f2d7cb6 to 1714136 Compare August 5, 2026 00:02
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@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 (2)
tests/unittest/others/test_cache_transceiver_precheck_run.py (2)

83-111: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a large exact-boundary case to the parametrization.

Only the 1024 case allocates the extra reserve page. 1024 is a multiple of tokens_per_block, so num_allocated is 9 while num_prompt_blocks is 8.

7408 is not a multiple of 128. num_allocated and num_prompt_blocks are both 58, so that case would still pass if the trim in _request_block_views were removed. Add a large exact-boundary length, such as 7424 (58 blocks, 59 allocated), to protect the boundary the stacked fix targets.

♻️ Proposed parametrization change
-@pytest.mark.parametrize(("prompt_len", "expected_blocks"), ((1024, 8), (7408, 58)))
+@pytest.mark.parametrize(("prompt_len", "expected_blocks"), ((1024, 8), (7408, 58), (7424, 58)))
🤖 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/others/test_cache_transceiver_precheck_run.py` around lines 83
- 111, Extend the parametrization of
test_request_block_views_excludes_untransferred_speculative_page with a large
exact-boundary prompt length such as 7424 and expect 58 verified blocks. Keep
the existing 1024 and 7408 cases unchanged so the test covers both reserve-page
allocation and the large exact-boundary trim in _request_block_views.

454-464: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add coverage for the DISAGG_TRANS_ERROR state branch.

Request 1 is in the failed list here, so ctx_finish_wave raises at the failed_pairs check. The later branch that inspects req.state == self.llm_request_state.DISAGG_TRANS_ERROR is never reached by any test in this file.

Add a case where block-all reports the rid as completed but the request state is the error state. That path also must retain pages.

💚 Proposed added test
def test_ctx_finish_wave_retains_pages_on_disagg_trans_error_state(monkeypatch):
    runner, events = _ctx_finish_runner(monkeypatch, lambda _n: ([101], []))
    reqs = {0: types.SimpleNamespace(py_request_id=101, state="error")}

    with pytest.raises(rp._TransferError, match=r"ctx DISAGG_TRANS_ERROR on pairs \[0\]"):
        runner.ctx_finish_wave(reqs)

    assert events == []
🤖 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/others/test_cache_transceiver_precheck_run.py` around lines
454 - 464, Add a test alongside
test_ctx_finish_wave_retains_pages_when_request_failed that makes block-all
report the request as completed while its state is DISAGG_TRANS_ERROR, using
_ctx_finish_runner with no failed IDs and a request for pair 0. Assert
ctx_finish_wave raises the DISAGG_TRANS_ERROR-specific _TransferError and that
events remains empty, confirming pages are retained.
🤖 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/others/test_cache_transceiver_precheck_run.py`:
- Around line 83-111: Extend the parametrization of
test_request_block_views_excludes_untransferred_speculative_page with a large
exact-boundary prompt length such as 7424 and expect 58 verified blocks. Keep
the existing 1024 and 7408 cases unchanged so the test covers both reserve-page
allocation and the large exact-boundary trim in _request_block_views.
- Around line 454-464: Add a test alongside
test_ctx_finish_wave_retains_pages_when_request_failed that makes block-all
report the request as completed while its state is DISAGG_TRANS_ERROR, using
_ctx_finish_runner with no failed IDs and a request for pair 0. Assert
ctx_finish_wave raises the DISAGG_TRANS_ERROR-specific _TransferError and that
events remains empty, confirming pages are retained.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 9fc46729-afee-487d-9cda-fe1261acdbf7

📥 Commits

Reviewing files that changed from the base of the PR and between 1982523 and 1714136.

📒 Files selected for processing (13)
  • jenkins/scripts/perf/local/submit.py
  • jenkins/scripts/perf/submit.py
  • tensorrt_llm/_torch/disaggregation/native/transfer.py
  • tensorrt_llm/_torch/disaggregation/transceiver.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/README.md
  • tests/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/run_precheck.py
  • tests/scripts/perf-sanity/disaggregated/gb300_deepseek-v4-pro-fp4_8k1k_con180_ctx3_dep4_gen1_dep32_eplb384_mtp3_ccb-NIXL.yaml
  • tests/unittest/disaggregated/test_cache_transceiver_precheck_e2e.py
  • tests/unittest/disaggregated/test_transceiver_bounded_polling.py
  • tests/unittest/others/test_cache_transceiver_precheck_config.py
  • tests/unittest/others/test_cache_transceiver_precheck_run.py
  • tests/unittest/scripts/test_perf_submit.py
🚧 Files skipped from review as they are similar to previous changes (11)
  • jenkins/scripts/perf/local/submit.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py
  • tensorrt_llm/_torch/disaggregation/native/transfer.py
  • jenkins/scripts/perf/submit.py
  • tests/unittest/disaggregated/test_cache_transceiver_precheck_e2e.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/README.md
  • tests/unittest/scripts/test_perf_submit.py
  • tensorrt_llm/_torch/disaggregation/transceiver.py
  • tests/scripts/perf-sanity/disaggregated/gb300_deepseek-v4-pro-fp4_8k1k_con180_ctx3_dep4_gen1_dep32_eplb384_mtp3_ccb-NIXL.yaml
  • tests/scripts/perf-sanity/cache_transceiver_precheck/run_precheck.py
  • tests/unittest/disaggregated/test_transceiver_bounded_polling.py

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63870 [ run ] triggered by Bot. Commit: 1714136 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #63870 [ run ] completed with state SUCCESS. Commit: 1714136
/LLM/main/L0_MergeRequest_PR pipeline #51810 completed with status: 'FAILURE'

CI Report

⚠️ Multi-GPU Label Required:
Multi-GPU tests require the ci: full pre-merge approved label on this PR. Ask a member of NVIDIA/trt-llm-ci-approvers to add the label, then re-trigger CI with the same bot command (no rebase needed).

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

CI Agent Failure Analysis

Link to invocation

@BowenFu

BowenFu commented Aug 5, 2026

Copy link
Copy Markdown

The tensorrt_llm/ portion of this PR is byte-identical to #17223 — I diffed the product hunks of both PR diffs and they match exactly. This PR is #17223 plus the kv_transfer_timeout_ms: 600000 → 60000 revert in the GB300 yaml.

That matters because the two are in very different review states. #17223 is [fix], has zero approvals, and carries my open findings. This one is [test], has two approvals and no open threads — so the disagg blocking-wait change would land here under a title that only advertises a timeout revert. Please either drop transfer.py/transceiver.py from this PR and let #17223 carry them, or bring the findings over. The two that matter:

  1. WaitResult.TIMEOUT becomes dead repo-wide. Both return WaitResult.TIMEOUT sites are removed from TxSession.wait_complete, but the consumer arm at transceiver.py:703 is kept with its log demoted warningdebug. Nothing can reach it, timed_out is permanently empty, and it is still threaded through _ctx_consensus_outcome. Delete the branch rather than quieting it.

  2. The blocking path now has no deadline. while not task.wait(wait_slice_s): if self.has_failed(): return FAILED exits only on completion or a reported failure. The diagnosis in the description says _timeout_s is the wrong bound and kv_transfer_timeout_ms is the right one — but the fix removes the bound instead of switching to it. A peer that stalls without erroring hangs forever.

Separately, jenkins/scripts/perf/submit.py and cache_transceiver_precheck/precheck_config.py collide with #17121, which is also review-ready:

  • Both add a parser for the same thing to the same file — extract_pytest_command_env() here, _get_pytest_command_env_var() there — with different semantics (yours stops at the first non-KEY= token and raises on every miss; theirs scans all tokens and returns None).
  • precheck_prefix_lines() gains llm_models_root in both, but here it is a required positional before stage_name and there it is optional after it.
  • The inline comments give directly opposite instructions: yours says "Keep this as a top-level assignment. shlex.quote() is not safe when nested inside the double-quoted pytestCommand exports below"; [https://nvbugs/6541356][fix] align cache transceiver harness setup #17121 says to quote the complete assignment as an export value and nests it. One of you is wrong about the quoting.

Worth sorting out between you before either merges. Also: _resolve_model_prefs now fails fast with "refusing to assume V1" — a real behavior change in the precheck that the [test] title doesn't cover.

@brnguyen2 brnguyen2 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approving — the comments below are optional touch-ups, not blockers.

Reviewed the prerequisite commit as the real content; the YAML edit itself is fine.

One framing note for the PR description: kv_transfer_timeout_ms and the sender wait slice are different knobs. The YAML value feeds rx_timeout_s and the py_executor request-cancel deadline (py_executor.py:6159); the sender's slice is kv_transfer_sender_future_timeout_ms (default 1000ms). So the revert restores the 60s request cancellation deadline, and it's safe now because wait_complete observes cancellation between slices rather than mistaking a slice expiry for completion. Worth saying that way in the commit message — "600s → 60s" alone reads like the thing that was failing is being re-enabled unchanged.

The main leftover is that TxSession.wait_complete can no longer return TIMEOUT, which leaves dead plumbing in check_context_transfer_status and removes the last diagnostic for a wedged sender (details inline). Otherwise the ownership contract is clearly stated and the unit tests cover the cases that matter — cancel-between-slices, failed sibling behind a pending task, and retain-on-failure for both ctx and gen.

for task in self.kv_tasks:
if not task.wait(timeout=self._timeout_s):
return WaitResult.TIMEOUT
while not task.wait(timeout=wait_slice_s):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(to be fixed in PR #17223, not here) This loop has no diagnostic at all. Previously a stuck task produced a TIMEOUT and a warning; now it spins on 1s slices silently. The only escape is the executor's request-cancel deadline (kv_transfer_timeout_ms, default 60000) — if a deployment sets that to null, check_context_transfer_status(None) blocks the executor thread forever with nothing in the log.

Suggest logging inside the loop on an escalating cadence, e.g. warn once past N slices with the elapsed time and rid, so a wedged NIXL write is diagnosable from a CI log without a stack dump.

@@ -703,8 +703,9 @@ def check_context_transfer_status(
elif result is None:
continue
elif result == WaitResult.TIMEOUT:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(to be fixed in PR #17223, not here) This branch is now unreachable for TxSession: the blocking path loops until terminal and the non-blocking path returns None, so wait_complete never yields TIMEOUT. That makes timed_out, its _ctx_consensus_outcome argument, and this (now debug-level) message dead code.

Either delete the branch and the timed_out plumbing, or keep it and make wait_complete actually return TIMEOUT after some bounded number of slices. Leaving a permanently-false branch that also happens to be the only place a stalled sender was ever logged is the worst of both.

if not self.aux_task.wait(timeout=self._timeout_s):
return WaitResult.TIMEOUT
if self._need_aux:
if self.aux_task is None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(to be fixed in PR #17223, not here) A blocking=True call returning None is surprising for the caller: check_context_transfer_status hits elif result is None: continue, so the rid stays in _send_sessions and block-all returns claiming it drained everything. Is aux_task guaranteed to be set before the first wait_complete when _need_aux is true? If it's a transient window this is fine but should say so; if it can persist, this is a silent stuck-request path (the precheck catches it as missing, production won't).

# block boundary those tokens allocate an additional page, but the
# transceiver intentionally trims its slice to prompt_len blocks.
# Verify the same payload range instead of the untransferred page.
valid = [b for b in blocks if b >= 0][:num_prompt_blocks]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(to be fixed in PR #17223, not here) The [:num_prompt_blocks] slice silently absorbs the under-allocated case too: if the KV manager hands back fewer valid blocks than the prompt needs — a real bug this precheck exists to catch — verification just checks fewer blocks and passes.

Add an explicit check, e.g. if len(valid) < num_prompt_blocks: raise/return a mismatch detail naming the layer and the counts. Only the extra trailing speculative page should be trimmed.

key, value = token.split("=", 1)
if key == name:
return value
raise ValueError(f"pytestCommand does not set leading environment variable {name}")

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(to be fixed in PR #17223, not here) This raises when LLM_MODELS_ROOT isn't a leading assignment in pytestCommand. Today getPytestBaseCommandLine (L0_Test.groovy:1358) always emits it third, so it works — but this turns a precheck-config detail into a hard abort of the whole disagg perf submission if that Groovy list is ever reordered or the var moves into envVarsToExport. Consider falling back to os.environ.get("LLM_MODELS_ROOT") before raising, or at least referencing the Groovy site in the error message so the next person knows where to look.

Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
Signed-off-by: Chien-Chun Hung <2679986+chienchunhung@users.noreply.github.com>
@chienchunhung
chienchunhung force-pushed the codex/nvbug-6480621-timeout-60s-ci branch from 1714136 to 6e9981a Compare August 7, 2026 02:46
@chienchunhung
chienchunhung requested a review from a team as a code owner August 7, 2026 02:46
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast --disable-reuse-test --stage-list "GB300-44_GPUs-11_Nodes-PyTorch-Disagg-PerfSanity-CTX3-NODE1-GPU4-GEN1-NODE8-GPU32-Post-Merge-2"

@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 (4)
tests/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py (1)

196-201: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Reject an empty llm_models_root as well.

The guard only rejects None. An empty string passes and produces export LLM_MODELS_ROOT=''. The precheck then fails later on the cluster with an INIT_ERROR from resolve_model_dir returning None. A falsy check fails at launch-script generation time with the precise cause.

♻️ Proposed fix
     if enabled:
-        if llm_models_root is None:
+        if not llm_models_root:
             raise ValueError("enabled cache-transceiver precheck requires LLM_MODELS_ROOT")
🤖 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/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py`
around lines 196 - 201, Update the guard in the enabled cache-transceiver
precheck configuration path to reject both None and empty llm_models_root values
before generating the export line. Preserve the existing ValueError message and
top-level LLM_MODELS_ROOT assignment for valid non-empty values.
tests/unittest/others/test_cache_transceiver_precheck_run.py (1)

83-112: 📐 Maintainability & Code Quality | 🔵 Trivial

Test coverage summary (tests/ path instruction).**

Changed test functions

tests/unittest/others/test_cache_transceiver_precheck_run.py — added: test_request_block_views_excludes_untransferred_speculative_page, test_resolve_model_prefs_allows_registered_class_without_defaults_hook, six ctx_finish_wave cases, two ctx_run_wave cases, seven gen_run_wave cases, two _hard_abort_unquiesced cases, two peer-loop cases.

tests/unittest/disaggregated/test_cache_transceiver_harness.py — added: TestRequestTransferOwnershipFlow (7 cases) and TestTransferOwnershipHelpers (7 cases), plus the AST loaders and fakes.

tests/unittest/disaggregated/test_transceiver_bounded_polling.py — added: bounded-slice, shared-deadline, terminal-wins-at-deadline, timeout-fallback, timeout-retention, TP/PP consensus, and timeout-wiring cases; removed the former default-blocking wait test.

tests/unittest/others/test_cache_transceiver_precheck_config.py — added model-root quoting and enable-policy cases.

Test list membership

All changed test files are unit tests under tests/unittest/. They are not integration tests, so entries under tests/integration/test_lists/test-db/ or qa/ do not apply. The one integration-adjacent file, tests/unittest/disaggregated/test_cache_transceiver_precheck_e2e.py, requires a GPU. Confirm it is reachable from an existing CI stage rather than only runnable by hand.

Verdict: needs follow-up

Coverage of the ownership contract is strong. The release ordering (block_allcuda_syncpeer_ackfree), page retention on every failure class, timeout propagation, and finalizer skipping are all asserted directly. Two gaps remain:

  1. No case covers the KV manager returning fewer valid blocks than the prompt needs. Both parameterizations here supply enough or extra blocks. That is the under-allocation hole flagged in run_precheck.py. Add a case once that check lands.
  2. No case asserts that a repeated block-all after a TIMEOUT stays nonterminal at the transceiver level. test_tx_session_blocking_wait_times_out_stalled_task_and_does_not_reset_deadline covers the session, not the caller loop.

As per path instructions: "Always produce a test coverage summary, even if no issues are found" and "A coverage verdict: sufficient, insufficient, or needs follow-up."

Do you want me to write the two missing test cases?

🤖 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/others/test_cache_transceiver_precheck_run.py` around lines 83
- 112, The test coverage is missing under-allocation handling and
transceiver-level repeated block-all behavior after TIMEOUT. Add one test for
_request_block_views (or the relevant precheck validation) where the KV manager
returns fewer valid blocks than the prompt requires, and add one caller-loop
test asserting a repeated block-all after TIMEOUT remains nonterminal; preserve
existing session-level coverage and follow current test helpers and
parametrization patterns.

Source: Path instructions

tests/unittest/disaggregated/test_cache_transceiver_harness.py (1)

61-172: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract the shared AST loader.

_load_driver_ownership_helpers and _load_driver_request_flow are near-identical. They differ only in the module name, selected_names, and the stand-in namespace. Roughly 50 lines are duplicated, including the parse, the node filter, the exec, and the missing-symbol assertion. A rename in the driver now requires editing two selection sets and two stand-in dicts.

The missing assertion is the right safeguard for this loading technique. Keep it in the extracted helper.

♻️ Proposed refactor
+def _load_driver_symbols(module_name: str, selected_names: set, namespace: dict) -> types.ModuleType:
+    """Load selected top-level driver symbols without importing GPU/MPI runtime modules."""
+    source = Path(DRIVER_SCRIPT).read_text()
+    tree = ast.parse(source, filename=DRIVER_SCRIPT)
+    selected = [
+        node
+        for node in tree.body
+        if isinstance(node, (ast.ClassDef, ast.FunctionDef)) and node.name in selected_names
+    ]
+    module = types.ModuleType(module_name)
+    module.__dict__.update(namespace)
+    exec(
+        compile(ast.Module(body=selected, type_ignores=[]), DRIVER_SCRIPT, "exec"),
+        module.__dict__,
+    )
+    missing = selected_names - set(module.__dict__)
+    assert not missing, f"{module_name}: driver symbols not loaded: {sorted(missing)}"
+    return module

Then both loaders reduce to a selected_names set, a namespace dict, and one call.

🤖 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/disaggregated/test_cache_transceiver_harness.py` around lines
61 - 172, Extract the common AST parsing, top-level node selection, module
creation, execution, and missing-symbol assertion from
_load_driver_ownership_helpers and _load_driver_request_flow into a shared
loader helper. Keep each existing loader responsible only for its selected_names
and stand-in namespace, pass those values to the helper, and preserve the
missing-symbol safeguard and current module behavior.
examples/disaggregated/slurm/cache_transceiver_test/run_cache_transceiver_test.py (1)

411-461: 🔒 Security & Privacy | 🔵 Trivial | ⚖️ Poor tradeoff

Consider authenticated framing for the new release handshake.

_exchange_release_decision adds a second pickle exchange on the leader-to-leader ZMQ socket. pickle.loads executes arbitrary code from the payload. The socket binds tcp://*:<zmq_port> with no authentication, so any process that can reach the context node's port can drive this decode.

The sibling driver tests/scripts/perf-sanity/cache_transceiver_precheck/run_precheck.py already solved this. It frames control messages with an HMAC key exchanged through a 0600 work-dir file (pack_msg/unpack_msg). The payload here is a (status, reason) string pair, so JSON plus the same HMAC framing would carry it without pickle.

This harness is a tuning example, not production serving, so the risk is bounded by the cluster network. Aligning the two drivers still removes the divergence and the code-execution surface.

🤖 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
`@examples/disaggregated/slurm/cache_transceiver_test/run_cache_transceiver_test.py`
around lines 411 - 461, Replace the unauthenticated pickle send/receive calls in
_exchange_release_decision with the authenticated JSON/HMAC framing used by
pack_msg and unpack_msg in the sibling precheck driver. Reuse the 0600
work-directory key exchange and validate the decoded payload as a (status,
reason) string pair before applying the existing handshake logic; preserve
timeout and fatal-error handling.

Source: Linters/SAST tools

🤖 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
`@examples/disaggregated/slurm/cache_transceiver_test/run_cache_transceiver_test.py`:
- Around line 411-461: Replace the unauthenticated pickle send/receive calls in
_exchange_release_decision with the authenticated JSON/HMAC framing used by
pack_msg and unpack_msg in the sibling precheck driver. Reuse the 0600
work-directory key exchange and validate the decoded payload as a (status,
reason) string pair before applying the existing handshake logic; preserve
timeout and fatal-error handling.

In `@tests/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py`:
- Around line 196-201: Update the guard in the enabled cache-transceiver
precheck configuration path to reject both None and empty llm_models_root values
before generating the export line. Preserve the existing ValueError message and
top-level LLM_MODELS_ROOT assignment for valid non-empty values.

In `@tests/unittest/disaggregated/test_cache_transceiver_harness.py`:
- Around line 61-172: Extract the common AST parsing, top-level node selection,
module creation, execution, and missing-symbol assertion from
_load_driver_ownership_helpers and _load_driver_request_flow into a shared
loader helper. Keep each existing loader responsible only for its selected_names
and stand-in namespace, pass those values to the helper, and preserve the
missing-symbol safeguard and current module behavior.

In `@tests/unittest/others/test_cache_transceiver_precheck_run.py`:
- Around line 83-112: The test coverage is missing under-allocation handling and
transceiver-level repeated block-all behavior after TIMEOUT. Add one test for
_request_block_views (or the relevant precheck validation) where the KV manager
returns fewer valid blocks than the prompt requires, and add one caller-loop
test asserting a repeated block-all after TIMEOUT remains nonterminal; preserve
existing session-level coverage and follow current test helpers and
parametrization patterns.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 7c7cb1e4-dfdc-4d43-ba6a-fe04def30db0

📥 Commits

Reviewing files that changed from the base of the PR and between e447b6c and 6e9981a.

📒 Files selected for processing (17)
  • examples/disaggregated/slurm/cache_transceiver_test/README.md
  • examples/disaggregated/slurm/cache_transceiver_test/config.yaml
  • examples/disaggregated/slurm/cache_transceiver_test/run_cache_transceiver_test.py
  • jenkins/scripts/perf/local/submit.py
  • jenkins/scripts/perf/submit.py
  • tensorrt_llm/_torch/disaggregation/native/transfer.py
  • tensorrt_llm/_torch/disaggregation/transceiver.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/README.md
  • tests/scripts/perf-sanity/cache_transceiver_precheck/precheck_config.py
  • tests/scripts/perf-sanity/cache_transceiver_precheck/run_precheck.py
  • tests/scripts/perf-sanity/disaggregated/gb300_deepseek-v4-pro-fp4_8k1k_con180_ctx3_dep4_gen1_dep32_eplb384_mtp3_ccb-NIXL.yaml
  • tests/unittest/disaggregated/test_cache_transceiver_harness.py
  • tests/unittest/disaggregated/test_cache_transceiver_precheck_e2e.py
  • tests/unittest/disaggregated/test_transceiver_bounded_polling.py
  • tests/unittest/others/test_cache_transceiver_precheck_config.py
  • tests/unittest/others/test_cache_transceiver_precheck_run.py
  • tests/unittest/scripts/test_perf_submit.py
🚧 Files skipped from review as they are similar to previous changes (5)
  • jenkins/scripts/perf/local/submit.py
  • tests/unittest/disaggregated/test_cache_transceiver_precheck_e2e.py
  • tests/unittest/scripts/test_perf_submit.py
  • jenkins/scripts/perf/submit.py
  • tensorrt_llm/_torch/disaggregation/native/transfer.py

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64469 [ run ] triggered by Bot. Commit: 6e9981a Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #64469 [ run ] completed with state FAILURE. Commit: 6e9981a
/LLM/main/L0_MergeRequest_PR pipeline #52341 (Partly Tested) completed with status: 'UNSTABLE'

CI Report

⚠️ Multi-GPU Label Required:
Multi-GPU tests require the ci: full pre-merge approved label on this PR. Ask a member of NVIDIA/trt-llm-ci-approvers to add the label, then re-trigger CI with the same bot command (no rebase needed).

⚠️ Action Required:

  • Please check the failed tests and fix your PR
  • If you cannot view the failures, ask the CI triggerer to share details
  • Once fixed, request an NVIDIA team member to trigger CI again

Link to invocation

@Shixiaowei02
Shixiaowei02 self-requested a review August 7, 2026 08:41
@Shixiaowei02

Shixiaowei02 commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

This and #17121 add llm_models_root to the same call at different positions, so merging both gives a repeated keyword argument. cc @chuangz0

@Shixiaowei02
Shixiaowei02 requested a review from chuangz0 August 7, 2026 08:42
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.

6 participants