[None][perf] Add TRTLLM_DSV4_MEM_OPTS master switch for DSv4 memory optimizations - #14053
[None][perf] Add TRTLLM_DSV4_MEM_OPTS master switch for DSv4 memory optimizations#14053qiaoxj07 wants to merge 3 commits into
Conversation
ec142b3 to
cb66e08
Compare
|
/bot run --disable-fail-fast |
|
PR_Github #48162 [ run ] triggered by Bot. Commit: |
|
PR_Github #48162 [ run ] completed with state |
0a93d10 to
118e7a5
Compare
…ptimizations Introduce a single env switch TRTLLM_DSV4_MEM_OPTS that turns on three sized-from-runtime-config memory optimizations together. Validated end to end on DSv4-Pro on GB300 (bench 49,127 tok/s, gsm8k 96.25% on 1319 samples). 1. Rope cos/sin table cap. tensorrt_llm/_torch/attention_backend/interface.py adds RopeParams.from_config auto-cap of max_positions to runtime max_seq_len when the master switch is on. Yarn cos/sin at position p depends only on p and the yarn constants (which use original_max_position_embeddings, not the table size), so truncating to max_seq_len yields identical values for indices < cap. tensorrt_llm/_torch/models/modeling_deepseekv4.py plumbs llm_args.max_seq_len onto the HF PretrainedConfig so from_config can see it. 2. Attention workspace pre-allocation. tensorrt_llm/_torch/attention_backend/ trtllm.py sizes the workspace at AttentionMetadata.__init__ time from the live model_config using an empirically validated formula (2 x max_num_tokens x num_heads x head_size x bytes_per_elt x 1.25 for paged-context FMHA, with MLA / attention-DP / FP8-KV awareness). Without this, the C++ runtime's lazy `workspace_.value().resize_(...)` tries a single 0 -> ~1.6 GiB jump during warmup at large max_num_tokens, fails under tight memory, and leaves CUDA state degraded enough that the MoE kernel later hits CUDA_ERROR_LAUNCH_FAILED on a real forward. AttentionMetadata gains an optional model_config field; tensorrt_llm/_torch/pyexecutor/model_engine.py wires it in. 3. MHC pool routing. tensorrt_llm/_torch/modules/mhc/mhc_cuda.py routes _FusedHcWorkspaceCache outputs (residual_cur, post_mix_cur, etc.) through the global Buffers pool so MHC scratch can share backing memory with other layer-transient buffers. For DSv4-Pro ctx-only shapes the resulting alignment is naturally 128-byte friendly, so TMA descriptor encoding does not fail. All three are gated on a single TRTLLM_DSV4_MEM_OPTS env (truthy = on). There are no per-feature knobs; the optimizations are auto-sized from the live config. With the switch off (default), behavior is byte-identical to current source. Reproduction config and per-stage PyTorch memory snapshots are recorded out-of-tree under bench-mewtwo/claude_opt/optims_final_20260512.md and bench-mewtwo/claude_opt/mem_opts_profile_compare_20260512.md. Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
…id rank-divergent deadlock With ADP + MoE EP, different ranks see different per-expert routing shapes, so the result of profiling_cache.search_cache (is_cache_hit) can diverge across ranks. The slow path below ends in _maybe_sync_cache_data, which issues a TP/CP collective (allgather or broadcast). If some ranks early-return at the cache-hit shortcut while others enter the collective, the collective deadlocks. This patch makes the early-return decision a collective vote: every rank runs tp_cp_allgather(is_cache_hit) and only short-circuits if ALL ranks hit. The allgather is unconditional (not gated on local is_cache_hit) so that hit and miss ranks all participate symmetrically. Validated on DSv4-Pro ctx-only with TP=4 EP=4, gpu_frac=0.5: 4/5 jobs PASS bench (50.4-50.7k tok/s) + gsm8k (96.40-96.47%). The remaining 1/5 failure is a different rank-divergent issue inside _profile_runners (PARALLEL strategy distributes tactics across ranks and MoE forward calls on different tactics can desync on internal all-to-all collectives); not addressed by this patch. Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
7313f54 to
3886f92
Compare
…ream PR NVIDIA#14126 NVIDIA#14126 ("Fail loudly on asymmetric warmup batch under attention-DP") addresses the same rank-divergent warmup-config failure mode this PR previously patched in `_get_max_shape_warmup_requests`. Its philosophy (raise RuntimeError with diagnostics, ask user to bump `--kv_cache_free_gpu_mem_fraction`) is more conservative than the silent fix-and-proceed we had here, and keeps the warmup contract explicit. To avoid duplicating the upstream effort and to reduce review surface in this PR, drop the local synchronization. The remaining fixes (autotuner pre/post barriers and AutoTuner.choose_one collective vote) are independent and stay. Note: this revert is safe only if PR NVIDIA#14126 (or an equivalent) lands before merging this branch into mainline. If neither lands, the rank-divergent warmup-config deadlock remains observable on DSv4-Pro ADP runs and would need to be re-introduced. Signed-off-by: Xianjie <5410381+qiaoxj07@users.noreply.github.com>
|
/bot run --disable-fail-fast |
|
PR_Github #48349 [ run ] triggered by Bot. Commit: |
|
PR_Github #48349 [ run ] completed with state
|
|
/bot run --disable-fail-fast |
|
PR_Github #48407 [ run ] triggered by Bot. Commit: |
|
PR_Github #48407 [ run ] completed with state |
|
/bot run --disable-fail-fast |
|
PR_Github #48736 [ run ] triggered by Bot. Commit: |
|
PR_Github #48736 [ run ] completed with state
|
…s pool Add an opt-in path in _FusedHcWorkspaceCache.get that routes the four output buffers (residual_cur, post_mix_cur, comb_mix_cur, layer_input_cur) and the three internal scratch buffers (y_acc_ws, r_acc_ws, done_counter_ws) through get_memory_buffers() so MHC scratch can share backing memory with other layer-transient buffers (e.g., the attention workspace). The env switch TRTLLM_DSV4_MEM_OPTS is read once at class definition (cached as _USE_POOL) so the lookup doesn't run on every workspace request. Pool routing is gated to decode-sized B (B <= _CACHE_MAX_B). For B > _CACHE_MAX_B (prefill), the code falls through to fresh torch.empty per call, matching the upstream uncached path; this preserves prefill's no-aliasing semantics where layer N's *_prev inputs and layer N+1's *_cur outputs live in distinct tensors. At decode, upstream's existing per-runner LRU already returns the same tensor across layers, so the kernel is already in-place safe; pool routing inherits that aliasing without widening it. With TRTLLM_DSV4_MEM_OPTS off (default), behavior is byte-identical to current source. Split out from PR NVIDIA#14053 (DSv4 mem-opts master switch) and from PR NVIDIA#14241 (RoPE cap + MHC pool): this PR contains only the MHC pool routing piece, still gated on TRTLLM_DSV4_MEM_OPTS so it can be validated in isolation. Signed-off-by: Lanyu Liao <lancelly@users.noreply.github.com>
Summary
Two related categories of changes for DSv4-Pro on GB300 with attention-DP (ADP) + MoE EP:
TRTLLM_DSV4_MEM_OPTS(the original scope of this PR).tp_barrieraround_run_autotuner_warmupand a collective-vote on cache-hit inAutoTuner.choose_one. These are unconditional (not gated on the mem-opts env switch).A complementary rank-divergent-warmup-batch issue is addressed by upstream PR #14126; the local fix that previously lived in this branch has been reverted to defer to that PR.
With
TRTLLM_DSV4_MEM_OPTSoff (default), behavior is byte-identical to current source for the mem-opts code paths. The autotuner fixes are unconditional but only affect the autotuner warmup phase, not steady-state inference.What's in the env switch (
TRTLLM_DSV4_MEM_OPTS=1)Rope cos/sin table cap —
tensorrt_llm/_torch/attention_backend/interface.pyaddsRopeParams.from_configauto-cap ofmax_positionsto runtimemax_seq_len. Yarn cos/sin at positionpdepends only onpand yarn constants (which useoriginal_max_position_embeddings, not table size), so truncating tomax_seq_lenyields identical values for indices< cap.tensorrt_llm/_torch/models/modeling_deepseekv4.pyplumbsllm_args.max_seq_lenonto the HFPretrainedConfigsofrom_configcan see it.Attention workspace pre-allocation —
tensorrt_llm/_torch/attention_backend/trtllm.pysizes the workspace atAttentionMetadata.__init__time from the livemodel_configusing an empirically validated formula (2 × max_num_tokens × num_heads × head_size × bytes_per_elt × 1.25for paged-context FMHA, MLA / ADP / FP8-KV aware). Without this, the C++ runtime's lazyworkspace_.value().resize_(...)tries a single0 → ~1.6 GiBjump during warmup at largemax_num_tokens, fails under tight memory, and leaves CUDA state degraded enough that the MoE kernel later hitsCUDA_ERROR_LAUNCH_FAILED.AttentionMetadatagains an optionalmodel_configfield;tensorrt_llm/_torch/pyexecutor/model_engine.pywires it in.MHC pool routing —
tensorrt_llm/_torch/modules/mhc/mhc_cuda.pyroutes_FusedHcWorkspaceCacheoutputs (residual_cur,post_mix_cur, etc.) through the globalBufferspool so MHC scratch can share backing memory with other layer-transient buffers. For DSv4-Pro ctx-only shapes the resulting alignment is naturally 128-byte friendly so TMA descriptor encoding does not fail.Autotuner deadlock fixes (always on, gated by
tp_size > 1)4. Pre/post
tp_barrieraround_run_autotuner_warmupSymptom: when
Cache size after warmup is 0, the autotuner exits near-instantly on ranks that already had cache, while a slower rank is still inside its own autotuner. Faster ranks race ahead into the next collective-issuing_general_warmupstep → mismatched collectives → silent hang.Fix: bracket
_run_autotuner_warmupwith TP-group barriers so every rank enters and exits the autotuner together.5.
AutoTuner.choose_onecollective vote on cache hitSymptom: with ADP + MoE EP, different ranks see different per-expert routing shapes →
is_cache_hitdiverges across ranks. The slow path ofchoose_oneends in_maybe_sync_cache_data, which issues a TP/CP collective (allgather/broadcast). If some ranks early-return at the cache-hit shortcut while others enter the collective, the collective deadlocks.Fix: insert an unconditional
tp_cp_allgather(is_cache_hit)collective vote inchoose_one. Every rank participates in the allgather regardless of local cache state. Only short-circuit when all ranks hit.The collective must be unconditional (not gated on local
is_cache_hit) — otherwise hit ranks call the allgather while miss ranks skip it, recreating the deadlock at the vote site.Related upstream PR
NVIDIA/TensorRT-LLM#14126 ("Fail loudly on asymmetric warmup batch under attention-DP") addresses a separate but related rank-divergent failure mode where
_create_warmup_requestreturnsNoneon some ranks but not others. An earlier version of this branch had a localtp_allgather + minfix oncurr_max_num_tokensfor the same symptom (silent fix-and-proceed); it has been reverted in7ff13466b7to defer to #14126's fail-loudly approach and reduce review surface.Validation
1-job baseline (single ctx-only run, batch=2, max_seq=8192, TP=4 EP=4, ADP on)
5-job parallel (same config, all required env on)
4/5 = 80% pass rate, up from ~0% without these fixes and ~60% with only
expandable_segments.Required env (for parallel-job runs)
(The PR code is correct without
expandable_segments; that env reduces an upstream OOM-cascade failure mode in concurrent runs.)Memory footprint (rank 0, DSv4-Pro GB300 TP=4)
stage_end_model_engine_warmupTest plan
trtllm-eval gsm8k(1319 samples, max_batch=64, max_seq=2048): 96.02–96.89% ✓Files touched
Open follow-ups (not in this PR)
PARALLELstrategy tactic-split desync — in_profile_runners,_maybe_parallelize_tacticsdistributes tactics across ranks (each rank profiles1/N). MoE forward has internal NCCL all-to-all that requires all ranks at the same dispatch payload. Different per-rank tactics → mismatched payloads → dispatch timeout. Proposed 1-line fix: changeMoERunner.tuning_config.distributed_tuning_strategyfromPARALLELtoINDEPENDENTso all ranks profile all tactics in the same order. Validated as the root cause for the 1/5 failure in 5-job parallel; deferred to a follow-up PR to keep this one focused.getWorkspaceSizeForContextfrom C++ so the Python pre-alloc matches the runtime's request exactly (currently the heuristic undersizes by ~20 MiB and the C++ side does one quiet resize).Buffers._view_asto pad to a 128-byte aligned offset so the MHC pool is safe for all models, not just DSv4-Pro shapes.🤖 Generated with Claude Code