高性能计算训练营
HPC 性能分析完整指南:从理论峰值到经验 Roofline
本指南由两部分组成:
- 练习 1:用公式和命令,手动算出机器的理论性能上限(FLOP/s 峰值、内存带宽、机器平衡)
- 练习 2:用 Empirical Roofline Tool (ERT) 实测同一台机器,画出经验 Roofline 图
理论值画天花板,实测值告诉你"实际上限"。两者对照,才是完整的性能画像。
第一部分:理论性能计算
目标:拿到任意一台 Linux 机器,用几条命令 + 三个公式,估算它的三个理论性能上限。 这是理论峰值(理想上限),不是实测值——实测要靠 STREAM(内存)、HPL(浮点)这类基准。
0. 速查卡(只想照做,就看这张表)
| 想算 | 公式 | 变量从哪里来 |
|---|---|---|
| FLOP/s 峰值 | 核心数 × 每核每周期 FLOP × 主频 |
lscpu + 微架构表(第 2.3 节) |
| 内存带宽 | 已插内存的通道数 × 速率(MT/s) × 8 字节 |
sudo dmidecode -t memory(第 2.4 节) |
| 机器平衡 | 内存带宽 ÷ FLOP峰值 |
上面两个算完再除 |
⚠️ 三个最容易算错的地方,先记住:核心数别用超线程后的逻辑数;每核每周期 FLOP 不是看 flag 就能定,要查微架构;内存带宽按"已插了几根条子"算,不是按 CPU 支持几个通道算。
1. 三个概念,用你熟悉的话讲
1.1 FLOP/s 峰值 —— "算得有多快"
- FLOP(Floating-point Operations,浮点运算次数)= 一次浮点运算(加/减/乘/除都算一次)。
- FMA(Fused Multiply-Add,融合乘加)=
a×b+c一条指令做完,官方计作 2 个 FLOP(1 次乘 + 1 次加)。现代 CPU 的浮点峰值几乎全靠 FMA。 - 向量化(SIMD):一条指令同时算多个数。具体点就是:CPU
的一种单指令多数据(Single Instruction, Multiple
Data)并行技术——一条指令同时处理多个数据,而不是一条指令只处理一个数据。你写
C/C++ 时用到的
_mm256_add_ps、_mm512_fmadd_pd就是这类。向量越宽(128/256/512 位),一次算的数越多。 - 每周期 = 每个时钟周期;主频 2.0 GHz = 每秒 20 亿个周期。
所以:
1 | |
1.2 内存带宽 —— "喂数据有多快"
DDR 内存每根通道(channel)每个传输周期搬 64 bit = 8 字节。速率用 MT/s(兆传输/秒)标称,直接拿来乘即可:
1 | |
注意是"已插的通道数":某通道没插内存条,那个通道就不参与搬数据。一台双路服务器常说"8 通道 × 2 插槽 = 16 通道",是指满配;实际插了几根,就是几个通道在干活(详见第 2.4 节)。
1.3 机器平衡 —— "这台机器是算得快,还是内存快"
1 | |
含义:每做 1 次浮点运算,平均有多少字节的内存数据可以供应。
⚠️ 反过来写也常见:
FLOP峰值 ÷ 内存带宽,单位 FLOP/Byte,叫"运算强度"或 Roofline 的"转折点(ridge point)"。两者互为倒数,别混:
写法 公式 数值大小 Byte/FLOP 带宽 ÷ 峰值 小(约 0.05~0.6) FLOP/Byte 峰值 ÷ 带宽 大(约 2~20)
用途(Roofline 模型):某个计算 kernel 的"算术强度"(每搬 1 字节数据做几次 FLOP)
- 若 < FLOP/Byte(即受内存限制) → 性能被带宽卡住;
- 若 > FLOP/Byte → 性能被计算卡住。
本文统一用 Byte/FLOP 作为"机器平衡",需要时顺便给出倒数。
2. 动手:在你的 Ubuntu 服务器上收集数据
下面的命令都能在 Ubuntu 20.04 上跑。
sudo那条需要 root 权限。
2.1 核心数、主频、型号
1 | |
输出很长,只看这几行(下面是个双路服务器示例):
1 | |
只取关键字段:
1 | |
关键:核心数 =
Socket(s) × Core(s) per socket,不要用CPU(s)(那是把超线程算进去了)。超线程的两个线程共享同一套浮点单元,算峰值只认物理核。
2.2 判断 SIMD 宽度(看 flags)
1 | |
| 输出里出现 | 指令集 | 单条向量最宽 |
|---|---|---|
avx512f |
AVX-512 | 512 位 |
avx2(无 avx512f) |
AVX2 | 256 位 |
只有 sse2 |
SSE | 128 位 |
fma |
支持 FMA | 现代 CPU 基本都有 |
⚠️ flag 只能告诉你"一条指令最宽到多少位",不能直接定每周期 FLOP。因为每周期能做多少个 FMA,取决于"有几个多宽的 FMA 执行单元"——这是微架构决定的,CPU 型号相同才相同。两个反例:
- Intel Skylake-SP 报
avx512f,确实每周期 2 个 512 位 FMA;- AMD Zen4 也报
avx512f,但它内部是把 512 位拆成 2 个 256 位来做,每周期有效吞吐和"2×256 位"一样;- AMD Zen1 / 海光 Hygon 报
avx2(256 位指令),却只有 2 个 128 位 FMA 单元,256 位指令要"双泵"执行,每周期吞吐等于"2×128 位"。所以必须查微架构表(下节),不能只看 flags。
2.3 每核每周期 FLOP(查表,机器读不出来,得按型号对)
通用公式:
1 | |
- 每个元素位数:FP64=64 位、FP32=32 位;
×2是因为一次 FMA 算 2 个 FLOP。
常见 CPU 对照表(FMA单元 × 单元宽度
就是微架构决定的部分):
| CPU 类型 | 每核 FMA 单元 | 单元宽度 | FP64/核/周期 | FP32/核/周期 |
|---|---|---|---|---|
| 消费级 Intel Core(Skylake 及以后,AVX2) | 2 | 256 位 | 16 | 32 |
| Intel Xeon 可扩展(Skylake-SP → Sapphire/Emerald Rapids) | 2 | 512 位 | 32 | 64 |
| AMD Ryzen / EPYC(Zen2/Zen3/Zen4,2×256 位) | 2 | 256 位 | 16 | 32 |
| AMD Zen1 / Zen+ / 海光 Hygon Dhyana | 2 | 128 位(256 位指令双泵) | 8 | 16 |
| Intel 小核 E-core(Gracemont) | 1 | 256 位 | 8 | 16 |
例:2 个 512 位 FMA → FP64 = 2 × (512/64) × 2 =
32/核/周期;FP32 = 2 × (512/32) × 2 =
64/核/周期。
拿不准就查你 CPU 型号的官方规格或架构资料(关键词:
<型号> FMA units per core、vector width、flops per cycle)。
2.4 内存通道数与速率
1 | |
读输出的要点:
- 数"已装的内存条":看
Size有数值的条目(如Size: 32 GB),跳过Size: No Module Installed的空槽。 - 通道数 = 已插条子的数量(前提:每通道只插 1 根,服务器的标准插法)。别按 CPU 的满配通道数算。
- 速率:看
Speed(MT/s,DIMM 标称)和Configured Memory Speed(内存控制器实际跑的速率)。两者不同时,用 Configured(实际跑的)。
输出示例(每插槽 8 通道、但只插了 2 根 DDR4-2933):
1 | |
上例:装 2 根 → 只 2 个通道在干活 → 带宽 = 2 × 2933e6 × 8 ≈ 46.9 GB/s(不是满配 8 通道的 187 GB/s)。
没有 sudo 权限?按 CPU 型号查每插槽满配通道数,再问管理员插了几根条子。
3. 套公式:汇总填表
把第 2 节拿到的数填进来:
| 变量 | 值 | 从哪来 |
|---|---|---|
| 插槽数 | ____ |
lscpu → Socket(s) |
| 每插槽核数 | ____ |
lscpu → Core(s) per socket |
| 核心数 = 两者相乘 | ____ |
— |
| 主频 (GHz) | ____ |
lscpu → CPU max MHz(见第 9 节"频率用哪个") |
| FMA 单元数 | ____ |
第 2.3 节微架构表 |
| 单元宽度 (位) | ____ |
第 2.3 节微架构表(512/256/128) |
| 已插通道数 | ____ |
dmidecode:数 Size 有值的条子 |
| 实际内存速率 (MT/s) | ____ |
dmidecode → Configured Memory Speed |
然后:
1 | |
4. 参考示例一:双路 Xeon Platinum 8480+(假想配置)
| 指标 | 计算过程 | 结果 |
|---|---|---|
| 核心数 | 2 插槽 × 56 核 | 112 |
| 每核/周期 FP64 | 2 FMA × 512位/64 × 2 | 32 |
| FP64 峰值 | 112 × 32 × 2.0e9 | 7.17 TFLOP/s |
| FP32 峰值 | 112 × 64 × 2.0e9 | 14.34 TFLOP/s |
| 内存带宽(满配 16 通道) | 16 通道 × 4800e6 × 8 | 614 GB/s |
| 机器平衡(FP64) | 614.4e9 ÷ 7.168e12 | 0.086 Byte/FLOP(≈ 11.7 FLOP/Byte) |
一份常见讲义里这段算错过:把 2 个插槽漏算成 1 个(结果 3.58 TFLOP/s),且机器平衡单位差 1000 倍(写 0.17,实为把 TFLOP 当 GFLOP 所致,正确 0.086)。本文已订正。
5. 参考示例二:单路 i7-14700KF(他人机器,P 核 + E 核混合)
这个例子教你混合核心怎么算:P 核和 E 核的频率、每周期 FLOP 都不同,要分开乘再加。
| 项目 | P 核 (Raptor Cove) | E 核 (Gracemont) |
|---|---|---|
| 数量 | 8 | 12 |
| 峰值睿频 | 5.6 GHz | 4.3 GHz |
| FMA 单元 | 2 × 256 位 | 1 × 256 位 |
| FP64/核/周期 | 16 | 8 |
| FP32/核/周期 | 32 | 16 |
1 | |
6. 实战:你的 Hygon C86 5380(用真实命令输出走一遍)
下面把你贴的两段输出完整过一遍,展示怎么一步步读数。这台机器比上面两个假想例子更值得做,因为它同时踩中两个大坑:老 Zen 架构的向量单元、通道数虚高。
6.1 第一步:lscpu → 核心数与频率
你的输出里取这几行:
1 | |
- 核心数 = 2 × 16 = 32(不是 64)。
- 频率 = 2.5 GHz(boost
已关闭,
CPU MHz: 2477表明现在就跑在 ~2.48 GHz,用 2.5 做持续值很贴切)。
6.2 第二步:识别微架构 → 每核每周期 FLOP
Model name: Hygon C86 5380,海光(Hygon Dhyana),底层是
AMD Zen1 架构(lscpu 的 CPU family: 24
即海光的厂商号 0x18)。
按第 2.3 节表,Zen1/Hygon 每核只有 2 个 128 位 FMA 单元,虽然指令是 256 位(avx2)但要拆成两半执行:
1 | |
⚠️ 若照着"Intel 式"误填成 2×256 位,会高估一倍。这正是 2.2 节警告的"avx2 不等于 2×256 位"。海光/EPYC Zen1 与同代 Intel 单核浮点能力差一半,这是架构事实,不是频率造成的。
6.3 第三步:dmidecode → 数条子、定速率
你的输出里 Size: 32 GB(装了)的只有 4
根,分别插在:
| 内存条 | 位置 | 通道 |
|---|---|---|
| DIMM16 | P0 | CHANNEL D |
| DIMM3 | P0 | CHANNEL G |
| DIMM32 | P1 | CHANNEL D |
| DIMM19 | P1 | CHANNEL G |
其余全是 Size: No Module Installed。再看速率:
1 | |
- 已插通道数 = 4(别填 16。CPU 每插槽确实支持 8 通道 × 2 插槽 = 16,但那是满配,现在只有 4 个通道有内存)。
- 速率 = 2933 MT/s(控制器实际跑 2933,不是条子标称的 3200)。
- 单通道带宽 = 2933e6 × 8 ≈ 23.5 GB/s。
6.4 第四步:套公式出结果
1 | |
6.5 一个反直觉但重要的结论
这台"双路 32 核服务器"其实是内存受限机器:浮点峰值 0.64 TFLOP/s 还算常见,但内存带宽只有 ~94 GB/s(4 通道),因为 16 个通道只插了 4 根条子。
对比:若把 16 通道插满(每通道 1 根 DDR4-2933),带宽可达 16 × 2933e6 × 8 ≈ 375 GB/s,机器平衡(FP64) 会变成 0.59 Byte/FLOP。
含义(结合 Roofline):
- 现在跑带宽敏感的程序(STREAM 测速、稀疏矩阵/图计算、大数据量拷贝),就算 CPU 空转也只会拿到约 1/4 的内存带宽;
- 想让这类负载提速,加内存条(让通道跑满)是最直接的,比换更强 CPU 有用得多;
- 附带提醒:4 个 NUMA 节点各只有 1 个有内存的通道,写多线程程序要注意
NUMA 亲和(
numactl/绑定到本地节点),否则跨节点访问还要绕 Infinity Fabric。
上面是"理论峰值"。想验证:装 STREAM 跑 Triad 看实测带宽是否接近 ~94×0.8≈75 GB/s;浮点可跑 HPL/LINPACK 看是否接近 ~0.64×0.7≈0.45 TFLOP/s。
7. 一键脚本(把第 3 节的值填进顶部 6 个变量即可)
保存为 compute_peak.sh 并 chmod +x,改前 6
行后运行:
1 | |
脚本里我已按你的机器预填好。在服务器上执行预期输出:
1 | |
8. 常见坑(务必读)
- 频率用哪个?
CPU max MHz是单核睿频,多核全载达不到;AVX-512 重载还会进一步降频(AVX offset)。- 要"理想峰值"→ 用最大睿频(偏乐观);
- 要"可达到的持续值"→
用基础频率或全核睿频(更接近真实)。若
BIOS 关了 boost(如你的机器
Frequency boost: disabled),max MHz 本身就是持续值,直接用。
- 超线程不算核。 核心数 = 插槽数 × 每插槽核数,别用
CPU(s)。 - "支持 AVX-512/AVX2" ≠ 固定的每周期 FLOP。 一定按微架构定"FMA 单元数 × 单元宽度"(第 2.3 节)。Zen1/海光是 2×128 位,别当成 2×256。
- 内存带宽按"已插的条子"算。 CPU 支持 16 通道 ≠
现在有 16 通道带宽;数
dmidecode里Size有值的 DIMM。速率用Configured Memory Speed(实际跑的),不是条子标称。 - 单位别混。 带宽 GB/s = ×10⁹ B/s,峰值 TFLOP/s = ×10¹² FLOP/s。机器平衡 = 带宽/峰值,得到的是个很小的数(Byte/FLOP);若算出 0.6 以上的"Byte/FLOP",多半把 TFLOP 当 GFLOP 了,或把满配通道当已插通道了。
- 这是理论值,不是实测。 实际持续性能还要看功耗墙、缓存、访存模式、NUMA。ERT 实测值通常只有理论值的 30%~60%,这正是"Roofline 模型"存在的意义——先画天花板,再实测能摸到哪。
第二部分:ERT 实测与 Roofline 分析
练习 1 算的是"理论天花板",ERT 做的是"实际能摸到多高"。两者结合,就是完整的 Roofline 分析。
你已经在服务器上跑完了
./ert Config/config.mycpu.01,结果在Results.MyCPU/Run.001/下。下面教你怎么读、怎么看图。
9. ERT 输出文件总览
执行 ./ert Config/config.mycpu.01
后,在结果目录下会生成:
1 | |
| 文件/目录 | 用途 |
|---|---|
roofline.json |
原始数据(JSON):实测 GFLOP/s、各层级带宽、kernel 信息 |
roofline.ps |
主图表(PostScript 格式):Roofline 图 |
roofline.gnu |
gnuplot 脚本:可重新生成或转换图表 |
FLOPS.001/ ~ FLOPS.016/ |
每个 FLOP 强度的详细测试数据 |
10. 读 roofline.json——最快的数据概览
roofline.json 是 ERT
的核心输出,所有数据都在里面。用任意文本编辑器或 cat
打开,关注两个关键段。
10.1 实测浮点峰值
1 | |
195 GFLOP/s = ERT 实测的 FP64 浮点峰值(所有 FLOP 强度下跑到的最高 GFLOP/s)。
10.2 实测各级带宽
1 | |
| 层级 | 你的实测 | 说明 |
|---|---|---|
| L1 | 1560 GB/s | 工作集 < 32 KB 时,数据在 L1 内循环 |
| L2 | 859 GB/s | 工作集 32 KB ~ 256 KB |
| L3 | 52 GB/s | 工作集 256 KB ~ 16 MB |
| DRAM | 36.27 GB/s | 工作集 > 64 MB,必须走内存 |
10.3 配置元数据
1 | |
可以看到 ERT 的完整编译参数、线程配置、时间戳等。
11. 看 Roofline 图表——三种方法
ERT 生成的是 roofline.ps(PostScript 格式)。在 macOS
上查看:
方法一:安装Ghostscript转换PostScript(最稳)
1 | |
装完转换成 PDF:
1 | |
这是最稳的路,Ghostscript 就是 PostScript/PDF 的行业标准解释器。
方法二:用 gnuplot 重新生成 PNG
ERT 自带的 roofline.gnu 是为 PostScript
终端写的。生成高清 PNG:
1 | |
方法三:用 Python 读 JSON 自动画图(最灵活,可叠加你的应用数据)
1 | |
12. 理解 Roofline 模型——看图说话
Roofline 图只有两种线,全貌就清楚了:
1 | |
12.1 三条线 / 一个点的含义
| 元素 | 是什么 | 你的海光机器的值 |
|---|---|---|
| 水平天花板 | CPU 纯浮点计算上限 | 195 GFLOP/s |
| DRAM 斜线 | 内存带宽能支撑的最大性能 | 36.27 × AI GFLOP/s |
| 转折点 | 斜线和天花板的交点,AI 多大时从"内存瓶颈"切换为"计算瓶颈" | 195 ÷ 36.27 ≈ 5.4 FLOP/Byte |
| 数据点 | 你的应用实测的性能 | 你叠加上去的 |
12.2 怎么判断你的应用是内存瓶颈还是计算瓶颈
算法公式:你的 kernel 的"算术强度" =
FLOPs 数 ÷ 搬运的字节数
| 场景 | 判断 | 优化方向 |
|---|---|---|
| 算术强度 < 5.4 FLOP/Byte | 内存受限:性能被 DRAM 带宽卡住 | 优化访存模式、数据布局、利用缓存/寄存器;加内存通道 |
| 算术强度 > 5.4 FLOP/Byte | 计算受限:性能被浮点峰值卡住 | 优化向量化(确保 AVX2 编译生效)、减少分支、用 FMA |
12.3 以你的机器为例,几个典型 kernel 的位置
| Kernel 类型 | 典型算术强度 | 在 Roofline 上的位置 | 瓶颈 |
|---|---|---|---|
向量加法 C[i]=A[i]+B[i] |
~0.67 FLOP/Byte(3 数组各读一次,算 1 次) | 斜线下方,很低的位置 | 内存 |
| 矩阵乘法(朴素三循环) | ~2 FLOP/Byte | 斜线下方 | 内存 |
| 矩阵乘法(分块缓存优化) | 610 FLOP/Byte | 刚过转折点,靠近天花板 | 轻内存,主要是计算 |
| SAXPY(向量内积) | ~1.5 FLOP/Byte | 斜线下方 | 内存 |
| 密集线性代数(L3/L2 内完成) | 501560 FLOP/Byte | 天花板附近 | 计算 |
13. 逐线程数分析
FLOPS.001/ ~ FLOPS.016/ 分别对应 FLOP 强度
1 到 16 的测试。每个目录下有 OpenMP.0001/ ~
OpenMP.0016/(对应 1 到 16 线程,ERT 在你的配置里实际跑了
1,2,4,8,16 线程)。
13.1 max 文件格式详解
max 文件是该 FLOP
强度下,所有线程数、所有工作集大小中跑出的最大性能。每列含义:
| 列 | 内容 | 示例(FLOPS=1, 工作集=1MB) |
|---|---|---|
| 1 | FLOP 强度 | 1 |
| 2 | 工作集大小(字节) | 1048576 (= 1 MB) |
| 3-5 | 三次试验的 GFLOP/s | 20648.323 20782.992 20814.359 |
| 6-8 | 三次试验的 FLOP/Byte(算术强度) | 98.347 98.496 99.138 |
| 9-11 | 三次试验的内存带宽(GB/s) | 6.147 6.156 6.197 |
关键理解:ERT 用一个"stream kernel"(类似 STREAM triad)来测带宽,同时改变 FLOP 强度来改变算术强度。同一个 kernel,FLOP 强度越高 → 每次迭代算的 FLOP 越多 → 算术强度越高 → 在 Roofline 图上越靠右上方。
13.2 sum 文件格式
sum 文件是该 FLOP 强度 +
线程数组合下,各级存储层级的峰值:
1 | |
Weight是 ERT 内部的归一化因子,一般不用管。DRAM行就是该线程数下的内存带宽——16 线程时约 17 GB/s,与roofline.json里汇总的 36.27 GB/s 的差异来自:sum是单线程数配置的测量,roofline.json取了最优线程配置。
13.3 快速对比各线程数
1 | |
13.4 你的数据中观察到的现象
从 FLOPS.001/max 可以看到:
| 工作集大小 | 算术强度 (FLOP/Byte) | 性能 (GFLOP/s) | 所在的存储层级 |
|---|---|---|---|
| 1 KB ~ 256 KB | ~17 | ~123K | L1/L2 内循环 |
| 1 MB ~ 64 MB | 617 | 95K100K | L3 缓存 |
| 128 MB ~ 1 GB | 16 | 20K100K | DRAM 访问 |
- 小工作集(< 256 KB):数据全在 L1/L2,算术强度 ~17 FLOP/Byte,性能 ~123K GFLOP/s(计算受限)
- 大工作集(> 128 MB):数据在 DRAM,算术强度降到 12 FLOP/Byte,性能跌到 ~20K GFLOP/s(内存受限)
- 这就是 Roofline 图的完整曲线——左边低性能(带宽受限),右边高性能(计算受限),中间斜率就是内存带宽
14. 环境准备与工具获取
14.1 环境准备
ERT 需要编译和运行 C++ 微内核,确保 Ubuntu 20.04 上有:
1 | |
验证:
1 | |
14.2 获取 ERT
ERT 官方仓库是
https://github.com/opencollab/ert,也可以用你课程提供的
fork:
1 | |
目录结构预览:
1 | |
15. 配置你的机器
ERT 通过配置文件告诉它:测几个线程、几种 FLOP 强度、内存多大等。
1 | |
打开 config.mycpu.01,你会看到类似这样的内容:
1 | |
关键参数说明:
| 参数 | 含义 | 你的机器建议值 |
|---|---|---|
ERT_FLOPS |
测几种 FLOP/迭代(即算术强度):1=纯内存拷贝, 16=重计算 | 保持 1,2,4,8,16 |
ERT_PROCS_THREADS |
测几个线程/进程 | 保持 1,2,4,8,16,32,64 |
ERT_NUM_EXPERIMENTS |
每个配置跑几次 | 保持 3(取中位数,剔除异常) |
ERT_MEMORY_MAX |
最大工作集(字节) | 保持 1GB(足够覆盖 L3) |
ERT_PRECISION |
浮点精度 | FP64(双精度)或 FP32(单精度) |
如果你的机器是海光 C86 5380(32 核),
ERT_PROCS_THREADS设为1,2,4,8,16,32就够了(超线程的两个线程共享浮点单元,测到 64 线程意义不大)。
16. 运行 ERT
1 | |
ERT 会自动完成以下步骤:
- 编译:用
-O3 -march=native编译出 5 个 FLOP 强度的微内核 - 逐个配置运行:5 种 FLOP 强度 × 7 种线程数 × 3 次重复 = 105 次运行
- 收集数据:每次运行记录 GFLOP/s、带宽、算术强度
- 汇总:取三次运行的中位数,写入
roofline.json - 画图:调用 gnuplot 生成
roofline.ps
运行时间取决于机器性能,32 核的海光大约 5-15 分钟。
17. 与练习1 理论值对照
| 指标 | 第 3 节理论值 | ERT 实测 | 利用率 | 差距原因 |
|---|---|---|---|---|
| FP64 峰值 | 640 GFLOP/s | 195 GFLOP/s | ~30% | 全核持续跑达不到睿频;Zen1 AVX2 重载降频;NUMA 跨节点损耗;功耗墙 |
| DRAM 带宽 | 93.9 GB/s(4 通道 × 2933) | 36.27 GB/s | ~39% | ERT 用流式访存模式(非最优);只测了 1 个 socket 的 16 线程;跨 NUMA 访问有损耗 |
30%~40% 的理论利用率对这台机器是正常的。海光 C86 5380(Zen1 架构)+ DDR4-2933 + 只插 4 根内存条,持续浮点/内存性能本来就到不了理论峰值。这正是 ERT 存在的意义——理论值画天花板,ERT 实测告诉你"实际上限"。
17.1 Roofline 图的四个关键数据
结合第 3 节(第 6.4-6.5 步)和 ERT 结果,你机器的 Roofline 参数:
| 参数 | 值 | 来源 |
|---|---|---|
| 计算峰值(水平线) | 195 GFLOP/s | ERT 实测 |
| DRAM 带宽(最陡斜线) | 36.27 GB/s | ERT 实测 |
| 转折点 | 195 ÷ 36.27 ≈ 5.4 FLOP/Byte | 计算得出 |
| 你的机器是 | 内存受限型(转折点低、带宽窄) | 判断 |
17.2 如果插满 16 通道内存呢?
如果加内存到 16 通道 DDR4-2933:
| 指标 | 当前(4 通道) | 插满(16 通道) |
|---|---|---|
| 理论带宽 | 93.9 GB/s | 375 GB/s |
| 转折点 | 5.4 FLOP/Byte | 21.6 FLOP/Byte |
| 影响 | 大部分应用受 DRAM 限制 | 更多应用进入计算受限区 |
18. 常见问题
Q1:ERT 输出的
roofline.ps 在 Windows 上怎么打开?
PostScript 在 Windows 上不原生支持。方法:
- 转 PDF:用 Ghostscript
gswin64c -sDEVICE=pdfwrite -sOutputFile=roofline.pdf roofline.ps - 或直接看
roofline.json里的数值 - 或用第 11 节方法三(Python)自己画 PNG
Q2:ERT 测出来的峰值比 HPL/LINPACK 高/低,正常吗?
正常。ERT 用的是人工微内核,访存模式最优;HPL 是实际 Linpack,访存模式更复杂。ERT 峰值 ≈ HPL 的 1.3~2 倍是正常范围。
Q3:我的
roofline.json 里 FP64 峰值只有理论值的
30%,是不是有问题?
没问题。理论峰值是单核单线程的理想值(睿频、无开销、无 NUMA),ERT 测的是多核全载、持续运行的实测值。30-50% 是正常范围。
Q4:ERT 只测了 FP64,想看 FP32 怎么办?
改配置文件里的 ERT_PRECISION:
1 | |
然后重新运行 ./ert Config/config.mycpu.01。
Q5:数据点为什么有的不在 Roofline 线上?
Roofline 线是"上限"。实测数据点理论上不该超过线。如果超过,可能是:
- ERT 运行时间太短,数据还在缓存内,没到 DRAM
- 编译器做了优于预期的优化
- 数据点恰好落在 L2/L3 斜线区间,被更快的缓存层级支撑
Q6:海光机器的 ERT 结果和其他 Intel 机器差很多,正常吗?
正常。海光 C86 5380(Zen1 内核):
- 每核只有 2 个 128 位 FMA(Intel 同代是 2 个 256 位),FP64 峰值只有一半
- DDR4-2933(Intel 新机器用 DDR5-4800+),内存带宽也更低
- 只插 4 根内存(16 通道只用了 4 个),带宽大打折扣
附录:你的海光 C86 5380 的完整结果速查
练习 1 理论值
| 指标 | 值 | 来源 |
|---|---|---|
| 核心数 | 32(2 插槽 × 16 核) | lscpu |
| 主频 | 2.5 GHz(boost disabled) | lscpu |
| 每核 FP64/周期 | 8(2×128 位 FMA) | 微架构表 |
| FP64 理论峰值 | 0.64 TFLOP/s | 32×8×2.5e9 |
| FP32 理论峰值 | 1.28 TFLOP/s | 32×16×2.5e9 |
| 已插通道数 | 4 | dmidecode |
| 内存速率 | 2933 MT/s | dmidecode |
| 理论内存带宽 | 93.9 GB/s | 4×2933e6×8 |
| 机器平衡(FP64) | 0.15 Byte/FLOP | 93.9e9÷640e9 |
练习 2 ERT 实测值
| 指标 | 值 | 来源 |
|---|---|---|
| FP64 实测峰值 | 195 GFLOP/s | roofline.json |
| L1 带宽 | 1560 GB/s | roofline.json |
| L2 带宽 | 859 GB/s | roofline.json |
| L3 带宽 | 52 GB/s | roofline.json |
| DRAM 带宽 | 36.27 GB/s | roofline.json |
| DRAM 转折点 | 5.4 FLOP/Byte | 计算:195/36.27 |
| 机器类型 | 内存受限 | 判断 |
| 实测/理论峰值比 | ~30% | 195/640 |
| 实测/理论带宽比 | ~39% | 36.27/93.9 |