【问题标题】:large loop for timing tests gets somehow optimized to nothing?定时测试的大循环以某种方式优化到什么都没有?
【发布时间】:2014-05-03 13:42:57
【问题描述】:

我正在尝试测试一系列用于矩阵向量计算的库。为此,我只是做了一个大循环,在里面我调用我想要计时的例程。非常简单。但是,我有时会看到,当我提高编译器的优化级别时,无论循环有多大,时间都会下降到零。请参阅下面的示例,其中我尝试对 C 宏计时以计算叉积。编译器在做什么?我怎样才能避免它,但允许对浮点算术进行最大优化?提前谢谢你

下面的示例是在具有 i5 intel 处理器的计算机上使用 g++ 4.7.2 编译的。 使用优化级别 1 (-O1) 需要 0.35 秒。对于二级或更高级别,它下降到零。请记住,我想为此计时,因此我希望计算实际发生,即使对于这个简单的测试而言,这是不必要的。

#include<iostream>
using namespace std;

typedef double  Vector[3];
#define VecCross(A,assign_op,B,dummy_op,C)              \
(   A[0] assign_op (B[1] * C[2]) - (B[2] * C[1]),       \
    A[1] assign_op (B[2] * C[0]) - (B[0] * C[2]),       \
    A[2] assign_op (B[0] * C[1]) - (B[1] * C[0])        \
)

double get_time(){
  return clock()/(double)CLOCKS_PER_SEC;
}

int main()
{
  unsigned long n = 1000000000u;
  double start;

  {//C macro cross product                                                                                                                                              
    Vector u = {1,0,0};
    Vector v = {1,1,0};
    Vector w = {1.2,1.2,1.2};

    start = get_time();
    for(unsigned long i=0;i<n;i++){
      VecCross (w, =, u, X, v);
    }
    cout << "C macro cross product: " << get_time()-start << endl;
  }

  return 0;
}

【问题讨论】:

  • 查看生成的机器码。
  • 你永远不会对你的计算结果做任何事情,所以编译器不会费心计算它。
  • @KerrekSB,你能扩展一下吗?我该怎么做?更重要的是它对我有什么帮助?我的最终目标是能够计算出完成所有这些交叉产品需要多长时间。
  • @AlanStokes,谢谢。好吧,这是我的猜测,但是,我如何禁用该行为但仍优化单叉积操作本身?我还想计时。还有其他更聪明的测试建议吗?
  • 这将帮助您检查您是否正在测量正确的东西。您可以在循环中添加 volatile asm("":::"memory"); 之类的内容,以鼓励编译器不要删除代码,但您必须检查您是否确实在执行所需的代码。

标签: c++ optimization compiler-optimization timing


【解决方案1】:

问问自己,就最终用户可见的内容而言,您的程序实际上做了什么

它显示计算结果:get_time()-start。循环的内容与该计算的结果无关,因为您从未真正使用循环内正在修改的变量。

因此,编译器优化了整个循环,因为它无关紧要。

一种解决方案是输出循环中正在修改的变量的最终状态,作为cout 语句的一部分,从而强制编译器计算循环。然而,一个聪明的编译器也可以计算出循环总是计算同样的东西,它可以简单地将结果直接插入到你的cout语句中,因为不需要在运行时实际计算它。作为一种解决方法,例如,您可以要求在运行时提供循环的输入之一(例如,从文件、命令行参数、cin 等中读取它)。

有关更多(可能更好)的解决方案,请查看此重复线程:Force compiler to not optimize side-effect-less statements

【讨论】:

  • 更好的解决方案是使用cerr 打印结果并将stderr 重定向到/dev/null,以便流成本不会影响配置文件结果(或至少影响最小值)。
  • @JBentley,我的时间仍然为零。显然编译器“太聪明了”。还有其他建议吗?
  • @JBentley。 volatile 在我的简单 C 宏案例中清楚地显示了不同的结果。事情不适用于对象!因为 c++ 检查参数是“Vector”而不是“volatile Vector”,所以我无法更改,因为我使用的是库。
猜你喜欢
  • 2013-09-11
  • 1970-01-01
  • 2018-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-13
相关资源
最近更新 更多