Write, optimize, and debug high-performance AI compute kernels using TileLang (a Python DSL for GPU programming)...
Write high-performance AI compute kernels using TileLang - a tile-based programming model that bridges the gap between CUDA's low-level control and high-level abstractions.
Use this skill when the user needs to:
Follow these steps when writing a TileLang kernel:
Gather essential information:
Input/Output Specifications:
Hardware Target:
Performance Goals:
Ask clarifying questions if details are missing.
Create the basic kernel scaffold:
import tilelang
import tilelang.language as T
@tilelang.jit(target="cuda", out_idx=[2]) # Specify output indices
def kernel_name(M, N, K, block_M, block_N, block_K):
@T.prim_func
def main(
A: T.Buffer((M, K), "float16"),
B: T.Buffer((K, N), "float16"),
C: T.Buffer((M, N), "float16")
):
# Kernel logic will go here
pass
return main
Key decisions:
target: "cuda" (NVIDIA), "hip" (AMD), or "cpu"out_idx: List indices of output parametersSet up computation grid and allocate memory:
# Define grid dimensions
with T.Kernel(
T.ceildiv(N, block_N), # Grid X
T.ceildiv(M, block_M), # Grid Y
threads=128
) as (bx, by):
# Allocate shared memory (L1 cache)
A_shared = T.alloc_shared((block_M, block_K), "float16")
B_shared = T.alloc_shared((block_K, block_N), "float16")
# Allocate register fragments (accumulators)
C_local = T.alloc_fragment((block_M, block_N), "float32")
# CRITICAL: Apply swizzle layout to avoid bank conflicts
T.annotate_layout({
A_shared: T.make_swizzled_layout(A_shared),
B_shared: T.make_swizzled_layout(B_shared)
})
Memory hierarchy:
Critical optimization: Always apply T.make_swizzled_layout to shared memory to eliminate bank conflicts.
Use TileLang primitives for data movement and computation:
# Initialize accumulator
T.clear(C_local)
# Main computation loop with software pipelining
for k in T.Pipelined(T.ceildiv(K, block_K), num_stages=3):
# Load tiles from global to shared memory
T.copy(A[by * block_M, k * block_K], A_shared)
T.copy(B[k * block_K, bx * block_N], B_shared)
# Compute using Tensor Cores
T.gemm(A_shared, B_shared, C_local, transpose_B=False)
# Write results back
T.copy(C_local, C[by * block_M, bx * block_N])
Key primitives:
T.copy: Intelligent data transfer (auto-selects cp.async, TMA, etc.)T.gemm: Matrix multiplication using Tensor CoresT.Pipelined: Software pipelining to overlap compute and memory transferT.Parallel: Element-wise parallel operationsPipeline stages:
num_stages=2: Double bufferingnum_stages=3: Triple buffering (recommended for most workloads)num_stages=4+: Diminishing returns, increases shared memory usageGenerate test code to verify correctness:
# Example instantiation
func = kernel_name(
M=1024, N=1024, K=1024,
block_M=128, block_N=128, block_K=32
)
# Test against reference implementation
import torch
A = torch.randn(1024, 1024, dtype=torch.float16, device='cuda')
B = torch.randn(1024, 1024, dtype=torch.float16, device='cuda')
C_tilelang = torch.empty(1024, 1024, dtype=torch.float16, device='cuda')
C_reference = A @ B
func(A, B, C_tilelang)
# Verify with appropriate tolerance for FP16
torch.testing.assert_close(C_tilelang, C_reference, rtol=1e-3, atol=1e-3)
Apply advanced optimizations if performance is suboptimal:
Block Size Tuning:
Pipeline Depth:
num_stages if memory-boundWarp Policy (for advanced cases):
T.gemm(A, B, C, policy=T.GemmWarpPolicy.FullRow) # For attention
T.gemm(A, B, C, policy=T.GemmWarpPolicy.FullCol) # For MLA decode
Block-level swizzle:
T.use_swizzle(panel_size=10) # Improves L2 cache hit rate
Most fundamental kernel. See EXAMPLES.md for complete implementation.
Key features:
Memory-efficient attention with online softmax. See EXAMPLES.md for complete implementation.
Key features:
Multi-Head Latent Attention with KV compression. See EXAMPLES.md for complete implementation.
Key features:
When you need specific information:
Always include these optimizations:
Swizzle layout for shared memory:
T.annotate_layout({
A_shared: T.make_swizzled_layout(A_shared)
})
Software pipelining:
for k in T.Pipelined(num_blocks, num_stages=3):
Float32 accumulators:
C_local = T.alloc_fragment((M, N), "float32") # Not float16
Aligned block_K:
block_K = 32 # Or 16, must align for Tensor Core
Initialize accumulators:
T.clear(C_local)
When generating TileLang code:
User: "Write a FP16 matrix multiplication kernel for A100"
Response:
Compilation errors:
Runtime errors:
Performance issues:
For detailed solutions, consult DEBUGGING.md.