Skip to content

[Example] Generalize TCGEN05 GEMMs for Thor (sm110a) and add Stream-K scheduling - #2902

Merged
LeiWang1999 merged 6 commits into
tile-ai:mainfrom
xinhao-luo:main
Aug 13, 2026
Merged

LeiWang1999 merged 6 commits into
tile-ai:mainfrom
xinhao-luo:main

Conversation

@xinhao-luo

@xinhao-luo xinhao-luo commented Aug 6, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This PR generalizes the TCGEN05 GEMM examples to support NVIDIA Thor/SM110a while preserving SM100 compatibility, and adds a 2-CTA Stream-K scheduler for workloads with under-filled persistent waves.

Changes

  • Rename examples/gemm_sm100 to examples/gemm_tcgen05, as these kernels rely on TCGEN05 capabilities rather than being exclusive to SM100.
  • Generalize the architecture guard used by warpgroup_reg_alloc and warpgroup_reg_dealloc to support Thor/SM110a targets.
  • Add a 2-CTA TCGEN05 Stream-K scheduler for GEMMs with under-filled persistent waves and sufficiently long K dimensions.

The Stream-K implementation splits the under-filled tail wave along the K dimension and distributes its work across the resident clusters. Partial accumulators are stored in a workspace and combined before the epilogue, while the remaining full waves continue to use ordinary data-parallel persistent scheduling.

Performance

The kernels were tuned independently for each shape on an NVIDIA Thor T5000. The following table reports BF16 GEMM latency in milliseconds; the best result in each row is shown in bold.

M N K cuBLAS Static Persistent CLC Pipelined CLC Stream-K
256 2048 4096 0.2331 0.3428 0.3312 0.3337 0.3082
256 2048 8192 0.2277 0.2406 0.2372 0.2450 0.2392
256 2048 16384 0.5166 0.5510 0.5131 0.5055 0.4692
1024 1024 1024 0.0860 0.0889 0.0854 0.0854 0.0908
2048 2048 2048 0.2451 0.2513 0.2553 0.2610 0.2721
4096 4096 4096 1.4441 1.4719 1.4054 1.4057 1.7721
2560 512 8192 0.7082 0.5243 0.5349 0.5335 0.4050
2560 512 16384 1.2433 1.2011 1.4068 1.3981 0.8351
2560 512 32768 2.2219 2.4162 2.6746 2.6666 1.5638

The tuning space covered:

  • block_M × block_N: 128 × 128, 128 × 256, and 256 × 128 when valid
  • block_K: 64 and 128
  • Pipeline stages: 3, 4, and 6
  • TMA store enabled and disabled
  • Valid swizzle-group sizes
  • Pipelined CLC stages: 2, 3, and 4

Stream-K is not universally faster, but it consistently performs best for the tested 2560 × 512 × long-K workloads.

These shapes contain 20 cluster tiles. With six resident 2-CTA clusters on Thor, ordinary persistent scheduling produces waves of 6 + 6 + 6 + 2, leaving only two clusters active during the final long-K wave. Stream-K splits the remaining two tiles along K and distributes their work across all six clusters, reducing tail underutilization.

For these long-K cases, Stream-K achieves up to 1.75× speedup over cuBLAS and 1.44× over the best non-Stream-K implementation.

Summary

  • Generalizes GEMM examples from SM100 to TCGEN05 while preserving SM100 compatibility.
  • Renames the example directory and updates architecture documentation.
  • Adds persistent and 2-CTA Stream-K GEMM examples for long-K workloads.
  • Broadens warpgroup_reg_alloc and warpgroup_reg_dealloc architecture guards.
  • Adds CLI configuration, validation, benchmarking, and generated-source output across the examples.
  • Stream-K stores partial accumulators in workspace buffers and combines them before the epilogue.

Performance

On NVIDIA Thor T5000, Stream-K achieved up to 1.75× the cuBLAS performance and 1.44× the best non-Stream-K implementation for tested 2560 × 512 × long-K workloads. Stream-K does not improve all workloads.

C++ style / lint notes

  • The PR changes src/tl_templates/cuda/intrin.h.
  • It does not change docs/developer_guide/cpp_style.md.
  • No C++ API Style Audit (warning only) CI change is reported.
  • No correctness, build, or test issue is reported. Advisory style warnings, if any, are non-blocking unless they indicate an API, FFI, or maintainability risk.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

👋 Hi! Thank you for contributing to the TileLang project.

Please remember to run pre-commit run --all-files in the root directory of the project to ensure your changes are properly linted and formatted. This will help ensure your contribution passes the format check.

We appreciate you taking this step! Our team will review your contribution, and we look forward to your awesome work! 🚀

@coderabbitai

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

Walkthrough

Added baseline and configurable TCGEN05 GEMM examples, persistent and Stream-K scheduling variants, benchmark controls, CUDA architecture gating, and updated documentation.

Changes

TCGEN05 GEMM implementation

Layer / File(s) Summary
Kernel primitives and architecture support
README.md, examples/gemm_tcgen05/README.md, examples/gemm_tcgen05/gemm_mma.py, examples/gemm_tcgen05/gemm_tcgen5mma.py, src/tl_templates/cuda/intrin.h
Adds tiled and TCGEN05 GEMM kernels with validation and benchmarks. Updates architecture documentation and warpgroup register-operation guards.
Persistent GEMM kernels and controls
examples/gemm_tcgen05/gemm_tcgen5mma_ws.py, examples/gemm_tcgen05/gemm_tcgen5mma_ws_clc.py, examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py
Updates TCGEN05 terminology, exposes group_size, accepts configurable matrix dimensions, and standardizes benchmark iterations.
Stream-K scheduling and execution
examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent_streamk.py, examples/gemm_tcgen05/README.md
Adds 2-CTA Stream-K scheduling, workspace accumulation, fixup synchronization, persistent waves, validation, benchmarking, and related documentation.

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

Sequence Diagram(s)

sequenceDiagram
  participant main
  participant gemm_streamk_2cta
  participant Workspace
  participant Fixup
  participant Output
  main->>gemm_streamk_2cta: Dispatch Stream-K GEMM
  gemm_streamk_2cta->>Workspace: Publish partial tile accumulation
  gemm_streamk_2cta->>Fixup: Update atomic fixup state
  Fixup->>Workspace: Read peer partial tiles
  Fixup->>Output: Store reduced tile
  gemm_streamk_2cta->>Output: Store complete tile
Loading

Possibly related PRs

Suggested reviewers: leiwang1999

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: generalizing TCGEN05 GEMMs for Thor and adding Stream-K scheduling.
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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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)
examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py (3)

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

Rename the unused loop variable.

Ruff reports B007. wave is not read in this loop body, unlike the loops at lines 404 and 608. Rename it to _wave.

♻️ Proposed change
-            for wave in T.serial(blocking_waves):
+            for _wave in T.serial(blocking_waves):
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py` at line 458, Rename
the unused loop variable in the T.serial(blocking_waves) loop from wave to
_wave, leaving the loop body and behavior unchanged.

Source: Linters/SAST tools


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

Use the same measurement settings for both benchmarks.

The TileLang measurement fixes _n_warmup=50 and _n_repeat=50. The Torch measurement uses the auto-calculated defaults. The two latency numbers are therefore not directly comparable. Pass the same warmup and repeat counts to both calls.

♻️ Proposed change
-    torch_latency = do_bench(lambda: a @ b, backend="cupti")
+    torch_latency = do_bench(lambda: a @ b, _n_warmup=50, _n_repeat=50, backend="cupti")
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py` around lines 722 -
728, Use identical measurement settings for the Torch benchmark in the latency
comparison: update the do_bench call for torch_latency alongside tl_latency to
pass _n_warmup=50 and _n_repeat=50, while preserving the existing
backend="cupti" configuration.

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

The full-tile store path ignores use_tma_store.

Lines 509-514 always store through C_local_cast. The data-parallel wave at lines 625-635 honors use_tma_store. When use_tma_store is True (the default), C_shared is allocated at line 332 but the Stream-K wave never uses it. The two paths should behave the same, or the docstring should record the difference.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py` around lines 509 -
514, The full-tile store branch in the persistent GEMM flow must honor
use_tma_store consistently with the data-parallel wave. Update the is_full_tile
path to use the TMA store/C_shared flow when use_tma_store is enabled, while
preserving the existing C_local_cast store as the fallback when it is disabled.
🤖 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 `@examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py`:
- Around line 533-534: Initialize or invalidate each cluster’s PartialTile entry
at the start of every kernel launch before any publication occurs, ensuring
clusters that do not publish partial tiles cannot retain prior-launch values.
Update the reduction logic around PartialTile[producer] and Workspace so only
entries written during the current launch can match tile_id and contribute to
fixup.
- Around line 347-366: Guard the even-division branch in the persistent GEMM
scheduling logic so it is selected only when clusters_per_tile is no greater
than k_blocks. Extract the combined condition into a host-side even_split flag
and reuse that flag at the related branch and fixup checks, ensuring cases with
empty splits fall through to the general partitioning path.

---

Nitpick comments:
In `@examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py`:
- Line 458: Rename the unused loop variable in the T.serial(blocking_waves) loop
from wave to _wave, leaving the loop body and behavior unchanged.
- Around line 722-728: Use identical measurement settings for the Torch
benchmark in the latency comparison: update the do_bench call for torch_latency
alongside tl_latency to pass _n_warmup=50 and _n_repeat=50, while preserving the
existing backend="cupti" configuration.
- Around line 509-514: The full-tile store branch in the persistent GEMM flow
must honor use_tma_store consistently with the data-parallel wave. Update the
is_full_tile path to use the TMA store/C_shared flow when use_tma_store is
enabled, while preserving the existing C_local_cast store as the fallback when
it is disabled.
🪄 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: Pro Plus

Run ID: 3fcc5b1c-8eb4-440b-9d0f-f74ba833af68

📥 Commits

Reviewing files that changed from the base of the PR and between af47530 and b2f08bb.

📒 Files selected for processing (8)
  • examples/gemm_sm100/gemm_tcgen5mma_ws_persistent.py
  • examples/gemm_tcgen05/README.md
  • examples/gemm_tcgen05/gemm_mma.py
  • examples/gemm_tcgen05/gemm_tcgen5mma.py
  • examples/gemm_tcgen05/gemm_tcgen5mma_ws.py
  • examples/gemm_tcgen05/gemm_tcgen5mma_ws_clc.py
  • examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py
  • src/tl_templates/cuda/intrin.h
💤 Files with no reviewable changes (1)
  • examples/gemm_sm100/gemm_tcgen5mma_ws_persistent.py

Comment thread examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py Outdated
Comment thread examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py Outdated
@LeiWang1999
LeiWang1999 requested a review from Rachmanino August 7, 2026 08:05
Comment thread src/tl_templates/cuda/intrin.h

@Rachmanino Rachmanino left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for helping us validate these kernels on sm110!

  1. In my view, simply renaming the gemm_sm100 folder to gemm_tcgen05, along with a dedicated gemm_tcgen5mma_ws_persistent_streamk example would be better, or there's too much duplication in gemm_tcgen05 and gemm_sm100
  2. plz double check the comment I left in intrin.h

@xinhao-luo

xinhao-luo commented Aug 8, 2026 •

Copy link
Copy Markdown
Contributor Author

@Rachmanino

Thanks for the review!

  1. I've split the Stream-K kernel into a dedicated example: gemm_tcgen5mma_ws_persistent_streamk.py.
  2. Regarding intrin.h, I've replied in the inline thread.

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

🤖 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 `@examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent_streamk.py`:
- Around line 237-242: Make PartialTile validation launch-scoped in the
persistent Stream-K path: replace raw tile-id publication and matching with an
epoch-tagged value that includes the current launch identity, and ensure the
same tag is used by the fixup scan around PartialTile. Remove reliance on the
unsynchronized in-kernel reset at the tx == 128 block, while preserving the
existing even_split path.
🪄 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: Pro Plus

Run ID: 56e246c0-b7fc-48e1-9ae6-00e0b72e1e93

📥 Commits

Reviewing files that changed from the base of the PR and between b2a8c08 and 2f2cd05.

📒 Files selected for processing (5)
  • README.md
  • examples/gemm_tcgen05/README.md
  • examples/gemm_tcgen05/gemm_tcgen5mma_ws.py
  • examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py
  • examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent_streamk.py
🚧 Files skipped from review as they are similar to previous changes (3)
  • examples/gemm_tcgen05/README.md
  • examples/gemm_tcgen05/gemm_tcgen5mma_ws.py
  • examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py

Comment thread examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent_streamk.py Outdated
Comment thread examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py Outdated

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

Caution

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

⚠️ Outside diff range comments (1)
examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py (1)

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

Add input validation before get_kernel_source and launch.

The kernels still accept arbitrary CLI values until the scheduler/codegen/launch path runs. Make M, N, K, block_M, block_N, block_K, and group_size positive/integers, reject group_size that does not satisfy n_blocks % (2 * group_size) == 0, keep the existing K % (2 * block_K) == 0 checks, or document/update the 2-CTA M-tile constraint before launching.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py` at line 269, Validate
the parsed GEMM arguments before calling get_kernel_source or launching the
kernel: require M, N, K, block_M, block_N, block_K, and group_size to be
positive integers; reject group_size unless n_blocks is divisible by 2 *
group_size; preserve the existing K % (2 * block_K) checks; and enforce or
explicitly update the 2-CTA M-tile constraint before launch.
🤖 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.

Outside diff comments:
In `@examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py`:
- Line 269: Validate the parsed GEMM arguments before calling get_kernel_source
or launching the kernel: require M, N, K, block_M, block_N, block_K, and
group_size to be positive integers; reject group_size unless n_blocks is
divisible by 2 * group_size; preserve the existing K % (2 * block_K) checks; and
enforce or explicitly update the 2-CTA M-tile constraint before launch.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8d77f4aa-794a-4f47-9b20-1ef7d8eae6bf

📥 Commits

Reviewing files that changed from the base of the PR and between 22c3647 and a8451af.

📒 Files selected for processing (2)
  • examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent.py
  • examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent_streamk.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • examples/gemm_tcgen05/gemm_tcgen5mma_ws_persistent_streamk.py

@Rachmanino

Copy link
Copy Markdown
Collaborator

cc @LeiWang1999

@LeiWang1999
LeiWang1999 merged commit 14bac09 into tile-ai:main Aug 13, 2026
7 checks passed
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