Host-side TMA implementation involves creating TensorDescriptor objects on the CPU and passing them as arguments to the Triton kernel. This approach replaces manual pointer arithmetic with descriptor-based loading and storing.
Workflow:
- Create Descriptors: Use
triton.tools.tensor_descriptor.TensorDescriptor to define the tensor, its shape, strides, and the block size for TMA operations. - Pass to Kernel: Pass these descriptor objects directly into the kernel launch.
- Kernel Usage: Inside the
@triton.jit kernel, use the .load([offset_coordinates]) and .store([offset_coordinates], value) methods on the descriptor objects to perform memory operations.
from triton.tools.tensor_descriptor import TensorDescriptor
def matmul_with_tma(a, b, c, kernel, grid, BLOCK_SIZE_M, BLOCK_SIZE_K, BLOCK_SIZE_N, num_pid_n):
# Create TMA descriptors on host
a_desc = TensorDescriptor(
a, # the tensor
a.shape, # tensor shape
a.stride(), # tensor strides
[BLOCK_SIZE_M, BLOCK_SIZE_K] # block size for TMA operations
)
b_desc = TensorDescriptor(
b,
b.shape,
b.stride(),
[BLOCK_SIZE_K, BLOCK_SIZE_N]
)
c_desc = TensorDescriptor(
c,
c.shape,
c.stride(),
[BLOCK_SIZE_M, BLOCK_SIZE_N]
)
# Pass descriptors to kernel
kernel[grid](a_desc, b_desc, c_desc, ...)
@triton.jit
def matmul_kernel(a_desc, b_desc, c_desc, ...):
pid = tl.program_id(axis=0)
pid_m = pid // num_pid_n
pid_n = pid % num_pid_n
# Load using TMA descriptors
a = a_desc.load([pid_m * BLOCK_SIZE_M, 0])
b = b_desc.load([0, pid_n * BLOCK_SIZE_N])
# Compute
accumulator = tl.dot(a, b)
# Store using TMA descriptor
c_desc.store([pid_m * BLOCK_SIZE_M, pid_n * BLOCK_SIZE_N], accumulator)