Swizzle Helper API¶
gemm_swizzle2d¶
Converts a GEMM iteration index to a 2D tile coordinate in the output matrix.
By default, tiles are grouped by columns, with adjacent groups traversing rows in reverse order to form a serpentine scheduling pattern. swizzle_direction can instead group rows and traverse columns. A partial final group is handled automatically in either direction.
gemm_swizzle2d_Nz remains supported with its original signature and defaults. It is a special case of gemm_swizzle2d with swizzle_direction=1. We recommend gemm_swizzle2d for new code.
Signature¶
gemm_swizzle2d(
iter_id,
data_row_shape,
data_col_shape,
tile_row_shape,
tile_col_shape,
swizzle_offset=7,
swizzle_direction: tl.constexpr = 1,
)
Parameters¶
Parameter |
Data type |
Description |
|---|---|---|
|
Integer |
Current iteration index. Range: |
|
Integer |
Number of rows in the output matrix, typically |
|
Integer |
Number of columns in the output matrix, typically |
|
Integer |
Number of rows per tile, typically |
|
Integer |
Number of columns per tile, typically |
|
Integer |
Maximum number of tiles in the grouped dimension. Valid range: |
|
|
Grouped dimension: |
Return Value¶
Returns (data_row_idx, data_col_idx), the row and column indices of the tile.
Scheduling Order¶
For example, with a 3-row by 10-column tile grid, swizzle_offset=7, and swizzle_direction=1: the first 7 columns traverse rows in the order 0 -> 1 -> 2, while the last 3 columns traverse in the order 2 -> 1 -> 0.
Use Cases¶
Used in the GEMM phase of distributed fused kernels.
Grouping tiles from adjacent columns helps improve cache locality for matrix data.
Serpentine traversal connects adjacent groups on the same row, reducing large jumps in tile coordinates.
The returned
(block_id_m, block_id_n)can be directly used to compute block addresses for A, B, and C.
Notes¶
iter_idand all fourshapeparameters must be greater than0;swizzle_offsetmust be in[1, 7]. A value of0is invalid because it makes the group size zero.swizzle_directionmust be0or1.This function only adjusts the scheduling order and does not change the data layout.
Example¶
import triton
import triton.language as tl
from triton_dist.language.extra.ascend.algorithm import gemm_swizzle2d
@triton.jit
def gemm_tile_kernel(c_ptr, M, N, stride_cm, stride_cn,
BLOCK_M: tl.constexpr, BLOCK_N: tl.constexpr):
pid = tl.program_id(0)
ncore = tl.num_programs(0)
num_tiles = tl.cdiv(M, BLOCK_M) * tl.cdiv(N, BLOCK_N)
for iter_id in range(pid, num_tiles, ncore):
block_m, block_n = gemm_swizzle2d(
iter_id, M, N, BLOCK_M, BLOCK_N,
)
# Use offs_m and offs_n to compute the block addresses for A, B, and C.
offs_m = block_m * BLOCK_M + tl.arange(0, BLOCK_M)
offs_n = block_n * BLOCK_N + tl.arange(0, BLOCK_N)
c_offsets = (
offs_m[:, None] * stride_cm
+ offs_n[None, :] * stride_cn
)
c_mask = (offs_m[:, None] < M) & (offs_n[None, :] < N)
# Omit the A and B tile loads and the accumulation over the K dimension.
accumulator = ...
tl.store(c_ptr + c_offsets, accumulator, mask=c_mask)
Compatibility API¶
gemm_swizzle2d_Nz(
iter_id,
data_row_shape,
data_col_shape,
tile_row_shape,
tile_col_shape,
swizzle_offset=7,
)
dist_swizzle2d¶
Converts a communication iteration index to a data tile, target rank, and tail block size.
Different tiles start communication from different ranks, avoiding multiple AI Cores concentrating access on the same rank.
dist_swizzle2d_Nz remains supported with its original signature and defaults. It is a special case of dist_swizzle2d with comm_data_split=1 and swizzle_direction=1. We recommend dist_swizzle2d for new code.
Signature¶
dist_swizzle2d(
iter_id,
rank_size,
data_row_shape,
data_col_shape,
tile_row_shape,
tile_col_shape,
comm_npu_split=1,
comm_data_split=1,
swizzle_direction: tl.constexpr = 1,
)
Parameters¶
Parameter |
Data type |
Description |
|---|---|---|
|
Integer |
Current iteration index. Range: |
|
Integer |
Number of ranks participating in communication. |
|
Integer |
Number of data rows. |
|
Integer |
Number of data columns. |
|
Integer |
Maximum number of rows per tile. |
|
Integer |
Maximum number of columns per tile. |
|
Integer |
Number of ranks per interleaved scheduling group, defaults to |
|
Integer |
Maximum number of data tiles per scheduling group when |
|
|
Grouped dimension: |
Return Value¶
Returns (data_row_idx, data_col_idx, rank_idx, comm_row_size, comm_col_size):
data_row_idx,data_col_idx: Row and column indices of the current tile.rank_idx: Target rank.comm_row_size,comm_col_size: Actual number of rows and columns in the current tile.
Use Cases¶
Used in fused kernels such as AllGather-GEMM, GEMM-ReduceScatter, and GEMM-AllReduce.
Rotating target ranks for different tiles helps reduce communication hotspots and access contention between ranks.
Notes¶
comm_npu_splitmust satisfyrank_size % comm_npu_split == 0.comm_data_splitmust be greater than0.swizzle_directionmust be0or1.This function only adjusts the scheduling order and does not change the data layout.
Example¶
import triton
import triton.language as tl
from triton_dist.language.extra.ascend.algorithm import dist_swizzle2d
@triton.jit
def communication_kernel(rank_size, rows, cols,
TILE_M: tl.constexpr, TILE_N: tl.constexpr):
pid = tl.program_id(0)
ncore = tl.num_programs(0)
num_iters = rank_size * tl.cdiv(rows, TILE_M) * tl.cdiv(cols, TILE_N)
for iter_id in range(pid, num_iters, ncore):
# target_rank is used to select the remote rank; tile_rows and tile_cols are used to generate the tail block mask.
tile_m, tile_n, target_rank, tile_rows, tile_cols = dist_swizzle2d(
iter_id, rank_size, rows, cols, TILE_M, TILE_N,
)
Compatibility API¶
dist_swizzle2d_Nz(
iter_id,
rank_size,
data_row_shape,
data_col_shape,
tile_row_shape,
tile_col_shape,
comm_npu_split=1,
)