算法复杂度、内存带宽与 Roofline 模型
有一百万个传感器读数,需要依次进行两项处理:先做标定
可以先算完全部
两种写法都随
先数工作量,理解复杂度保留了什么
这里把一次浮点加法或乘法各计为 1 次浮点运算,单位写作 FLOP。它是计数;FLOP/s 是每秒完成的浮点运算数,表示吞吐率。一次乘加融合指令 FMA 能计算乘法加加法,按这个惯例计为 2 FLOP,不能把指令数直接当作 FLOP 数。
对一个元素,先乘
先在实验里改变
规模从
大
本例没有由输入数值触发的提前退出,两种实现都处理所有元素,因而在上述模型下时间都是
对比一个不同的任务:枚举
仅枚举这些对就有
空间也要明确口径。输入和输出各占
把数据搬运纳入成本
处理器做算术前,需要把数据放进可直接使用的寄存器。主存容量较大;缓存位于它与处理器之间,用来保存近期使用的数据,减少反复访问主存。下面只统计主存与处理器侧缓存之间跨过边界的读写字节。
可以把计算想成工作台,把内存系统想成供料通道。工作台每秒能处理多少份、通道每秒能送多少字节,共同限制任务的完成速度。这个类比只帮助辨认两种吞吐约束,不包含真实机器的延迟、缓存和并行细节。
内存带宽是单位时间传输的数据量,本文记作
先约定一个用于核算的流式模型:
- 输入、输出和中间数组使用互不重叠的连续存储,每个元素为 8 byte 的双精度数;
留在寄存器中,忽略其固定开销。 - 数组足够大,分两遍时,中间数组不能完整留在缓存供第二遍使用;每条列出的数组读写都跨过所选主存边界一次。
- 写入只计最终写出的数据,暂不计写分配引起的额外读流量;这对应一种理想化流量口径,例如适当的流式写入。它不是所有机器的默认行为。
分两遍时,跨边界的四项流量为:读
| 同一标定任务 | 浮点运算 |
主存流量 |
额外临时数组 |
|---|---|---|---|
| 分两遍 | |||
| 合并一遍 | 无 |
实验中可以逐步追踪四次或两次搬运;箭头表示跨越同一内存边界的读或写,播放速度仅用于讲解,不代表硬件速度。试着切换元素大小,区分“元素个数没变”和“流量没变”。
默认
若可持续带宽假设为
实际流量还会受缓存行、预取和写策略影响。例如,冷的普通写入可能先把目标缓存行读进来,这叫写分配;之后还要写回。若两种实现中的每次数组写入都多读同样多的字节,上表会分别变成
STREAM 官方说明把它定位为可持续带宽基准,要求数据规模足够大,并解释了其字节计数约定。实测带宽时应同时记录线程数、访问模式、数据规模和读写计数口径;不要把接口标称速率直接当成应用一定能达到的吞吐。
每搬一个字节,能完成多少计算
用总浮点运算数除以主存流量,得到
代入刚才的流量:
强度翻倍是因为流量减半,工作量没有增加。
还可以通过数据复用提高强度:把同一批数据留在缓存或寄存器中,多完成一些任务本来就需要的计算,再换下一批。反复做无用运算也可能提高 FLOP/byte,但不会帮助原任务更快完成。
从两个时间下界推导 Roofline
假设所选处理器范围内的浮点吞吐上限为
完成
这里取较大值,是因为任务不可能比任一必要环节更早完成。它表示允许理想重叠时的乐观下界;若两者完全串行,时间会接近两项之和,而不是较大值。
对
Roofline 给出的是吞吐上限,而不是保证达到的性能。 将横轴设为算术强度、纵轴设为吞吐,
两条线的交点满足
当
实验默认假设
图中两轴都采用以 2 为底的对数刻度,等距刻度表示相同倍数的增长,不是增加相同的绝对数。实心圆表示当前模型上限;保留点使用空心方块。它们都不是测量值。真实分析时,应该把实测点画在对应强度与实测吞吐的位置;上限与实测点之间的距离,才反映还有多少没有解释的损失。
回到数组标定,合并写法的
只将算力提高到
用时间再核对一次:
矩阵乘法:复杂度不变,复用可以改变强度
现在换一个任务:把两个
这表示从
若每次乘加都从主存重新读取两个 8 byte 的输入,且每个
更好的组织方式是分块:把输出矩阵分成小块,每次取相应的输入块到快速存储中,反复使用其中的数。看一个边长为
1 | 缓存中的 A 小块 ─┐ |
若三个
例如
整次矩阵乘法的流量为什么不能只按三张矩阵计算
三个矩阵一共有
若
两种组织都没有改变传统矩阵乘法的立方级算术工作量,却可能大幅改变跨内存层级的流量。复杂度分析与 Roofline 正是在回答不同层面的成本问题。
回到 Roofline 实验,选择“块更新
用一个条件变化检验判断
考虑同样的标定任务,但这次整个输入和中间数组都很小,能够留在缓存中。此时,分两遍不一定把
核对依据:先固定内存边界,再选择屋顶
不能直接沿用。应先确认实际跨过主存边界的数据;中间数组的写和读若都在缓存内完成,就不产生前面所假定的两项主存流量。合并可能仍减少缓存流量、循环开销和临时分配,但主存 Roofline 未必能解释主要耗时。可以进一步分析对应层级的缓存带宽,并使用该层级的流量计算强度。
分层 Roofline 为 L1、L2、主存等边界分别建立带宽线。每条线必须使用对应的
再考虑按指针逐个访问、下一次地址依赖上一次结果的结构。即使每步字节数很少、算术强度很低,也可能因为等待请求完成而远低于带宽屋顶。增加带宽不能自动消除这种依赖。数据连续且有足够并发请求的数组流式处理,更符合本文用吞吐上限解释性能的出发点。
实际优化时,先确认输入规模和所需输出,避免做不必要的工作;再统计重要计算与跨层级流量,选用匹配精度、线程范围和访问模式的上限。把实测
参考资料
- MIT 6.006,Recitation 1: Asymptotic Complexity, Peak Finding,2011。课程讲义。
- Samuel Williams、Andrew Waterman、David Patterson,Roofline: An Insightful Visual Performance Model for Multicore Architectures,Communications of the ACM,52(4),65–76,2009。DOI;2008 年技术报告。
- John D. McCalpin,STREAM Benchmark Reference Information。官方说明与计数规则。
- NERSC,Roofline Performance Model。官方指南。
- NVIDIA,Nsight Compute User Guide,Roofline Charts。官方文档。
- Title: 算法复杂度、内存带宽与 Roofline 模型
- Author: 姜智浩
- Created at : 2026-10-23 10:00:00
- Updated at : 2026-10-23 16:34:23
- Link: https://super-213.github.io/zhihaojiang.github.io/2026/10/23/algorithm-complexity-memory-bandwidth-roofline/
- License: This work is licensed under CC BY-NC-SA 4.0.
Loading comments…