通过翻牌计数进行算法分析过时了吗?

计算科学 算法 表现 复杂 教育 建筑学
2021-12-20 19:41:25

在我的数值分析课程中,我学会了通过计算相对于问题大小所需的浮点运算(触发器)的数量来分析算法的效率。例如,在 Trefethen & Bau 关于数值线性代数的文章中,甚至还有翻牌数的 3D 外观图片。

现在流行说“触发器是免费的”,因为获取不在缓存中的任何内容的内存延迟比触发器的成本要大得多。但我们仍在教学生数失败,至少在数值分析课程中是这样。我们应该教他们计算内存访问次数吗?我们需要写新的教科书吗?或者内存访问是否过于特定于机器而无法花时间?触发器或内存访问是否是瓶颈的长期趋势是什么?

注意:下面的一些答案似乎在回答一个不同的问题,例如“我应该痴迷地重写我的实现以节省一些失败或提高缓存性能吗?” 但我要问的更多的是“根据算术运算或内存访问来估计算法复杂性是否更有用?”

4个回答

我认为(一阶)正确的做法是查看算法中所需的触发器与字节的比率,我称之为β. Fmax是处理器的最大翻转率,并且Bmax最大带宽。如果Fmaxβ>Bmax,那么算法将受到带宽限制。如果Bmaxβ>Fmax, 该算法是有限的。

我认为计算内存访问是强制性的,但我们也应该考虑:

  • 需要多少本地内存

  • 我们有多少可能的并发

然后你就可以开始分析现代硬件的算法了。

我不明白为什么必须成为“赢家”;这不是一个零和游戏,翻牌数和内存访问必须淹没另一个。你可以教他们两个,我认为他们都有自己的用途。毕竟,很难说你的O(N4)算法与O(N)内存访问一定会比你的更快O(NlogN)算法与O(N2)访问。这完全取决于不同部分的相对成本(我们在这些分析中总是忽略的讨厌的先决条件!)。

从更广泛的角度来看,我认为对算法性能的分析应该是“包罗万象”的。如果我们教人们成为真正的 HPC 开发人员和用户,那么他们需要了解在现实世界中编程的成本是多少。我们的抽象分析模型没有考虑程序员的时间。我们应该考虑“解决问题的总时间”,而不仅仅是失败次数和算法效率。除非你计划运行几百万次计算,否则花三到四个程序员的时间来重写一个例程,从而为每个作业节省一秒钟的计算机时间是没有意义的。同样,为节省一两个小时的计算时间而进行的几天投资很快就会得到回报。那个新颖的算法可能是惊人的,

正如其他人指出的那样,答案当然取决于瓶颈是 CPU 还是内存带宽。对于在一些任意大小的数据集上工作的许多算法,瓶颈通常是内存带宽,因为数据集不适合 CPU 缓存。

此外,Knuth 提到内存访问分析更有可能经受住时间的考验,大概是因为与现代 CPU 管道和分支预测的复杂性相比,它相对简单(即使考虑到缓存友好性)。

在分析 BDD 时, Knuth 在 TAOCP 第 4A 卷中使用了术语gigamems我不确定他是否在以前的卷中使用它。他在 2010 年的年度圣诞树讲座中就经受住了时间的考验发表了上述评论。

有趣的是,You're Doing It Wrong表明,即使基于内存操作分析性能也并不总是那么简单,因为如果数据不能一次全部放入物理 RAM,就会出现诸如 VM 压力之类的因素。

您如何确定算法的成本取决于您工作的科学计算“级别”以及您考虑的(狭义或广义)问题类别。

如果您考虑缓存优化,这显然与诸如 BLAS 和类似库之类的数值线性代数包的实现更相关。所以这属于低级优化,如果你有一个针对特定问题的固定算法并且对​​输入有足够的约束就可以了。例如,如果矩阵被保证足够稀疏,缓存优化可能与快速实现共轭梯度迭代有关。

另一方面,问题的类别越广泛,您对实际计算的预测就越少(例如,您不知道您的 CG 实现的输入矩阵到底有多稀疏)。您的程序应该运行的机器类别越广泛,您对缓存架构的预测就越少。

此外,在更高层次的科学计算上,改变问题结构可能更相关。例如,如果您花时间为线性方程组寻找一个好的预条件子,这种优化通常优于任何低级优化,因为迭代次数大大减少。

总而言之,缓存优化只有在没有任何东西可以通过并行性和渐近 FLOP 数减少来优化的情况下才有用。

我认为调整理论计算机科学的立场是明智的:最终,提高算法的渐近复杂度比对一些现有代码行的微优化有更多的回报。因此,FLOPs 计数仍然是首选。