Skip to content

[None][perf] Optimize Gemma4 serving: fused kernels, sync-free FlashInfer plans, CUDA graph padding prealloc - #16033

Closed
kaiyux wants to merge 3 commits into
NVIDIA:mainfrom
kaiyux:perf-optimize/gemma-4-combined-20260706
Closed

[None][perf] Optimize Gemma4 serving: fused kernels, sync-free FlashInfer plans, CUDA graph padding prealloc#16033
kaiyux wants to merge 3 commits into
NVIDIA:mainfrom
kaiyux:perf-optimize/gemma-4-combined-20260706

Conversation

@kaiyux

@kaiyux kaiyux commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Added faster fused Gemma4 execution paths for attention prep, MLP quantization, RMSNorm, QKV processing, and decoder tail operations.
    • Improved CUDA-graph batch handling with safer padding-dummy preallocation during warmup.
  • Bug Fixes

    • Improved fallback behavior when padding requests cannot be allocated, reducing first-run CUDA-graph failures.
    • Updated mixed-precision handling to produce the expected output dtype in FP8-related flows.
  • Tests

    • Added parity coverage for the new fused Gemma4 paths, including strided inputs, extreme scales, and zero-row cases.

Description

Combines three groups of Gemma4 single-GPU serving optimizations, building on the page-table trimming introduced in #15848. Measured together on 1x B200 (Gemma-4-31B-IT-NVFP4, ISL 1024 / OSL 128, 1024 prompts, concurrency 1024, trtllm-serve + benchmark_serving):

Metric main (f4742f6) this PR delta
Output throughput 1324.44 tok/s 1732.96 tok/s +30.9%
Median TTFT 49.3 s 37.6 s -23.6%
Median TPOT 140.0 ms 105.8 ms -24.4%
P99 ITL 416.1 ms 357.3 ms -14.1%
Median E2EL 67.1 s 51.1 s -23.9%

1. FlashInfer host-path preparation (flashinfer.py, kv_cache_manager_v2.py)

  • Build all page-table metadata (kv lens, block counts, decode/prefill/mixed indptrs, last-page lens) with numpy on the host and stage through pinned tensors for async H2D, removing per-step GPU arithmetic and syncs from prepare().
  • Add KVCacheManagerV2.get_batch_cache_indices_flat(): gathers only the live block-table widths straight into a pinned CPU tensor with one vectorized transform, instead of materializing padded per-request Python lists.
  • Retain host copies of the decode indptr and per-pool flat page indices, and pre-build persistent trtllm-gen decode block tables on the host, so BatchDecodeWithPagedKVCacheWrapper.plan() no longer triggers flashinfer's per-request rebuild loop (one stream sync + one scalar D2H per generation request per plan). Buffers are allocated once at capacity under CUDA graphs so captured decode kernels keep reading stable addresses.
  • Vectorize the VSWA decode block-table refresh (one gather + where instead of a per-request slice-copy loop).

2. Fused Gemma4 modules (modeling_gemma4.py + new gemma4_fused_*.py)

  • Fused QKV prep (QK norm + RoPE + FP8 quant), fused GeLU-mul + NVFP4 quant, fused RMSNorm + NVFP4 quant, and a fused residual-add tail.
  • Each fusion is enabled by default with a dedicated opt-out env var (TRTLLM_GEMMA4_DISABLE_FUSED_QKV_PREP, ..._FUSED_GELU_QUANT, ..._FUSED_NORM_QUANT, ..._FUSED_TAIL, ..._FUSED_TAIL_NORM2, ..._FUSED_NORM_ADD).
  • FlashInfer attention now allocates BF16 output when Q arrives pre-quantized to FP8 (trtllm-gen QkvE4m3OBfloat16 cubins emit BF16).

3. CUDA graph padding-dummy preallocation (cuda_graph_runner.py, model_engine.py)

  • Pre-allocate the draft_len-0 padding dummy request at the end of warmup, while the KV cache still has free blocks. Previously the dummy was allocated lazily at the first padded step; if the cache was already saturated by then, allocation failed on every step and padded batches permanently fell back to eager mode.
  • Refactors the dummy creation into _get_or_create_padding_dummy() (keeping the encoder-decoder handling) and logs a warning_once when padding falls back to eager.

Test Coverage

  • New unit tests for every fused module (77 cases, all passing on B200): tests/unittest/_torch/modules/test_gemma4_fused_qkv_prep.py, test_gemma4_fused_gelu_quant.py, test_gemma4_fused_norm_quant.py, test_gemma4_fused_tail.py — parity checks against the unfused reference paths.
  • tests/unittest/_torch/executor/test_pytorch_model_engine.py updated to cover the warmup padding-dummy preallocation (asserts the dummy exists after warmup and that no blocks leak beyond it).
  • Existing FlashInfer/KV-cache paths are exercised by the current _torch attention and executor test suites; get_batch_cache_indices keeps its trimmed-list semantics for non-flat callers.
  • End-to-end serving benchmark above (1024/1024 successful requests on both baseline and this PR).

PR Checklist

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

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

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

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

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

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

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

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

GitHub Bot Help

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

🤖 Generated with Claude Code

…nfer plans, CUDA graph padding prealloc

Combine three groups of Gemma4 single-GPU serving optimizations on top of
the page-table work from NVIDIA#15848:

- FlashInfer host-path: build all page-table metadata (kv lens, block
  counts, indptrs, last-page lens) with numpy on the host and stage
  through pinned tensors, add a flat KV cache indices path
  (get_batch_cache_indices_flat) that never materializes padded
  per-request lists, retain host copies of decode indptr and pool
  indices, and pre-build persistent trtllm-gen decode block tables on
  the host so decode plans need no GPU round trips; vectorize the VSWA
  decode block-table refresh.

- Fused Gemma4 modules: model-side fused QKV prep (norm + RoPE + FP8
  quant), fused GeLU-mul + NVFP4 quant, fused RMSNorm + NVFP4 quant, and
  a fused residual-add tail, wired into modeling_gemma4 with per-fusion
  opt-out env vars (TRTLLM_GEMMA4_DISABLE_*); FlashInfer emits BF16
  output when Q arrives pre-quantized to FP8.

- CUDA graph padding: pre-allocate the padding dummy request at warmup
  while the KV cache still has free blocks, so padded batches cannot
  permanently fall back to eager mode once the cache saturates.

Benchmark (1xB200, Gemma-4-31B-IT-NVFP4, ISL 1024 / OSL 128, 1024
prompts, concurrency 1024): output throughput 1324 -> 1733 tok/s
(+30.9%), median TTFT -23.6%, median TPOT -24.4%, median E2EL -23.9%.

Signed-off-by: Kaiyu Xie <26294424+kaiyux@users.noreply.github.com>
@kaiyux
kaiyux requested review from a team as code owners July 7, 2026 03:59
@kaiyux
kaiyux marked this pull request as draft July 7, 2026 04:01
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces sync-free host-side decode planning for the FlashInfer attention backend (pinned staging buffers, vectorized block-table construction, CUDA-graph updates), a CUDA-graph padding-dummy preallocation mechanism, a KVCacheManagerV2 flat block-index builder, and four new Gemma4 fused Triton kernels (GeLU+FP4 quant, RMSNorm+FP4 quant, QKV norm+RoPE+quant, decoder tail) wired into modeling_gemma4.py with accompanying parity tests.

Changes

FlashInfer Sync-Free Decode Planning & CUDA Graph Padding

Layer / File(s) Summary
Host staging helpers and persistent buffer init
tensorrt_llm/_torch/attention_backend/flashinfer.py
Adds _staging_int32() pinned-memory helper and initializes persistent host/device decode block-table state sized across all VSWA pools.
Paged KV index and decode block table construction
tensorrt_llm/_torch/attention_backend/flashinfer.py, tensorrt_llm/_torch/pyexecutor/kv_cache_manager_v2.py
Adds get_batch_cache_indices_flat() in KVCacheManagerV2 and _get_paged_kv_indices()/_build_decode_block_tables() in the FlashInfer backend for host-built decode block tables.
prepare() refactor to host-computed page metadata
tensorrt_llm/_torch/attention_backend/flashinfer.py
Computes cached-token lengths, page indices, last-page lengths, and indptrs via host numpy arrays instead of CUDA-side ops.
CUDA-graph update and decode_plan wiring
tensorrt_llm/_torch/attention_backend/flashinfer.py
Vectorizes CUDA-graph block-table refresh, reuses retained host indptr in decode_plan(), and fixes FP8→BF16 output allocation in forward().
CUDA graph padding dummy preallocation
tensorrt_llm/_torch/pyexecutor/cuda_graph_runner.py, tensorrt_llm/_torch/pyexecutor/model_engine.py, tests/unittest/_torch/executor/test_pytorch_model_engine.py
Extracts _get_or_create_padding_dummy(), adds preallocate_padding_dummy() invoked during warmup, and updates the warmup test to validate padding-dummy accounting.

Gemma4 Fused Triton Kernels

Layer / File(s) Summary
Fused GeLU+mul+NVFP4 quant kernel
tensorrt_llm/_torch/models/gemma4_fused_gelu_quant.py, tests/unittest/_torch/modules/test_gemma4_fused_gelu_quant.py
New Triton kernel and wrapper fusing gelu_tanh+mul with NVFP4 quantization; parity tests vs. unfused reference.
Fused RMSNorm+NVFP4 quant kernel
tensorrt_llm/_torch/models/gemma4_fused_norm_quant.py, tests/unittest/_torch/modules/test_gemma4_fused_norm_quant.py
New Triton kernel and wrapper fusing RMSNorm with NVFP4 quantization; tests cover extreme scales, strided rows, zero rows.
Fused QKV norm+RoPE+quant kernel
tensorrt_llm/_torch/models/gemma4_fused_qkv.py, tests/unittest/_torch/modules/test_gemma4_fused_qkv_prep.py
New Triton kernel/wrapper applying per-head RMSNorm+RoPE to Q/K and norm to V with FP8/BF16 output; parity tests vs. reference chain.
Fused decoder tail kernel
tensorrt_llm/_torch/models/gemma4_fused_tail.py, tests/unittest/_torch/modules/test_gemma4_fused_tail.py
New Triton kernel/wrappers for fused RMSNorm+residual-add with optional scalar/secondary next-layer norm output; parity tests for several variants.
Gemma4 model wiring of fused paths
tensorrt_llm/_torch/models/modeling_gemma4.py
Wires fused kernels into Gemma4Attention/Gemma4DecoderLayer/Gemma4TextModel via env-gated predicates, MLP substitution, fused rope/norm/tail branches, and next-layer norm threading.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ModelEngine as PyTorchModelEngine
  participant CudaGraphRunner
  participant KVCacheManager

  ModelEngine->>CudaGraphRunner: preallocate_padding_dummy(resource_manager)
  CudaGraphRunner->>KVCacheManager: allocate dummy request (draft_len=0)
  KVCacheManager-->>CudaGraphRunner: dummy request or failure
  CudaGraphRunner-->>ModelEngine: cached in padding_dummy_requests

  Note over ModelEngine,CudaGraphRunner: Later, during a padded step
  ModelEngine->>CudaGraphRunner: _get_padded_batch(runtime_draft_len)
  CudaGraphRunner->>CudaGraphRunner: _get_or_create_padding_dummy(runtime_draft_len)
  alt cached dummy exists
    CudaGraphRunner-->>ModelEngine: reuse cached dummy request
  else allocation fails
    CudaGraphRunner-->>ModelEngine: warning_once + eager fallback (0)
  end
Loading
sequenceDiagram
  participant Attention as Gemma4Attention
  participant FusedQKV as gemma4_fused_qkv_norm_rope_quant
  participant DecoderLayer as Gemma4DecoderLayer
  participant FusedTail as gemma4_fused_norm_add_scale
  participant MLP as _Gemma4GeluQuantMLP

  Attention->>Attention: _fused_qkv_prep_enabled() check
  Attention->>FusedQKV: apply_rope(qkv, position_ids, cos_sin)
  FusedQKV-->>Attention: fp8 Q, K, V
  DecoderLayer->>DecoderLayer: _fused_norm_quant_enabled() check
  DecoderLayer->>MLP: Fp4QuantizedTensor input
  MLP-->>DecoderLayer: fp4-quantized MLP output
  DecoderLayer->>FusedTail: gemma4_fused_norm_add_scale(hidden, residual, next_norm_weight)
  FusedTail-->>DecoderLayer: (hidden_states, pre_normed)
Loading

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • NVIDIA/TensorRT-LLM#12262: Both PRs modify CUDA-graph padding dummy/warmup logic for runtime/speculative draft-length token buffer sizing in the same runner/engine files.
  • NVIDIA/TensorRT-LLM#15637: Both PRs touch CUDA-graph padding dummy request creation logic within _get_padded_batch/dummy allocation paths in cuda_graph_runner.py.
  • NVIDIA/TensorRT-LLM#15848: Both PRs change host-computed num_blocks usage feeding into FlashInferAttentionMetadata/KVCacheManagerV2 paged KV index construction during prepare().

Suggested reviewers: moraxu, aswinvisva, lfr-0531, Hudayday, yizhang-nv, yechank-nvidia, PerkzZheng

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly summarizes the main Gemma4 serving optimizations in the change set.
Description check ✅ Passed The description matches the template with Description, Test Coverage, and PR Checklist sections filled in.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
tensorrt_llm/_torch/models/gemma4_fused_qkv.py (1)

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

Consider asserting the head_dim power-of-two assumption.

block_n = max(1, min(32, 4096 // head_dim)) is only guaranteed power-of-two (required by tl.arange and HALF) when head_dim is a power-of-two divisor of 4096. That holds for the gated shapes today, but a stray head_dim (e.g. 192) would silently produce a non-power-of-two block_n/half and a confusing kernel-compile failure. A cheap assert (head_dim & (head_dim - 1)) == 0 would fail fast with a clear message.

🤖 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/gemma4_fused_qkv.py` at line 175, The block_n
calculation in gemma4_fused_qkv relies on head_dim being a power-of-two divisor
of 4096, but this assumption is not checked and can lead to invalid kernel
settings and opaque compile failures. Add a fast-fail assertion near the block_n
setup in the relevant fused QKV path to verify head_dim is power-of-two before
computing block_n, and include a clear error message so the failure is explicit
and easy to trace.
tensorrt_llm/_torch/models/gemma4_fused_gelu_quant.py (1)

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

Prefer built-in tuple over typing.Tuple.

The codebase targets Python 3.10+, so annotate with tuple[...] and drop the typing.Tuple import (applies to the sibling fused-kernel modules gemma4_fused_norm_quant.py, gemma4_fused_qkv.py, and gemma4_fused_tail.py as well).

As per coding guidelines: "Prefer built-in types list, dict, tuple over typing.List, typing.Dict, typing.Tuple".

🤖 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/gemma4_fused_gelu_quant.py` at line 42, The module
still imports and uses typing.Tuple even though the codebase targets Python
3.10+, so update the type annotations in gemma4_fused_gelu_quant and the sibling
fused-kernel modules gemma4_fused_norm_quant, gemma4_fused_qkv, and
gemma4_fused_tail to use built-in tuple[...] syntax instead. Remove the Tuple
import from each module after switching the relevant return/type annotations so
the code follows the project guideline to prefer built-in collection types.

Source: Coding guidelines

tensorrt_llm/_torch/attention_backend/flashinfer.py (1)

922-948: 🩺 Stability & Availability | 🔵 Trivial | ⚖️ Poor tradeoff

Persistent per-plan_params buffers are never reclaimed.

_decode_block_tables_dev / _decode_block_tables_stage accumulate a (max_num_requests, width) int32 device buffer (plus pinned stage) per distinct non-masked PlanParams. _clean_cached_plans drops masked entries from _plan_params_to_wrappers but nothing prunes these two dicts, so any churn in plan params (e.g. varying attention_window_size/dtype across steps) slowly leaks device memory. In steady state plan params are few, so impact is limited; consider pruning entries whose plan_params no longer appear in _plan_params_to_wrappers.

🤖 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/attention_backend/flashinfer.py` around lines 922 - 948,
Persistent per-PlanParams decode buffers are never reclaimed, so
_decode_block_tables_dev and _decode_block_tables_stage can grow indefinitely as
plan params change. Update the cache management in FlashinferBackend to prune
these entries when _clean_cached_plans removes stale plans, using the existing
_plan_params_to_wrappers / plan_params keys to identify buffers no longer in
use. Keep the cleanup aligned with the decode buffer allocation path in the
plan/replan logic so both the device tensor and pinned stage buffer are dropped
together.
tensorrt_llm/_torch/models/modeling_gemma4.py (1)

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

De-duplicate the FP4 pre-quant eligibility check.

The five "pre-quantized-input path" checks here on gate_up_proj (Lines 833-837) are identical to those on down_proj in _Gemma4GeluQuantMLP._fused_gelu_quant_enabled (Lines 137-141). Since both intentionally mirror Linear._input_prepare, extracting a small module-level helper keeps the two call sites from silently diverging if that contract changes.

♻️ Suggested helper
def _linear_accepts_prequant_fp4(linear) -> bool:
    # Mirror the checks the pre-quantized-input path in
    # Linear._input_prepare enforces for Fp4QuantizedTensor.
    return (
        getattr(linear, "has_nvfp4", False)
        and not getattr(linear, "force_dynamic_quantization", True)
        and getattr(linear, "input_scale", None) is not None
        and getattr(linear, "pre_quant_scale", None) is None
        and getattr(linear, "scaling_vector_size", None) == 16
    )

Then both predicates reduce to ... and _linear_accepts_prequant_fp4(dp) / _linear_accepts_prequant_fp4(gu).

🤖 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/modeling_gemma4.py` around lines 824 - 838,
De-duplicate the repeated FP4 pre-quant eligibility logic used in
`_fused_norm_quant_enabled` and `_Gemma4GeluQuantMLP._fused_gelu_quant_enabled`
by introducing a small shared helper for the `Linear._input_prepare`-style
checks. Move the common `gate_up_proj`/`down_proj` predicate into a module-level
function (for example, one that validates `has_nvfp4`,
`force_dynamic_quantization`, `input_scale`, `pre_quant_scale`, and
`scaling_vector_size`) and call it from both `gu` and `dp` sites so the two
paths stay in sync.
🤖 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 `@tensorrt_llm/_torch/attention_backend/flashinfer.py`:
- Around line 922-948: Persistent per-PlanParams decode buffers are never
reclaimed, so _decode_block_tables_dev and _decode_block_tables_stage can grow
indefinitely as plan params change. Update the cache management in
FlashinferBackend to prune these entries when _clean_cached_plans removes stale
plans, using the existing _plan_params_to_wrappers / plan_params keys to
identify buffers no longer in use. Keep the cleanup aligned with the decode
buffer allocation path in the plan/replan logic so both the device tensor and
pinned stage buffer are dropped together.

In `@tensorrt_llm/_torch/models/gemma4_fused_gelu_quant.py`:
- Line 42: The module still imports and uses typing.Tuple even though the
codebase targets Python 3.10+, so update the type annotations in
gemma4_fused_gelu_quant and the sibling fused-kernel modules
gemma4_fused_norm_quant, gemma4_fused_qkv, and gemma4_fused_tail to use built-in
tuple[...] syntax instead. Remove the Tuple import from each module after
switching the relevant return/type annotations so the code follows the project
guideline to prefer built-in collection types.

In `@tensorrt_llm/_torch/models/gemma4_fused_qkv.py`:
- Line 175: The block_n calculation in gemma4_fused_qkv relies on head_dim being
a power-of-two divisor of 4096, but this assumption is not checked and can lead
to invalid kernel settings and opaque compile failures. Add a fast-fail
assertion near the block_n setup in the relevant fused QKV path to verify
head_dim is power-of-two before computing block_n, and include a clear error
message so the failure is explicit and easy to trace.

In `@tensorrt_llm/_torch/models/modeling_gemma4.py`:
- Around line 824-838: De-duplicate the repeated FP4 pre-quant eligibility logic
used in `_fused_norm_quant_enabled` and
`_Gemma4GeluQuantMLP._fused_gelu_quant_enabled` by introducing a small shared
helper for the `Linear._input_prepare`-style checks. Move the common
`gate_up_proj`/`down_proj` predicate into a module-level function (for example,
one that validates `has_nvfp4`, `force_dynamic_quantization`, `input_scale`,
`pre_quant_scale`, and `scaling_vector_size`) and call it from both `gu` and
`dp` sites so the two paths stay in sync.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 4f345f2f-912e-4dc1-8564-ba9446b121ee

📥 Commits

Reviewing files that changed from the base of the PR and between 39452fd and 47ad43c.

📒 Files selected for processing (14)
  • tensorrt_llm/_torch/attention_backend/flashinfer.py
  • tensorrt_llm/_torch/models/gemma4_fused_gelu_quant.py
  • tensorrt_llm/_torch/models/gemma4_fused_norm_quant.py
  • tensorrt_llm/_torch/models/gemma4_fused_qkv.py
  • tensorrt_llm/_torch/models/gemma4_fused_tail.py
  • tensorrt_llm/_torch/models/modeling_gemma4.py
  • tensorrt_llm/_torch/pyexecutor/cuda_graph_runner.py
  • tensorrt_llm/_torch/pyexecutor/kv_cache_manager_v2.py
  • tensorrt_llm/_torch/pyexecutor/model_engine.py
  • tests/unittest/_torch/executor/test_pytorch_model_engine.py
  • tests/unittest/_torch/modules/test_gemma4_fused_gelu_quant.py
  • tests/unittest/_torch/modules/test_gemma4_fused_norm_quant.py
  • tests/unittest/_torch/modules/test_gemma4_fused_qkv_prep.py
  • tests/unittest/_torch/modules/test_gemma4_fused_tail.py

kaiyux added 2 commits July 6, 2026 23:20
_torch/models/ holds only modeling_*.py files; architecture-specific
building blocks belong under _torch/modules/ (like mhc/, engram/,
fused_moe/). Move the four gemma4_fused_* kernel files into a new
modules/gemma4/ subpackage and update imports in modeling_gemma4 and
the unit tests. No functional change.

Signed-off-by: Kaiyu Xie <26294424+kaiyux@users.noreply.github.com>
The fused paths (gelu+quant, qkv prep, norm+add, norm+quant, layer tail,
tail norm2) are now unconditional wherever structurally applicable; the
unfused code remains only for configurations the kernels do not support
(MoE block, PLE, KV-shared layers, non-NVFP4/FP8 configs, LoRA,
torch.compile, custom-mask prefill).

Signed-off-by: Kaiyu Xie <26294424+kaiyux@users.noreply.github.com>
@kaiyux

kaiyux commented Jul 8, 2026

Copy link
Copy Markdown
Member Author

This PR is split to 3 PRs: #16072 #16073 #16074, closing this one.

@kaiyux kaiyux closed this Jul 8, 2026
@kaiyux
kaiyux deleted the perf-optimize/gemma-4-combined-20260706 branch July 8, 2026 00:30
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.

1 participant