(a, b, activation="")
| 133 | |
| 134 | |
| 135 | def matmul(a, b, activation=""): |
| 136 | # Check constraints. |
| 137 | assert a.shape[1] == b.shape[1], "Incompatible dimensions" |
| 138 | assert a.is_contiguous(), "Matrix A must be contiguous" |
| 139 | assert b.is_contiguous(), "Matrix B must be contiguous" |
| 140 | M, K = a.shape # noqa: N806 |
| 141 | N, K = b.shape # noqa: N806 |
| 142 | |
| 143 | # TMA requires the innermost (stride-1) dimension to be aligned to 16 bytes. |
| 144 | # For bfloat16 (2 bytes per element) that means multiples of 8 elements. |
| 145 | tma_align = 16 // a.element_size() |
| 146 | if K % tma_align != 0: |
| 147 | raise ValueError( |
| 148 | f"K={K} is not a multiple of {tma_align}. " |
| 149 | f"TMA descriptors require the innermost dimension to be aligned to 16 bytes." |
| 150 | ) |
| 151 | if N % tma_align != 0: |
| 152 | raise ValueError( |
| 153 | f"N={N} is not a multiple of {tma_align}. " |
| 154 | f"TMA descriptors require the innermost dimension to be aligned to 16 bytes." |
| 155 | ) |
| 156 | |
| 157 | # Pre-transpose B: [N, K] -> [K, N] contiguous. |
| 158 | # TMA enforces strides[-1]==1, so we can't describe the transpose via strides. |
| 159 | b_t = b.T.contiguous() |
| 160 | # Allocates output. |
| 161 | c = torch.empty((M, N), device=a.device, dtype=torch.bfloat16) |
| 162 | |
| 163 | # TMA descriptors require a global memory allocation |
| 164 | def alloc_fn(size: int, alignment: int, stream: Optional[int]): |
| 165 | return torch.empty(size, device="cuda", dtype=torch.int8) |
| 166 | |
| 167 | triton.set_allocator(alloc_fn) |
| 168 | |
| 169 | # 2D launch kernel with N first to match fused kernel pattern. |
| 170 | # This enables processing many N blocks for the same M block, |
| 171 | # allowing A matrix (small M dimension) to be reused from L2 cache. |
| 172 | def grid(meta): |
| 173 | return ( |
| 174 | triton.cdiv(N, meta["BLOCK_SIZE_N"]), |
| 175 | triton.cdiv(M, meta["BLOCK_SIZE_M"]), |
| 176 | ) |
| 177 | |
| 178 | matmul_kernel[grid]( |
| 179 | a, |
| 180 | b_t, |
| 181 | c, |
| 182 | M, # noqa: N803 |
| 183 | N, # noqa: N803 |
| 184 | K, # noqa: N803 |
| 185 | ACTIVATION=activation, # |
| 186 | ) |
| 187 | return c |
| 188 | |
| 189 | |
| 190 | def get_cublas(): |
no outgoing calls