跳到主要内容
TileLang 系统教程

tilelang-tutorial.huandu.me

第 14 章 算子实战 II:GEMM 全家族

/code/14-operators-gemm/

01-gemm-ledger/README.md2651 字节
# 示例 01:GEMM 的性能账本与 tile 占用估算

## 目的

把第 14 章 1.1 与 1.3 节的公式写成可运行的脚本:

```
计算量        = 2·M·N·K                         (FLOP)
最小访存      = (M·K + K·N + M·N) · dtype_bytes (Byte)
算术强度 AI   = 计算量 / 最小访存               (FLOP/Byte)
机器平衡点    = 峰值算力 / 峰值带宽             (FLOP/Byte)

单级 shared   = dtype_bytes · (block_M·block_K + block_K·block_N)
每线程累加 reg = block_M·block_N·(accum_bytes/4) / threads
```

它回答两个问题:**这个 GEMM 是先撞带宽还是先撞算力;这份 tile 配置放不放得下。**

## 运行前提

* Python 3.9 或更高(脚本只用标准库:`argparse`、`dataclasses`)。
* **不需要 GPU、NPU,也不需要 TileLang 与 PyTorch。**

## 运行命令

```bash
# 默认:4096^3,fp16,H100 SXM5 的公开规格
python3 gemm_ledger.py

# 小 M/N 大 K(习题 E10 第 2、3 问)
python3 gemm_ledger.py --m 256 --n 256 --k 16384

# 一次打印多个 shape 的对比表
python3 gemm_ledger.py --sweep

# 换一份 tile 配置(习题 E2、E11)
python3 gemm_ledger.py --block-m 256 --block-n 128 --block-k 64 --stages 2
```

## 期望输出

正确性判据:脚本正常退出(退出码 0)。默认参数下的实际输出(在 macOS
Apple Silicon、Python 3.11 上运行得到):

```
========================================================================
机器模型:H100 SXM5  peak=1000.0 TFLOPS  bw=3.0 TB/s  balance=333.3 F/B
========================================================================

GEMM 4096 x 4096 x 4096  (dtype 16 bit)
  计算量          : 137.4 GFLOP
  最小 DRAM 访存  : 96 MiB
  算术强度        : 1365.33 FLOP/Byte
  机器平衡点      : 333.33 FLOP/Byte
  判定            : compute-bound

tile 配置 block_M=128 block_N=128 block_K=32 stages=3 threads=128
  单级 shared memory   : 16 KiB
  多级 shared memory   : 48 KiB
  每线程累加寄存器     : 128
  受 shared 限制的 block 数 : 4
```

`--sweep` 下几组 shape 的实际结果:

| shape(fp16) | 计算量 | 最小访存 | 算术强度 | 判定 |
| --- | --- | --- | --- | --- |
| 4096³ | 137.4 GFLOP | 96 MiB | 1365.33 | compute-bound |
| 512³ | 268.4 MFLOP | 1.5 MiB | 170.67 | memory-bound |
| 128³ | 4.194 MFLOP | 96 KiB | 42.67 | memory-bound |
| 256×256×16384 | 2.147 GFLOP | 16.12 MiB | 127.01 | memory-bound |
| 8192³ | 1.1 TFLOP | 384 MiB | 2730.67 | compute-bound |

## 性能口径

**本示例不测量任何性能。** 它输出的数字全部是公式推导:

* 机器参数(1000 TFLOPS、3 TB/s)来自
  `../../../../../tilelang-corpus/05-nvidia-backend/raw/nvidia-blog-hopper-architecture-in-depth.md`
  (H100 SXM5,厂商公开 preliminary specs,未实测);
* 机器平衡点是这两个数相除,不是厂商给出的数字;
* 所有算子成本按「理论最小访存量」计算,真实 kernel 一定高于这个下界;
* tile 占用只统计 A/B tile 与 C 累加器,不含 epilogue、barrier 与 padding,
  因此也是乐观下界。

## 作者实际做到的验证级别

**CPU 逻辑验证。** 在 macOS (Apple Silicon)、Python 3.11 上运行过默认参数、
`--sweep`、`--m 256 --n 256 --k 16384` 与多组 tile 参数等调用,输出与本
文档一致。没有在 GPU/NPU 上运行过任何内容。

## 已知局限

* 只统计「读入 + 写出」一行,不考虑中间量回写显存。
* 不考虑 cache 命中、kernel 启动开销、尾部效应(wave quantization)。
* 寄存器估算只算累加器,不含地址、索引、流水所需的其它寄存器;真实占用
  一定更高。CUDA 的寄存器上限 255 与 cc7.0 的 occupancy 结论见
  `../../references.md` 的 R10。

← 浏览本章全部代码