测试算法速度。如何?
Posted
技术标签:
【中文标题】测试算法速度。如何?【英文标题】:Testing an Algorithms speed. How? 【发布时间】:2013-09-17 16:36:11 【问题描述】:我目前正在测试不同的算法,这些算法确定整数是否是实数正方形。在我的研究中,我在 SOF 发现了这个问题: Fastest way to determine if an integer's square root is an integer
我对编程场景比较陌生。在测试问题中提出的不同算法时,我发现这是一个
bool istQuadratSimple(int64 x)
int32 tst = (int32)sqrt(x);
return tst*tst == x;
实际上比 A. Rex 在我发布的问题中提供的更快。我使用 NS-Timer 对象进行此测试,并使用 NSLog 打印我的结果。
我现在的问题是:如何以专业的方式进行速度测试?如何获得与我在上面发布的问题中提供的结果相同的结果?
【问题讨论】:
创建一个循环调用函数几千次。 So You Want To Write Your Own Benchmark presentation(Java,但足够接近)。 Top benchmarking question on ***(也是 Java,但包含有用的通用技巧)。 调用函数的次数足够多,至少需要 1 秒的实时时间。这也将允许其他进程执行,模拟真实环境。否则,您可能看不到缓存未命中的影响。 鉴于今天的机器每秒能够进行数百万次计算以可视化不同算法速度之间的巨大差异,因此您应该运行所需的代码片段数百或可能数千次,然后取总运行时间的平均值。唯一可以看到的速度有相当大的差异。希望对您有所帮助。 【参考方案1】:在循环中仅调用此函数的问题是所有内容都将在缓存中(数据和指令)。你不会衡量任何明智的;我不会那样做的。
鉴于这个函数有多小,我会尝试查看生成的这个函数和另一个函数的汇编代码,我会尝试根据汇编代码(指令数和cost of the individual instructions,例如)。
不幸的是,它只适用于微不足道/近乎微不足道的情况。例如,如果汇编代码相同,那么您就知道没有区别,您不需要测量任何东西。或者,如果一个代码与另一个代码相似,加上附加说明;在这种情况下,您知道执行时间越长执行时间越长。还有一些不太清楚的案例...... :( (请参阅下面的更新。)
您可以从 clang 获取带有 -S -emit-llvm
标志的程序集,并从 gcc 获取带有 -S
标志的程序集。
希望对您有所帮助。
更新:回复Prateek's question in the comment“有没有办法确定一种特定算法的速度?”
是的,这是可能的,但它很快就会变得非常复杂。长话短说,忽略现代处理器的复杂性并简单地累积一些与指令相关的预定义成本可能会导致非常非常不准确的结果(由于缓存和管道等原因,估计值会降低 100 倍)。如果您尝试考虑现代处理器、分层缓存、管道等的复杂性,事情会变得非常困难。参见例如Worst Case Execution Time Prediction。
除非您处于明确的情况(微不足道/接近微不足道的情况),例如生成的汇编代码相同或一个与另一个相似加上一些指令,否则也很难根据生成的汇编比较算法。
但是,这里显示了一个简单的两行函数,为此,查看程序集可能会有所帮助。因此我的回答。
【讨论】:
是的,我同意通过汇编将是我们能做的最好的事情,以获得比较两种算法速度的最佳结果。但我很好奇这如何有助于确定算法的速度。它可能能够比较两种给定的算法,但有没有办法确定一种特定算法的速度? @Prateek 如果你找到了答案(我又稍微更新了,插入了一个新链接),请随时点赞! ;) 所以我在我发布的问题中检查了 A. Rex 的算法的汇编代码。它比我发布的要大得多。我很好奇:不知何故,我发布的问题中的人一定找到了一种方法来相互检查算法。我现在想要的是对他们提供的结果的实际证明。如果我有,我想知道他们是如何发现这个特定算法 xy 比另一个算法快 xy%。 @GeorgZänker 众所周知,微基准测试很难可靠地进行。为了增加侮辱,可以使用许多执行不力的基准/实验。所以,仅仅因为有人说算法 X 快 Y%,这并不一定是真的。【参考方案2】:我不确定是否有任何专业的方法来检查速度(如果有,请告诉我)。对于您在问题中指向的方法,我可能会在 java 中执行此操作。
package Programs;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class SquareRootInteger
public static boolean isPerfectSquare(long n)
if (n < 0)
return false;
long tst = (long) (Math.sqrt(n) + 0.5);
return tst * tst == n;
public static void main(String[] args)
long iterator = 1;
int precision = 10;
long startTime = System.nanoTime(); //Getting systems time before calling the isPerfectSquare method repeatedly
while (iterator < 1000000000)
isPerfectSquare(iterator);
iterator++;
long endTime = System.nanoTime(); // Getting system time after the 1000000000 executions of isPerfectSquare method
long duration = endTime - startTime;
BigDecimal dur = new BigDecimal(duration);
BigDecimal iter = new BigDecimal(iterator);
System.out.println("Speed "
+ dur.divide(iter, precision, RoundingMode.HALF_UP).toString()
+ " nano secs"); // Getting average time taken for 1 execution of method.
您可以以类似的方式检查您的方法,并检查哪一种优于其他方法。
更新:- 由于 OP 可能对 java 不满意,我在代码中添加了 cmets 以更清楚地传递这个想法。对于否决票,如果我能得到关于为什么这被否决的建设性反馈,我将非常感激。谢谢!!
【讨论】:
【参考方案3】:-
记录海量计算之前的时间值和之后的值。不同之处在于执行的时间。
编写一个shell 脚本,您将在其中运行该程序。并运行 'time ./xxx.sh' 来获取它的运行时间。
【讨论】:
以上是关于测试算法速度。如何?的主要内容,如果未能解决你的问题,请参考以下文章