【问题标题】:likely(x) and __builtin_expect((x),1)可能(x)和__builtin_expect((x),1)
【发布时间】:2014-06-19 07:48:54
【问题描述】:

我知道内核大量使用likelyunlikely 宏。宏的文档位于Built-in Function: long __builtin_expect (long exp, long c)。但他们并没有真正讨论细节。

编译器究竟如何处理likely(x)__builtin_expect((x),1)

是由代码生成器还是优化器处理?

是否取决于优化级别?

生成的代码示例是什么?

【问题讨论】:

  • 为什么不检查生成的代码?注意:你不会看到任何特别的东西。如果您了解这些“宏”的作用,就应该清楚为什么...
  • 这是一个很重要的问题,但基本上编译器生成的机器代码将对它进行一些小的目标特定更改,以使分支预测器和缓存以某种方式运行。老实说,您最好查看英特尔的处理器文档以了解其细节,至少对于 x86 而言。
  • @jww:这不是对话。
  • 学习从编译器读取生成的汇编程序以了解正在发生的事情非常有用。尤其是当您对此类纳米优化感兴趣时。
  • 是的,Art 说的是认真的。由于这个原因,我对 x86 和 ARM 汇编的学习比我想象的要多得多。

标签: c optimization macros code-generation built-in


【解决方案1】:

我刚刚在 gcc 上测试了一个简单的例子。

对于 x86,这似乎由优化器处理并取决于优化级别。虽然我猜这里的正确答案是“它取决于编译器”。

生成的代码取决于 CPU。一些 cpus(sparc64 立即出现在我的脑海中,但我相信还有其他的)在条件分支指令上有标志,告诉 CPU 如何预测它,因此编译器生成“预测真/预测假”指令取决于内置编译器中的规则和代码中的提示(如__builtin_expect)。

英特尔在这里记录了他们的行为:https://software.intel.com/en-us/articles/branch-and-loop-reorganization-to-prevent-mispredicts。简而言之,英特尔 CPU 的行为是,如果 CPU 没有关于分支的先前信息,它将预测前向分支不太可能被采用,而后向分支可能会被采用(考虑循环与错误处理)。

这是一些示例代码:

int bar(int);
int
foo(int x)
{
    if (__builtin_expect(x>10, PREDICTION))
        return bar(10);
    return 42;
}

编译时使用(我使用 omit-frame-pointer 使输出更具可读性,但我仍然在下面清理它):

$ cc -S -fomit-frame-pointer -O0 -DPREDICTION=0 -o 00.s foo.c
$ cc -S -fomit-frame-pointer -O0 -DPREDICTION=1 -o 01.s foo.c
$ cc -S -fomit-frame-pointer -O2 -DPREDICTION=0 -o 20.s foo.c
$ cc -S -fomit-frame-pointer -O2 -DPREDICTION=1 -o 21.s foo.c

00.s 和 01.s 之间没有区别,因此这表明这取决于优化(至少对于 gcc)。

这是 20.s 的(清理后的)生成代码:

foo:
    cmpl    $10, %edi
    jg  .L2
    movl    $42, %eax
    ret
.L2:
    movl    $10, %edi
    jmp bar

这里是 21.s:

foo:
    cmpl    $10, %edi
    jle .L6
    movl    $10, %edi
    jmp bar
.L6:
    movl    $42, %eax
    ret

正如预期的那样,编译器重新排列了代码,以便我们不希望采用的分支在前向分支中完成。

【讨论】:

  • 谢谢艺术。我不知道 x86 中的前进/后退分支“提示”!此外,当您的“冷”代码位于函数的末尾(在生成的代码中)时,除非需要,否则它可能永远不会加载到 CPU 的缓存中,这是一件好事。哦,是的 jww,还要了解 coldhot 属性。我相信include/linux/compiler.h 也有它们的宏。如果您将函数标记为此类,则可以省略(不)可能的宏。
猜你喜欢
  • 2014-09-19
  • 2016-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-20
  • 1970-01-01
  • 2017-03-02
相关资源
最近更新 更多