如何确定方法A比方法B更有效

时间:2014-12-27 18:32:05

标签: performance benchmarking

我正在编写一个代码,我遇到了一种情况,我想测试两种不同的做法和时间的方法,以便我可以确保使用两者中效率最高的方法。我看到大家在这里发布各种问题/答案的时间信息,但我找不到任何与如何收集和评估数据有关的问题或答案。我的问题有3个部分,我将用这个例子来解释:

我编写了一个评估数学表达式的函数,我将结果存储在一个特征矩阵中。矩阵是完全对称的,所以我想确定两次计算所有非对角线元素的速度是否更快。

//Method A
for( int i=0; i < max; i++){
   for(int j= 0; j < max; j++){
        storage_matrix(i,j)=my_function(i,j);
       } 
    } 

或者我应该在我只计算它们之后复制非对角线元素,这实际上使第二个循环受到第一个限制,就像这样。

//Method B 
for( int i=0; i < max; i++){
   for(int j= 0; j < i; j++){
        storage_matrix(i,j)=my_function(i,j);
        storage_matrix(j,i)=storage_matrix(i,j);
       } 
    } 

现在这是一个非常简单的例子,但我想学习如何评估这些类型的东西,所以我认为一个简单的例子是最好的。我知道哪个更快,但我想知道。我想看一些数字并说“是的,这是更快的”,或者甚至,“哇看起来并没有那么大的差别。”

现在我的三部分问题:

如何查看代码的一般时序信息?

根据max的大小,是否会有更快的差异? (即我应该测试最大值和小值)

我只是想知道在更短的时间内完成哪项工作,或者在我研究这些问题时是否需要考虑其他因素?

注意:我正在使用C ++

1 个答案:

答案 0 :(得分:1)

基准测试是一种实验。

实验必须针对您在您设定的条件下进行检查的假设而设计,没有一种尺寸适合所有。众所周知,基准测试很难做到,很容易意外地设计一个实验,结果却没有回答你的问题。这是非常偷偷摸摸的,因为你可以在任何地方获得结果,并且通常没有任何东西可以告诉你,你所做的是错的 - 因此,你应该考虑所有事情,解释一切,并设计实验,以便它真的告诉你你想知道什么。

有时情况并非如此糟糕,如果两件事之间的时差非常大,即使是在一个草率的实验中也会显而易见。如果时间或时间差非常小,那就很难了。

有几件事需要注意:

  • 基准测试运行在预期的输入上(显而易见,但通常是问题的根源)
  • 噪音没有实际时差那么显着(理想的是,你不需要统计测试就足够大了)
  • 编译器没有优化你想要测量的东西,这特别影响用于放大时差的循环(即重复一次百万次的函数)
  • 有时比较最快测量时间比平均时间更合适,最快的运行受抢占和页面错误的影响最小(那么你可能想要包含页面错误,这取决于你的实验)
  • 第二次(或第一次)跑不应该有不公平的优势。包括缓存效果,首次实际触摸分配的内存时发生的页面错误,必须学习某些模式的分支预测器,很多东西。要非常小心。在某些情况下,最好丢弃前几次,并且只考虑“稳定状态”,其中一切都具有不首先的优势。但有时候它是第一次 - 例如,初始化程序只发生一次,所以“第二次”的速度并不重要,初始化代码的基准应该考虑到这一点。
  • 在测量延迟时,请确保您没有测量吞吐量(反之亦然)。这意味着根据您的意图,进行基准循环的下一次迭代(放大时差的循环)依赖或独立。特别是影响小片段。这并不总是微不足道的,例如参见this case。
  • 当代码足够小时,请查看汇编代码以确保它符合您的期望。

小/快速代码尤其具有挑战性,如果您打算设计这种基准测试,请确保您对处理器的工作原理非常熟悉。如果您正在为PC开发,则意味着阅读thisthis,有时会查看here。对于移动设备,您可能还需要考虑用电量。

  

根据max的大小,是否会有更快的差异? (即我应该测试最大值和小值)

是的!通常情况下,小尺寸赢了,而大尺寸赢了。实际上你也应该测试一些尺寸。

在这种特定情况下,您可以看到第二个片段可能会以较差的方式访问矩阵。如果整个矩阵无论如何都适合缓存,这并不重要,但如果它太大,那么它也很重要,另见this。当然,这与进行不同的计算量是平衡的。