test: probe torch.matmul backend + ixformer.matmul/linear + Python loop overhead

This commit is contained in:
Claude
2026-08-15 05:17:13 +00:00
parent 395b3e4042
commit 9514092980

View File

@@ -0,0 +1,172 @@
#!/bin/bash
# probe_torch_matmul_backend.sh — Find out what torch.matmul actually calls on BI-V100
echo "=== 1. torch.matmul profiling — which kernel launches ==="
python3 << 'PY'
import torch
import os
M, N, K = 256, 11008, 4096
A = torch.randn(M, K, dtype=torch.float16, device='cuda')
B = torch.randn(K, N, dtype=torch.float16, device='cuda')
# Warmup
for _ in range(5):
torch.matmul(A, B)
torch.cuda.synchronize()
# Profile with torch profiler
with torch.profiler.profile(
activities=[torch.profiler.ProfilerActivity.CPU,
torch.profiler.ProfilerActivity.CUDA],
record_shapes=True,
) as prof:
for _ in range(3):
torch.matmul(A, B)
torch.cuda.synchronize()
print(prof.key_averages().table(sort_by="cuda_time_total", row_limit=20))
PY
echo ""
echo "=== 2. CUDA_LAUNCH_BLOCKING trace ==="
CUDA_LAUNCH_BLOCKING=1 python3 << 'PY'
import torch
import os
M, N, K = 256, 11008, 4096
A = torch.randn(M, K, dtype=torch.float16, device='cuda')
B = torch.randn(K, N, dtype=torch.float16, device='cuda')
# Warmup
torch.matmul(A, B)
torch.cuda.synchronize()
# Single call with sync
torch.cuda.synchronize()
C = torch.matmul(A, B)
torch.cuda.synchronize()
print("torch.matmul completed")
print(f"Result shape: {C.shape}, dtype: {C.dtype}")
PY
echo ""
echo "=== 3. Check if ixformer.matmul is faster or same as torch.matmul ==="
python3 << 'PY'
import torch
import time
M, N, K = 256, 11008, 4096
A = torch.randn(M, K, dtype=torch.float16, device='cuda')
B = torch.randn(K, N, dtype=torch.float16, device='cuda')
# torch.matmul
for _ in range(10):
torch.matmul(A, B)
torch.cuda.synchronize()
t0 = time.time()
for _ in range(100):
torch.matmul(A, B)
torch.cuda.synchronize()
ms_torch = (time.time() - t0) / 100 * 1000
# torch.mm (should be same)
for _ in range(10):
torch.mm(A, B)
torch.cuda.synchronize()
t0 = time.time()
for _ in range(100):
torch.mm(A, B)
torch.cuda.synchronize()
ms_mm = (time.time() - t0) / 100 * 1000
# ixformer.matmul
import ixformer
A_ix = ixformer.Tensor(A)
B_ix = ixformer.Tensor(B)
for _ in range(10):
ixformer.matmul(A_ix, B_ix)
torch.cuda.synchronize()
t0 = time.time()
for _ in range(100):
ixformer.matmul(A_ix, B_ix)
torch.cuda.synchronize()
ms_ix = (time.time() - t0) / 100 * 1000
# ixformer.linear
A2 = torch.randn(M, K, dtype=torch.float16, device='cuda')
W = torch.randn(N, K, dtype=torch.float16, device='cuda') # (out, in)
A2_ix = ixformer.Tensor(A2)
W_ix = ixformer.Tensor(W)
for _ in range(10):
ixformer.linear(A2_ix, W_ix)
torch.cuda.synchronize()
t0 = time.time()
for _ in range(100):
ixformer.linear(A2_ix, W_ix)
torch.cuda.synchronize()
ms_linear = (time.time() - t0) / 100 * 1000
# F.linear (torch)
for _ in range(10):
torch.nn.functional.linear(A2, W)
torch.cuda.synchronize()
t0 = time.time()
for _ in range(100):
torch.nn.functional.linear(A2, W)
torch.cuda.synchronize()
ms_flinear = (time.time() - t0) / 100 * 1000
# cublas via direct cublasHgemm (through torch C++ extension would need compile)
# Skip for now
print(f"torch.matmul: {ms_torch:.3f} ms")
print(f"torch.mm: {ms_mm:.3f} ms")
print(f"ixformer.matmul: {ms_ix:.3f} ms")
print(f"ixformer.linear: {ms_linear:.3f} ms")
print(f"F.linear: {ms_flinear:.3f} ms")
PY
echo ""
echo "=== 4. MoE hot loop: Python for-loop overhead measurement ==="
python3 << 'PY'
import torch
import time
num_experts = 8
top_k = 8
K, N = 4096, 11008
# Simulate decode: 1 token, 8 experts
hidden = torch.randn(1, K, dtype=torch.float16, device='cuda')
weights = [torch.randn(N, K, dtype=torch.float16, device='cuda') for _ in range(num_experts)]
# Warmup
for w in weights:
torch.nn.functional.linear(hidden, w)
torch.cuda.synchronize()
# Measure: 8 F.linear calls in Python loop
t0 = time.time()
for _ in range(1000):
results = []
for i in range(top_k):
results.append(torch.nn.functional.linear(hidden, weights[i]))
out = sum(results)
torch.cuda.synchronize()
ms_loop = (time.time() - t0) / 1000 * 1000
# Measure: single F.linear with same total FLOPS
big_w = torch.randn(N * top_k, K, dtype=torch.float16, device='cuda')
big_hidden = hidden.expand(top_k, K).contiguous().view(top_k, K)
t0 = time.time()
for _ in range(1000):
out = torch.mm(big_hidden, big_w.t())
torch.cuda.synchronize()
ms_single = (time.time() - t0) / 1000 * 1000
print(f"8x F.linear loop (decode): {ms_loop:.3f} ms")
print(f"1x torch.mm equivalent: {ms_single:.3f} ms")
print(f"Python loop overhead: {ms_loop - ms_single:.3f} ms")
print(f"Per-expert overhead: {(ms_loop - ms_single)/top_k:.3f} ms")
PY