Skip to content

[None][test] Reduce multi-GPU pre-merge time via shared MPI sessions and HF weight cache - #15872

Closed
sunnyqgg wants to merge 21 commits into
NVIDIA:mainfrom
sunnyqgg:grouped_test_premerge
Closed

[None][test] Reduce multi-GPU pre-merge time via shared MPI sessions and HF weight cache#15872
sunnyqgg wants to merge 21 commits into
NVIDIA:mainfrom
sunnyqgg:grouped_test_premerge

Conversation

@sunnyqgg

@sunnyqgg sunnyqgg commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Depends on #15873 — merge that PR first.
Until #15873 merges, this PR's diff shows its commits too; the only commit in scope here is the last one ([None][test] Group P0/P1 pre-merge multi-GPU accuracy cases onto shared MPI sessions). Do not run CI on this PR before #15873 merges and this branch is rebased onto main.

Summary

Extends the shared-MPI-session grouping infrastructure from #15873 to the highest-ROI (P0/P1) pre-merge stages. No library changes in this PR — test-only.

New grouped pre-merge variants (*_premerge_grouped, module-scoped shared 4-GPU/8-GPU sessions + HF weight cache):

  • DeepSeekV3Lite (DGX_H100): 14 fp8_block_scales_4gpus cases + 2 cuda_graph_padding cases
  • GPT-OSS-120B w4_4gpus: one union matrix; DGX_H100 selects 6 case ids, GB200 selects 4
  • Llama3.3-70B (GB200): fp8_tp4 x2, nvfp4_tp4 x2, fp4_tp2pp2[fusion_off_compile_on]
  • NemotronV3 Super (GB200): block_reuse x3; NemotronV3 Ultra (GB200): block_reuse[ADP4_MTP], parallelism[ADP2_PP2], mtp_ar
  • DeepSeekV32 (DGX_B200, new shared 8-GPU session fixture): nvfp4 baselines x2 + piecewise_cuda_graph[baseline]

Grouping eligibility rules applied (documented in code comments):

  • Cases needing per-case worker env (OVERRIDE_QUANT_ALGO, TRTLLM_XGUIDANCE_LENIENT, gemm-allreduce fusion=True) stay ungrouped — the pool snapshots env at spawn.
  • Waived cases stay on their original test ids: moving one to a new (grouped) id would silently un-waive it. DeepSeekR1 groups were dropped entirely for this reason.
  • EPLB cases deferred pending a reused-worker shared-state audit; sampler_async_worker cases are ordered last in their group.

Changes

  • tests/integration/defs/accuracy/test_llm_api_pytorch.py_run_*_case runner refactors + grouped variants + shared 8-GPU fixture
  • tests/integration/test_lists/test-db/{l0_dgx_h100,l0_gb200_multi_gpus,l0_dgx_b200}.yml — swap grouped case ids for the replaced entries (fully-parametrized ids; same-checkpoint cases adjacent for weight-cache LRU hits)

Test plan

sunnyqgg added 19 commits July 1, 2026 19:52
Signed-off-by: qgai <qgai@nvidia.com>
Signed-off-by: qgai <qgai@nvidia.com>
Signed-off-by: qgai <qgai@nvidia.com>
Signed-off-by: qgai <qgai@nvidia.com>
…cesses

When multiple LLM instances share the same worker processes (e.g. a reused
MpiPoolSession), the module-global _pp_comm was reassigned on each new
pp>1 LLM, dropping the previous NcclCommunicatorOp and triggering a
collective ncclCommDestroy at an unsynchronized point during the next
model build. On reused workers this can deadlock in commDestroySync.

Since the PP comm is a world communicator depending only on
(world_size, rank), reuse the existing one when world_size matches and
only refresh the routing mapping. Single-LLM runs are unaffected.

Signed-off-by: qgai <qgai@nvidia.com>
- Fix weight-cache env ordering: shared_mpi_session_4gpu now depends on
  hf_weight_cache so TRTLLM_HF_WEIGHT_CACHE is exported before the MPI pool
  spawns (MpiPoolSession snapshots env at spawn time); add an assertion to
  pin the contract.
- Add a _make_shared_llm factory (shared_llm_* fixtures) so tests inject the
  shared MPI session transparently, and migrate the RPC/NVFP4 direct-construction
  tests onto it.
- Mark the grouped NVFP4 test threadleak(enabled=False): the reused session
  keeps mpi4py's _manager_spawn thread alive by design.
- Only compute the HF weight-cache key when the cache is enabled (avoid a
  per-shard os.stat on the default path).

Signed-off-by: qgai <qgai@nvidia.com>
On a reused MpiPoolSession, Dynamo's per-code-object recompile counter is
process-global in the worker and never reset across LLMs. Each torch_compile
case recompiles the same model.forward under new guards; the count
accumulates and eventually trips recompile_limit (16), which is a HARD
failure under enable_fullgraph=True (FailOnRecompileLimitHit) and aborts the
whole MPI job (observed as a silent crash at the ~10th case).

Submit torch._dynamo.reset() to each worker after every case so compile state
starts clean per LLM. Test-only; production (non-reused) paths are untouched.
Verified: full 13-case grouped run now passes 13/13 on B300.

Signed-off-by: qgai <qgai@nvidia.com>
…ckage module

The grouped multi-GPU session-reuse helpers (shared_mpi_session,
make_shared_llm, mpi_session_kwargs, reset_worker_torch_compile_state,
restore_env_var) were duplicated across the unittest and integration test
roots, and had already begun to diverge. Consolidate them into
tensorrt_llm/llmapi/_grouped_test_utils.py so both roots (which have separate
sys.paths and cannot share a module under tests/) import one source. Heavy
imports are lazy to avoid circular imports at package init. Test-infra only.

Verified: package import + pytest collection resolve (13 tests collected).
Signed-off-by: qgai <qgai@nvidia.com>
Move the HF-weight-cache env enable/restore logic into a reusable
contextmanager (hf_weight_cache_env) in _grouped_test_utils.py, keeping only a
thin pytest fixture wrapper in the test. The fixture itself stays test-side so
the shipped package never imports pytest. Docstring documents the load-bearing
ordering (must be entered before the MpiPoolSession spawns).

Verified: contextmanager sets/restores env correctly; 13 tests collected.
Signed-off-by: qgai <qgai@nvidia.com>
Replace the repeated 'take shared_mpi_session_Ngpu + spread
**_mpi_session_kwargs(...)' boilerplate in every harness-based test with
module-scoped mpi_kwargs_2gpu / mpi_kwargs_4gpu fixtures that yield the
ready-to-spread kwargs dict. Tests now just spread **mpi_kwargs_Ngpu and never
reference the raw session or the helper; _mpi_session_kwargs is used only
inside the two fixtures. RPC tests keep the shared_llm_2gpu factory. No
behavior change.

Signed-off-by: qgai <qgai@nvidia.com>
- Collapse the 13 hand-spelled _NVFP4_4GPU_PREMERGE_CASES dicts (which
  repeated 4 constant keys x13 + one lpc flip) into a compact tuple matrix of
  the varying axes plus a builder that fills the constants. Same ids and field
  values, ~130 lines -> ~30.
- make_shared_llm's closure now reuses mpi_session_kwargs instead of
  re-implementing the 'inject _mpi_session if not None' conditional.

Signed-off-by: qgai <qgai@nvidia.com>
…ardown

The per-worker HF raw-weight cache previously relied on the shared session's
worker processes exiting to be cleared. Make invalidation explicit: on
shared_llm_4gpu teardown (which runs before the session shuts down its
workers), submit clear_worker_weight_cache() to each worker. This closes the
'setup cache / teardown invalidate' loop instead of leaning on process death.

Signed-off-by: qgai <qgai@nvidia.com>
…ss-scoped sessions

Group test_llm_multi_gpu_pytorch.py into TestLlmMultiGpu2gpu (@gpu2) and
TestLlmMultiGpu4gpu (@gpu4), sharing a small _MultiGpuLlmTests base whose
class-scoped mpi_session/mpi_kwargs/shared_llm fixtures build one MpiPoolSession
of self.n_gpus workers. The session is created lazily and torn down at class
end, so the 2-GPU and 4-GPU pools no longer coexist (as they did with the
previous module-scoped fixtures). Update the two explicit nodeid references for
test_phi3_lora_fused_modules_output_on_tp2_identical_to_tp1 (l0_dgx_h100.yml,
waives.txt) to include the class; -m gpu2/gpu4 and -k filters are unaffected.

Signed-off-by: qgai <qgai@nvidia.com>
Upstream's independently-curated pre-merge smoke set (superseded by the grouped
test during the rebase) included two CUTEDSL configs. Add them to
_NVFP4_4GPU_PREMERGE_MATRIX so the grouped test preserves that coverage;
_run_nvfp4_4gpus_case already skips CUTEDSL off SM100/103.

Signed-off-by: qgai <qgai@nvidia.com>
The case dicts embedded id=row[0] only to strip it back out at call time
(ids=[case['id']...] + a case_kwargs comprehension). Keep the id in the matrix
(row[0]) for the parametrize ids, make each case a pure _run_nvfp4_4gpus_case
kwargs dict, and splat it directly (**case). No behavior change.

Signed-off-by: qgai <qgai@nvidia.com>
Rename HfWeightLoader.clear_weight_cache -> _clear_weight_cache: its only
callers are tests (via _grouped_test_utils.clear_worker_weight_cache and the
weight-loader unit tests), and it matches the sibling private cache helpers
(_get_cached_weights, _cache_loaded_weights). Signals it is test-infra, not a
supported production API.

Signed-off-by: qgai <qgai@nvidia.com>
…ession

Extract _run_bfloat16_4gpus_case from test_bfloat16_4gpus and add
test_bfloat16_4gpus_premerge_grouped, which reuses the SAME module-scoped
shared_llm_4gpu MPI session as the nvfp4 group (both are 4-worker
DeepSeek-V3-Lite, so world_size matches). This saves one more session
spawn in the gb200 pre-merge stage.

The shared runner resets per-worker torch.compile/Dynamo state between
cases (same FailOnRecompileLimitHit guard as the nvfp4 group). The HF
weight cache is keyed by checkpoint file fingerprint, so the bf16 model
gets its own entry; with max_entries=1 the LRU evicts the other model on
the first cross-model miss, bounding CPU cache to one model's raw tensors.

Replace the three individual bf16 pre-merge entries in
l0_gb200_multi_gpus.yml with the grouped test; the post-merge individual
test_bfloat16_4gpus[...] entries are unaffected (method still exists).

Signed-off-by: qgai <qgai@nvidia.com>
… peak

On a cache miss, evict LRU entries down to the cap BEFORE loading the new
weights, so the old (cached) and new (loading) raw tensors are never held
in CPU at the same time. Previously the eviction happened only at store
time (after the load), so switching models on a reused MPI-session worker
transiently held both models' weights (~2x CPU peak). CPU now stays bounded
by max_entries models even during a cross-model load.

Add a unit test asserting the cache is already empty when the new load runs
(max_entries=1), proving eviction precedes allocation.

Signed-off-by: qgai <qgai@nvidia.com>
/simplify cleanup on the bf16-grouping + weight-cache-eviction changes:

- Hoist the identical per-case torch.compile-reset finally block (duplicated
  verbatim in _run_nvfp4_4gpus_case and _run_bfloat16_4gpus_case) into
  reset_shared_session_torch_compile_state(make_llm) in _grouped_test_utils,
  so both call it in one line and a future grouped test can't drift.
- Trim the over-long _evict_to_make_room docstring (10 lines -> 2).

No behavior change.

Signed-off-by: qgai <qgai@nvidia.com>
@sunnyqgg
sunnyqgg requested review from a team as code owners July 2, 2026 07:35
@sunnyqgg

sunnyqgg commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator Author

/bot run --disable-fail-fast

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57161 [ run ] triggered by Bot. Commit: f94c700 Link to invocation

@sunnyqgg

sunnyqgg commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator Author

/bot kill

sunnyqgg added 2 commits July 2, 2026 00:49
Test-list matching is exact-nodeid (test_list_parser.modify_by_test_list),
so an unbracketed yml entry for a parametrized test never matches any
collected test and is silently ignored as an invalid filter. Expand the
grouped DeepSeek-V3-Lite nvfp4/bf16 entries to per-case bracketed ids;
same-checkpoint cases stay adjacent so the HF weight-cache LRU
(max_entries=1) stays hot across cases.

Signed-off-by: qgai <qgai@nvidia.com>
…ed MPI sessions

Extend the shared-MpiPoolSession grouping (method 1: session reuse;
method 2: session reuse + HF weight cache) to the highest-ROI pre-merge
stages:

- DeepSeekV3Lite (H100): 14 fp8_block_scales_4gpus cases + 2
  cuda_graph_padding cases grouped onto the shared 4-GPU session.
  test_guided_decoding_4gpus is excluded: it uses the bf16 checkpoint and
  sets TRTLLM_XGUIDANCE_LENIENT via mocker, which cannot reach workers of
  a pre-spawned pool (env is snapshotted at spawn).
- GPTOSS (H100 + GB200): one union w4_4gpus premerge matrix; each
  platform's test-db yml selects its own case ids. Only non-waived cases
  are in the matrix -- moving a waived case to a new (grouped) test id
  would silently un-waive it. test_w4a16 is excluded (OVERRIDE_QUANT_ALGO
  env cannot reach pre-spawned workers).
- Llama3.3-70B (GB200): fp8_tp4 x2, nvfp4_tp4 x2 and fp4_tp2pp2
  (fusion=False only: the TRTLLM_GEMM_ALLREDUCE_FUSION_ENABLED patch
  cannot reach pre-spawned workers, and False matches the default).
- NemotronV3 Super/Ultra (GB200): block_reuse / parallelism / mtp_ar
  cases grouped; online_eplb cases deferred pending an EPLB
  shared-state-on-reused-workers audit.
- DeepSeekV32 (B200, new shared 8-GPU session fixture): nvfp4 baselines
  and piecewise_cuda_graph[baseline] share one FP4-v2 weight-cache entry.
  DeepSeekR1 groups were dropped: all member cases are currently waived.

Also fix a latent bug: test-list matching is exact-nodeid
(test_list_parser.modify_by_test_list), so the earlier unbracketed
premerge_grouped yml entries never matched any collected test. All
grouped entries (including the existing DeepSeekV3Lite nvfp4/bf16 ones)
now list fully-parametrized ids; yml order keeps same-checkpoint cases
adjacent so the weight-cache LRU (max_entries=1) stays hot.

Verified: pytest --collect-only shows a 1:1 match between all 58 grouped
yml entries and collected node ids; the 342 original parametrized cases
still collect unchanged.

Signed-off-by: qgai <qgai@nvidia.com>
@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57166 [ kill ] triggered by Bot. Commit: c96e862 Link to invocation

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

PR_Github #57161 [ run ] completed with state ABORTED. Commit: f94c700

Link to invocation

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds an LRU cache for HuggingFace checkpoint weights, introduces MPI session ownership tracking across executor/proxy/LLM components to avoid shutting down externally-owned sessions, and adds grouped-test infrastructure plus test suite refactors enabling shared MPI sessions/LLM instances across many multi-GPU accuracy and unit tests.

Changes

Weight caching and MPI session ownership

Layer / File(s) Summary
PP communicator reuse
tensorrt_llm/_torch/distributed/communicator.py
init_pp_comm reuses an existing PPCommNCCL when world_size matches, refreshing its mapping instead of recreating it.
HF weight loader caching
tensorrt_llm/_torch/models/checkpoints/hf/weight_loader.py, tests/unittest/_torch/models/checkpoints/hf/test_weight_loader.py
Adds a global thread-safe LRU cache for checkpoint weights keyed by file fingerprint, with cache hit/miss handling, eviction, MPI barrier on hits, and new unit tests.
MPI session ownership tracking
tensorrt_llm/executor/executor.py, tensorrt_llm/executor/proxy.py, tensorrt_llm/executor/rpc_proxy.py, tensorrt_llm/llmapi/llm.py
Adds _owns_mpi_session flags so shutdown only occurs for internally-created sessions, and passes mpi_session through to IPC executor creation.

Grouped multi-GPU test infrastructure and coverage

Layer / File(s) Summary
Grouped test utility module
tensorrt_llm/llmapi/_grouped_test_utils.py
New module with helpers for HF weight-cache env setup, shared MPI session creation, worker compile-state reset, weight-cache clearing, and a shared LLM factory.
Accuracy test grouped fixtures and cases
tests/integration/defs/accuracy/test_llm_api_pytorch.py
Adds shared fixtures for weight cache/MPI sessions/LLM and numerous *_premerge_grouped test methods across multiple model test classes using make_llm.
Multi-GPU pytest module refactor
tests/unittest/llmapi/test_llm_multi_gpu_pytorch.py, tests/unittest/llmapi/test_llm.py
Refactors standalone functions into TestLlmMultiGpu2gpu/TestLlmMultiGpu4gpu classes with shared fixtures, and extends test harnesses with extra_llm_kwargs and shutdown cleanup.
Test list and waiver updates
tests/integration/test_lists/test-db/l0_dgx_b200.yml, l0_dgx_h100.yml, l0_gb200_multi_gpus.yml, tests/integration/test_lists/waives.txt
Replaces non-grouped test entries with *_premerge_grouped variants and updates the waived test identifier to a class-qualified name.

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

Sequence Diagram(s)

sequenceDiagram
  participant HfWeightLoader
  participant WeightCache
  participant Disk

  HfWeightLoader->>WeightCache: compute cache key (file stat + use_consolidated)
  alt cache hit
    WeightCache-->>HfWeightLoader: return cached weights
    HfWeightLoader->>HfWeightLoader: local_mpi_barrier()
  else cache miss
    WeightCache->>WeightCache: evict LRU entry
    HfWeightLoader->>Disk: load weights in parallel
    Disk-->>HfWeightLoader: raw weights
    HfWeightLoader->>WeightCache: store loaded weights
  end
Loading
sequenceDiagram
  participant TestCase
  participant SharedMpiSession
  participant MakeSharedLlm
  participant Worker

  TestCase->>SharedMpiSession: request shared MpiPoolSession
  SharedMpiSession-->>TestCase: session
  TestCase->>MakeSharedLlm: build LLM factory(mpi_session)
  MakeSharedLlm->>Worker: construct LLM with _mpi_session kwarg
  TestCase->>Worker: run inference
  TestCase->>Worker: reset_worker_torch_compile_state / clear_worker_weight_cache
Loading

Suggested reviewers: leslie-fang25, yingguo-trt, byshiue

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
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.
Title check ✅ Passed The title is concise, specific, and accurately summarizes the main change to shared MPI sessions and HF weight caching.
Description check ✅ Passed The description explains the change and test plan well, but it does not follow the template's Description/Test Coverage/PR Checklist headings exactly.
✨ 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.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tensorrt_llm/executor/proxy.py (1)

442-446: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

shutdown_abort() on worker-init failure bypasses _owns_mpi_session, can kill a shared/external session.

Line 531-532 correctly guards the graceful shutdown path with _owns_mpi_session, but the abort path at line 444 (triggered when a worker fails during initialization) still unconditionally calls self.mpi_session.shutdown_abort(...). For an externally-owned (e.g. grouped-test shared MpiPoolSession) session, this forcibly destroys it, cascading the failure to all other consumers of that shared session — the exact outcome this PR's ownership tracking is meant to prevent.

🛡️ Proposed fix
         if ready_signal != GenerationExecutorProxy.READY_SIGNAL:
             logger.error(f"Executor worker initialization error: {error_trace}")
-            self.mpi_session.shutdown_abort(reason=ready_signal)
+            if self._owns_mpi_session:
+                self.mpi_session.shutdown_abort(reason=ready_signal)
             raise RuntimeError(
                 "Executor worker returned error") from ready_signal

Also applies to: 531-532

🤖 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 `@tensorrt_llm/executor/proxy.py` around lines 442 - 446, The worker-init
failure path in GenerationExecutorProxy._get_worker_ready unconditionally calls
self.mpi_session.shutdown_abort, which can destroy an externally owned shared
MpiPoolSession. Update the abort handling to follow the same _owns_mpi_session
ownership guard used in the graceful shutdown path, and only abort the MPI
session when this proxy owns it. Keep the logger.error and RuntimeError behavior
in place, but avoid calling shutdown_abort on shared/external sessions.
🧹 Nitpick comments (1)
tests/unittest/_torch/models/checkpoints/hf/test_weight_loader.py (1)

103-208: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Coverage is insufficient for the bin/pth cache path.

The new tests only create .safetensors files, but HfWeightLoader.load_weights() has a separate .bin/.pth cache branch. Add at least one cache-hit test in tests/unittest/_torch/models/checkpoints/hf/test_weight_loader.py using model.bin or model.pth so both changed loader paths are covered. As per path instructions, coverage for this test file is currently insufficient for the changed branches.

🤖 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/models/checkpoints/hf/test_weight_loader.py` around
lines 103 - 208, Add a cache-hit test in test_weight_loader.py that exercises
the .bin/.pth branch of HfWeightLoader.load_weights, since the current coverage
only uses .safetensors and misses the separate cache path. Reuse the existing
HfWeightLoader, ConsumableWeightsDict, and mock.patch.object patterns, but
create a checkpoint with model.bin or model.pth and assert the second load hits
the cache and does not call _load_weights_in_parallel again. Keep the existing
cache cleanup via HfWeightLoader._clear_weight_cache.

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.

Inline comments:
In `@tensorrt_llm/_torch/models/checkpoints/hf/weight_loader.py`:
- Around line 55-71: The HF weight cache disabling logic is incomplete because
_weight_cache_max_entries() can return 0 for max_entries=0 or invalid values,
but load_weights() still performs cache reads through _get_cached_weights() when
_is_weight_cache_enabled() is true. Update the cache gating in load_weights()
(and any shared cache path around _get_cached_weights()/cache population) so a
max entries value of 0 or a parse failure disables both reads and writes,
preventing stale cached weights from being reused or retained in memory.

In `@tests/integration/defs/accuracy/test_llm_api_pytorch.py`:
- Around line 77-87: The remaining late imports from _grouped_test_utils in
test_llm_api_pytorch still violate E402, so update the import block to either
add # noqa: E402 to each of the remaining imports or move the entire grouped
import block above patch_mpi_pool_session_for_env(). Use the existing symbols
clear_worker_weight_cache, hf_weight_cache_env, make_shared_llm,
reset_shared_session_torch_compile_state, and shared_mpi_session to locate the
affected imports.

In `@tests/unittest/_torch/models/checkpoints/hf/test_weight_loader.py`:
- Line 104: The cache-enabled test is inheriting an external
TRTLLM_HF_WEIGHT_CACHE_MAX_ENTRIES value, which can make the test fail for
unrelated environment reasons. In the cache setup around the monkeypatch in
test_weight_loader, explicitly set TRTLLM_HF_WEIGHT_CACHE_MAX_ENTRIES to a known
positive value or remove it before the weight loader is exercised, so the
behavior is controlled within the test.

---

Outside diff comments:
In `@tensorrt_llm/executor/proxy.py`:
- Around line 442-446: The worker-init failure path in
GenerationExecutorProxy._get_worker_ready unconditionally calls
self.mpi_session.shutdown_abort, which can destroy an externally owned shared
MpiPoolSession. Update the abort handling to follow the same _owns_mpi_session
ownership guard used in the graceful shutdown path, and only abort the MPI
session when this proxy owns it. Keep the logger.error and RuntimeError behavior
in place, but avoid calling shutdown_abort on shared/external sessions.

---

Nitpick comments:
In `@tests/unittest/_torch/models/checkpoints/hf/test_weight_loader.py`:
- Around line 103-208: Add a cache-hit test in test_weight_loader.py that
exercises the .bin/.pth branch of HfWeightLoader.load_weights, since the current
coverage only uses .safetensors and misses the separate cache path. Reuse the
existing HfWeightLoader, ConsumableWeightsDict, and mock.patch.object patterns,
but create a checkpoint with model.bin or model.pth and assert the second load
hits the cache and does not call _load_weights_in_parallel again. Keep the
existing cache cleanup via HfWeightLoader._clear_weight_cache.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b5ebd729-f52d-4441-acf7-a2d78f3e27e2

📥 Commits

Reviewing files that changed from the base of the PR and between e5a05b2 and f94c700.

📒 Files selected for processing (15)
  • tensorrt_llm/_torch/distributed/communicator.py
  • tensorrt_llm/_torch/models/checkpoints/hf/weight_loader.py
  • tensorrt_llm/executor/executor.py
  • tensorrt_llm/executor/proxy.py
  • tensorrt_llm/executor/rpc_proxy.py
  • tensorrt_llm/llmapi/_grouped_test_utils.py
  • tensorrt_llm/llmapi/llm.py
  • tests/integration/defs/accuracy/test_llm_api_pytorch.py
  • tests/integration/test_lists/test-db/l0_dgx_b200.yml
  • tests/integration/test_lists/test-db/l0_dgx_h100.yml
  • tests/integration/test_lists/test-db/l0_gb200_multi_gpus.yml
  • tests/integration/test_lists/waives.txt
  • tests/unittest/_torch/models/checkpoints/hf/test_weight_loader.py
  • tests/unittest/llmapi/test_llm.py
  • tests/unittest/llmapi/test_llm_multi_gpu_pytorch.py

Comment on lines +55 to +71
def _is_weight_cache_enabled() -> bool:
return os.environ.get(_WEIGHT_CACHE_ENV,
"0").lower() in ("1", "true", "yes", "on")

@staticmethod
def _weight_cache_max_entries() -> int:
try:
return max(
0,
int(
os.environ.get(_WEIGHT_CACHE_MAX_ENTRIES_ENV,
_DEFAULT_WEIGHT_CACHE_MAX_ENTRIES)))
except ValueError:
logger.warning(
f"Invalid {_WEIGHT_CACHE_MAX_ENTRIES_ENV} value; disabling HF weight cache."
)
return 0

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Make max_entries=0/invalid disable reads too.

_weight_cache_max_entries() returns 0 for invalid values and logs that the cache is disabled, but load_weights() still calls _get_cached_weights() when TRTLLM_HF_WEIGHT_CACHE is truthy. If the cache was previously populated, stale entries can still be returned and kept in memory despite TRTLLM_HF_WEIGHT_CACHE_MAX_ENTRIES=0 or an invalid value.

Proposed fix
     `@staticmethod`
     def _is_weight_cache_enabled() -> bool:
-        return os.environ.get(_WEIGHT_CACHE_ENV,
-                              "0").lower() in ("1", "true", "yes", "on")
+        enabled = os.environ.get(_WEIGHT_CACHE_ENV,
+                                 "0").lower() in ("1", "true", "yes", "on")
+        if not enabled:
+            HfWeightLoader._clear_weight_cache()
+            return False
+        if HfWeightLoader._weight_cache_max_entries() <= 0:
+            HfWeightLoader._clear_weight_cache()
+            return False
+        return True

Also applies to: 125-131

🤖 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 `@tensorrt_llm/_torch/models/checkpoints/hf/weight_loader.py` around lines 55 -
71, The HF weight cache disabling logic is incomplete because
_weight_cache_max_entries() can return 0 for max_entries=0 or invalid values,
but load_weights() still performs cache reads through _get_cached_weights() when
_is_weight_cache_enabled() is true. Update the cache gating in load_weights()
(and any shared cache path around _get_cached_weights()/cache population) so a
max entries value of 0 or a parse failure disables both reads and writes,
preventing stale cached weights from being reused or retained in memory.

Comment on lines +77 to +87
from tensorrt_llm.llmapi._grouped_test_utils import \
clear_worker_weight_cache as _clear_worker_weight_cache # noqa: E402
from tensorrt_llm.llmapi._grouped_test_utils import \
hf_weight_cache_env as _hf_weight_cache_env
from tensorrt_llm.llmapi._grouped_test_utils import \
make_shared_llm as _make_shared_llm
from tensorrt_llm.llmapi._grouped_test_utils import \
reset_shared_session_torch_compile_state as \
_reset_shared_session_torch_compile_state
from tensorrt_llm.llmapi._grouped_test_utils import \
shared_mpi_session as _shared_mpi_session

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect what precedes these imports to determine whether E402 is actually triggered here.
sed -n '1,90p' tests/integration/defs/accuracy/test_llm_api_pytorch.py

Repository: NVIDIA/TensorRT-LLM

Length of output: 3906


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check whether this file or test subtree is exempt from E402 elsewhere in config.
rg -n --hidden --glob '!**/.git/**' 'E402|ignore\s*=|per-file-ignores|extend-per-file-ignores' \
  pyproject.toml ruff*.toml .pre-commit-config.yaml tests || true

# Inspect the exact import block and the preceding code shape with line numbers.
sed -n '1,110p' tests/integration/defs/accuracy/test_llm_api_pytorch.py

Repository: NVIDIA/TensorRT-LLM

Length of output: 14244


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Run Ruff on the file to see exactly which lines, if any, trigger E402.
ruff check --select E402 tests/integration/defs/accuracy/test_llm_api_pytorch.py || true

# Show the import block with line numbers for mapping diagnostics to statements.
nl -ba tests/integration/defs/accuracy/test_llm_api_pytorch.py | sed -n '70,90p'

Repository: NVIDIA/TensorRT-LLM

Length of output: 2994


Add # noqa: E402 to the remaining _grouped_test_utils imports
tests/integration/defs/accuracy/test_llm_api_pytorch.py:79-86 — the last four late imports still trigger E402; either suppress each one or move the whole block above patch_mpi_pool_session_for_env().

🤖 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/integration/defs/accuracy/test_llm_api_pytorch.py` around lines 77 -
87, The remaining late imports from _grouped_test_utils in test_llm_api_pytorch
still violate E402, so update the import block to either add # noqa: E402 to
each of the remaining imports or move the entire grouped import block above
patch_mpi_pool_session_for_env(). Use the existing symbols
clear_worker_weight_cache, hf_weight_cache_env, make_shared_llm,
reset_shared_session_torch_compile_state, and shared_mpi_session to locate the
affected imports.



def test_weight_cache_reuses_raw_weights_with_fresh_consumable_wrapper(tmp_path, monkeypatch):
monkeypatch.setenv("TRTLLM_HF_WEIGHT_CACHE", "1")

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Isolate TRTLLM_HF_WEIGHT_CACHE_MAX_ENTRIES in cache-enabled tests.

This test enables the cache but inherits any outer TRTLLM_HF_WEIGHT_CACHE_MAX_ENTRIES; a developer/CI env value of 0 or invalid text can make the cache test fail for the wrong reason. Set it to a known positive value or delete it before loading.

Proposed fix
 def test_weight_cache_reuses_raw_weights_with_fresh_consumable_wrapper(tmp_path, monkeypatch):
     monkeypatch.setenv("TRTLLM_HF_WEIGHT_CACHE", "1")
+    monkeypatch.delenv("TRTLLM_HF_WEIGHT_CACHE_MAX_ENTRIES", raising=False)
     HfWeightLoader._clear_weight_cache()
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
monkeypatch.setenv("TRTLLM_HF_WEIGHT_CACHE", "1")
monkeypatch.setenv("TRTLLM_HF_WEIGHT_CACHE", "1")
monkeypatch.delenv("TRTLLM_HF_WEIGHT_CACHE_MAX_ENTRIES", raising=False)
🤖 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/models/checkpoints/hf/test_weight_loader.py` at line
104, The cache-enabled test is inheriting an external
TRTLLM_HF_WEIGHT_CACHE_MAX_ENTRIES value, which can make the test fail for
unrelated environment reasons. In the cache setup around the monkeypatch in
test_weight_loader, explicitly set TRTLLM_HF_WEIGHT_CACHE_MAX_ENTRIES to a known
positive value or remove it before the weight loader is exercised, so the
behavior is controlled within the test.

@tensorrt-cicd

Copy link
Copy Markdown
Collaborator

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

Link to invocation


@pytest.fixture(scope="module")
def shared_mpi_session_8gpu(hf_weight_cache):
# See shared_mpi_session_4gpu for why hf_weight_cache must be set up before

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.

Nit: why not move the comment from shared_mpi_session_4gpu into the _shared_mpi_session helper? (Can be done in a future PR though).

@sunnyqgg sunnyqgg closed this Jul 14, 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.

3 participants