Skip to content

[TRTLLM-14867][feat] Auto-tuning for split-K in LoRA grouped GEMM - #17315

Draft
AlessioNetti wants to merge 20 commits into
NVIDIA:mainfrom
AlessioNetti:lora-splitk-autotuning
Draft

[TRTLLM-14867][feat] Auto-tuning for split-K in LoRA grouped GEMM#17315
AlessioNetti wants to merge 20 commits into
NVIDIA:mainfrom
AlessioNetti:lora-splitk-autotuning

Conversation

@AlessioNetti

@AlessioNetti AlessioNetti commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Added automatic split-K tuning for LoRA grouped GEMM.
  • Added _LoraGroupedGemmRunner and ModelEngine.maybe_autotune_lora().
  • Added LoRA autotuner tests and Qwen3 BF16/FP8 overlap tests.

Dev Engineer Review

  • Verify valid split-K tactics for all supported grouped GEMM shapes.
  • Verify API consistency and error handling for invalid layer_idx and autotuner inputs.

QA Engineer Review

Added or modified tests for:

  • LoRA autotuner profile selection, default split-K behavior, runner reuse, synthetic inputs, and CUDA graph slot metadata.

No tests/integration/test_lists/, test-db/, or qa/ coverage entries are identified for these tests. CI or manual-QA coverage requires verification.

Verdict: needs follow-up

Description

NOTE: this PR is based on and should be merged only after 16951.

As of TRT-LLM 1.3.0rc23, the grouped GEMM kernel used for LoRA (in tensorrt_llm/_torch/peft/lora/layer.py) uses a hardcoded split-K value of 16, which might not be ideal for all workloads. This PR addresses this by introducing auto-tuning for the split-K value, allowing to find and use optimal split-K values depending on the LoRA module, hidden size as well as GPU type.

This was achieved by introducing a new _LoraGroupedGemmRunner, which encapsulates all logic required in order to auto-tune LoraLayer._forward_cuda_graph_mode(). Small changes were required in model_engine.py as well, in order to perform one more auto-tuning pass during CUDA graph warmup (as the grouped GEMM kernel in question is only used in the CUDA graph path).

Below you can find a latency comparison, benchmarked using a Qwen3 32B FP8 model, 256 ISL/OSL and a rank 32 LoRA adapter (gate_up_proj, down_proj, qkv_proj and o_proj modules), on H100. We are also showing performance achieved as of PR 16951, upon which this PR is based, as a reference point.

plot_optim_ksplit_v2

Test Coverage

Any test that uses LoRA with CUDA graphs and auto-tuning enabled, such as tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py. Additional auto-tuner focused tests were added in tests/unittest/_torch/lora/test_lora_autotuner.py.

Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
…o empty_like() for init

Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The change adds shared base-and-LoRA forwarding, optional CUDA-stream overlap, and CUDA-graph grouped-GEMM split-K autotuning. Model warmup coordinates autotuning, and tests cover runner behavior, synthetic inputs, and Qwen3 overlap execution.

Changes

LoRA execution changes

Layer / File(s) Summary
Overlap configuration and stream wiring
tensorrt_llm/lora_helper.py, tensorrt_llm/_torch/peft/lora/cuda_graph_lora_manager.py, tensorrt_llm/_torch/pyexecutor/model_engine.py, tensorrt_llm/usage/llm_args_golden_manifest.json
Adds LoraConfig.overlap_lora_and_base, creates an optional auxiliary CUDA stream, and passes it through CUDA-graph LoRA parameters.
Shared base and LoRA forwarding
tensorrt_llm/_torch/peft/lora/layer.py, tensorrt_llm/_torch/modules/attention.py, tensorrt_llm/_torch/modules/gated_mlp.py, tensorrt_llm/_torch/modules/linear.py, tensorrt_llm/_torch/modules/mlp.py
Adds LoraLayer.forward_with_base and updates projection paths to combine base and LoRA outputs through it.
CUDA-graph split-K autotuning
tensorrt_llm/_torch/peft/lora/layer.py, tensorrt_llm/_torch/pyexecutor/model_engine.py
Adds grouped-GEMM runner reuse, synthetic tuning inputs, split-K selection, copied parameters, and autotuner coordination during CUDA-graph warmup.
Autotuner and overlap validation
tests/unittest/_torch/lora/test_lora_autotuner.py, tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py
Tests split-K profile selection, runner reuse, synthetic inputs, and BF16 and FP8 Qwen3 overlap execution.

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

Suggested reviewers: qijune, bowenfu, brnguyen2

Sequence Diagram(s)

sequenceDiagram
  participant ModelEngine
  participant CudaGraphLoraManager
  participant ProjectionModules
  participant LoraLayer
  participant LoraGroupedGemmRunner
  ModelEngine->>CudaGraphLoraManager: prepare_cuda_graph_lora_params()
  CudaGraphLoraManager-->>ModelEngine: return LoRA parameters and auxiliary stream
  ProjectionModules->>LoraLayer: call forward_with_base(...)
  LoraLayer->>ProjectionModules: execute base projection
  LoraLayer->>LoraGroupedGemmRunner: autotune split-K and run grouped GEMM
  LoraGroupedGemmRunner-->>LoraLayer: return LoRA output
  LoraLayer-->>ProjectionModules: accumulate base and LoRA outputs
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.84% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
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 clearly and concisely describes the main change: split-K auto-tuning for LoRA grouped GEMM.
Description check ✅ Passed The description explains the problem, solution, dependency, performance context, and relevant test coverage.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 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: 2

🧹 Nitpick comments (3)
tests/unittest/_torch/lora/test_lora_autotuner.py (1)

35-193: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add required function annotations.

New test functions and local test doubles omit parameter or return annotations.

  • tests/unittest/_torch/lora/test_lora_autotuner.py#L35-L193: annotate test functions and local fake methods.
  • tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py#L152-L212: annotate _run_lora_test and the new test functions.

As per coding guidelines, **/*.py requires: “Annotate every function.”

🤖 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/lora/test_lora_autotuner.py` around lines 35 - 193, Add
type annotations to every function introduced in these LoRA test files: update
the test functions in tests/unittest/_torch/lora/test_lora_autotuner.py and the
helper/test functions in
tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py, including
local fake methods like FakeLayerParams.__init__,
FakeCudaGraphParams.__init__/get_layer_params/get_problem_count,
FakeTuner.choose_one, and fake_forward_impl. Keep the existing test behavior
unchanged while adding parameter and return annotations consistently across the
affected symbols.

Source: Coding guidelines

tensorrt_llm/_torch/peft/lora/cuda_graph_lora_manager.py (1)

32-32: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Align the constructor default with the config default.

LoraConfig.overlap_lora_and_base defaults to False in tensorrt_llm/lora_helper.py, but this parameter defaults to True. The only caller in this cohort passes the value explicitly, so behavior is correct today. A future caller that omits the argument would silently enable the auxiliary stream. Use False here so both defaults agree.

♻️ Proposed default alignment
-        overlap_lora_and_base: bool = True,
+        overlap_lora_and_base: bool = 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 `@tensorrt_llm/_torch/peft/lora/cuda_graph_lora_manager.py` at line 32, Update
the constructor parameter overlap_lora_and_base in the LoRA manager to default
to False, matching LoraConfig.overlap_lora_and_base and preserving explicitly
supplied values.
tensorrt_llm/_torch/peft/lora/layer.py (1)

858-891: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Skip the redundant copy_lora_params on the inference path.

_forward_cuda_graph_mode already assigns runner.lora_params = runner.copy_lora_params(lora_params) (Line 624). forward then copies the same structure again at Line 860. The second copy is only required when len(inputs) > 1, because that branch rebinds attributes on cuda_graph_params and layer_params.

On the inference path this runs once per LoRA layer per decode step and produces two dict allocations, two CudaGraphLoraParams shallow copies, and two LoraLayerParams copies that are immediately discarded. Copy only when the synthetic inputs are present.

♻️ Proposed refactor
         del kwargs
         assert self.lora_params is not None
-        lora_params = self.copy_lora_params(self.lora_params)
-        cuda_graph_params = lora_params['cuda_graph_params']
-        layer_params = cuda_graph_params.get_layer_params(self.layer_key)
-        assert layer_params is not None
 
         # The list of tensor input arguments is re-packed into
         # the local lora_params copy such that we can invoke
         # LoraLayer's _forward_cuda_graph_mode_impl().
         x = inputs[0]
-        if len(inputs) > 1:
+        if len(inputs) == 1:
+            # Inference path: reuse the copy made by _forward_cuda_graph_mode.
+            lora_params = self.lora_params
+        else:
+            # Tuning path: the synthetic tensors below overwrite fields on the
+            # copy, so isolate it from the caller's parameters.
+            lora_params = self.copy_lora_params(self.lora_params)
+            cuda_graph_params = lora_params['cuda_graph_params']
+            layer_params = cuda_graph_params.get_layer_params(self.layer_key)
+            assert layer_params is not None
             (
                 x,
                 cuda_graph_params.slot_counts,
🤖 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/peft/lora/layer.py` around lines 858 - 891, Update the
forward path around _forward_cuda_graph_mode_impl to avoid copying
self.lora_params when len(inputs) is 1, since the runner has already copied it.
Reuse self.lora_params directly for the normal inference path, and only call
copy_lora_params when len(inputs) > 1 before rebinding cuda_graph_params and
layer_params fields. Preserve the existing parameter setup and output behavior.
🤖 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/peft/lora/layer.py`:
- Around line 612-621: Update the _split_k_runner initialization in the relevant
CUDA-graph path to pass x.shape[-1] as input_hidden_size, matching
_forward_cuda_graph_mode_impl and preserving the correct hidden dimension for
both 2-D and 3-D inputs.

In `@tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py`:
- Around line 196-211: Strengthen the overlap coverage in
test_qwen3_bf16_lora_overlap and test_qwen3_fp8_lora_overlap by adding focused
assertions around LoraLayer.forward_with_base that confirm an auxiliary stream
is available and the parallel executor is entered. Ensure the tests fail when
overlap_lora_and_base is ignored or execution falls back to the serial path,
while preserving the existing output checks.

---

Nitpick comments:
In `@tensorrt_llm/_torch/peft/lora/cuda_graph_lora_manager.py`:
- Line 32: Update the constructor parameter overlap_lora_and_base in the LoRA
manager to default to False, matching LoraConfig.overlap_lora_and_base and
preserving explicitly supplied values.

In `@tensorrt_llm/_torch/peft/lora/layer.py`:
- Around line 858-891: Update the forward path around
_forward_cuda_graph_mode_impl to avoid copying self.lora_params when len(inputs)
is 1, since the runner has already copied it. Reuse self.lora_params directly
for the normal inference path, and only call copy_lora_params when len(inputs) >
1 before rebinding cuda_graph_params and layer_params fields. Preserve the
existing parameter setup and output behavior.

In `@tests/unittest/_torch/lora/test_lora_autotuner.py`:
- Around line 35-193: Add type annotations to every function introduced in these
LoRA test files: update the test functions in
tests/unittest/_torch/lora/test_lora_autotuner.py and the helper/test functions
in tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py,
including local fake methods like FakeLayerParams.__init__,
FakeCudaGraphParams.__init__/get_layer_params/get_problem_count,
FakeTuner.choose_one, and fake_forward_impl. Keep the existing test behavior
unchanged while adding parameter and return annotations consistently across the
affected symbols.
🪄 Autofix

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: fe310c79-065d-4aa2-ab96-4b8bdaea9c45

📥 Commits

Reviewing files that changed from the base of the PR and between a6aeaff and 1bf46c2.

📒 Files selected for processing (11)
  • tensorrt_llm/_torch/modules/attention.py
  • tensorrt_llm/_torch/modules/gated_mlp.py
  • tensorrt_llm/_torch/modules/linear.py
  • tensorrt_llm/_torch/modules/mlp.py
  • tensorrt_llm/_torch/peft/lora/cuda_graph_lora_manager.py
  • tensorrt_llm/_torch/peft/lora/layer.py
  • tensorrt_llm/_torch/pyexecutor/model_engine.py
  • tensorrt_llm/lora_helper.py
  • tensorrt_llm/usage/llm_args_golden_manifest.json
  • tests/unittest/_torch/lora/test_lora_autotuner.py
  • tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py

Comment thread tensorrt_llm/_torch/peft/lora/layer.py
…alse

Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
@AlessioNetti
AlessioNetti force-pushed the lora-splitk-autotuning branch from 1bf46c2 to 77550d2 Compare August 6, 2026 06:38
@coderabbitai

coderabbitai Bot commented Aug 6, 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.

@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.

♻️ Duplicate comments (1)
tensorrt_llm/_torch/peft/lora/layer.py (1)

612-621: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use x.shape[-1] for input_hidden_size.

Line 616 reads the hidden size as x.shape[1], but _forward_cuda_graph_mode_impl reads it as x.shape[-1] at Line 521. The two values differ for a rank-3 input, which would give wrong synthetic LoRA A shapes and a wrong unique_id.

🤖 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/peft/lora/layer.py` around lines 612 - 621, Update the
_split_k_runner initialization in _forward_cuda_graph_mode_impl to pass
x.shape[-1] as input_hidden_size, matching the existing hidden-size calculation
and preserving correct LoRA shapes and unique_id generation for rank-3 inputs.
🧹 Nitpick comments (1)
tensorrt_llm/_torch/peft/lora/layer.py (1)

623-632: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid both LoRA-parameter copies outside tuning. Assign runner.lora_params = lora_params directly, and call copy_lora_params in _LoraGroupedGemmRunner.forward only when AutoTuner.get().is_tuning_mode is set. The non-tuning path only reads the parameters and uses [x], so this removes two hierarchy copies from each cached decode call while preserving tuning isolation.

🤖 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/peft/lora/layer.py` around lines 623 - 632, Update the
split-k execution path around _split_k_runner to assign lora_params directly
instead of calling copy_lora_params. In _LoraGroupedGemmRunner.forward, perform
copy_lora_params only when AutoTuner.get().is_tuning_mode is enabled, while
retaining direct parameter reads and the [x] input in non-tuning execution.
🤖 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.

Duplicate comments:
In `@tensorrt_llm/_torch/peft/lora/layer.py`:
- Around line 612-621: Update the _split_k_runner initialization in
_forward_cuda_graph_mode_impl to pass x.shape[-1] as input_hidden_size, matching
the existing hidden-size calculation and preserving correct LoRA shapes and
unique_id generation for rank-3 inputs.

---

Nitpick comments:
In `@tensorrt_llm/_torch/peft/lora/layer.py`:
- Around line 623-632: Update the split-k execution path around _split_k_runner
to assign lora_params directly instead of calling copy_lora_params. In
_LoraGroupedGemmRunner.forward, perform copy_lora_params only when
AutoTuner.get().is_tuning_mode is enabled, while retaining direct parameter
reads and the [x] input in non-tuning execution.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 8aae3487-5ded-4a1d-b685-03c0c38de695

📥 Commits

Reviewing files that changed from the base of the PR and between b7a9d6f and 77550d2.

📒 Files selected for processing (11)
  • tensorrt_llm/_torch/modules/attention.py
  • tensorrt_llm/_torch/modules/gated_mlp.py
  • tensorrt_llm/_torch/modules/linear.py
  • tensorrt_llm/_torch/modules/mlp.py
  • tensorrt_llm/_torch/peft/lora/cuda_graph_lora_manager.py
  • tensorrt_llm/_torch/peft/lora/layer.py
  • tensorrt_llm/_torch/pyexecutor/model_engine.py
  • tensorrt_llm/lora_helper.py
  • tensorrt_llm/usage/llm_args_golden_manifest.json
  • tests/unittest/_torch/lora/test_lora_autotuner.py
  • tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py
🚧 Files skipped from review as they are similar to previous changes (9)
  • tensorrt_llm/lora_helper.py
  • tensorrt_llm/_torch/modules/mlp.py
  • tensorrt_llm/_torch/modules/linear.py
  • tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py
  • tensorrt_llm/_torch/modules/attention.py
  • tensorrt_llm/usage/llm_args_golden_manifest.json
  • tensorrt_llm/_torch/pyexecutor/model_engine.py
  • tensorrt_llm/_torch/modules/gated_mlp.py
  • tests/unittest/_torch/lora/test_lora_autotuner.py

Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
@AlessioNetti
AlessioNetti force-pushed the lora-splitk-autotuning branch from 2c4f9d7 to 3a058df Compare August 6, 2026 08:12
@coderabbitai

coderabbitai Bot commented Aug 6, 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.

@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: 2

🧹 Nitpick comments (5)
tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py (2)

232-247: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Assert that overlap preserves the non-overlap result.

Both new tests only call _assert_lora_changes_output, which compares the LoRA output against the base output. Overlap execution changes only scheduling, so the LoRA output must match the serial LoRA output token for token. The current assertions pass even if overlap produces a different, incorrect result, which is the failure mode a stream-synchronization defect produces.

Add an equivalence check between overlap=True and overlap=False for the same dtype and adapter. Sampling already uses temperature=0.0, so the comparison is deterministic.

The four test_qwen3_*_lora* methods now differ only by dtype and overlap. Consider @pytest.mark.parametrize("dtype, overlap", ...) over a single body to remove the duplication.

🤖 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/modules/tests_lora_modules/test_qwen3_sanity.py` around
lines 232 - 247, Update the Qwen3 LoRA tests so overlap=True outputs are
compared token-for-token with the corresponding overlap=False result for the
same adapter and dtype, while retaining the base-output LoRA assertion.
Consolidate the four test_qwen3_*_lora* methods into one parametrized test over
dtype and overlap where practical, using the existing deterministic sampling
configuration.

178-247: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add output-equivalence and split-K coverage.

  • Added: test_lora_forward_with_base_executes_overlap, TestQwen3LoRA.test_qwen3_bf16_lora_overlap, and TestQwen3LoRA.test_qwen3_fp8_lora_overlap.
  • Modified: _run_lora_test gained overlap.
  • Removed: none.
  • Existing directory bridges cover this file in l0_b200.yml, l0_gb300_multi_gpus.yml, l0_b300.yml, and l0_h100.yml. No QA entry is required for this unit-test bridge.
  • Gaps remain: no comparison proves overlap and non-overlap produce identical output, and no end-to-end test covers split-K autotuning. The autotuner tests use fakes.
  • Verdict: needs follow-up because no CBTS coverage artifact is available.
🤖 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/modules/tests_lora_modules/test_qwen3_sanity.py` around
lines 178 - 247, Extend the LoRA test coverage around _run_lora_test and
TestQwen3LoRA to compare overlap and non-overlap outputs for equivalent Qwen3
configurations, including relevant BF16 and FP8 paths, and add an end-to-end
split-K autotuning test using the real execution path rather than fakes.
Preserve the existing CUDA skip and model-availability setup while ensuring both
coverage gaps produce verifiable assertions.

Source: Path instructions

tensorrt_llm/_torch/peft/lora/layer.py (2)

623-632: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Avoid the per-forward copy_lora_params call on the inference path.

Line 624 copies the LoRA parameter hierarchy on every forward. The copy is only required when the autotuner re-packs synthetic inputs. forward already calls copy_lora_params itself at Line 865 when len(inputs) > 1, so the inference path never mutates the dict it receives. The outer copy therefore allocates a dict, a CudaGraphLoraParams shallow copy, and a LoraLayerParams copy per LoRA layer per forward with no isolation benefit.

Assign the parameters directly and let forward copy only when it tunes.

♻️ Proposed change
         runner = self._split_k_runner
-        runner.lora_params = runner.copy_lora_params(lora_params)
+        runner.lora_params = lora_params
         runner_inputs = [x]

Note that tests/unittest/_torch/lora/test_lora_autotuner.py Lines 124 and 129-132 assert the outer copy happens. Update those assertions if you apply this change.

🤖 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/peft/lora/layer.py` around lines 623 - 632, Remove the
per-forward runner.copy_lora_params call in the _split_k_runner path and assign
lora_params directly to runner.lora_params before autotuning. Keep forward’s
existing copy_lora_params behavior for the len(inputs) > 1 tuning case, and
update the corresponding test assertions in test_lora_autotuner.py to expect no
outer copy.

828-838: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Bind the synthetic input layout to a named schema.

_prepare_synthetic_inputs builds a nine-element positional list and forward unpacks the same nine positions at Lines 869-880. The two sites share no constant, so a reordering in one place silently misassigns tensors in the other. tests/unittest/_torch/lora/test_lora_autotuner.py also indexes these positions by literal integers at Lines 140-141 and 174-177, which multiplies the coupling.

Define the field order once, for example as a module-level tuple of attribute paths, and drive both the pack and the unpack from it.

🤖 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/peft/lora/layer.py` around lines 828 - 838, Define a
module-level named schema for the synthetic input fields used by
_prepare_synthetic_inputs, forward, and the autotuner tests, then build and
consume the positional list through that schema instead of duplicated ordering
and literal indexes. Preserve the existing nine-field order and update all
references consistently so reordering the schema cannot silently misassign
inputs.
tests/unittest/_torch/lora/test_lora_autotuner.py (1)

39-49: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test the bucket mapping through DynamicTensorSpec. Replace the private AutoTuner._find_nearest_profile call and cache reset with assert spec.map_to_tuning_buckets(7) == 4. This keeps the test focused on token-bucket behavior without coupling it to AutoTuner internals.

🤖 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/lora/test_lora_autotuner.py` around lines 39 - 49,
Replace the private AutoTuner._find_nearest_profile call and its cache_clear
setup with an assertion that spec.map_to_tuning_buckets(7) returns 4. Keep the
existing spec.input_idx and spec.dim_idx assertions, and remove the
profile-based assertion.
🤖 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 `@tests/unittest/_torch/lora/test_lora_autotuner.py`:
- Around line 63-68: Update FakeLayerParams.__init__ so d_b_ptrs and
d_b_prime_ptrs are initialized as 2-D tensors with shape (1, 4), matching
CudaGraphLoraParams._allocate_layer_params and allowing indexed writes in
_prepare_synthetic_inputs.
- Around line 13-32: Add coverage in the existing LoRA autotuner tests around
_make_runner and the relevant runner invocation for tactic=-1, asserting it
resolves to _LORA_DEFAULT_SPLIT_K, and update the CUDA-graph warmup test to
observe the split-K argument passed to
torch.ops.trtllm.lora_grouped_gemm_cuda_graph instead of only patching
_forward_cuda_graph_mode_impl. Preserve the current warmup and active-slot
assertions while validating both operator-boundary behaviors.

---

Nitpick comments:
In `@tensorrt_llm/_torch/peft/lora/layer.py`:
- Around line 623-632: Remove the per-forward runner.copy_lora_params call in
the _split_k_runner path and assign lora_params directly to runner.lora_params
before autotuning. Keep forward’s existing copy_lora_params behavior for the
len(inputs) > 1 tuning case, and update the corresponding test assertions in
test_lora_autotuner.py to expect no outer copy.
- Around line 828-838: Define a module-level named schema for the synthetic
input fields used by _prepare_synthetic_inputs, forward, and the autotuner
tests, then build and consume the positional list through that schema instead of
duplicated ordering and literal indexes. Preserve the existing nine-field order
and update all references consistently so reordering the schema cannot silently
misassign inputs.

In `@tests/unittest/_torch/lora/test_lora_autotuner.py`:
- Around line 39-49: Replace the private AutoTuner._find_nearest_profile call
and its cache_clear setup with an assertion that spec.map_to_tuning_buckets(7)
returns 4. Keep the existing spec.input_idx and spec.dim_idx assertions, and
remove the profile-based assertion.

In `@tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py`:
- Around line 232-247: Update the Qwen3 LoRA tests so overlap=True outputs are
compared token-for-token with the corresponding overlap=False result for the
same adapter and dtype, while retaining the base-output LoRA assertion.
Consolidate the four test_qwen3_*_lora* methods into one parametrized test over
dtype and overlap where practical, using the existing deterministic sampling
configuration.
- Around line 178-247: Extend the LoRA test coverage around _run_lora_test and
TestQwen3LoRA to compare overlap and non-overlap outputs for equivalent Qwen3
configurations, including relevant BF16 and FP8 paths, and add an end-to-end
split-K autotuning test using the real execution path rather than fakes.
Preserve the existing CUDA skip and model-availability setup while ensuring both
coverage gaps produce verifiable assertions.
🪄 Autofix

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: d6ad3521-1a88-4ca2-982d-6f887f648f54

📥 Commits

Reviewing files that changed from the base of the PR and between aafc4eb and 3a058df.

📒 Files selected for processing (11)
  • tensorrt_llm/_torch/modules/attention.py
  • tensorrt_llm/_torch/modules/gated_mlp.py
  • tensorrt_llm/_torch/modules/linear.py
  • tensorrt_llm/_torch/modules/mlp.py
  • tensorrt_llm/_torch/peft/lora/cuda_graph_lora_manager.py
  • tensorrt_llm/_torch/peft/lora/layer.py
  • tensorrt_llm/_torch/pyexecutor/model_engine.py
  • tensorrt_llm/lora_helper.py
  • tensorrt_llm/usage/llm_args_golden_manifest.json
  • tests/unittest/_torch/lora/test_lora_autotuner.py
  • tests/unittest/_torch/modules/tests_lora_modules/test_qwen3_sanity.py
🚧 Files skipped from review as they are similar to previous changes (8)
  • tensorrt_llm/_torch/modules/gated_mlp.py
  • tensorrt_llm/lora_helper.py
  • tensorrt_llm/usage/llm_args_golden_manifest.json
  • tensorrt_llm/_torch/modules/mlp.py
  • tensorrt_llm/_torch/modules/attention.py
  • tensorrt_llm/_torch/peft/lora/cuda_graph_lora_manager.py
  • tensorrt_llm/_torch/pyexecutor/model_engine.py
  • tensorrt_llm/_torch/modules/linear.py

Comment thread tests/unittest/_torch/lora/test_lora_autotuner.py
Comment thread tests/unittest/_torch/lora/test_lora_autotuner.py
… to grouped GEMM properly

Signed-off-by: Alessio Netti <26897207+AlessioNetti@users.noreply.github.com>
@AlessioNetti
AlessioNetti marked this pull request as draft 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.

2 participants