Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
6b2d7b6
extract_tile_strides
ph0375 Apr 1, 2026
3fbcb08
[TLE] Extend the strides parameter of insert_tile
lzllx123 Apr 13, 2026
d882b7d
[TLE]Fix the issue of extract_tile and insert_tile allocating separat…
lzllx123 Apr 21, 2026
7254883
[TLE]Update the strides parameters of extract_tile and insert_tile, a…
lzllx123 Jun 4, 2026
fd6e15e
[FlagCICD] Add a step to test the accuracy of the FlagGems operator (…
git-flyer Jun 3, 2026
397cf64
[TLE]Modify the test file of glu
lzllx123 Jun 4, 2026
f524eba
Apply code-format changes
flagtree-bot Jun 4, 2026
6334df4
Apply code-format changes
flagtree-bot Jun 4, 2026
03b4a0d
Merge branch 'triton_v3.6.x' into feature/extrac_tile_strides_new
lzllx123 Jun 4, 2026
a5866c9
[TLE]fix some GCU backend problems
lzllx123 Jun 4, 2026
0c5a412
Apply code-format changes
flagtree-bot Jun 4, 2026
5f82345
[TLE]fix some GCU backends problems 2.
lzllx123 Jun 4, 2026
64e082c
Apply code-format changes
flagtree-bot Jun 4, 2026
4f9dd87
[TLE]fix some GCU backend problems 3.
lzllx123 Jun 4, 2026
da21a7d
[TLE] fix some GCU backend problems 4.
lzllx123 Jun 4, 2026
0d74e82
[TLE] Handle misaligned address errors gracefully in cluster-gemm aut…
lzllx123 Jun 4, 2026
b1f8dac
fix 04-cluster-gemm problems
lzllx123 Jun 4, 2026
9f14df6
Revert 04-cluster-gemm.py to c7e6953
lzllx123 Jun 5, 2026
aaba5bc
Debug CI cluster GEMM failure
sunnycase Jun 5, 2026
70fc3f4
Fix debug import lint
sunnycase Jun 5, 2026
6e254a5
Debug cold full cluster GEMM CI run
sunnycase Jun 5, 2026
b7c8f2e
Debug nonblocking cluster GEMM CI run
sunnycase Jun 5, 2026
ce073c4
Update hopper-build-and-test.yml
lzllx123 Jun 5, 2026
51d1b1b
Test cluster GEMM with blocking launches
sunnycase Jun 5, 2026
15734b7
Run only cluster GEMM in Hopper debug
sunnycase Jun 5, 2026
b840cad
Debug cluster GEMM without autotune
sunnycase Jun 5, 2026
3614cab
Debug first remote cluster GEMM config
sunnycase Jun 5, 2026
ad7bd5b
Debug remote autotune only
sunnycase Jun 5, 2026
c1bea15
Debug fixed config without lowering warmup
sunnycase Jun 5, 2026
72bc8a5
Debug remote fixed launch only
sunnycase Jun 5, 2026
8725fef
Debug remote autotune candidate progress
sunnycase Jun 5, 2026
790f435
Debug second remote candidate alone
sunnycase Jun 5, 2026
7943cb3
Debug cluster GEMM slots for pipelining
sunnycase Jun 5, 2026
c962a16
Debug power-of-two remote slots
sunnycase Jun 5, 2026
baea8f2
Verify full cluster GEMM with slot fix
sunnycase Jun 5, 2026
dfbccf2
Restore Hopper workflow after debug
sunnycase Jun 5, 2026
db71b55
Debug Hopper TTGIR for remote slots
sunnycase Jun 8, 2026
ed0acaf
Restore Hopper workflow after TTGIR debug
sunnycase Jun 8, 2026
ba677ad
Revert cluster GEMM slot workaround
sunnycase Jun 8, 2026
096f19d
Debug Hopper LLVM PTX for remote slots
sunnycase Jun 8, 2026
69e74e2
Guard TLE shared store vectorization by alignment
sunnycase Jun 8, 2026
c84241a
Restore Hopper workflow after alignment debug
sunnycase Jun 8, 2026
f53f2ba
Merge remote-tracking branch 'origin/feature/extrac_tile_strides_new'…
sunnycase Jun 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/hopper-build-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ jobs:
python3 python/tutorials/tle/01-fft.py
python3 python/tutorials/tle/02-moe_align_block_size.py
python3 python/tutorials/tle/03-topk.py
python3 python/tutorials/tle/04-cluster-gemm.py
CUDA_LAUNCH_BLOCKING=1 python3 python/tutorials/tle/04-cluster-gemm.py
python3 python/tutorials/tle/deepseek_v32/01-topk_selector.py
python3 python/tutorials/tle/deepseek_v32/02-sparse-mla.py --mode test
python3 python/tutorials/tle/deepseek_v32/02-sparse-mla.py
Expand Down Expand Up @@ -180,7 +180,7 @@ jobs:
python3 python/tutorials/tle/01-fft.py
python3 python/tutorials/tle/02-moe_align_block_size.py
python3 python/tutorials/tle/03-topk.py
python3 python/tutorials/tle/04-cluster-gemm.py
CUDA_LAUNCH_BLOCKING=1 python3 python/tutorials/tle/04-cluster-gemm.py
python3 python/tutorials/tle/deepseek_v32/01-topk_selector.py
python3 python/tutorials/tle/deepseek_v32/02-sparse-mla.py
# python unit test
Expand Down
11 changes: 8 additions & 3 deletions lib/Conversion/TritonToTritonGPU/TritonToTritonGPUPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -882,12 +882,13 @@ class TleExtractTileOpPattern : public OpConversionPattern<tle::ExtractTileOp> {

Type retType = op.getType().cloneWithEncoding(srcEnc);

auto stridesAttr =
mlir::dyn_cast_or_null<mlir::DenseI64ArrayAttr>(op->getAttr("strides"));
auto newOp = rewriter.replaceOpWithNewOp<tle::ExtractTileOp>(
op, retType, adaptor.getSrc(), adaptor.getIndex());
op, retType, adaptor.getSrc(), adaptor.getIndex(), stridesAttr);

if (auto tileShapeAttr = op->getAttr("tile_shape"))
newOp->setAttr("tile_shape", tileShapeAttr);

addNamedAttrs(newOp, adaptor.getAttributes());

return success();
Expand Down Expand Up @@ -925,8 +926,12 @@ class TleInsertTileOpPattern : public OpConversionPattern<tle::InsertTileOp> {

Type retType = op.getType().cloneWithEncoding(srcEnc);

auto stridesAttr =
mlir::dyn_cast_or_null<mlir::DenseI64ArrayAttr>(op->getAttr("strides"));

auto newOp = rewriter.replaceOpWithNewOp<tle::InsertTileOp>(
op, retType, adaptor.getSrc(), adaptor.getTile(), adaptor.getIndex());
op, retType, adaptor.getSrc(), adaptor.getTile(), adaptor.getIndex(),
stridesAttr);

addNamedAttrs(newOp, adaptor.getAttributes());

Expand Down
149 changes: 126 additions & 23 deletions python/test/tle/unit/test_insert_tile_dynamic_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,22 @@


@triton.jit
def simple_insert_kernel(x_ptr, y_ptr, stride_xb, stride_xm, stride_xn, stride_ym, stride_yn, BLOCK_M: tl.constexpr,
BLOCK_N: tl.constexpr, TILE_M: tl.constexpr, TILE_N: tl.constexpr):
def simple_insert_dynamic_index_kernel(
x_ptr,
y_ptr,
index_ptr,
stride_xb,
stride_xm,
stride_xn,
stride_ym,
stride_yn,
stride_ib,
stride_ic,
BLOCK_M: tl.constexpr,
BLOCK_N: tl.constexpr,
TILE_M: tl.constexpr,
TILE_N: tl.constexpr,
):
# 1. Get 3D coordinates: z (layer/batch), m (row block), n (col block)
pid_z = tl.program_id(0)
pid_m = tl.program_id(1)
Expand All @@ -25,13 +39,51 @@ def simple_insert_kernel(x_ptr, y_ptr, stride_xb, stride_xm, stride_xn, stride_y
y_ptrs = y_ptr + offs_tm[:, None] * stride_ym + offs_tn[None, :] * stride_yn
small_tile = tl.load(y_ptrs)

# 4. Determine insertion position:
# Layer 0 inserts at top-left [0, 0], Layer 1 inserts at bottom-right [1, 1]
# Note: tle.insert_tile 'index' usually must be a constant or determined by static logic
if pid_z % 2 == 0:
res_tile = tle.insert_tile(bg_tile, small_tile, index=[0, 0])
else:
res_tile = tle.insert_tile(bg_tile, small_tile, index=[1, 1])
# 4. Runtime index per layer: index[pid_z] = [idx_m, idx_n]
idx_m = tl.load(index_ptr + pid_z * stride_ib + 0 * stride_ic)
idx_n = tl.load(index_ptr + pid_z * stride_ib + 1 * stride_ic)
res_tile = tle.insert_tile(bg_tile, small_tile, index=[idx_m, idx_n])

# 5. Store the resulting tile back to memory
tl.store(x_ptrs, res_tile)


@triton.jit
def simple_insert_dynamic_index_stride_kernel(
x_ptr,
y_ptr,
index_ptr,
stride_xb,
stride_xm,
stride_xn,
stride_ym,
stride_yn,
stride_ib,
stride_ic,
BLOCK_M: tl.constexpr,
BLOCK_N: tl.constexpr,
TILE_M: tl.constexpr,
TILE_N: tl.constexpr,
STRIDE_M: tl.constexpr,
STRIDE_N: tl.constexpr,
):
pid_z = tl.program_id(0)
pid_m = tl.program_id(1)
pid_n = tl.program_id(2)

offs_m = pid_m * BLOCK_M + tl.arange(0, BLOCK_M)
offs_n = pid_n * BLOCK_N + tl.arange(0, BLOCK_N)
x_ptrs = x_ptr + pid_z * stride_xb + offs_m[:, None] * stride_xm + offs_n[None, :] * stride_xn
bg_tile = tl.load(x_ptrs)

offs_tm = tl.arange(0, TILE_M)
offs_tn = tl.arange(0, TILE_N)
y_ptrs = y_ptr + offs_tm[:, None] * stride_ym + offs_tn[None, :] * stride_yn
small_tile = tl.load(y_ptrs)

idx_m = tl.load(index_ptr + pid_z * stride_ib + 0 * stride_ic)
idx_n = tl.load(index_ptr + pid_z * stride_ib + 1 * stride_ic)
res_tile = tle.insert_tile(bg_tile, small_tile, index=[idx_m, idx_n], strides=(STRIDE_M, STRIDE_N))

# 5. Store the resulting tile back to memory
tl.store(x_ptrs, res_tile)
Expand All @@ -43,7 +95,7 @@ def simple_insert_kernel(x_ptr, y_ptr, stride_xb, stride_xm, stride_xn, stride_y


@pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA not available")
def test_simple_insert_kernel_inserts_tiles_correctly():
def test_simple_insert_kernel_with_dynamic_index():
B = 2 # 2 layers (Z dimension)
M, N = 32, 32 # 32x32 size per layer
TM, TN = 16, 16 # The inserted small tile is 16x16
Expand All @@ -53,33 +105,84 @@ def test_simple_insert_kernel_inserts_tiles_correctly():
# y is an all-99.0 2D small tile
y = torch.ones((TM, TN), device="cuda", dtype=torch.float32) * 99.0

# Dynamic insertion indices per layer (no stride argument):
# Layer 0 -> [0, 0] => start at [0, 0]
# Layer 1 -> [1, 1] => start at [16, 16] (tile size is 16x16)
index = torch.tensor([[0, 0], [1, 1]], device="cuda", dtype=torch.int32)

# Launch Kernel: B layers, each needs exactly 1x1 block (since M=32 and BLOCK_M=32)
grid = (B, 1, 1)

simple_insert_kernel[grid](
simple_insert_dynamic_index_kernel[grid](
x,
y,
index,
x.stride(0),
x.stride(1),
x.stride(2),
y.stride(0),
y.stride(1),
index.stride(0),
index.stride(1),
BLOCK_M=32,
BLOCK_N=32,
TILE_M=16,
TILE_N=16,
)

# --- Verification ---
# Layer 0 (Z=0): tile inserted at top-left [0:16, 0:16]
layer0_tl_mean = x[0, 0:16, 0:16].mean().item()
layer0_br_mean = x[0, 16:32, 16:32].mean().item()

# Layer 1 (Z=1): tile inserted at bottom-right [16:32, 16:32]
layer1_tl_mean = x[1, 0:16, 0:16].mean().item()
layer1_br_mean = x[1, 16:32, 16:32].mean().item()

assert layer0_tl_mean == pytest.approx(99.0)
assert layer0_br_mean == pytest.approx(0.0)
assert layer1_tl_mean == pytest.approx(0.0)
assert layer1_br_mean == pytest.approx(99.0)
expected = torch.zeros_like(x)
expected[0, 0:16, 0:16] = 99.0 # [idx_m, idx_n] = [0, 0]
expected[1, 16:32, 16:32] = 99.0 # [idx_m, idx_n] = [1, 1]

assert torch.allclose(x, expected)


@pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA not available")
@pytest.mark.parametrize(
"SM,SN,idx_m1,idx_n1",
[
(4, 4, 3, 2),
(8, 8, 2, 1),
(16, 8, 1, 1),
],
)
def test_simple_insert_kernel_with_dynamic_index_and_stride(SM, SN, idx_m1, idx_n1):
B = 2 # 2 layers (Z dimension)
M, N = 32, 32 # 32x32 size per layer
TM, TN = 16, 16 # The inserted small tile is 16x16

x = torch.zeros((B, M, N), device="cuda", dtype=torch.float32)
y = torch.ones((TM, TN), device="cuda", dtype=torch.float32) * 99.0

# Layer 0 is fixed at top-left; Layer 1 uses parameterized dynamic index.
index = torch.tensor([[0, 0], [idx_m1, idx_n1]], device="cuda", dtype=torch.int32)

grid = (B, 1, 1)

simple_insert_dynamic_index_stride_kernel[grid](
x,
y,
index,
x.stride(0),
x.stride(1),
x.stride(2),
y.stride(0),
y.stride(1),
index.stride(0),
index.stride(1),
BLOCK_M=32,
BLOCK_N=32,
TILE_M=16,
TILE_N=16,
STRIDE_M=SM,
STRIDE_N=SN,
)

expected = torch.zeros_like(x)
expected[0, 0:16, 0:16] = 99.0
start_m = idx_m1 * SM
start_n = idx_n1 * SN
expected[1, start_m:start_m + TM, start_n:start_n + TN] = 99.0

assert torch.allclose(x, expected)
56 changes: 56 additions & 0 deletions python/test/tle/unit/test_insert_tile_static_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,33 @@
import pytest


@triton.jit
def insert_tile_stride_kernel(
x_ptr,
y_ptr,
out_ptr,
M: tl.constexpr,
N: tl.constexpr,
TM: tl.constexpr,
TN: tl.constexpr,
SM: tl.constexpr,
SN: tl.constexpr,
idx_m: tl.constexpr,
idx_n: tl.constexpr,
):
offs_m = tl.arange(0, M)
offs_n = tl.arange(0, N)
x = tl.load(x_ptr + offs_m[:, None] * N + offs_n[None, :])

tile_m = tl.arange(0, TM)
tile_n = tl.arange(0, TN)
y = tl.load(y_ptr + tile_m[:, None] * TN + tile_n[None, :])

z = tle.insert_tile(x, y, index=[idx_m, idx_n], strides=(SM, SN))

tl.store(out_ptr + offs_m[:, None] * N + offs_n[None, :], z)


@triton.jit
def insert_tile_kernel(
x_ptr,
Expand Down Expand Up @@ -61,3 +88,32 @@ def test_insert_tile_static_index():
print(out[128:132, 128:132].cpu().int())

assert torch.allclose(out, expected)


# 新增:专门测试 stride ≠ tile_shape 的 insert_tile
@pytest.mark.skipif(not torch.cuda.is_available(), reason="CUDA is required for this test")
def test_insert_tile_with_stride():
M, N = 256, 256
TM, TN = 64, 64
SM, SN = 32, 32 # stride < tile_shape
idx_m, idx_n = 2, 3

x = torch.arange(M * N, device="cuda", dtype=torch.float32).reshape(M, N)
y = (10000 + torch.arange(TM * TN, device="cuda", dtype=torch.float32)).reshape(TM, TN)
out = torch.empty_like(x)

print(
f"Running insert_tile kernel with stride: x={M}x{N}, tile={TM}x{TN}, stride={SM}x{SN}, index=[{idx_m},{idx_n}]..."
)
insert_tile_stride_kernel[(1, )](x, y, out, M, N, TM, TN, SM, SN, idx_m, idx_n)
print("Kernel executed.\n")

expected = x.clone()
start_m = idx_m * SM
start_n = idx_n * SN
expected[start_m:start_m + TM, start_n:start_n + TN] = y

max_abs_diff = (out - expected).abs().max().item()
print(f"max_abs_diff = {max_abs_diff}")
assert torch.allclose(out, expected)
print("Test passed: insert_tile with stride updated the correct region.")
Loading
Loading