我有
#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()
(或者至少不是这种特定的优化)。我能以某种方式这样做吗?
在这种特定情况下,它有什么优化?它有点奇怪而且相当不错。
答案 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)已朝这个方向发展。