85.3 GFlops:在单个AMD Zen 3核心上优化FP32矩阵乘法

Hacker News Top 论文

摘要

在AMD Zen 3上对FP32矩阵乘法优化的系统性探索,使用AVX2/FMA内联指令实现了85.30 GFLOPS(理论峰值的63.5%),超越了朴素实现56.5倍,并达到了优化库的性能水平。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/07/20 21:30

houslast3/85.30-GFLOPS-Single-Core-FP32-Matrix-Multiplication-on-AMD-Zen-3

来源:https://github.com/houslast3/85.30-GFLOPS-Single-Core-FP32-Matrix-Multiplication-on-AMD-Zen-3

🚀 在 AMD Zen 3 上实现 85.30 GFLOPS 单核 FP32 GEMM

系统性地探索了使用 AVX2/FMA C++ intrinsics 优化矩阵乘法的方法,在 AMD Ryzen 5 5500 上达到了 134.4 GFLOPS 理论峰值的 63.5%。


📖 概述

本仓库包含一份关于在 AMD Zen 3 微架构单核上优化单精度 (FP32) 矩阵乘法 (GEMM) 的深入研究源代码、结果和分析。我们测试了 28 种不同的配置(MX01 至 MX28),这些配置结合了以下技术:

  • 三级缓存分块(L1、L2、L3 分块)
  • 寄存器分块(2、4 和 8 行)
  • FMA 指令链化(chain1 至 chain6)
  • 打包策略(无打包、转置、B 矩阵即时打包)
  • 内存对齐(32 字节)
  • 软件预取
  • 非暂态存储(流式存储)

最佳模型 MX24 实现了 85.30 GFLOPS,是朴素实现的 56.5 倍,性能与 AMD AOCL 和 OpenBLAS 等优化库相当。


🏆 主要结果

模型描述GFLOPS峰值占比
MX244行 + chain4 + B-pack (BK=256)85.3063.5%
MX224行 + chain4 + B-pack (BK=128)84.1062.6%
MX234行 + chain4 + B-pack (BK=64)82.9361.7%
MX164行 + chain4 + 对齐 (无 pack)72.5854.0%
MX204行 + chain4 + BT (转置)79.2158.9%
MX184行 + chain4 + 预取79.7559.3%

i️ 理论峰值计算方式:2 个 FMA 端口 × 8 个 float × 2 次操作 × 4.2 GHz = 134.4 GFLOPS


🔬 方法

评估的优化技术

  1. 缓存分块 (Tiling)

    • 调整 BIBJBK 使分块保持在 L1 (32 KB)、L2 (512 KB) 和 L3 (16 MB) 缓存内。
    • 最佳 BK 值为 256,可在不超出 L2 的前提下最大化数据复用。
  2. 寄存器分块

    • C 的累加器保存在 YMM 寄存器中(可用 16 个)。
    • 4 行 提供了最佳平衡:尽管需要 溢出(额外 16 个寄存器),但复用 A 足以弥补代价。
  3. FMA 链化

    • Zen 3 上 FMA 指令的延迟为 4 个周期chain4(4 个独立累加器)可隐藏该延迟,达到两个 FMA 端口的最大利用率。
  4. 打包 (Packing)

    • B 矩阵即时打包:将 B 的分块(BK×BJ)复制到连续缓冲区中,将非连续访问转换为顺序访问。
    • 优于完全转置(会污染 L3)和直接访问(会导致 TLB 缺失)。
  5. 对齐

    • 使用 _mm_malloc(..., 32) 分配内存,以便使用 vmovaps(对齐)指令,带来约 5% 的提升。
  6. 预取

    • 使用 _mm_prefetch 降低了约 8% 的性能,因为 Zen 3 的硬件预取器对于流模式已经足够高效。
  7. 非暂态存储

    • _mm256_stream_ps 带来了灾难性的结果 (1.24 GFLOPS),因为 C 是读‐修改‐写的,该指令每次写入都会使缓存行失效。

📂 仓库结构

zen3-gemm/ ├── README.md ├── src/ │ └── mx85.c # 包含全部 28 个模型 + 基准测试的完整代码 ├── docs/ │ ├── artigo_en.tex # 完整的科学论文 (LaTeX) │ └── resultados/ # 基准测试输出日志 │ ├── mx85_benchmark.txt │ └── mx85_output8.txt └── build/ └── Makefile #(可选)用于简化编译


⚙️ 编译与运行

前置条件

  • 处理器:支持 AVX2 和 FMA(例如 AMD Zen、Intel Haswell 或更高版本)
  • 操作系统:Windows (10/11) 或 Linux
  • 编译器:GCC 12.2+(Windows 上使用 MinGW‐w64)或支持 AVX2 intrinsics 的等效编译器
  • 内存:足以容纳 2048×2048 的矩阵(约 48 MB 用于三个矩阵)

使用 GCC 编译(Windows/MinGW 或 Linux)

src/ 目录下执行:

bash gcc -O3 -mavx2 -mfma -march=native -funroll-loops -frename-registers -o mx85.exe mx85.c

重要标志:

  • -mavx2 -mfma -march=native – 启用 SIMD 指令并针对当前 CPU 优化。
  • -funroll-loops – 展开内部循环。
  • -frename-registers – 改善寄存器分配(减少溢出)。

运行

bash ./mx85.exe

程序将:

  • 将线程亲和性设置为核心 0(Windows)并设置高优先级。
  • 每个模型执行 3 次(预热)+ 15 次测量。
  • 生成两个输出文件:
    • mx85_benchmark.txt – 完整排名和验证结果。
    • mx85_validate.txt – 与参考实现的最大误差。

自定义

若要仅测试特定模型,可以修改 main() 函数以直接调用所需函数(例如 mx24(A, B, C, N))。或者,若要使用其他大小的矩阵,可修改常量 N(约第 230 行)。


📊 完整结果表

以下列出了所有 28 个测试模型,包括测量的 GFLOPS 及理论峰值占比。

排名模型描述GFLOPS峰值占比
1MX244行 + chain4 + B-pack BK=25685.3063.5%
2MX224行 + chain4 + B-pack BK=12884.1062.6%
3MX234行 + chain4 + B-pack BK=6482.9361.7%
4MX254行 + chain4 + B-pack + 预取83.1561.9%
5MX204行 + chain4 + BT (转置)79.2158.9%
6MX184行 + chain4 + 预取79.7559.3%
7MX174行 + chain4 + 无 pack78.8058.6%
8MX164行 + chain4 + 对齐72.5854.0%
9MX154行 + chain3 + B-pack62.3446.4%
10MX144行 + chain2 + B-pack55.7641.5%
11MX132行 + chain4 + B-pack53.5839.9%
12MX122行 + chain3 + B-pack50.5637.6%
13MX114行 + chain2 + 对齐47.1535.1%
14MX082行 + chain4 + BK=12845.0433.5%
15MX072行 + chain3 + 无 Bt43.5232.4%
16MX052行 + chain2 + Bt41.9331.2%
17MX194行 + chain5 + 对齐42.0731.3%
18MX062行 + chain1 + 预取42.5431.7%
19MX044行 + chain1 + Bt40.0429.8%
20MX032行 + chain1 + Bt39.3429.3%
21MX022行 + chain1 + j-block37.6028.0%
22MX01Bt + 2Dtile + 8acc (基准)35.1626.2%
23MX104行 + chain6 + Bt14.2610.6%
24MX268行 + chain4 + B-pack12.249.1%
25MX284行 + chain4 + dual1613.7510.2%
26MX274行 + chain4 + C-in-regs9.136.8%
27MX09BI=128, BK=256 + chain48.386.2%
28MX214行 + chain4 + 流式存储1.240.9%

🔍 主要失败案例分析

模型技术GFLOPS原因
MX21非暂态存储1.24C 是读‐修改‐写的;每次存储使缓存行失效,强制从 DRAM 重载。
MX268 行寄存器分块12.24需要 64 个 YMM 寄存器;48 个被 溢出,主导了运行时间。
MX27通过 k-block 保持 C 寄存器9.13累加器存活多个迭代,增加寄存器压力。
MX09BI=128, BK=2568.38工作集 (128×256×4 = 128 KB) 超出 L1,导致大量缺失。
MX10Chain614.26链过长;寄存器不足导致过度溢出。

🧪 验证

所有模型均针对参考实现(朴素 ijk)进行了验证。最佳三个模型 (MX24、MX22、MX23) 的最大绝对误差为 0.0(位一致),因为累加顺序得以保持。其余模型误差在 1e-6 数量级,属于浮点运算的正常范围。


📚 如何引用

如果您在研究中使用本工作,请引用相关论文:

bibtex @article{housl2025gemm, title={85.30 GFLOPS Single-Core FP32 Matrix Multiplication on AMD Zen 3}, author={Housl}, journal={arXiv preprint}, year={2025} }


🤝 贡献

欢迎贡献!请随时提交 issuespull requests,提供改进、新模型或针对其他架构的适配。


##📄 许可证 本项目采用 MIT 许可证。这意味着您可以自由使用、复制、修改、合并、发布、分发、再许可和/或出售本软件的副本,前提是保留版权声明和许可声明。完整条款请参阅 LICENSE 文件。

##📧 联系与作者 作者:Lucas Lima Freitag

邮箱:[email protected]

角色:作者

所属机构:里奥格兰德联邦大学 (UFRN)

ORCID:0009-0006-8849-5619

祝优化愉快!🚀 如有疑问、建议或想分享您自己的结果,请随时联系。

相似文章

在Ryzen AI 7 350 NPU上达到峰值TOPS性能

Lobsters Hottest

关于在AMD Ryzen AI 7 350 NPU上实现峰值TOPS性能的技术深度剖析,与Xilinx AIE-ML v2 AI引擎进行比较,并解释用于矩阵乘法工作负载的硬件架构。

FP8就是你所需的一切(第一部分):驳斥硬件FP64作为HPC圣杯的观点

arXiv cs.AI

本文认为,在使用Ozaki Scheme II的情况下,FP8张量核心可以替代原生FP64硬件,用于像NVIDIA B300这样的AI优化GPU上的高性能科学计算,以更高的吞吐量实现完全的双精度精度。作者提出了张量-内存均衡模型,并表明在所有工作负载中,模拟的FP64性能可以比原生FP64高出数个数量级。

性价比不断提升,成本不断降低

Reddit r/singularity

Wafer 证实,AMD MI355X GPU 在推理前沿模型(如 GLM5.2)时,提供了有竞争力的性能,且成本远低于 NVIDIA Blackwell,使用 MXFP4 量化和 sglang 框架,以不到一半的价格实现了 B200 80% 的吞吐量。