@tilelang.jit(out_idx=[-1]) def make_matmul(M: int, N: int, K: int, block_M: int = 128, block_N: int = 128, block_K: int = 32, num_stages: int = 3, subprocesos: int = 128, use_swizzle: bool = False, dtype: str = “float16”, accum_dtype: str = “float”): @T.prim_func def main(A: T.Tensor((M, K), dtype), B: T.Tensor((K, N), dtype), C: T.Tensor((M, N), dtype)): con T.Kernel(T.ceildiv(N, block_N), T.ceildiv(M, block_M), threads=threads) as (bx, by): A_shared = T.alloc_shared((block_M, block_K), dtype) B_shared = T.alloc_shared((block_K, block_N), dtype) C_local = T.alloc_fragment((block_M, block_N), accum_dtype) if use_swizzle: T.use_swizzle(panel_size=10, enable=True) T.clear(C_local) para ko in T.Pipelined(T.ceildiv(K, block_K), num_stages=num_stages): T.copia(A[by * block_M, ko * block_K]A_compartido) T.copiar(B[ko * block_K, bx * block_N]B_compartido) T.gemm(A_compartido, B_compartido, C_local) T.copia(C_local, C[by * block_M, bx * block_N]) return main def smem_bytes(bloque_M, bloque_N, bloque_K, etapas, tamaño de elemento=2): return (bloque_M * bloque_K + bloque_K * bloque_N) * tamaño de elemento * etapas def sección_2(): banner(“2. JERARQUÍA DE MEMORIA – GEMM de núcleo tensor en mosaico”) M = N = K = 2048 bm, bn, bk, st = 128, 128, 32, DEFAULT_STAGES mientras smem_bytes(bm, bn, bk, st) > SMEM_CAP y st > 1: st -= 1 print(f” config: {bm}x{bn}x{bk}, num_stages={st}, ” f”smem={smem_bytes(bm,bn,bk,st)/1024:.0f} KB”) kernel = make_matmul(M, N, K, bm, bn, bk, num_stages=st, threads=128) a = torch.randn(M, K, dispositivo=DEV, dtype=torch.float16) b = torch.randn(K, N, dispositivo=DEV, dtype=torch.float16) c = kernel(a, b) check(c, a @ b, “matmul 2048^3″) flops = 2 * M * N * K ms = banco(lambda: kernel(a, b)) ms_ref = banco(lambda: a @ b) print(f” Tilelang : {ms:7.3f} ms -> {flops/(ms*1e-3)/1e12:6.2f} TFLOP/s”) print(f” cuBLAS : {ms_ref:7.3f} ms -> {flops/(ms_ref*1e-3)/1e12:6.2f} TFLOP/s”) print(f” ratio: {ms_ref/ms*100:5.1f}% de cuBLAS de ~20 líneas de Python”) src = kernel.get_kernel_source() para aguja en (“mma.sync”, “wgmma”, “ldmatrix”, “cp.async”, “tl::gemm”): if aguja en src: print(f” emitido: {aguja}”) return kernel def sección_3(): banner(“3. KNOBS — barriendo el programa a mano”) M = N = K = 2048 a = torch.randn(M, K, dispositivo=DEV, dtype=torch.float16) b = torch.randn(K, N, dispositivo=DEV, dtype=torch.float16) fracasos = 2 * M * N * K candidatos = [
(64, 64, 32, 2, 128, False),
(128, 128, 32, 2, 128, False),
(128, 128, 32, 2, 128, True),
(128, 128, 32, 3, 128, False),
(128, 128, 64, 2, 256, False),
(128, 256, 32, 2, 256, False),
]
print(f” {’tile’:>16} {‘stg’:>4} {‘thr’:>4} {‘swz’:>4} {‘smem’:>7} ” f”{‘ms’:>8} {‘TFLOP/s’:>9}”) resultados = []
para bm, bn, bk, st, thr, swz en candidatos: need = smem_bytes(bm, bn, bk, st) tag = f”{bm}x{bn}x{bk}” si es necesario > SMEM_CAP: print(f” {tag:>16} {st:>4} {thr:>4} {str(swz):>4} {necesidad//1024:>5}KB ” f” SALTADO (sobre el presupuesto de smem)”) continúe intente: k = make_matmul(M, N, K, bm, bn, bk, num_stages=st, threads=thr, use_swizzle=swz) c = k(a, b) ok = (c – (a @ b)).float().norm() / (a @ b).float().norm() < 2e-2 ms = banco(lambda: k(a, b), calentamiento=5, rep=20) resultados.append((ms, tag, st, thr, swz)) print(f" {tag:>16} {st:>4} {thr:>4} {str(swz):>4} {necesidad//1024:>5}KB ” f”{ms:>8.3f} {flops/(ms*1e-3)/1e12:>9.2f}” f”{” if ok else ‘ <- NUMÉRICAMENTE MAL'}") excepto excepción como e: print(f" {tag:>16} {st:>4} {thr:>4} {str(swz):>4} – ” f”falló: {type(e).__name__}”) si resultados: mejor = min(resultados) print(f”\n ganador: {mejor[1]}, etapas={mejor[2]}, hilos={mejor[3]}, ” f”swizzle={mejor[4]} ({mejor[0]:.3f} ms)”) print(” Conclusión: el mejor cronograma depende del arco y la forma, que es”) print(” exactamente por qué existe la sección 7.”)
(64, 64, 32, 2, 128, False),
(128, 128, 32, 2, 128, False),
(128, 128, 32, 2, 128, True),
(128, 128, 32, 3, 128, False),
(128, 128, 64, 2, 256, False),
(128, 256, 32, 2, 256, False),
]
print(f” {’tile’:>16} {‘stg’:>4} {‘thr’:>4} {‘swz’:>4} {‘smem’:>7} ” f”{‘ms’:>8} {‘TFLOP/s’:>9}”) resultados = []
para bm, bn, bk, st, thr, swz en candidatos: need = smem_bytes(bm, bn, bk, st) tag = f”{bm}x{bn}x{bk}” si es necesario > SMEM_CAP: print(f” {tag:>16} {st:>4} {thr:>4} {str(swz):>4} {necesidad//1024:>5}KB ” f” SALTADO (sobre el presupuesto de smem)”) continúe intente: k = make_matmul(M, N, K, bm, bn, bk, num_stages=st, threads=thr, use_swizzle=swz) c = k(a, b) ok = (c – (a @ b)).float().norm() / (a @ b).float().norm() < 2e-2 ms = banco(lambda: k(a, b), calentamiento=5, rep=20) resultados.append((ms, tag, st, thr, swz)) print(f" {tag:>16} {st:>4} {thr:>4} {str(swz):>4} {necesidad//1024:>5}KB ” f”{ms:>8.3f} {flops/(ms*1e-3)/1e12:>9.2f}” f”{” if ok else ‘ <- NUMÉRICAMENTE MAL'}") excepto excepción como e: print(f" {tag:>16} {st:>4} {thr:>4} {str(swz):>4} – ” f”falló: {type(e).__name__}”) si resultados: mejor = min(resultados) print(f”\n ganador: {mejor[1]}, etapas={mejor[2]}, hilos={mejor[3]}, ” f”swizzle={mejor[4]} ({mejor[0]:.3f} ms)”) print(” Conclusión: el mejor cronograma depende del arco y la forma, que es”) print(” exactamente por qué existe la sección 7.”)