首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >有没有一个编译器提示,让GCC强制分支预测总是以特定的方式进行?

有没有一个编译器提示,让GCC强制分支预测总是以特定的方式进行?
EN

Stack Overflow用户
提问于 2015-05-09 02:54:48
回答 5查看 26.6K关注 0票数 120

对于英特尔体系结构,是否有一种方法可以指示GCC编译器生成始终以特定方式强制在代码中进行分支预测的代码?英特尔硬件是否支持这一点?其他的编译器或硬件呢?

我会在C++代码中使用这一点,在这种情况下,我希望快速运行,而不关心当需要采用另一个分支时的速度减慢,即使它最近已经采用了该分支。

代码语言:javascript
复制
for (;;) {
  if (normal) { // How to tell compiler to always branch predict true value?
    doSomethingNormal();
  } else {
    exceptionalCase();
  }
}

作为Evdzhan Mustafa的一个后续问题,提示能否仅指定处理器第一次遇到指令时的提示,所有后续分支预测,是否正常运行?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2020-01-15 18:36:07

从C++20开始,likely and unlikely attributes应该是标准化的,并且已经支持in g++9。因此,正如前面所讨论的here,您可以编写

代码语言:javascript
复制
if (a > b) {
  /* code you expect to run often */
  [[likely]] /* last statement here */
}

例如,在下面的代码中,由于if块中的[[unlikely]],else块被内联

代码语言:javascript
复制
int oftendone( int a, int b );
int rarelydone( int a, int b );
int finaltrafo( int );

int divides( int number, int prime ) {
  int almostreturnvalue;
  if ( ( number % prime ) == 0 ) {
    auto k                         = rarelydone( number, prime );
    auto l                         = rarelydone( number, k );
    [[unlikely]] almostreturnvalue = rarelydone( k, l );
  } else {
    auto a            = oftendone( number, prime );
    almostreturnvalue = oftendone( a, a );
  }
  return finaltrafo( almostreturnvalue );
}

godbolt link comparing the presence/absence of the attribute

票数 11
EN

Stack Overflow用户

发布于 2017-05-09 20:44:41

在C++11中定义可能/不太可能的宏的正确方法如下:

代码语言:javascript
复制
#define LIKELY(condition) __builtin_expect(static_cast<bool>(condition), 1)
#define UNLIKELY(condition) __builtin_expect(static_cast<bool>(condition), 0)

[[likely]]不同,此方法与所有C++版本兼容,但依赖于非标准扩展__builtin_expect

当这些宏以这种方式定义时:

代码语言:javascript
复制
#define LIKELY(condition) __builtin_expect(!!(condition), 1)

这可能会改变if语句的含义并破坏代码。考虑以下代码:

代码语言:javascript
复制
#include <iostream>

struct A
{
    explicit operator bool() const { return true; }
    operator int() const { return 0; }
};

#define LIKELY(condition) __builtin_expect((condition), 1)

int main() {
    A a;
    if(a)
        std::cout << "if(a) is true\n";
    if(LIKELY(a))
        std::cout << "if(LIKELY(a)) is true\n";
    else
        std::cout << "if(LIKELY(a)) is false\n";
}

及其输出:

代码语言:javascript
复制
if(a) is true
if(LIKELY(a)) is false

如您所见,可能使用!!作为对bool的强制转换的定义打破了if的语义。

这里的重点不是operator int()operator bool()应该是相关的。这是一个很好的实践。

相反,使用!!(x)而不是static_cast<bool>(x)会丢失C++11 contextual conversions的上下文。

票数 24
EN

Stack Overflow用户

发布于 2015-05-09 18:02:39

正如其他答案所充分建议的那样,您可以使用__builtin_expect给编译器一个关于如何排列汇编代码的提示。正如the official docs指出的那样,在大多数情况下,内置在你大脑中的汇编程序不会像GCC团队精心制作的汇编程序那么好。最好是使用实际的配置文件数据来优化您的代码,而不是猜测。

沿着类似的路线,但尚未提到,是一种特定于GCC的方法,强制编译器在“冷”路径上生成代码。这涉及到noinlinecold属性的使用,这两个属性的作用与它们听起来完全一样。这些属性只能应用于函数,但是使用C++11,您可以声明内联的lambda函数,并且这两个属性也可以应用于lambda函数。

虽然这仍然属于微优化的一般类别,因此标准建议适用-测试不要猜测-我觉得它比__builtin_expect更有用。几乎没有几代x86处理器使用分支预测提示(reference),因此您唯一能够影响的就是汇编代码的顺序。因为您知道什么是错误处理或“边缘情况”代码,所以可以使用此注释来确保编译器不会预测到它的分支,并在优化大小时将其链接到“热”代码。

示例用法:

代码语言:javascript
复制
void FooTheBar(void* pFoo)
{
    if (pFoo == nullptr)
    {
        // Oh no! A null pointer is an error, but maybe this is a public-facing
        // function, so we have to be prepared for anything. Yet, we don't want
        // the error-handling code to fill up the instruction cache, so we will
        // force it out-of-line and onto a "cold" path.
        [&]() __attribute__((noinline,cold)) {
            HandleError(...);
        }();
    }

    // Do normal stuff
    ⋮
}

更好的是,当配置文件反馈可用时(例如,当使用-fprofile-use编译时),GCC将自动忽略它,而支持配置文件反馈。

请在此处查看官方文档:https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes

票数 19
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30130930

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档