【问题标题】:static pre-calculation optimization in clangclang中的静态预计算优化
【发布时间】:2013-11-28 20:27:26
【问题描述】:

我有

#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-loop 的初始化处,即:

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()(或者至少不是这个特定的优化)。我可以这样做吗?

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

【问题讨论】:

  • 旁注:gettimeofday 已过时,clock_gettime 现在是首选。
  • 您可以尝试将代码放在循环中的函数中,该函数将值作为参数传递给调用fib
  • @JoachimPileborg:嗯,即使现在可行,也许未来的版本会更聪明,也会优化它,所以这似乎不是一个可靠的解决方案。
  • @Shahbaz 的旁注:Mac OS X 没有clock_gettime(),因此使用gettimeofday() 作为不错的替代代码是正确的。
  • 您是否查看了生成的汇编程序,看看是否有任何解释?

标签: c optimization clang


【解决方案1】:

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

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

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

目前我的编译器不需要volatile int f,但当编译器发现fib 没有副作用并且它的结果和f 都被使用时,它可能会在将来出现。


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

我不确定编译器是否会进行此类优化,但可以。 Profile Guided Optimization (PGO) 已经朝着这个方向发展。

【讨论】:

    猜你喜欢
    • 2018-11-29
    • 2013-09-04
    • 2021-07-31
    • 1970-01-01
    • 2022-10-02
    • 1970-01-01
    • 2010-12-04
    • 1970-01-01
    • 2016-02-07
    相关资源
    最近更新 更多