Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
The roofline model plots the best performance a kernel can achieve as a function of its arithmetic intensity: FLOPs performed per byte moved from memory. Two flat 'roofs' bound every kernel — a memory roof set by HBM bandwidth, and a compute roof set by peak FLOP/s — and they cross at a single ridge point. Kernels to the left of the ridge are memory-bound no matter how fast your tensor cores are; kernels to the right are compute-bound no matter how fast your memory is. This single number, computed from nothing but the operation's shape, tells you the ceiling before you've profiled anything, and it explains a pattern you'll see constantly in this course: matmuls are usually compute-bound, but layernorm, softmax, dropout, and activation functions are almost always memory-bound, because they move a byte for nearly every FLOP they do. That's why the fix for those ops is never 'faster math' — it's fusion, which is the subject of Module 4.
The demo computes arithmetic intensity for a few real operations and classifies each against a ridge point derived from representative GPU specs, so you can see which ops land on which side before ever touching a profiler.
RIDGE_POINT, and check whether the matmul's classification changes.def arithmetic_intensity(flops, bytes_moved):
return flops / bytes_moved
# Edit these to match your GPU's spec sheet.
PEAK_TFLOPS = 312e12 # e.g. A100 FP16 tensor-core peak
PEAK_GBPS = 2039e9 # e.g. A100 80GB HBM2e bandwidth
RIDGE_POINT = PEAK_TFLOPS / PEAK_GBPS # FLOPs/byte where the two roofs cross
ops = {
"matmul (n=4096, fp16)": arithmetic_intensity(2 * 4096 ** 3, 3 * 4096 ** 2 * 2),
"elementwise add (n=64M, fp16)": arithmetic_intensity(64_000_000, 64_000_000 * 2 * 3),
"layernorm (n=64M, fp16, ~5 passes)": arithmetic_intensity(64_000_000 * 5, 64_000_000 * 2 * 2),
}
print(f"ridge point: {RIDGE_POINT:.1f} FLOPs/byte\n")
for name, ai in ops.items():
bound = "compute-bound" if ai > RIDGE_POINT else "memory-bound"
print(f"{name:35s} AI={ai:8.2f} -> {bound}")python3 main.py