繁体   English   中英

GCC优化?

[英]GCC optimization?

我正在使用GCC 4.8.1。 我正在尝试通过将其放入嵌套循环来对某些代码的速度进行基准测试,如下例所示。 每当我这样做时,它都会在最短的时间内执行(例如.02秒),并且执行-03或不进行任何优化,无论执行多少次迭代。 有什么原因吗? 我确信它工作正常,因为值始终正确,并且如果我在循环中使用printf ,那么它将按预期运行。

int main()
{
    int i,j,k;
    int var;
    int big_num = 1000000;
    int x[1];

    for (i = 0;i<big_num;++i){
        for (j = 0;j<big_num;++j){
            for (k = 0;k<big_num;++k){
               // any short code fragment such as:
               var = i - j + k; 
               x[0] = var;
            }
        }
    }
    return 0;
}

对于您所编辑的问题,还不那么正确: 您的代码声明一个单元素数组 int x[1]; 并使用 x[1]作为界外索引(索引应小于1但非负,因此只能为0)访问它; 这是典型的 未定义行为 ,编译器可以通过发出任何代码来合法地对其进行优化。

顺便说一句, GCC 4.9 (在我的Debian / Sid / x86-64上) 正在 (正确地) 将您的代码优化为一个空的main (因为没有有用的计算发生); 您可以通过使用gcc -fverbose-asm -O2 -S进行编译并查看生成的*.s汇编文件来进行检查; 如果您真的对优化过程中的各种内部表示感到好奇,请使用-fdump-tree-all编译; 您还可以更改编译器的行为(或添加一些检查步骤),例如通过使用MELT扩展它

通过替换x[0] = var;可以使您的计算有意义x[0] = var; x[0] += var; 并通过对x[0]产生副作用来结束main ,例如printf("%d\\n", x[0]); return x[0] != 0; 然后,编译器可能会生成一个循环(它可能会在编译时计算循环的结果,但我认为GCC不够聪明)。

最后,典型的当前微处理器通常是乱序的和超标量的,因此每个周期执行一个以上的指令(时钟频率至少为2GHz)。 因此,它们每秒运行数十亿个基本操作。 通常,您需要一个基准持续时间超过半秒(否则,测量结果就没有足够的意义),并且需要重复几次基准。 因此,您需要对基准测试代码进行编码,其中执行了数百亿个(即,超过10 10个 )基本C操作。 并且您需要该代码有用(带有副作用或在其他地方使用的结果计算),否则编译器将通过删除代码进行优化。 同样,基准测试代码应该接受一些输入(否则,编译器可能会在编译时进行大量计算)。 在您的情况下,您可以像这样初始化bignum

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

您如何设置优化? 对我来说,它有效(big_num = 1000):

$ gcc -o x -O0 x.c && time ./x
./x  2.08s user 0.00s system 99% cpu 2.086 total
$ gcc -o x -O1 x.c && time ./x 
./x  0.31s user 0.00s system 99% cpu 0.309 total
$ gcc -o x -O2 x.c && time ./x  
./x  0.00s user 0.00s system 0% cpu 0.000 total

您的代码实际上不执行任何操作。 GCC和大多数编译器都很聪明。 它可以查看它,确定它没有可见的效果并将其完全删除。

您的代码没有副作用 :它不会通过网络发送任何内容,也不会编写文件,因此gcc会删除该代码。 现代的gcc版本具有-fdump-*选项,这些选项允许记录编译器的每个阶段:

$ gcc -O2 -fdump-tree-all elide.c

之后,gcc将生成一堆输出文件:

$ ls -1 | head
a.out
elide.c
elide.c.001t.tu
elide.c.003t.original
elide.c.004t.gimple
elide.c.007t.omplower
...

比较它们可能会揭示删除代码的阶段。 就我而言(GCC 4.8.1),它是cddce阶段。 从GCC源文件gcc/tree-ssa-dce.c

/* Dead code elimination.

References:

    Building an Optimizing Compiler,
    Robert Morgan, Butterworth-Heinemann, 1998, Section 8.9.

    Advanced Compiler Design and Implementation,
    Steven Muchnick, Morgan Kaufmann, 1997, Section 18.10.

Dead-code elimination is the removal of statements which have no
impact on the program's output.  "Dead statements" have no impact
on the program's output, while "necessary statements" may have
impact on the output.

The algorithm consists of three phases:
1. Marking as necessary all statements known to be necessary,
    e.g. most function calls, writing a value to memory, etc;
2. Propagating necessary statements, e.g., the statements
    giving values to operands in necessary statements; and
3. Removing dead statements.  */

您可以通过将变量标记为volatile来显式破坏优化器:

volatile int i,j,k;
volatile int var;
volatile int big_num = 1000000;
volatile int x[1];

volatile将告诉编译器,写入存储单元有副作用

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM