铿锵声中的静态预计算优化

时间:2013-11-15 12:32:49

标签: c optimization clang

我有

#include <stdlib.h>
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
#include <math.h>

int fib(int n) {
    return n < 2 ? n : fib(n-1) + fib(n-2);
}

double clock_now()
{
    struct timeval now;

    gettimeofday(&now, NULL);
    return (double)now.tv_sec + (double)now.tv_usec/1.0e6;
}

#define NITER 5

在我的main()中,我正在做一个像这样的简单基准:

printf("hi\n");
double t = clock_now();
int f = 0;
double tmin = INFINITY;
for (int i=0; i<NITER; ++i) {
    printf("run %i, %f\n", i, clock_now()-t);
    t = clock_now();
    f += fib(40);
    t = clock_now()-t;
    printf("%i %f\n", f, t);
    if (t < tmin) tmin = t;
    t = clock_now();
}
printf("fib,%.6f\n", tmin*1000);

当我使用clang -O3(来自Xcode 5.0.1的LLVM 5.0)进行编译时,它总是打印出零时间,除了在for - 循环的初始化,即:

hi
run 0, 0.866536
102334155 0.000000
run 1, 0.000001
204668310 0.000000
run 2, 0.000000
307002465 0.000000
run 3, 0.000000
409336620 0.000000
run 4, 0.000001
511670775 0.000000
fib,0.000000

它似乎静态地预先计算fib(40)并将其存储在某个地方。对?开始时的奇怪延迟(0.8秒)可能是因为它加载了缓存?

我这样做是为了进行基准测试。 C编译器应该尽可能地优化fib()本身。但是,我不希望它在编译时预先计算它。所以基本上我希望尽可能多地优化所有代码,但不是main()(或者至少不是这种特定的优化)。我能以某种方式这样做吗?

在这种特定情况下,它有什么优化?它有点奇怪而且相当不错。

1 个答案:

答案 0 :(得分:2)

我通过标记某些数据volatile找到了解决方案。 Esp,我做的是:

volatile int f = 0;
//...
    volatile int FibArg = 40;
    f += fib(FibArg);

这样,它会强制编译器在调用函数时读取FibArg,并强制它不假设它是常量。因此,它必须调用函数来计算它。

目前我的编译器不需要volatile int f,但是当编译器发现fib没有副作用且其结果也不是f时,它可能在将来。每次使用。


请注意,这仍然不是结束。到目前为止,未来的编译器可能已经进步,它猜测40可能是fib的参数。也许它为可能的值构建了一个数据库。对于最可能的值,它会构建一个小缓存。当调用fib时,它会快速运行时检查是否缓存了该值。当然,运行时检查会增加一些开销,但编译器估计这个开销对于某些特定代码而言是微不足道的,与缓存所获得的速度有关。

我不确定编译器是否会进行此类优化但是可以。配置文件引导优化(PGO)已朝这个方向发展。