2. 科学计算负载特征分析
优化科学计算程序的第一步,不是急着改代码,而是先判断“这段程序到底被什么卡住了”。同样是浮点运算密集的代码,有的受限于处理器的计算峰值,有的受限于内存带宽,还有的受限于延迟或并行度不足。要做出这种判断,最有效的入门工具就是算术强度与Roofline 模型。本节围绕稠密线性代数、稀疏迭代、N 体模拟、格点计算四类典型负载,剖析它们的计算与访存模式,并给出用 Roofline 初步定位瓶颈的方法。
一、算术强度:把负载翻译成一个数
算术强度(Arithmetic Intensity, AI)定义为单位访存字节所对应的浮点运算次数,常用单位为 FLOP/Byte:
AI = 浮点运算次数(FLOP) / 访存字节数(Byte)
这里的“访存字节数”指算法在理想缓存复用假设下,从主存搬入的数据量。以经典的矩阵乘法 C = A·B(n×n 双精度)为例,浮点运算量为 2n³,若三块矩阵各读一次、结果写一次,主存流量约为 4n²×8 字节,于是 AI ≈ 2n³ / (32n²) = n/16。当 n=1024 时 AI≈64 FLOP/Byte,远高于现代多核 CPU 的带宽拐点(典型值约 10~20 FLOP/Byte),因此大矩阵乘法天然是计算受限的。这个推导说明:AI 不是代码的固有属性,而与问题规模、数据布局和分块策略密切相关。
二、Roofline:把 AI 放到硬件坐标系里
Roofline 模型把硬件性能画成一条“屋顶线”:横轴为算术强度(对数坐标),纵轴为可达性能。屋顶由两段组成——低 AI 区受内存带宽限制,性能上限为 带宽×AI,是一条斜线;高 AI 区受计算峰值限制,是一条水平线。两线交点对应的 AI 即“带宽拐点”。把某段程序的实测 AI 与性能点画上去,就能直观看出它离哪条屋顶更近、还有多少提升空间。
三、四类负载的计算与访存模式
稠密线性代数(GEMM、LU、Cholesky 等)以规则二维/三维数据块为对象,运算量随规模呈立方增长,而访存量仅平方增长,AI 高,属于计算受限。优化重点是提高浮点流水线利用率:分块(blocking)提升缓存复用、向量化、多线程并行、使用 BLAS 库。此时若性能仍低,应查指令效率、寄存器压力和并行扩展性,而非内存带宽。
稀疏迭代(以 SpMV 为代表)是典型的低 AI 负载。稀疏矩阵每行非零元少且不规则,一次乘加只搬运少量数据,还伴随间接寻址(CSR 格式的列索引数组)。其 AI 通常只有 0.1~0.5 FLOP/Byte,几乎必然落在带宽斜线上。优化方向是压缩存储、提高数据局部性、采用分块 CSR 或 ELL 格式改善访存规则性,而不是追求更高主频。
N 体模拟介于两者之间。朴素 O(N²) 算法每对粒子做一次力计算,AI 中等;引入树结构(Barnes-Hut)或快速多极子后,计算量降到 O(N log N),但访存变得不规则、分支增多,实际 AI 下降。优化需在算法复杂度与访存规则性之间权衡,并关注粒子数据的空间重排(如 Morton 排序)以提升缓存命中。
格点计算(如 LBM、Stencil、Jacobi 迭代)每个格点只与邻居交互,计算量小但访存频繁,AI 偏低到中等。其瓶颈常是带宽与边界处理开销。优化手段包括时间分块(temporal blocking)、空间分块、SIMD 对齐以及减少 halo 交换。以三维 7 点 Stencil 为例,每点约 13 次浮点运算、需读 7 个邻居,AI 约 0.2~0.4 FLOP/Byte,属于带宽敏感型。
四、实操:用 Roofline 做一次初步判断
假设在一台双路服务器上测得:内存带宽约 100 GB/s,双精度峰值约 800 GFLOP/s,则带宽拐点 AI ≈ 800/100 = 8 FLOP/Byte。现在对四段程序做粗略估算(以下为教学示例参数,非实测):
| 负载 | 估算 AI (FLOP/Byte) | 相对拐点 | 初步判断 |
|---|---|---|---|
| 稠密 GEMM (n=2048) | ≈128 | 远高于 8 | 计算受限 |
| SpMV (CSR) | ≈0.25 | 远低于 8 | 带宽受限 |
| N 体(树算法) | ≈2 | 低于 8 | 偏带宽/延迟受限 |
| 3D 7 点 Stencil | ≈0.3 | 远低于 8 | 带宽受限 |
判断规则很直接:AI 明显高于拐点,优先查计算效率(向量化、指令混合、并行度);AI 明显低于拐点,优先查访存效率(缓存命中率、预取、数据布局、NUMA 亲和性)。介于两者之间的负载,则需结合实测性能点与屋顶的距离,判断是“离斜线近”还是“离水平线近”。
掌握这套方法后,面对任何一段科学计算代码,都可以先问三个问题:它的 AI 大概是多少?硬件拐点在哪里?实测性能点落在屋顶的哪一侧?答案会直接决定你下一步该优化计算还是优化访存。