如何避免编译器优化某些操作?

时间:2015-03-06 05:24:50

标签: c++ performance optimization compiler-optimization

如何避免编译器优化某些操作?

例如,如果我实现自己的sprintf2,我想比较我的sprintf2和stdlib' s sprintf的效果,所以我写了这段代码:

#include<iostream>
#include<string>
#include<ctime>
using namespace std;
int main()
{
    char c[50];
    double d=-2.532343e+23;
    int MAXN=1e8;
    time_t t1,t2,t3;

    t1=clock();

    for(int i=0;i<MAXN;i++)
        sprintf2(c,"%16.2e",d);//my own implemention of sprintf

    t2=clock();

    for(int i=0;i<MAXN;i++)
        sprintf(c,"%16.2e",d);

    t3=clock();

    printf("sprintf2:%dms\nsprintf:%dms\n",t2-t1,t3-t2);
    return 0;
}

事实证明:

sprintf2:523538ms//something big, i forgot
sprintf:0ms

众所周知,sprintf需要花费时间,而且MAXN非常大,因此t3-t2不应该是0

由于我们不使用数组c,每次d都相同,所以我猜编译器对其进行了优化,sprintf只执行一次

所以这就是问题,我如何衡量1e8 sprintf花费的实际时间?

2 个答案:

答案 0 :(得分:2)

编译器优化了对sprintf的调用,因为您没有使用结果,并且因为它始终打印相同的数字。因此也要更改打印的数字(因为如果在循环中调用相同的sprintf,编译器可以优化并在循环之前移动sprintf

所以只需使用结果,例如通过计算一些(无意义的)一些字符的总和。

int s=0;
memset(c, 0, sizeof(c));
for(int i=0;i<MAXN;i++) {
    sprintf2(c,"%16.2e",d+i*1.0e-9);
    s+=c[i%8];
}; 
t2=clock();
for(int i=0;i<MAXN;i++) {
    sprintf(c,"%16.2e",d+i*1.0e-9);
    s+=c[i%8];
}
t3=clock();

printf("sprintf2:%dms\nsprintf:%dms\ns=%d\n",t2-t1,t3-t2,s);

t3=clock();

然后你应该能够进行基准测试和编译。您可能希望显示每次通话的时间成本:

printf("sprintf2:%f ms\nsprintf:%f ms\n",
       1.0e3*(t2-t1)/(double)maxn, 1.0e3*(t3-t2)/(double)maxn);

因为POSIX要求CLOCKS_PER_SEC等于1000000,所以clock刻度是1微秒。

BTW,MAXN(应该用小写拼写,所有大写字母通常用于宏!)可能是一些输入(否则聪明的优化编译器可以在编译时展开循环),例如

 int main(int argc, char**argv) {
   int maxn = argc>1 ? atoi(argv[1]) : 1000000;

请注意,在进行基准测试时,您确实应该要求编译器使用-O2进行优化。 衡量未优化代码的速度是没有意义的

您可以随时查看汇编代码(例如gcc -O2 -fverbose-asm -S)并检查sprintf2sprintf是否确实在循环中调用。

在我的Linux Debian / Sid / x86-64 i7 3770K桌面上BTW:

 /// file b.c
#include <stdio.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>

int main(int argc, char**argv) {
  int s=0;
  char buf[50];
  memset(buf, 0, sizeof(buf));
  int maxn = (argc>1) ? atoi(argv[1]) : 1000000;
  clock_t t1 = clock();
  for (int i=0; i<maxn; i++) {
    snprintf(buf, sizeof(buf), "%12.3f",
     123.45678+(i*0.01)*(i%117));
    s += buf[i%8];
  };
  clock_t t2 = clock();
  printf ("maxn=%d s=%d deltat=%.3f sec, each iter=%.3f µsec\n",
      maxn, s, (t2-t1)*1.0e-6, ((double)(t2-t1))/maxn);
  return 0;
}   

编译为gcc -std=c99 -Wall -O3 b.c -o b(GCC为4.9.2,Glibc为2.19)给出以下一致时序:

% time ./b 4000000               
maxn=4000000 s=191871388 deltat=2.180 sec, each iter=0.545 µsec
./b 4000000  2.18s user 0.00s system 99% cpu 2.184 total
% time ./b 7000000
maxn=7000000 s=339696631 deltat=3.712 sec, each iter=0.530 µsec
./b 7000000  3.71s user 0.00s system 99% cpu 3.718 total
% time ./b 6000000                             
maxn=6000000 s=290285020 deltat=3.198 sec, each iter=0.533 µsec
./b 6000000  3.20s user 0.00s system 99% cpu 3.203 total
% time ./b 6000000
maxn=6000000 s=290285020 deltat=3.202 sec, each iter=0.534 µsec
./b 6000000  3.20s user 0.00s system 99% cpu 3.207 total

BTW,请参阅this有关Windows clock实施(可能被视为错误)。您可能会像在我的机器上安装和使用Linux一样高兴(我从未使用过Windows,但自1987年以来我使用的是Unix或POSIX系统)。

答案 1 :(得分:1)

至少在GCC中,优化在文档中声明为默认情况下均未打开

  

只有在命令行上设置-O级别时,才会启用大多数优化。否则,即使指定了单独的优化标志,它们也会被禁用。

你可以在这里阅读

https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

但我无法分享这种印象。

因此,如果没有指定-O参数(或者对于MSVC,您可以在属性中设置优化级别,我记得有一个标记&#34;没有优化&#34;)而不是预期的行为发生,我想说,没有办法以你想要的方式关闭优化。

但请记住,编译器正在做很多优化工作,你甚至不能直接在代码中做。所以,甚至没有理由关闭所有东西&#34;如果是你感兴趣的话。 所以通过文档证明后者似乎是不可能的。