Skip to content

feat(cake_tinygemm2): add CAKE-generated SM100/SM103 tinygemm2 variants with bit-identical outputs - #4274

Merged
yyihuang merged 4 commits into
flashinfer-ai:mainfrom
xslingcn:tinygemm2-loom
Aug 5, 2026
Merged

yyihuang merged 4 commits into
flashinfer-ai:mainfrom
xslingcn:tinygemm2-loom

Conversation

@xslingcn

@xslingcn xslingcn commented Jul 30, 2026

Copy link
Copy Markdown
Member

📌 Description

This PR adds tinygemm2_sm100: four CAKE-generated SM100/SM103 device
kernels specializing csrc/tinygemm2.cu (the TensorRT-LLM tinygemm2 port
behind tinygemm_bf16) for Blackwell, with bit-identical outputs and
lower latency. The bias path
of tinygemm_bf16 automatically dispatches to them on compute capability
10.0/10.3; every other path and architecture is unchanged, and
FLASHINFER_DISABLE_TINYGEMM2_SM100=1 forces the reference implementation.

The kernels are CAKE-generated Loom schedules, following the
frozen-generated-source pattern of the CAKE-generated FlashKDA prefill
export (#4262): generated kernel sources checked in verbatim
(clang-format off, provenance headers, no host-library dependency),
concatenated into a single translation unit
(csrc/tinygemm2_sm100/tinygemm2_sm100.cu) with per-variant kernel symbol
renames and a small hand-written binding section doing validation, TMA
descriptor encode, and launch — one TU, one JIT module, mirroring the
incumbent csrc/tinygemm2.cu layout. The single-TU restructure is
SASS-verified: all four kernels are byte-identical to per-variant builds on
both sm_100a and sm_103a (cuobjdump -sass, symbol names normalized).

The variants are {deep, shallow} pipeline ring x {PDL on, off}:

  • stage selection at the Python layer follows the measured B200 crossover axes
    (shallow ring for K <= 1024 or grids past 2x the SM count);
  • PDL variants compile the griddepcontrol pair in-kernel and launch with
    programmatic stream serialization, matching the reference kernel's
    USE_PDL=true instantiation;
  • the activation TMA descriptor allows an out-of-bounds box on the batch axis
    (TMA zero-fills), covering batch 1-7 decode shapes.

Correctness contract: bitwise equality with csrc/tinygemm2.cu, not a
tolerance.
On B200: torch.equal parity across batch {1,2,4,7,8,13,16,64}
x five (M, K) pairs x PDL on/off, per-variant direct launches, PDL
back-to-back replay, dispatch/escape-hatch — 23/23; existing
test_tinygemm2.py unchanged and green (59/59) with the bias path routed to
the new backend. Internally, the same generated kernels passed a 239-row
bitwise shape sweep and end-to-end gpt-oss serving with zero token flips on
both B200 and GB300 (sm_103a): greedy outputs bit-identical across arms on
gpt-oss-20b and -120b, GSM8K-200 scores identical.

Performance (torch.profiler kernel-time medians, B200, bias path, 200
launches): (1,128,720) 2.24us vs 2.34us reference; (16,1024,1024) 2.50 vs
2.58; (64,4096,3072) 18.22 vs 32.58 (1.79x). Small decode shapes are
launch-bound; a wider internal CUPTI sweep (cold L2, 35 canonical + 239
regression shapes) measured an 18-23% geometric-mean kernel-time reduction. In SGLang serving
(gpt-oss-120b) the swap measures up to +7.6% output throughput at high
concurrency (c128, TP1) over the reference path, and parity within noise at
TP4.

Limitations: the nobias path stays on the reference kernel (no generated
nobias variant yet).

🔍 Related Issues

Related to #4254 (long-term CAKE-generated kernel progress tracker).
Follows the frozen generated-kernel export pattern introduced in #4262.

🚀 Pull Request Checklist

Thank you for contributing to FlashInfer! Before we review your pull request, please make sure the following items are complete.

✅ Pre-commit Checks

  • I have installed pre-commit by running pip install pre-commit (or used your preferred method).
  • I have installed the hooks with pre-commit install.
  • I have run the hooks manually with pre-commit run --all-files and fixed any reported issues.

🧪 Tests

  • Tests have been added or updated as needed.
  • All tests are passing (unittest, etc.).

Reviewer Notes

The generated kernel sections are frozen artifacts (regeneration happens
outside this repo, as with FlashKDA); review focus is best spent on the
binding section at the tail of csrc/tinygemm2_sm100/tinygemm2_sm100.cu, the
dispatch in flashinfer/gemm/routergemm.py, and the parity tests. The TMA descriptor
encode in the binding is field-for-field identical to the reference kernel's
own cuTensorMapEncodeTiled calls.

Summary by CodeRabbit

  • New Features

    • Added optimized BF16 GEMM execution for eligible SM100/SM103 GPUs.
    • Added automatic selection among multiple kernel stages, including PDL variants, based on workload and device capabilities.
    • Added an environment-variable override to disable the optimization and retain the existing execution path.
  • Bug Fixes

    • Improved routing for bias-enabled BF16 operations while preserving existing behavior on unsupported devices and bias-free operations.
  • Tests

    • Added coverage for correctness, parity, repeated launches, variant execution, dispatch, and fallback behavior.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 30, 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

Adds SM100/SM103 TinyGEMM2 CUDA kernels with stage4, stage8, and PDL variants, JIT compilation support, architecture- and shape-aware bias dispatch, an environment override, and CUDA correctness and routing tests.

Changes

SM100 TinyGEMM2

Layer / File(s) Summary
Input contracts and launch infrastructure
csrc/tinygemm2_sm100.cu
Adds BF16 tensor validation, SM100-family checks, TMA descriptor encoding, launch configuration, PDL support, and four TVM-FFI operations.
Stage4 and stage8 regular kernels
csrc/tinygemm2_sm100.cu
Adds regular stage4 and stage8 kernels with TMA pipelines, BF16 MMA, bias addition, and guarded stores.
Stage4 and stage8 PDL kernels
csrc/tinygemm2_sm100.cu
Adds PDL stage4 and stage8 kernels with programmatic stream dependency handling.
JIT compilation and runtime dispatch
flashinfer/jit/tinygemm2.py, flashinfer/jit/__init__.py, flashinfer/gemm/routergemm.py
Adds SM100A/SM103A JIT generation, updates the re-export, selects stage variants, and routes eligible biased BF16 calls with an environment escape hatch.
SM100 correctness and dispatch coverage
tests/model_optimizations/test_tinygemm2_sm100.py
Adds parity, per-variant, repeated PDL, dispatch, and disable-override tests.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller as tinygemm_bf16
  participant Router as routergemm dispatch
  participant JIT as SM100 module loader
  participant Kernel as tinygemm2_sm100 variant
  Caller->>Router: submit biased BF16 GEMM
  Router->>Router: check SM100a support, SM count, shape, and environment
  Router->>JIT: load generated SM100 module
  JIT-->>Router: return stage4/stage8 and PDL operations
  Router->>Kernel: launch selected variant
  Kernel-->>Caller: return BF16 output
Loading

Possibly related issues

Possibly related PRs

  • flashinfer-ai/flashinfer#4279: Both PRs add SM100/SM103-specific frozen CUDA backends with JIT/AOT dispatch and escape-hatch testing, but target different kernels and APIs.

Suggested reviewers: aleozlx, dhiraj113, yzh119

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.32% 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
Title check ✅ Passed The title clearly identifies the addition of CAKE-generated SM100/SM103 tinygemm2 variants and their bit-identical outputs.
Description check ✅ Passed The description covers the change, related issues, implementation details, tests, performance, limitations, and completed checklist items.
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: 3

🧹 Nitpick comments (4)
csrc/tinygemm2_sm100/tinygemm2_sm100_binding_common.cuh (2)

181-205: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Optional: hoist the per-invocation driver queries out of the launch path.

cudaFuncSetAttribute here plus the two cudaDeviceGetAttribute calls in CheckSm100Family run on every call. Both results are stable per (device, kernel), so caching them (e.g. a function-local static table keyed by device id) removes a few microseconds of host work from a kernel selected specifically for its low latency.

🤖 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 `@csrc/tinygemm2_sm100/tinygemm2_sm100_binding_common.cuh` around lines 181 -
205, Cache the stable per-device results used by CheckSm100Family and the
cudaFuncSetAttribute setup in the launch path, using a function-local static
table keyed by device ID. Update the relevant query and attribute-setting logic
so repeated invocations reuse cached values while preserving existing behavior
for each device and kernel.

110-118: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add an explicit in_features alignment guard before TMA encoding.

EncodeWeightTma and EncodeActivationTma pass stride(0) * sizeof(__nv_bfloat16) as the global TMA stride, which must be 16B-aligned. Since stride(0) equals in_features for these 2D contiguous bfloat16 tensors, reject in_features % 8 != 0 here instead of failing later inside cuTensorMapEncodeTiled with an opaque CUresult= error.

♻️ Proposed guard
   TVM_FFI_ICHECK(in_features >= kTileK)
       << "in_features (" << in_features << ") must be at least " << kTileK << " (one TMA box)";
+  TVM_FFI_ICHECK(in_features % 8 == 0)
+      << "in_features (" << in_features
+      << ") must be a multiple of 8 so the TMA global stride is 16B-aligned";
🤖 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 `@csrc/tinygemm2_sm100/tinygemm2_sm100_binding_common.cuh` around lines 110 -
118, Add an explicit validation in the existing dimension-check block before TMA
encoding, requiring in_features to be divisible by 8 and reporting the received
value when it is not. Keep the current checks unchanged and anchor the guard
alongside the in_features validation in the binding setup.
csrc/tinygemm2_sm100/tinygemm2_sm100_stage4_binding.cu (1)

26-42: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename the generated device TUs to .cuh so they cannot be compiled standalone. The JIT source list only includes the *_binding.cu files, but the generated device units currently carry a .cu extension and are only meant to be included with per-boundary macros defined. Renaming them to .cuh/.inc removes the stale csrc/tinygemm2_sm100/*.cu glob risk and makes the include contracts explicit.

🤖 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 `@csrc/tinygemm2_sm100/tinygemm2_sm100_stage4_binding.cu` around lines 26 - 42,
Rename the generated device translation units included by the binding files to
.cuh or .inc, and update the include targets in
csrc/tinygemm2_sm100/tinygemm2_sm100_stage4_binding.cu:26-42,
csrc/tinygemm2_sm100/tinygemm2_sm100_stage8_binding.cu:26-42,
csrc/tinygemm2_sm100/tinygemm2_sm100_stage4_pdl_binding.cu:26-42, and
csrc/tinygemm2_sm100/tinygemm2_sm100_stage8_pdl_binding.cu:26-42. Preserve the
existing per-boundary macro definitions and undefinitions while ensuring the
generated units are no longer standalone .cu files.
flashinfer/jit/tinygemm2_sm100.py (1)

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

Optional: use iterable unpacking instead of list concatenation.

Static analysis flags sm100a_nvcc_flags + [...] for RUF005; [*sm100a_nvcc_flags, "-gencode=arch=compute_103a,code=sm_103a"] is the idiomatic equivalent.

🧹 Proposed nit
-        extra_cuda_cflags=sm100a_nvcc_flags
-        + ["-gencode=arch=compute_103a,code=sm_103a"],
+        extra_cuda_cflags=[
+            *sm100a_nvcc_flags,
+            "-gencode=arch=compute_103a,code=sm_103a",
+        ],
🤖 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 `@flashinfer/jit/tinygemm2_sm100.py` around lines 63 - 72, Update the
extra_cuda_cflags argument in gen_jit_spec to use iterable unpacking for
sm100a_nvcc_flags and append the compute_103a gencode flag without list
concatenation, preserving the resulting flag order and values.

Source: Linters/SAST tools

🤖 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 `@csrc/tinygemm2_sm100/tinygemm2_sm100_binding_common.cuh`:
- Around line 124-127: Correct the weight descriptor comment near tmap_wt: state
that the reduction/K axis may exceed K for non-multiple-of-1024 sizes and
correctness depends on TMA zero-filling via FLOAT_OOB_FILL_NONE, while only the
out_features axis is guaranteed in bounds. Remove the inaccurate claim that both
boxed axes remain in bounds.
- Around line 170-185: Add a CUDA device guard for input.device().device_id at
the RunStage* entry path, before stream creation/configuration and before
LaunchVariant performs cudaFuncSetAttribute or kernel launch. Match the existing
csrc binding guard pattern and keep the guard active through the full stream and
kernel execution flow.

In `@tests/model_optimizations/test_tinygemm2_sm100.py`:
- Around line 16-21: Update _skip_if_not_sm100_family to use
flashinfer.utils.is_sm100a_supported with the CUDA device, while preserving the
existing no-CUDA skip behavior. Skip the tests whenever that utility reports the
device or CUDA toolkit is unsupported, and remove the manual
get_compute_capability tuple check.

---

Nitpick comments:
In `@csrc/tinygemm2_sm100/tinygemm2_sm100_binding_common.cuh`:
- Around line 181-205: Cache the stable per-device results used by
CheckSm100Family and the cudaFuncSetAttribute setup in the launch path, using a
function-local static table keyed by device ID. Update the relevant query and
attribute-setting logic so repeated invocations reuse cached values while
preserving existing behavior for each device and kernel.
- Around line 110-118: Add an explicit validation in the existing
dimension-check block before TMA encoding, requiring in_features to be divisible
by 8 and reporting the received value when it is not. Keep the current checks
unchanged and anchor the guard alongside the in_features validation in the
binding setup.

In `@csrc/tinygemm2_sm100/tinygemm2_sm100_stage4_binding.cu`:
- Around line 26-42: Rename the generated device translation units included by
the binding files to .cuh or .inc, and update the include targets in
csrc/tinygemm2_sm100/tinygemm2_sm100_stage4_binding.cu:26-42,
csrc/tinygemm2_sm100/tinygemm2_sm100_stage8_binding.cu:26-42,
csrc/tinygemm2_sm100/tinygemm2_sm100_stage4_pdl_binding.cu:26-42, and
csrc/tinygemm2_sm100/tinygemm2_sm100_stage8_pdl_binding.cu:26-42. Preserve the
existing per-boundary macro definitions and undefinitions while ensuring the
generated units are no longer standalone .cu files.

In `@flashinfer/jit/tinygemm2_sm100.py`:
- Around line 63-72: Update the extra_cuda_cflags argument in gen_jit_spec to
use iterable unpacking for sm100a_nvcc_flags and append the compute_103a gencode
flag without list concatenation, preserving the resulting flag order and values.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f130ab3b-7310-4a56-a3f4-a28a3a3601f3

📥 Commits

Reviewing files that changed from the base of the PR and between a02d94d and 48f225a1dd1ccf1dc35dff9167a8c5b0038d3885.

📒 Files selected for processing (13)
  • csrc/tinygemm2_sm100/tinygemm2_sm100_binding_common.cuh
  • csrc/tinygemm2_sm100/tinygemm2_sm100_stage4.cu
  • csrc/tinygemm2_sm100/tinygemm2_sm100_stage4_binding.cu
  • csrc/tinygemm2_sm100/tinygemm2_sm100_stage4_pdl.cu
  • csrc/tinygemm2_sm100/tinygemm2_sm100_stage4_pdl_binding.cu
  • csrc/tinygemm2_sm100/tinygemm2_sm100_stage8.cu
  • csrc/tinygemm2_sm100/tinygemm2_sm100_stage8_binding.cu
  • csrc/tinygemm2_sm100/tinygemm2_sm100_stage8_pdl.cu
  • csrc/tinygemm2_sm100/tinygemm2_sm100_stage8_pdl_binding.cu
  • flashinfer/gemm/routergemm.py
  • flashinfer/jit/__init__.py
  • flashinfer/jit/tinygemm2_sm100.py
  • tests/model_optimizations/test_tinygemm2_sm100.py

Comment on lines +124 to +127
// 2D TMA descriptor for the weight matrix — field-for-field the descriptor
// the Loom host shim encodes for 'tmap_wt': box (kTileK, kTileM), 128B
// swizzle, no L2 promotion, no OOB fill. Both boxed axes stay in bounds
// (CheckInputs guarantees in_features >= kTileK and out_features >= kTileM).

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

The in-bounds claim for the weight descriptor is inaccurate.

The reduction axis goes out of bounds whenever K is not a multiple of 1024: the loaders address k_base = (ki * 4 + wslot) * 256 for ki < ceil(K/1024), so e.g. K = 1536 issues boxes ending at 1984. Correctness relies on TMA zero-filling those boxes (FLOAT_OOB_FILL_NONE ⇒ zero fill), exactly like the activation batch axis. Only the out_features axis is guaranteed in bounds (multiple of kTileM). Please correct the comment so the zero-fill dependency is explicit — a future reader could otherwise "harden" the descriptor and silently break non-multiple-of-1024 K.

🤖 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 `@csrc/tinygemm2_sm100/tinygemm2_sm100_binding_common.cuh` around lines 124 -
127, Correct the weight descriptor comment near tmap_wt: state that the
reduction/K axis may exceed K for non-multiple-of-1024 sizes and correctness
depends on TMA zero-filling via FLOAT_OOB_FILL_NONE, while only the out_features
axis is guaranteed in bounds. Remove the inaccurate claim that both boxed axes
remain in bounds.

Comment on lines +170 to +185
template <typename TMap>
inline void LaunchVariant(void (*kernel)(TMap, TMap, __nv_bfloat16*, __nv_bfloat16*, int, int, int),
int smem_bytes, bool pdl, const CUtensorMap& weight_map,
const CUtensorMap& activation_map, __nv_bfloat16* out,
__nv_bfloat16* bias, const ProblemDims& dims, cudaStream_t stream) {
static_assert(sizeof(TMap) == sizeof(CUtensorMap),
"generated tensor-map parameter must be layout-compatible with CUtensorMap");
TMap wt_param, act_param;
std::memcpy(&wt_param, &weight_map, sizeof(TMap));
std::memcpy(&act_param, &activation_map, sizeof(TMap));

CheckCuda(cudaFuncSetAttribute(kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, smem_bytes),
"cudaFuncSetAttribute(tinygemm2_sm100 dynamic smem)");

const dim3 grid((dims.out_features + kTileM - 1) / kTileM, (dims.batch + kTileN - 1) / kTileN);
const dim3 block(kThreads);

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# How do other csrc operators bind the device before launching?
rg -nP -C3 '(CUDADeviceGuard|cudaSetDevice|DeviceGuard)\b' csrc | head -60
# Definition of get_stream to see whether it implies a device binding
rg -nP -C6 '\bget_stream\s*\(' --iglob '*tvm_ffi_utils*'

Repository: flashinfer-ai/flashinfer

Length of output: 4550


🏁 Script executed:

#!/bin/bash
set -u

echo "== target file outline/size =="
wc -l csrc/tinygemm2_sm100/tinygemm2_sm100_binding_common.cuh
ast-grep outline csrc/tinygemm2_sm100/tinygemm2_sm100_binding_common.cuh --view expanded || true

echo
echo "== target section =="
cat -n csrc/tinygemm2_sm100/tinygemm2_sm100_binding_common.cuh | sed -n '1,240p'

echo
echo "== tinygemm2 sm100 bindings list =="
fd -t f . csrc/tinygemm2_sm100 -E 'tinygemm2_sm100_binding_common.cuh' | sort | xargs -r -n1 sh -c 'echo "--- $0"; wc -l "$0"; rg -n "RunStage|CheckInputs|LaunchVariant|get_stream|CUDADeviceGuard|cudaSetDevice|CheckCuda" "$0" -C 3 || true'

Repository: flashinfer-ai/flashinfer

Length of output: 16267


🏁 Script executed:

#!/bin/bash
set -u

echo "== tvm_ffi_utils declarations/usages =="
rg -n -C 5 '\bget_stream\s*\(' | head -120
fd -t f 'tvm_ffi_utils.*' csrc | sort | xargs -r -n1 sh -c 'echo "--- $0"; wc -l "$0"; rg -n -C 8 "get_stream|CUDADeviceGuard|class CUDADeviceGuard|struct CUDADeviceGuard|namespace ffi|inline.*device" "$0" || true'

echo
echo "== cudaFuncSetAttribute device-stream semantics references in repo comments =="
rg -n "cudaFuncSetAttribute|cudaLaunchKernelEx|programmatic stream|invalid resource|cudaErrorInvalidResourceHandle|SetDevice" csrc/include csrc | head -120

Repository: flashinfer-ai/flashinfer

Length of output: 202


🌐 Web query:

CUDA cudaFuncSetAttribute target of attribute is current device stream invalid resource handle documentation

💡 Result:

The error message "target of attribute is current device stream" is not a standard, documented error string for the cudaFuncSetAttribute API in official NVIDIA CUDA documentation [1][2][3][4]. cudaFuncSetAttribute (and its Driver API counterpart cuFuncSetAttribute) is used to set attributes for a global function (kernel) [3][4]. If the call fails due to an invalid handle or invalid resource, it typically returns specific error codes defined by the CUDA API, most commonly cudaErrorInvalidValue (or CUDA_ERROR_INVALID_VALUE in the Driver API) if the attribute cannot be written, the value is incorrect, or the function pointer is invalid [2][3][5]. In the Driver API, CUDA_ERROR_INVALID_HANDLE is also a possibility if the CUfunction handle is invalid [2]. If you are encountering an error message referring to a "current device stream," it is highly likely that you are conflating cudaFuncSetAttribute with a different API that operates on streams, such as cudaStreamSetAttribute [6]. Key distinctions: 1. cudaFuncSetAttribute: Sets attributes for a kernel (function) [3][4]. It does not take a stream as an argument [3]. 2. cudaStreamSetAttribute: Sets attributes for a stream [6]. If this API is misused or called with an invalid stream handle, it may produce errors related to stream resources [6]. To troubleshoot: - Verify that you are calling the correct API for your intent. If you intend to modify kernel properties, use cudaFuncSetAttribute [3]. If you intend to modify stream properties, use cudaStreamSetAttribute [6]. - Ensure your handles (function pointers or stream handles) are valid and have been correctly initialized before use [3][6]. - Check for cudaErrorInvalidValue or cudaErrorInvalidResourceHandle return codes, which indicate the specific nature of the configuration or handle issue [3][4].

Citations:


🌐 Web query:

CUDA driver API cuFuncSetAttribute current context launch stream foreign stream invalid resource handle

💡 Result:

In CUDA, an "invalid resource handle" error (often associated with the CUDA_ERROR_INVALID_HANDLE return code) during API calls like cuFuncSetAttribute, cuLaunchKernel, or memory operations typically indicates that a resource—such as a stream, context, or memory handle—is being used in an invalid context [1][2][3]. While cuFuncSetAttribute itself manages kernel attributes, the error does not necessarily mean the function handle is invalid. It most frequently signifies a mismatch between the current CUDA device/context and the resource handle provided [2][4][3]. Key causes and troubleshooting steps include: Device/Context Mismatch: CUDA resources (streams, memory, kernels) are bound to specific devices and contexts at the time of creation [2][4][3]. If you attempt to use a stream or other handle that was created while a different device was active, the driver will return an invalid resource handle [4][3]. Ensure that cudaSetDevice() or cuCtxSetCurrent() is called correctly for the thread before any resources are created and before they are used [5][4]. Thread-Safety: If your application is multi-threaded, each CPU thread must properly manage its current context or device [5][4]. If a thread spawns or switches devices without re-associating its context, it may inadvertently attempt to access resources owned by a different device's context [5][4][3]. Stream Lifecycle: Ensure the stream handle being passed is valid and has not been destroyed [6]. A stream created on one device cannot be used to launch work on another device [2][4][3]. "Foreign" Stream Context: While the term "foreign stream" is not a standard CUDA technical term, it often refers to streams imported from other APIs (such as Graphics interop via Direct3D or OpenGL) or streams created in a different process/context. If you are performing interop, you must ensure the foreign handle is correctly mapped and synchronized according to the specific interop requirements (e.g., using cuExternalMemory or similar mechanisms) before use [2]. Verification: To debug, verify that the device ID is consistently set for all operations involving a specific resource [4][3]. If the code works on the default device but fails on others, it is almost certainly a device-association issue [4]. Always check the return value of every CUDA driver API call to isolate exactly which function is reporting the error [1][2].

Citations:


🌐 Web query:

CUDA error cudaErrorInvalidResourceHandle launch kernel stream created on other device cudaStreamCreateWithFlags

💡 Result:

The error cudaErrorInvalidResourceHandle typically indicates that a CUDA stream is being accessed or used in a context that does not recognize it, often because it is bound to a different device or context than the one currently active [1][2]. CUDA streams are created specifically on the device context that is active at the time of creation [3][4]. If you attempt to launch a kernel, synchronize, or query a stream on a thread where a different device (or context) is currently active, the runtime may fail with cudaErrorInvalidResourceHandle because the stream handle is not valid for that specific device context [1][2][5]. Key causes and solutions include: 1. Device Context Mismatch: If you switch devices using cudaSetDevice or create a new context (e.g., when initializing libraries like TensorRT), a previously created stream may become invalid if it is not associated with the newly active context [1]. Always ensure that the correct device is set via cudaSetDevice before performing any operations on a specific stream [6][5][7]. 2. Cross-Thread Access: CUDA streams are associated with a specific host thread's context state [4][8]. While they can technically be used across threads, you must ensure that the thread attempting to use the stream has the correct device context active [2][9]. 3. Verification: To prevent these issues, it is recommended to keep track of which device a stream was created on [2][6]. You can verify the current device using cudaGetDevice and ensure it matches the device expected for that stream [6]. 4. Best Practices: If you are working in a multi-GPU environment, explicitly manage your stream-to-device association [6][5]. Some developers use a wrapper class to encapsulate both the stream and its associated device ID to ensure that cudaSetDevice is called before any operations are performed on that stream [2][6]. For further debugging, note that while some API calls (like cudaMemcpyPeerAsync or cudaStreamWaitEvent) are designed to work across devices, standard kernel launches will fail if issued to a stream not associated with the current device [5][10].

Citations:


Guard the device before configuring/launching the kernels.

RunStage* builds the stream and calls LaunchVariant from CheckInputs, but CheckInputs only compares device_id values. If this function is called while a different CUDA device is current, cudaFuncSetAttribute/cudaLaunchKernelEx can operate against the wrong device/stream context. Introduce a device guard for input.device().device_id before stream config, kernel attribute setup, and launch, matching the existing csrc binding pattern.

🤖 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 `@csrc/tinygemm2_sm100/tinygemm2_sm100_binding_common.cuh` around lines 170 -
185, Add a CUDA device guard for input.device().device_id at the RunStage* entry
path, before stream creation/configuration and before LaunchVariant performs
cudaFuncSetAttribute or kernel launch. Match the existing csrc binding guard
pattern and keep the guard active through the full stream and kernel execution
flow.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

hi @xslingcn I sugguested to encode. tma descriptor from a platform indepenty repr :

raw c pointer, layout of shape, stride

So the codes can be either neatly ported w or w/o TVM-FFI interfaces.

Comment thread tests/model_optimizations/test_tinygemm2_sm100.py
@xslingcn xslingcn changed the title feat(gemm): SM100/SM103 specialized tinygemm2 variants with bit-identical outputs feat(cake_tinygemm2): add CAKE-generated SM100/SM103 tinygemm2 variants with bit-identical outputs Jul 30, 2026

@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)
flashinfer/jit/tinygemm2_sm100.py (1)

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

Use iterable unpacking for CUDA flag construction.

Ruff RUF005 flags concatenating sm100a_nvcc_flags with a single-item list. This preserves the same flag order while avoiding the warning:

Proposed fix
-        extra_cuda_cflags=sm100a_nvcc_flags
-        + ["-gencode=arch=compute_103a,code=sm_103a"],
+        extra_cuda_cflags=[
+            *sm100a_nvcc_flags,
+            "-gencode=arch=compute_103a,code=sm_103a",
+        ],
🤖 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 `@flashinfer/jit/tinygemm2_sm100.py` around lines 34 - 35, Update the CUDA
flags passed via extra_cuda_cflags in the relevant build configuration to use
iterable unpacking of sm100a_nvcc_flags followed by the compute_103a flag,
preserving the existing order and values while removing list concatenation.

Source: Linters/SAST tools

csrc/tinygemm2_sm100/tinygemm2_sm100.cu (2)

1539-1540: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Per-invocation CUDA setup queries on a microsecond-scale path. Both sites re-query immutable state (kernel smem opt-in, device compute capability) on every RunStage* call; cache each once instead.

  • csrc/tinygemm2_sm100/tinygemm2_sm100.cu#L1539-L1540: issue cudaFuncSetAttribute once per kernel function pointer.
  • csrc/tinygemm2_sm100/tinygemm2_sm100.cu#L1409-L1419: cache the compute capability per device id and validate from the cache.
🤖 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 `@csrc/tinygemm2_sm100/tinygemm2_sm100.cu` around lines 1539 - 1540, The
RunStage* CUDA setup currently repeats immutable queries on every invocation. In
csrc/tinygemm2_sm100/tinygemm2_sm100.cu lines 1539-1540, cache successful
cudaFuncSetAttribute state once per kernel function pointer and skip subsequent
calls; in lines 1409-1419, cache compute capability by device ID and validate
using the cached value rather than querying CUDA each time.

1467-1470: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Validate the TMA global-stride constraint explicitly.

The 128B-swizzled descriptors require the row stride in bytes to be a multiple of 16, i.e. in_features % 8 == 0. Today an odd in_features (e.g. 100) passes CheckInputs and surfaces later as a bare cuTensorMapEncodeTiled failed ... CUresult=N. A direct check gives a usable message.

♻️ Suggested check
   TVM_FFI_ICHECK(in_features >= kTileK)
       << "in_features (" << in_features << ") must be at least " << kTileK << " (one TMA box)";
+  TVM_FFI_ICHECK(in_features % 8 == 0)
+      << "in_features (" << in_features
+      << ") must be a multiple of 8 so the row stride is 16B-aligned for the 128B-swizzled TMA "
+         "descriptors";
   TVM_FFI_ICHECK(out_features >= kTileM && out_features % kTileM == 0)
🤖 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 `@csrc/tinygemm2_sm100/tinygemm2_sm100.cu` around lines 1467 - 1470, Update the
input validation near the existing in_features check in CheckInputs to require
in_features % 8 == 0, with a clear message stating that in_features must be a
multiple of 8 for the TMA global stride. Preserve the existing minimum-size
validation and out_features checks.
🤖 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 `@csrc/tinygemm2_sm100/tinygemm2_sm100.cu`:
- Around line 1480-1483: Update the TMA descriptor comments near the
weight-matrix descriptor to state that the kernel’s K-axis traversal may extend
to ceil(K/1024)*1024 beyond in_features and relies on TMA zero-fill for the
overrun, rather than claiming both boxed axes remain in bounds or that there is
no OOB fill. Preserve the existing description of the descriptor’s box
dimensions and swizzle behavior.
- Around line 1568-1612: Update RunStage4, RunStage4Pdl, RunStage8, and
RunStage8Pdl to create an ffi::CUDADeviceGuard for input.device().device_id
before TMA encoding and LaunchVariant execution. Keep the guard active through
stream retrieval, cuTensorMap encoding, and kernel launch so all SM100 setup and
launch calls run on input’s device.

---

Nitpick comments:
In `@csrc/tinygemm2_sm100/tinygemm2_sm100.cu`:
- Around line 1539-1540: The RunStage* CUDA setup currently repeats immutable
queries on every invocation. In csrc/tinygemm2_sm100/tinygemm2_sm100.cu lines
1539-1540, cache successful cudaFuncSetAttribute state once per kernel function
pointer and skip subsequent calls; in lines 1409-1419, cache compute capability
by device ID and validate using the cached value rather than querying CUDA each
time.
- Around line 1467-1470: Update the input validation near the existing
in_features check in CheckInputs to require in_features % 8 == 0, with a clear
message stating that in_features must be a multiple of 8 for the TMA global
stride. Preserve the existing minimum-size validation and out_features checks.

In `@flashinfer/jit/tinygemm2_sm100.py`:
- Around line 34-35: Update the CUDA flags passed via extra_cuda_cflags in the
relevant build configuration to use iterable unpacking of sm100a_nvcc_flags
followed by the compute_103a flag, preserving the existing order and values
while removing list concatenation.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: beae5624-ed36-47bb-bdcf-cb15e8c26b41

📥 Commits

Reviewing files that changed from the base of the PR and between 48f225a1dd1ccf1dc35dff9167a8c5b0038d3885 and 57cf3f00aed451faa3d7c7d460d140f16754168d.

📒 Files selected for processing (3)
  • csrc/tinygemm2_sm100/tinygemm2_sm100.cu
  • flashinfer/jit/tinygemm2_sm100.py
  • tests/model_optimizations/test_tinygemm2_sm100.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/model_optimizations/test_tinygemm2_sm100.py

Comment thread csrc/tinygemm2_sm100.cu
Comment on lines +1480 to +1483
// 2D TMA descriptor for the weight matrix — field-for-field the descriptor
// the Loom host shim encodes for 'tmap_wt': box (kTileK, kTileM), 128B
// swizzle, no L2 promotion, no OOB fill. Both boxed axes stay in bounds
// (CheckInputs guarantees in_features >= kTileK and out_features >= kTileM).

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

Comment contradicts the kernels' K-axis access pattern.

Both loaders iterate k_loops = (K + 1023) / 1024 and issue boxes at k_base + i*64 (lines 406-421, 986-1001), so the K axis is read up to ceil(K/1024)*1024 — out of bounds whenever in_features % 1024 != 0 (the test suite's in_features=720 hits this). Correctness there relies on TMA zero-fill, exactly the property this comment denies; the activation comment at Line 1501-1503 documents zero-fill only for the batch axis. Please restate that the K axis may also overrun and is zero-filled, otherwise a future reader may "harden" the descriptor and silently break results.

As per coding guidelines: "Keep documentation synchronized with code changes, including infrastructure examples, skill files, conventions, deprecated approaches, and new error-handling patterns."

🤖 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 `@csrc/tinygemm2_sm100/tinygemm2_sm100.cu` around lines 1480 - 1483, Update the
TMA descriptor comments near the weight-matrix descriptor to state that the
kernel’s K-axis traversal may extend to ceil(K/1024)*1024 beyond in_features and
relies on TMA zero-fill for the overrun, rather than claiming both boxed axes
remain in bounds or that there is no OOB fill. Preserve the existing description
of the descriptor’s box dimensions and swizzle behavior.

Source: Coding guidelines

Comment thread csrc/tinygemm2_sm100.cu
Comment on lines +1568 to +1612
void RunStage4(TensorView input, TensorView weight, TensorView bias, TensorView out) {
const ProblemDims dims = CheckInputs(input, weight, bias, out);
const CUtensorMap weight_map = EncodeWeightTma(weight);
const CUtensorMap activation_map = EncodeActivationTma(input);
const cudaStream_t stream = get_stream(input.device());
LaunchVariant(&kernel_tinygemm2_sm100_stage4, kSmemBytesStage4, /*pdl=*/false, weight_map,
activation_map, reinterpret_cast<__nv_bfloat16*>(out.data_ptr()),
reinterpret_cast<__nv_bfloat16*>(bias.data_ptr()), dims, stream);
}

// out = input @ weight.T + bias (bf16, fp32 accumulation), column-major
// epilogue identical to csrc/tinygemm2.cu.
void RunStage4Pdl(TensorView input, TensorView weight, TensorView bias, TensorView out) {
const ProblemDims dims = CheckInputs(input, weight, bias, out);
const CUtensorMap weight_map = EncodeWeightTma(weight);
const CUtensorMap activation_map = EncodeActivationTma(input);
const cudaStream_t stream = get_stream(input.device());
LaunchVariant(&kernel_tinygemm2_sm100_stage4_pdl, kSmemBytesStage4Pdl, /*pdl=*/true, weight_map,
activation_map, reinterpret_cast<__nv_bfloat16*>(out.data_ptr()),
reinterpret_cast<__nv_bfloat16*>(bias.data_ptr()), dims, stream);
}

// out = input @ weight.T + bias (bf16, fp32 accumulation), column-major
// epilogue identical to csrc/tinygemm2.cu.
void RunStage8(TensorView input, TensorView weight, TensorView bias, TensorView out) {
const ProblemDims dims = CheckInputs(input, weight, bias, out);
const CUtensorMap weight_map = EncodeWeightTma(weight);
const CUtensorMap activation_map = EncodeActivationTma(input);
const cudaStream_t stream = get_stream(input.device());
LaunchVariant(&kernel_tinygemm2_sm100_stage8, kSmemBytesStage8, /*pdl=*/false, weight_map,
activation_map, reinterpret_cast<__nv_bfloat16*>(out.data_ptr()),
reinterpret_cast<__nv_bfloat16*>(bias.data_ptr()), dims, stream);
}

// out = input @ weight.T + bias (bf16, fp32 accumulation), column-major
// epilogue identical to csrc/tinygemm2.cu.
void RunStage8Pdl(TensorView input, TensorView weight, TensorView bias, TensorView out) {
const ProblemDims dims = CheckInputs(input, weight, bias, out);
const CUtensorMap weight_map = EncodeWeightTma(weight);
const CUtensorMap activation_map = EncodeActivationTma(input);
const cudaStream_t stream = get_stream(input.device());
LaunchVariant(&kernel_tinygemm2_sm100_stage8_pdl, kSmemBytesStage8Pdl, /*pdl=*/true, weight_map,
activation_map, reinterpret_cast<__nv_bfloat16*>(out.data_ptr()),
reinterpret_cast<__nv_bfloat16*>(bias.data_ptr()), dims, stream);
}

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 | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm the guard type/ctor signature used elsewhere in csrc.
rg -nP --type=cu -C2 '\bCUDADeviceGuard\b' | head -50
fd -t f 'tvm_ffi_utils.h' --exec rg -nP -C4 'class\s+CUDADeviceGuard|struct\s+CUDADeviceGuard'

Repository: flashinfer-ai/flashinfer

Length of output: 193


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file exists =="
git ls-files | rg '(^|/)csrc/tinygemm2_sm100/tinygemm2_sm100\.cu$|tvm_ffi_utils\.h$' || true

echo "== CUDADeviceGuard occurrences in tracked source =="
rg -n -C3 '\bCUDADeviceGuard\b' --glob '*.cu' --glob '*.h' --glob '*.cuh' .

echo "== get_stream / LaunchVariant / EncodeWeightTma definitions =="
rg -n -C5 'CUtensorMap Encode(Weight|Activation)Tma|CUDADeviceGuard|get_stream\(|LaunchVariant\b|cudaLaunchKernelEx|cudaFuncSetAttribute|cudaSetDevice\b' --glob '*.cu' --glob '*.h' --glob '*.cuh' .

Repository: flashinfer-ai/flashinfer

Length of output: 50381


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== target file outline / relevant lines =="
wc -l csrc/tinygemm2_sm100/tinygemm2_sm100.cu
sed -n '1,80p' csrc/tinygemm2_sm100/tinygemm2_sm100.cu
sed -n '1520,1635p' csrc/tinygemm2_sm100/tinygemm2_sm100.cu

echo "== locate tinygemm2_sm100 helpers =="
rg -n -C4 'std::variant|struct DeviceGuard|class DeviceGuard|struct CUDADeviceGuard|struct CUDAStreamGuard|inline cudaStream_t get_stream|TensorView device\(\)|cuTensorMapEncodeTiled|LaunchVariant\b' csrc/tinygemm2_sm100 csrc/include csrc -g '*tinygemm2_sm100*' --glob '*.h' --glob '*.cu' --glob '*.cuh'

Repository: flashinfer-ai/flashinfer

Length of output: 50380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== tvm_ffi_utils.h relevant definitions =="
sed -n '300,355p' csrc/tvm_ffi_utils.h
rg -n -C4 'struct CUDADeviceGuard|struct CUDAStreamGuard|inline cudaStream_t get_stream\(const TensorView|class TensorView|struct TensorView' csrc/tvm_ffi_utils.h

echo "== compact CUDADeviceGuard usage examples =="
rg -n --glob '*.cu' --glob '*.h' --glob '*.cuh' 'ffi::CUDADeviceGuard device_guard\(' | head -30

echo "== target launcher/calls compact =="
sed -n '1480,1615p' csrc/tinygemm2_sm100/tinygemm2_sm100.cu

Repository: flashinfer-ai/flashinfer

Length of output: 2731


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== CUDADeviceGuard definition and surrounding helpers =="
rg -n -C6 'CUDADeviceGuard|CUDAStreamGuard|TVMFFIEnvGetStream|kDLCUDA' csrc/tvm_ffi_utils.h csrc | head -160

echo "== compact target launcher/code =="
sed -n '1480,1615p' csrc/tinygemm2_sm100/tinygemm2_sm100.cu

Repository: flashinfer-ai/flashinfer

Length of output: 19489


Add the device guard around the SM100 TMA/lane setup.

RunStage4/4Pdl/8/8Pdl retrieve input.device()’s stream but do not make that device current before cuTensorMapEncodeTiled, cudaFuncSetAttribute, or the kernel launch. Add ffi::CUDADeviceGuard device_guard(input.device().device_id); before the encoding/launcher path and keep LaunchVariant device-scoped for the smem/launch calls, matching the existing csrc pattern.

🤖 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 `@csrc/tinygemm2_sm100/tinygemm2_sm100.cu` around lines 1568 - 1612, Update
RunStage4, RunStage4Pdl, RunStage8, and RunStage8Pdl to create an
ffi::CUDADeviceGuard for input.device().device_id before TMA encoding and
LaunchVariant execution. Keep the guard active through stream retrieval,
cuTensorMap encoding, and kernel launch so all SM100 setup and launch calls run
on input’s device.

@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 (1)
flashinfer/jit/tinygemm2.py (1)

30-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use iterable unpacking for the CUDA flags.

Ruff RUF005 flags concatenating a one-element list here. This preserves the same flags while matching the repository’s lint configuration.

Proposed fix
-        extra_cuda_cflags=sm100a_nvcc_flags
-        + ["-gencode=arch=compute_103a,code=sm_103a"],
+        extra_cuda_cflags=[
+            *sm100a_nvcc_flags,
+            "-gencode=arch=compute_103a,code=sm_103a",
+        ],
🤖 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 `@flashinfer/jit/tinygemm2.py` around lines 30 - 31, Update the
extra_cuda_cflags construction in the tinygemm2 configuration to use iterable
unpacking for sm100a_nvcc_flags and the additional CUDA flag instead of list
concatenation, preserving the exact flag order and values.

Source: Linters/SAST tools

🤖 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 `@csrc/tinygemm2_sm100.cu`:
- Around line 1466-1474: Add an ICHECK alongside the existing dimension
validation in the kernel entry-point checks, requiring in_features to be
divisible by 8 and reporting the received value and alignment requirement. Keep
the existing minimum-size and scalar-range validations unchanged so misaligned
inputs fail with a clear shape diagnostic before EncodeWeightTma or
EncodeActivationTma runs.

In `@flashinfer/gemm/routergemm.py`:
- Around line 518-522: The documentation for _use_tinygemm2_sm100 inaccurately
claims all SM100/SM103 devices use the generated kernel. Update its docstring to
state that dispatch requires compute capability 10.x and CUDA 12.8 or newer via
is_sm100a_supported, while preserving the FLASHINFER_DISABLE_TINYGEMM2_SM100
override description.

---

Nitpick comments:
In `@flashinfer/jit/tinygemm2.py`:
- Around line 30-31: Update the extra_cuda_cflags construction in the tinygemm2
configuration to use iterable unpacking for sm100a_nvcc_flags and the additional
CUDA flag instead of list concatenation, preserving the exact flag order and
values.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 21b4cd41-c96d-4fe2-b0c2-354287d2ec42

📥 Commits

Reviewing files that changed from the base of the PR and between 57cf3f00aed451faa3d7c7d460d140f16754168d and 80d4ef57adb9e023dd35a47d6087166af96ebaed.

📒 Files selected for processing (4)
  • csrc/tinygemm2_sm100.cu
  • flashinfer/gemm/routergemm.py
  • flashinfer/jit/__init__.py
  • flashinfer/jit/tinygemm2.py

Comment thread csrc/tinygemm2_sm100.cu
Comment on lines +1466 to +1474
TVM_FFI_ICHECK(batch > 0) << "batch must be positive, got " << batch;
TVM_FFI_ICHECK(in_features >= kTileK)
<< "in_features (" << in_features << ") must be at least " << kTileK << " (one TMA box)";
TVM_FFI_ICHECK(out_features >= kTileM && out_features % kTileM == 0)
<< "out_features (" << out_features << ") must be a positive multiple of " << kTileM;
TVM_FFI_ICHECK(batch <= std::numeric_limits<int>::max() &&
in_features <= std::numeric_limits<int>::max() &&
out_features <= std::numeric_limits<int>::max())
<< "problem dimensions exceed the kernel's i32 scalar range";

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

Add the in_features alignment precondition.

cuTensorMapEncodeTiled requires each globalStrides entry to be a multiple of 16 bytes, and both encoders pass stride(0) * sizeof(__nv_bfloat16) = in_features * 2. So in_features must be a multiple of 8; otherwise callers get an opaque CUresult= failure from EncodeWeightTma/EncodeActivationTma instead of a shape diagnostic.

🛡️ Proposed guard
   TVM_FFI_ICHECK(in_features >= kTileK)
       << "in_features (" << in_features << ") must be at least " << kTileK << " (one TMA box)";
+  TVM_FFI_ICHECK(in_features % 8 == 0)
+      << "in_features (" << in_features
+      << ") must be a multiple of 8 so the TMA global stride is 16B-aligned";
📝 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
TVM_FFI_ICHECK(batch > 0) << "batch must be positive, got " << batch;
TVM_FFI_ICHECK(in_features >= kTileK)
<< "in_features (" << in_features << ") must be at least " << kTileK << " (one TMA box)";
TVM_FFI_ICHECK(out_features >= kTileM && out_features % kTileM == 0)
<< "out_features (" << out_features << ") must be a positive multiple of " << kTileM;
TVM_FFI_ICHECK(batch <= std::numeric_limits<int>::max() &&
in_features <= std::numeric_limits<int>::max() &&
out_features <= std::numeric_limits<int>::max())
<< "problem dimensions exceed the kernel's i32 scalar range";
TVM_FFI_ICHECK(batch > 0) << "batch must be positive, got " << batch;
TVM_FFI_ICHECK(in_features >= kTileK)
<< "in_features (" << in_features << ") must be at least " << kTileK << " (one TMA box)";
TVM_FFI_ICHECK(in_features % 8 == 0)
<< "in_features (" << in_features
<< ") must be a multiple of 8 so the TMA global stride is 16B-aligned";
TVM_FFI_ICHECK(out_features >= kTileM && out_features % kTileM == 0)
<< "out_features (" << out_features << ") must be a positive multiple of " << kTileM;
TVM_FFI_ICHECK(batch <= std::numeric_limits<int>::max() &&
in_features <= std::numeric_limits<int>::max() &&
out_features <= std::numeric_limits<int>::max())
<< "problem dimensions exceed the kernel's i32 scalar range";
🤖 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 `@csrc/tinygemm2_sm100.cu` around lines 1466 - 1474, Add an ICHECK alongside
the existing dimension validation in the kernel entry-point checks, requiring
in_features to be divisible by 8 and reporting the received value and alignment
requirement. Keep the existing minimum-size and scalar-range validations
unchanged so misaligned inputs fail with a clear shape diagnostic before
EncodeWeightTma or EncodeActivationTma runs.

Comment on lines +518 to +522
On SM100/SM103 (B200/B300 class) devices the bias path dispatches to
``tinygemm2_sm100`` — generated variants of the same kernel with
bit-identical outputs and lower latency (see
``csrc/tinygemm2_sm100.cu``). Set ``FLASHINFER_DISABLE_TINYGEMM2_SM100=1``
to force the reference implementation everywhere.

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

Document the CUDA 12.8 eligibility gate.

_use_tinygemm2_sm100 delegates to is_sm100a_supported, so the optimized path is used only on compute capability 10.x with CUDA 12.8 or newer. The current docstring says all SM100/SM103 devices dispatch to the generated kernel.

-    On SM100/SM103 (B200/B300 class) devices the bias path dispatches to
+    When ``is_sm100a_supported(input.device)`` is true (SM100/SM103 with
+    CUDA 12.8 or newer), the bias path dispatches to

As per coding guidelines, documentation must remain synchronized with code changes.

📝 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
On SM100/SM103 (B200/B300 class) devices the bias path dispatches to
``tinygemm2_sm100``generated variants of the same kernel with
bit-identical outputs and lower latency (see
``csrc/tinygemm2_sm100.cu``). Set ``FLASHINFER_DISABLE_TINYGEMM2_SM100=1``
to force the reference implementation everywhere.
When ``is_sm100a_supported(input.device)`` is true (SM100/SM103 with
CUDA 12.8 or newer), the bias path dispatches to
``tinygemm2_sm100``generated variants of the same kernel with
bit-identical outputs and lower latency (see
``csrc/tinygemm2_sm100.cu``). Set ``FLASHINFER_DISABLE_TINYGEMM2_SM100=1``
to force the reference implementation everywhere.
🤖 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 `@flashinfer/gemm/routergemm.py` around lines 518 - 522, The documentation for
_use_tinygemm2_sm100 inaccurately claims all SM100/SM103 devices use the
generated kernel. Update its docstring to state that dispatch requires compute
capability 10.x and CUDA 12.8 or newer via is_sm100a_supported, while preserving
the FLASHINFER_DISABLE_TINYGEMM2_SM100 override description.

Source: Coding guidelines

@yyihuang

yyihuang commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

/bot run

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

GitLab MR !1117 has been created, and the CI pipeline #60909291 is currently running. I'll report back once the pipeline job completes.

Add four frozen device TUs generated from Loom schedules that exactly port
csrc/tinygemm2.cu (deep/shallow pipeline ring x PDL on/off), with
bit-identical outputs and lower measured latency on B200. The bias path of
tinygemm_bf16 dispatches to them on SM100/SM103; set
FLASHINFER_DISABLE_TINYGEMM2_SM100=1 to force the reference implementation.

- csrc/tinygemm2_sm100/: generated device TUs (verbatim, clang-format off)
  + one binding TU per variant (typedef isolation + per-variant kernel
  symbol rename), linked into a single JIT module
- stage selection mirrors the measured B200 crossover axes: shallow ring
  for K <= 1024 or grids past 2x SM count
- activation TMA descriptor allows an out-of-bounds box on the batch axis
  (TMA zero-fills), so batch 1..7 decode shapes are covered
- tests: bitwise parity vs csrc/tinygemm2.cu across the batch/K/stage
  axes, per-variant direct launches, PDL back-to-back, dispatch escape
  hatch
shanlix-nv and others added 3 commits August 4, 2026 01:09
…le JIT module

Follow the repo convention set by the incumbent csrc/tinygemm2.cu (one
translation unit holding the whole kernel family plus its TVM-FFI
binding, one JitSpec listing that single file): the four generated
SM100/SM103 variants (stage4/stage8 pipeline ring x PDL on/off) now
live in a single csrc/tinygemm2_sm100/tinygemm2_sm100.cu instead of
four device TUs + four binding TUs + a shared binding header.

Mechanical transform (no kernel code touched):
- the extern "C" symbol kernel_flashinfer_tinygemm2 is renamed per
  section to kernel_tinygemm2_sm100_{stage4,stage4_pdl,stage8,
  stage8_pdl}
- each section keeps its generated #define block verbatim and #undef's
  all 17 metadata macros plus the 3 in-kernel mbarrier address macros
  at section end; SMEM_TOTAL/USE_PDL are captured into per-variant
  constexprs carrying the same static_asserts the per-variant bindings
  had
- the generated prelude's fixed-width typedefs and opaque CUtensorMap
  typedef are dropped in favor of the host headers; the LoomTensorMap
  struct and __device__ helpers (byte-identical across the four
  generated TUs) are deduplicated to one copy
- binding_common.cuh and the four binding TUs fold into the same file;
  LaunchVariant is de-templatized (one concrete LoomTensorMap now);
  the exported op names (stage4_op, stage4_pdl_op, stage8_op,
  stage8_pdl_op) are unchanged, so routergemm.py dispatch and the test
  semantics needed no changes.

Kernel bodies are byte-identical to the generated output modulo the
symbol rename (asserted by the merge script). SASS identity was
verified with cuobjdump -sass on the JIT-built modules before/after
the merge: all 8 kernel/arch pairs
(4 variants x {sm_100a, sm_103a}) are byte-identical after normalizing only the kernel symbol name (1265/1281/1457/1473
SASS lines per stage4/stage4_pdl/stage8/stage8_pdl kernel).

Validation on GB200 (sm_100):
- tests/model_optimizations/test_tinygemm2_sm100.py: 23 passed
- tests/model_optimizations/test_tinygemm2.py: 59 passed (incumbent path
  unaffected)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mm2.py, reuse is_sm100a_supported

- csrc/tinygemm2_sm100/tinygemm2_sm100.cu -> csrc/tinygemm2_sm100.cu: after
  the single-TU merge the subdirectory held one file; the incumbent
  convention is a flat csrc/tinygemm2.cu. Pure rename, content unchanged.
- gen_tinygemm2_sm100_module moved into flashinfer/jit/tinygemm2.py next to
  gen_tinygemm2_module (family jit files hold all their variants — see
  jit/fused_moe.py with seven gens); flashinfer/jit/tinygemm2_sm100.py
  removed, package-level import path unchanged.
- _use_tinygemm2_sm100 now gates on flashinfer.utils.is_sm100a_supported
  instead of a hand-rolled compute-capability tuple check — same devices,
  plus the util's CUDA>=12.8 toolchain floor the ad-hoc check was missing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Same rationale as the dispatch change: reuse flashinfer's own capability
util instead of a hand-rolled compute-capability tuple check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@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 (1)
tests/model_optimizations/test_tinygemm2_sm100.py (1)

167-188: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Assert the selected backend.

Both backends have the same output contract. The current assertions can pass if tinygemm_bf16 always selects the reference module. Wrap or monkeypatch get_tinygemm2_sm100_module and get_tinygemm2_module, then assert that the enabled case calls the SM100 op and the escape-hatch case calls the reference op.

🤖 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/model_optimizations/test_tinygemm2_sm100.py` around lines 167 - 188,
Strengthen test_tinygemm2_sm100_dispatch_and_escape_hatch by monkeypatching
get_tinygemm2_sm100_module and get_tinygemm2_module with wrappers that record
invocations while preserving behavior. Assert the enabled call selects the SM100
backend and, after setting FLASHINFER_DISABLE_TINYGEMM2_SM100, the escape-hatch
call selects the reference backend, while retaining the existing output checks.
🤖 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 `@flashinfer/gemm/routergemm.py`:
- Line 441: In flashinfer/gemm/routergemm.py at line 441, rename the private
wrapper parameter `input` to a domain-specific identifier like `activations`, or
add a narrow A002 suppression if the registered custom-op schema requires
retaining the `input` name. In
tests/model_optimizations/test_tinygemm2_sm100.py, rename all variables
shadowing the builtin `input` to `activations` or an appropriate domain-specific
name at lines 25, 75, 118, 146, 159, and 174. These renames will resolve the
Ruff A001/A002 linting errors caused by shadowing Python builtins.

In `@tests/model_optimizations/test_tinygemm2_sm100.py`:
- Around line 3-6: Correct the CUDA source path in the test documentation to
reference csrc/tinygemm2_sm100.cu, matching the JIT generator specification; do
not alter the parity tests or their torch.equal behavior.

---

Nitpick comments:
In `@tests/model_optimizations/test_tinygemm2_sm100.py`:
- Around line 167-188: Strengthen test_tinygemm2_sm100_dispatch_and_escape_hatch
by monkeypatching get_tinygemm2_sm100_module and get_tinygemm2_module with
wrappers that record invocations while preserving behavior. Assert the enabled
call selects the SM100 backend and, after setting
FLASHINFER_DISABLE_TINYGEMM2_SM100, the escape-hatch call selects the reference
backend, while retaining the existing output checks.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0eb1ba4f-0ef5-4621-bd13-e05ab6918772

📥 Commits

Reviewing files that changed from the base of the PR and between ceeb31aee0f75e4d1e9076fa6088daa8c9d95545 and b38a0d6.

📒 Files selected for processing (5)
  • csrc/tinygemm2_sm100.cu
  • flashinfer/gemm/routergemm.py
  • flashinfer/jit/__init__.py
  • flashinfer/jit/tinygemm2.py
  • tests/model_optimizations/test_tinygemm2_sm100.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • flashinfer/jit/init.py
  • csrc/tinygemm2_sm100.cu

mutates_args=["out"],
)
def tinygemm2_sm100_op_impl(
input: torch.Tensor,

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

Resolve the new Ruff A001/A002 errors.

New code shadows the Python builtin input. Rename these identifiers to activations or another domain-specific name. If the registered custom-op schema must retain input, use a narrow A002 suppression with that rationale.

  • flashinfer/gemm/routergemm.py#L441-L441: rename the private wrapper parameter, or add a narrow documented A002 suppression if the schema requires this name.
  • tests/model_optimizations/test_tinygemm2_sm100.py#L25-L25: rename the generated activation tensor.
  • tests/model_optimizations/test_tinygemm2_sm100.py#L75-L75: rename the unpacked activation tensor.
  • tests/model_optimizations/test_tinygemm2_sm100.py#L118-L118: rename the unpacked activation tensor.
  • tests/model_optimizations/test_tinygemm2_sm100.py#L146-L146: rename the loop activation tensor.
  • tests/model_optimizations/test_tinygemm2_sm100.py#L159-L159: rename the unpacked activation tensor.
  • tests/model_optimizations/test_tinygemm2_sm100.py#L174-L174: rename the generated activation tensor.
🧰 Tools
🪛 Ruff (0.16.0)

[error] 441-441: Function argument input is shadowing a Python builtin

(A002)

📍 Affects 2 files
  • flashinfer/gemm/routergemm.py#L441-L441 (this comment)
  • tests/model_optimizations/test_tinygemm2_sm100.py#L25-L25
  • tests/model_optimizations/test_tinygemm2_sm100.py#L75-L75
  • tests/model_optimizations/test_tinygemm2_sm100.py#L118-L118
  • tests/model_optimizations/test_tinygemm2_sm100.py#L146-L146
  • tests/model_optimizations/test_tinygemm2_sm100.py#L159-L159
  • tests/model_optimizations/test_tinygemm2_sm100.py#L174-L174
🤖 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 `@flashinfer/gemm/routergemm.py` at line 441, In flashinfer/gemm/routergemm.py
at line 441, rename the private wrapper parameter `input` to a domain-specific
identifier like `activations`, or add a narrow A002 suppression if the
registered custom-op schema requires retaining the `input` name. In
tests/model_optimizations/test_tinygemm2_sm100.py, rename all variables
shadowing the builtin `input` to `activations` or an appropriate domain-specific
name at lines 25, 75, 118, 146, 159, and 174. These renames will resolve the
Ruff A001/A002 linting errors caused by shadowing Python builtins.

Source: Linters/SAST tools

Comment on lines +3 to +6
The four frozen variants in ``csrc/tinygemm2_sm100/tinygemm2_sm100.cu`` are
generated Loom schedules exactly porting ``csrc/tinygemm2.cu``; the contract
is bit-identical outputs. Every parity test below therefore uses
``torch.equal``, not a tolerance.

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

Correct the documented CUDA source path.

The JIT generator compiles csrc/tinygemm2_sm100.cu. This docstring instead names csrc/tinygemm2_sm100/tinygemm2_sm100.cu. Update the path so the test documentation matches the JIT specification.

Proposed fix
-The four frozen variants in ``csrc/tinygemm2_sm100/tinygemm2_sm100.cu`` are
+The four frozen variants in ``csrc/tinygemm2_sm100.cu`` are
📝 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
The four frozen variants in ``csrc/tinygemm2_sm100/tinygemm2_sm100.cu`` are
generated Loom schedules exactly porting ``csrc/tinygemm2.cu``; the contract
is bit-identical outputs. Every parity test below therefore uses
``torch.equal``, not a tolerance.
The four frozen variants in ``csrc/tinygemm2_sm100.cu`` are
generated Loom schedules exactly porting ``csrc/tinygemm2.cu``; the contract
is bit-identical outputs. Every parity test below therefore uses
``torch.equal``, not a tolerance.
🤖 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/model_optimizations/test_tinygemm2_sm100.py` around lines 3 - 6,
Correct the CUDA source path in the test documentation to reference
csrc/tinygemm2_sm100.cu, matching the JIT generator specification; do not alter
the parity tests or their torch.equal behavior.

Source: Coding guidelines

@yyihuang

yyihuang commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

/bot run tests/model_optimizations/test_tinygemm2_sm100.py

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

GitLab MR !1117 has been updated with latest changes, and the CI pipeline #61008116 is currently running. I'll report back once the pipeline job completes.

@yyihuang

yyihuang commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

/bot run tests/model_optimizations

@flashinfer-bot

Copy link
Copy Markdown
Collaborator

GitLab MR !1117 has been created, and the CI pipeline #61113105 is currently running. I'll report back once the pipeline job completes.

@yyihuang
yyihuang merged commit 339a8f4 into flashinfer-ai:main Aug 5, 2026
35 checks passed
bkryu pushed a commit that referenced this pull request Aug 11, 2026
…ge-K shapes (#4423)

## 📌 Description

Adds a third ring-depth tier to the `tinygemm2_sm100` family (#4274) and
moves ring selection into the binding. All six kernels are regenerated
from
the current CAKE generator state, which also updates the tensor-map
parameter passing to a single by-value `__grid_constant__` pack.

- **New STAGES=16 ring for single-wave large-K shapes.** The 4/8-stage
rings were tuned for K up to ~4K; at larger K the 8-deep ring no longer
covers the weight-stream latency when the working set is not
L2-resident,
and trails the reference kernel's own 16-deep configuration. The new
tier
closes that: at N=8/M=128/K=7168 (bias path) it measures **4.93 µs vs
the
reference's 5.22 µs on GB300, and 5.31 µs vs 5.56 µs on B200** (cold-L2
  CUPTI).
- **Ring selection in the binding**, following the reference
`csrc/tinygemm2.cu` launcher convention: stage 4 for K <= 1024 or grids
  past 2x the SM count (unchanged), stage 16 for single-wave grids with
K >= 4608 (measured crossover on both GB300 and B200), stage 8
otherwise.
  The Python dispatcher becomes a single call into the combined op.
- **Dispatch gates on exact compute capabilities (10, 0)/(10, 3).**
SM107
passes the previous `major == 10` predicate but must keep the reference
  path instead of erroring in the binding.
- The dynamic-SMEM attribute is now set once per (kernel, device)
instead
  of on every launch.

**Correctness contract unchanged: bitwise equality with
`csrc/tinygemm2.cu`** — verified per-variant and through the dispatcher
(`torch.equal`, batch 1-64, K to 7168, M to 4096, on B200 and GB300),
and
end-to-end in SGLang serving with zero token flips (gpt-oss-120b, and
Mistral-Large-3 whose router GEMM sits in the new tier).
`tests/model_optimizations/test_tinygemm2_sm100.py` extends to the
stage-16
variants and long-K parity shapes. compute-sanitizer synccheck is clean
on
all six variants.

Limitations: unchanged from #4274 — the nobias path stays on the
reference
kernel.

## 📊 End-to-end serving validation — Mistral-Large-3 (675B FP8), SGLang,
TP4, GB300

(CUDA graphs on, production defaults)

**Correctness**: 32 fixed greedy prompts — token streams bitwise
identical between arms; GSM8K-200: CAKE 0.950 / ref 0.945.

**Performance** (CAKE = this PR's kernels via default dispatch, ref =
reference `tinygemm2`; throughput in mean output tok/s, ITL is median in
ms):

| concurrency | throughput (CAKE) | throughput (ref) | ITL (CAKE) | ITL
(ref) |
|---|---|---|---|---|
| 1 | 100.7 | 101.0 | 9.47 | 9.48 |
| 8 | 488.6 | 487.9 | 15.47 | 15.48 |
| 32 | 1068 | 1073 | 28.90 | 28.92 |
| 128 | 3000 | 2997 | 41.31 | 41.44 |

## 🔍 Related Issues

Follow-up to #4274. Related to #4254 (CAKE-generated kernel progress
tracker).

## 🚀 Pull Request Checklist

Thank you for contributing to FlashInfer! Before we review your pull
request, please make sure the following items are complete.

### ✅ Pre-commit Checks

- [x] I have installed `pre-commit` by running `pip install pre-commit`
(or used your preferred method).
- [x] I have installed the hooks with `pre-commit install`.
- [x] I have run the hooks manually with `pre-commit run --all-files`
and fixed any reported issues.

## 🧪 Tests

- [x] Tests have been added or updated as needed.
- [x] All tests are passing (`unittest`, etc.).

## Reviewer Notes

The generated device sections are frozen artifacts (regeneration happens
outside this repo, as with #4262/#4274); review focus is best spent on
the
binding section of `csrc/tinygemm2_sm100.cu` (pack construction, stage
selection, launch attributes), the dispatcher in
`flashinfer/gemm/routergemm.py`, and the test additions. The single-TU
merge follows the mechanical transform documented in the file header.


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added support for larger matrix workloads through new stage16
execution variants.
* Automatically selects the appropriate execution stage based on
workload size and hardware.
  * Added direct launch support for all available execution variants.
* Expanded compatibility for supported compute capabilities and newer
CUDA versions.

* **Bug Fixes**
  * Improved handling of large reduction sizes and deep-ring workloads.

* **Tests**
* Added coverage for larger K dimensions, including 7168 and 14336, and
stage16 variants.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants