CUDA线程块Swizzle

💡 原文英文,约5000词,阅读约需19分钟。
📝

内容提要

CUDA线程块执行顺序会影响L2缓存命中与GEMM性能。文章介绍了线性、分组2D面板、Morton和异或等swizzle算法,并用Triton进行基准测试。结果显示,预测的缓存命中率与实际吞吐量几乎不相关,列主序明显慢于行主序,原因可能在于DRAM访问模式等底层因素。结论是应针对具体配置实测,而非依赖缓存命中率预测。

🔎

延伸解读

缓存命中率预测的局限性

文章通过基准测试发现,预测的L2缓存命中率与实际GEMM吞吐量几乎不相关。例如,行主序线性swizzle的预测命中率较低,但性能与分组2D面板swizzle相当;而列主序线性swizzle与行主序预测命中率相同,性能却明显更差。这表明离线LRU模型未考虑DRAM行缓冲区局部性、bank级竞争等底层因素,因此不能仅凭缓存命中率预测来指导优化。

列主序性能劣势的底层原因

列主序线性swizzle比行主序慢约20%,尽管两者预测的L2命中率相同。文章指出,行主序按波次访问矩阵B的连续行块,而列主序访问矩阵A的跨步列块。虽然两者内存访问都完全合并和向量化,但性能差异可能源于DRAM访问模式等底层因素,这些因素无法被简单的缓存模型捕捉。

Morton与XOR swizzle的适用条件

Morton/Z-order和按位异或swizzle仅当输出网格为正方形且边长为2的幂时才是双射的,否则会跳过或重复某些瓦片,导致结果错误。因此,在非正方形或非2的幂网格中,这些算法会被自动跳过并发出警告。实际使用时需注意网格形状,避免错误应用。

持久化与非持久化内核的对比

文章比较了持久化与非持久化GEMM内核。持久化内核启动恰好等于GPU并发容量的程序数,每个程序循环处理多个瓦片,使并发瓦片集确定;非持久化内核则为每个瓦片启动一个程序。但实验表明,两种方式下预测命中率与实际性能的相关性都很差,说明调度确定性并未改变模型盲区。

Q&A

CUDA线程块Swizzle是什么?它有什么作用?

CUDA线程块Swizzle是一种控制线程块执行顺序的算法,它决定了程序ID到输出瓦片位置的映射。通过改变执行顺序,可以影响L2缓存中驻留的数据,从而影响内存访问效率和内核性能,尤其是在内存访问成为瓶颈时。

常见的CUDA线程块Swizzle算法有哪些?

常见的线程块Swizzle算法包括:线性Swizzle(行主序和列主序)、分组2D面板Swizzle(可配置组大小)、Morton/Z-order Swizzle以及按位异或Swizzle。其中分组2D面板Swizzle是GEMM中最常用的算法。

Morton和异或Swizzle有什么使用限制?

Morton/Z-order和按位异或Swizzle仅当网格尺寸是正方形且为2的幂时才是双射的(即每个输出瓦片恰好访问一次)。否则它们会跳过某些瓦片并重复计算其他瓦片,导致结果不正确,因此在这些情况下会被自动跳过并发出警告。

预测的L2缓存命中率与实际GEMM性能是否相关?

几乎不相关。实验表明,对于持久化和非持久化GEMM内核,预测的L2缓存命中率与实际吞吐量之间很难建立相关性。例如,行主序线性Swizzle的预测命中率较低,但性能与分组2D面板Swizzle相比没有显著下降。

为什么列主序线性Swizzle比行主序慢?

尽管列主序和行主序的预测L2缓存命中率相同,但列主序性能明显更差。原因可能在于底层因素,如DRAM访问模式:行主序按波次访问矩阵B的连续行块,而列主序访问矩阵A的跨步列块,导致DRAM行缓冲区局部性差。

如何为GEMM内核选择最佳的线程块Swizzle算法?

不应依赖L2缓存命中率预测,而应针对具体配置进行实际基准测试。因为预测模型未考虑DRAM行缓冲区局部性、bank级竞争等底层因素,所以最佳算法需通过实测确定。

🏷️

标签

➡️

继续阅读