Roofline 模型由 Samuel Williams 等人于 2009 年提出,是 HPC 性能分析领域最经典、最直观的可视化工具之一。它以单一图表将程序的"性能天花板"与"实际表现"进行映射,帮助开发者快速判定瓶颈到底出在内存带宽还是计算峰值上。
Roofline 核心概念
Roofline 模型是一条由两段直线构成的"屋顶"曲线,横轴为计算强度(Operational Intensity, FLOPs/Byte),纵轴为性能(GFLOP/s)。
GFLOP/s
^
|
P_peak |-------------------\ 计算天花板 (Compute Roof)
| \
| \------- ridge point
| /|
| / |
| / |
| / |
| / |
| / |
B_peak * I |---------/ |
| / |
| / |
| / |
| / |
| / 内存带宽天花板 |
| / (Memory Roof) |
+--/-------------------+-------> Operational Intensity (FLOPs/Byte)
I_ridge
计算强度(Operational Intensity, I)
计算强度定义为:每字节内存流量所执行的浮点运算次数。它反映了算法对数据的重用程度。
I = (总浮点运算次数) / (总内存流量,Byte)
经典算法的计算强度量级:
| 算法 | 计算强度(双精度) | 瓶颈类型 |
|---|---|---|
| AXPY (y = a*x + y) | ~0.125 FLOPs/Byte | Memory-bound |
| 矩阵-向量乘法 (GEMV) | ~0.5-1 FLOPs/Byte | Memory-bound |
| 矩阵-矩阵乘法 (GEMM, 缓存最优) | ~8-32 FLOPs/Byte | Compute-bound |
| Stencil 3D (7-point, naive) | ~0.3 FLOPs/Byte | Memory-bound |
| Stencil 3D (空间分块优化后) | ~2-8 FLOPs/Byte | 过渡区 |
两段天花板
内存带宽天花板(Memory Roof):
Performance <= B_peak * I
其中 B_peak 是实测可持续内存带宽(非标称峰值)。在此区域,性能完全受限于数据搬运速度,与计算单元无关。
计算天花板(Compute Roof):
Performance <= P_peak
其中 P_peak 是 CPU/GPU 的峰值 GFLOP/s(考虑 AVX-512、FMA、多核并发)。在此区域,内存已不再是瓶颈,计算单元饱和。
Ridge Point(山脊点)
两段直线的交点即为 ridge point:
I_ridge = P_peak / B_peak
这是性能从 memory-bound 转换为 compute-bound 的临界点。以 Intel Xeon 8480+ 为例:
P_peak(FP64, AVX-512, 56核全速) ≈ 7.5 TFLOP/sB_peak(STREAM Triad, 8ch DDR5-4800)≈ 350 GB/sI_ridge≈ 7500 / 350 ≈ 21.4 FLOPs/Byte
这意味着:只有计算强度超过 21.4 的算法才能真正"喂饱"这颗 CPU。绝大多数 naive 实现的 stencil 和稀疏矩阵运算 falls far below this point。
Roofline 绘制实战
手动估算 Roofline
以 7-point 3D stencil 为例(单网格点 7 次浮点运算,双精度 8 字节):
// 朴素实现:每个网格点读 7 个邻居 + 写 1 个结果
// 理想情况(全部命中缓存):忽略,因为 stencil 不具备时间局部性
// 实际情况:每个点需从内存读取邻域数据
总运算: 7 * Nx * Ny * Nz FLOPs
总访存: (7读 + 1写) * 8B * Nx * Ny * Nz ≈ 64 * Nx * Ny * Nz Bytes
I = 7 / 64 ≈ 0.11 FLOPs/Byte (极端 Memory-bound)
经过空间分块(Tiling)优化后,面片数据驻留缓存被复用:
优化后有效访存降低至: ~8 * Nx * Ny * Nz Bytes (读写各一次主存)
I = 7 / 8 ≈ 0.88 FLOPs/Byte (仍在 Memory roof 上移动)
再叠加 temporal blocking,时间维度上迭代缓存驻留:
有效访存进一步降至: ~4 * Nx * Ny * Nz Bytes
I = 7 / 4 ≈ 1.75 FLOPs/Byte (接近 ridge point 右侧)
工具链:Empirical Roofline Toolkit (ERT)
ERT 是 Berkeley Lab 开发的实测 Roofline 工具,自动生成当前硬件的真实天花板:
# 安装 ERT
git clone https://github.com/berkeleylab/cs-roofline-toolkit.git
cd cs-roofline-toolkit/Empirical_Roofline_Tool-1.1.0
# 编译并运行
make
cat > config.ert << 'EOF'
ERT_RESULTS Results.x86_64
ERT_DRIVER driver1
ERT_KERNEL kernel1
ERT_MPI False
ERT_OPENMP True
ERT_NUM_THREADS 64
ERT_MEMORY_MAX 1073741824
ERT_WORKING_SET_MIN 1024
ERT_TRIALS_MIN 1
ERT_GLOB_IGNORE_BYTES 512
ERT_ALIGN 64
EOF
python3 ERT.py config.ert
ERT 会自动运行不同 workset 大小、不同 unroll 因子的微基准,拟合出真实的 B_peak 和 P_peak。
工具链:Intel Advisor Roofline
Intel Advisor 提供图形化的 Roofline 分析,支持源码级定位:
# 1. 收集 Survey 数据
advixe-cl -collect survey -project-dir ./adv_proj -- ./app
# 2. 收集 Tripcounts 与 FLOPs
advixe-cl -collect tripcounts -flop -project-dir ./adv_proj -- ./app
# 3. 生成 Roofline 报告
advixe-cl -report roofline -project-dir ./adv_proj -report-output roofline.html
Advisor 会为每个循环/函数标注在 Roofline 图上的位置,并自动标注:
- 哪些循环受 Vectorization 限制(计算效率低)
- 哪些循环受内存层级限制(L1/L2/L3/DRAM)
- 优化预测(如:若向量化和内存预取后可达的加速比)
案例分析:SGEMM 优化路径
以一个 2048x2048 单精度矩阵乘法为例,观察其 Roofline 上的演进:
阶段 计算强度 实测性能 Roofline 位置
-------------------------------------------------------------------
Naive i-j-k 三重循环 0.02 2.5 GFLOP/s 远低于内存带宽线
循环交换 (i-k-j) 0.1 12.0 GFLOP/s 内存带宽线左侧
分块 (Tiling 32x32) 0.8 45.0 GFLOP/s 接近 ridge point
向量化 (AVX2/AVX-512) 1.2 180 GFLOP/s 过渡区
手写汇编 + 寄存器重排 8.0 1200 GFLOP/s 计算天花板下方
调用 Intel MKL / cuBLAS 32+ 3500+ GFLOP/s 紧贴计算天花板
从 Roofline 视角,优化路径清晰可循:
如果点在 Memory Roof 上(I < I_ridge):
- 优先方向:增大计算强度(Tiling、Cache Blocking、Data Reuse)
- 次优方向:如果内存带宽未达硬件峰值,检查 NUMA 绑定、预取、非临时存储
如果点在 Compute Roof 下不远(I > I_ridge):
- 优先方向:向量化、指令级并行、减少数据依赖
- 检查:FMA 利用率、Port Pressure、VPU 指令占比
如果点远低于两段直线(既不贴 Memory 也不贴 Compute):
- 重点排查:分支预测 miss、任务并行粒度不足、同步开销、通信延迟
图形化 Roofline 脚本文本版
以下是一个典型双路 AMD EPYC 9654 服务器的屋顶线数值表:
| 计算强度 (FLOPs/Byte) | 理论上限 (GFLOP/s) | 瓶颈来源 |
|---|---|---|
| 0.01 | 3.5 | STREAM Triad 带宽 (350 GB/s) |
| 0.1 | 35 | STREAM Triad 带宽 |
| 0.5 | 175 | STREAM Triad 带宽 |
| 1.0 | 350 | STREAM Triad 带宽 |
| 2.0 | 700 | STREAM Triad 带宽 |
| 5.0 | 1750 | STREAM Triad 带宽 |
| 10.0 | 3500 | STREAM Triad 带宽 |
| 21.4 | 7500 | Ridge Point |
| 50.0 | 7500 | FP64 计算峰值 |
| 100.0 | 7500 | FP64 计算峰值 |
实践建议
先测 Roofline,再动手优化。盲目优化代码可能事倍功半——如果程序本身 memory-bound,投入大量精力做向量化往往收效甚微。
使用
perf快速估算。在没有 ERT/Advisor 的环境中:# 统计 FLOPs perf stat -e fp_arith_inst_retired.scalar_double,\ fp_arith_inst_retired.128b_packed_double,\ fp_arith_inst_retired.256b_packed_double,\ fp_arith_inst_retired.512b_packed_double ./app # 统计内存带宽 (需 root) perf stat -e uncore_imc_0/cas_count_read/,uncore_imc_0/cas_count_write/ ./app关注 AI/HPC 混合负载。HBM 的引入极大提升了
B_peak(NVIDIA H100 SXM5 约 3.35 TB/s),使得I_ridge向左侧移动,许多原本 compute-bound 的算法在 GPU 上变成了 memory-bound,优化策略需要重新评估。
Roofline 模型的魅力在于将复杂的硬件-软件交互提炼为简洁的可视化框架。它既是性能诊断的起点,也是优化效果的验收标准。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。