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


43

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

现在时髦地说“触发器是免费的”,因为获取不在缓存中的任何内容的内存等待时间比触发器的成本大得多。但是,我们仍在教学生数数失败,至少在数值分析课程中是如此。我们应该教他们计算内存访问吗?我们需要写新的教科书吗?还是内存访问太特定于机器而无法花费时间?从瓶颈还是访问内存的角度来看,长期趋势是什么?

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


1
> “根据算术运算或内存访问来估计算法复杂度是否更有用?” 。从实际的角度来看,嵌入式系统仍然受FPU速度而非内存带宽的限制。因此,即使HPC标准认为过时计数已经过时,其他社区仍然可以使用。
Damien 2014年

Answers:


31

我认为(一阶)正确的做法是查看算法中所需的触发器与字节的比率,我将其称为。令F m a x为处理器的最大翻转率,B m a x为最大带宽。如果F m a xβFmaxBmax,则算法将受到带宽限制。如果一个Xβ>˚F中号一个X,该算法是触发器的限制。Fmaxβ>BmaxBmaxβ>Fmax

我认为对内存访问进行计数是强制性的,但我们还应该考虑以下几点:

  • 需要多少本地内存

  • 我们有多少可能的并发

然后,您可以开始分析现代硬件的算法。


3
β

2
大卫在8年前做了更多工作
Matt Knepley 2011年

3
好的,因此有一个更好,更复杂的模型(一如既往)。但是此模型给出的答案取决于机器。我们应该教学生什么作为初步分析?
大卫·凯奇森2011年

3
关键是,该算法已将机器减少为单个数,即峰值触发器与峰值带宽之比。这很简单。如果没有计算模型,那么任何复杂性估计都是无用的,这是最简单的现实估计。
Matt Knepley 2011年

1
我认为您误解了这个问题。我们已经有了可以承载大负载的光传输装置。问题在于将其存储在芯片上。您只有这么多的电线和最高的时钟频率。光传输只会减轻光芯片上的这个问题。
Matt Knepley 2012年

22

O(N4)O(N)O(NlogN)O(N2)

从更广泛的角度来看,我认为对算法性能的分析应该是“包罗万象的”。如果我们要教人们成为真正的HPC开发人员和用户,那么他们需要了解现实中编程的成本。我们拥有的抽象分析模型没有考虑程序员的时间。我们应该考虑“解决的总时间”,而不是仅仅考虑翻牌计数和算法效率。花三到四天的程序员来重写一个例程,如果您不打算运行数百万次计算,那么每次例程可以节省一秒钟的计算机时间,这没有什么意义。同样,节省几天或两小时计算时间的投资很快就会收到回报。那个新颖的算法可能很棒


7
O(NlogN)O(N2)

2
O(NlogN)O(N2)

9

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

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

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

有趣的是,“做错了”表明,即使基于内存操作来分析性能也不总是那么简单,因为如果数据不能一次全部放入物理RAM中,那么诸如VM压力之类的因素就会发挥作用。


8

如何确定算法的成本取决于您工作的科学计算的“水平”以及所考虑的问题的范围(狭窄或广泛)。

如果考虑缓存优化,那么这显然与例如数字线性代数软件包(如BLAS和类似的库)的实现更为相关。因此,这属于低级优化,如果您对特定问题有固定的算法并且对​​输入有足够的约束,那就很好了。例如,如果保证矩阵足够稀疏,则高速缓存优化可能与快速实现共轭梯度迭代有关。

另一方面,问题类别越广,您对实际计算的预测就越少(例如,您不知道CG实现的输入矩阵实际上将多么稀疏)。您的程序应运行的计算机类别越广,您对Cache体系结构的预测就越少。

此外,在更高水平的科学计算中,更改问题结构可能更有意义。例如,如果您花时间为线性方程组找到一个好的前置条件,则这种优化通常会胜过任何低级优化,因为迭代次数会大大减少。

在总结中,只有在没有什么可以通过并行性和减少FLOP的渐近数量进行优化的情况下,缓存优化才有用。

我认为,适应理论计算机科学的立场是明智的:最后,提高算法的渐近复杂性比对某些现有代码行进行微优化有更多回报。因此,仍然希望使用FLOPs计数。


“只有在没有什么可以通过并行性和减少FLOP的渐近数量进行优化的情况下,缓存优化才有用”。我不同意。如果要计算一大堆数字的大型表达式,最好一次对所有数字执行一个步骤,而不是对每个数字执行所有步骤。两者的FLOPS数量相同,但其中一个在内存访问方面更好。如果您选择适合缓存的数据包大小(或由编译器为您完成),则可获赠。这就是numexpr在Python中所做的工作:github.com/pydata/numexpr
Davidmh 2014年

6

我一直拒绝考虑计算触发器,内存访问量或其他任何东西。这是1960年代的一个概念,当时您所做的工作几乎可以给出,而如何完成取决于算法优化。可以考虑使用Jacobi迭代的高斯消除来解决均匀xyz网格上的有限元问题。

现在,您可以优化它,节省一些失败,获得10%的运行时间。或者,您可以考虑实现多网格方法和最佳块预处理器,从而使运行时间增加10倍。这就是我们应该训练我们的学生要做的事情-考虑什么复杂的外部算法可以使您胜过试图找到更好的内部算法。您的老板(Keyes)拥有有关MHD计算进展的幻灯片,这使这一点非常明显。


实际上,我在问的是您建议的高级思考类型,而不是低级优化。您应该使用什么度量标准来确定多网格和预处理器是否比其他方法更快?
大卫·凯奇森2011年

我不知道如何手工计算FLOPS或任何其他指令数,这些复杂的算法需要运行数十或数千行代码。例如,考虑一下AMG算法的分析和构建阶段有多复杂。这些算法有很多部分,而所有这些都取决于实际数据,因此您无法预测操作次数。
Wolfgang Bangerth 2011年

1
我想我一开始误解了您的意思,但是我仍然不同意您的观点。“外部算法”可以(并且我认为应该)在设计时考虑到渐近复杂性。当然,您不会声称从二次算法降为近似线性算法最多只能将运行时间减少10%;然而,除了通过触发器和/或记忆运算之外,还有什么其他方法可以量化渐近复杂性?
杰克·普尔森

7
我认为这种“举起手来”算法的方法是胡扯。您只需要查看一阶成本,并简化模型以使其易于处理就可以简化分析,但是要说您无法分析MG或Cholesky之类的东西,因为它太复杂了是完全错误的。
Matt Knepley 2011年

1
好吧,但是当您计数的每个FLOP都隐藏在由超线程处理器,缓存,慢速RAM,多标量处理器和自动矢量化引起的几层延迟之后时,分析MG或Cholesky意味着什么?我要说的是,在5到10的范围内,您无法在没有定时的情况下预测算法的运行时间。当人们开始进行FLOP计数时,这与50年代和60年代完全不同。
Wolfgang Bangerth,2012年

1

是的,已过时。考虑到问题的严重性时,使用触发器或任何其他方法进行的算法分析仅与机器的抽象模型一样有用。实际性能取决于实现和硬件,并且任何抽象模型对于后者对现实的适用性都会随着时间的推移而下降。例如,当您进一步并行化复杂算法(如分子动力学)的实现时,不同方面将限制不同硬件的速率,并且算法分析与观察结果无关。从某种意义上说,唯一重要的是测量所讨论的硬件类型上算法的实现性能。

这样的抽象作为学习工具有用吗?是的,就像用于教学的许多模型一样,它们在理解模型局限性的同时也很有用。只要您了解古典力学不会在小距离或大速度的音阶上起作用...


-1

并不是真正回答您的问题,而是添加了另一个要考虑的变量:要考虑的是编程语言的功能。例如,Python sort使用Timsort算法,该算法被设计为(在其他一些不错的属性中)以最大程度地减少比较次数,这对于Python对象而言可能很慢。另一方面,比较C ++中的两个浮点数很快,但是交换它们的代价更高,因此它们使用其他算法。

其他示例是动态内存分配(在Python列表中是微不足道的,在运行时和开发人员时都很快.append()),而FORTRAN或C则相对于FORTRAN或C,尽管正确实现可能且更快,但它需要花费大量的编程时间和精力。看到Python比FORTRAN快。


的确如此,但是正如您所说,它并不能回答问题。这是一个不同的话题。
David Ketcheson 2014年

好吧,在进行适当的分析时,确定要实施的算法时要考虑到这一点。
Davidmh 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.