MSVC 可能/不太可能等效

发布于 2024-08-04 14:43:03 字数 247 浏览 7 评论 0原文

GCC 编译器支持 __builtin_expect 语句,用于定义可能和不可能的宏。

例如。

#define likely(expr)    (__builtin_expect(!!(expr), 1))
#define unlikely(expr)  (__builtin_expect(!!(expr), 0))

Microsoft Visual C 编译器是否有等效的语句或等效的语句?

GCC compiler supports __builtin_expect statement that is used to define likely and unlikely macros.

eg.

#define likely(expr)    (__builtin_expect(!!(expr), 1))
#define unlikely(expr)  (__builtin_expect(!!(expr), 0))

Is there an equivalent statement for the Microsoft Visual C compiler, or something equivalent ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

送舟行 2024-08-11 14:43:03

C++20 标准将包含 [[likely]][[unlikely]] 分支预测属性。

属性提案的最新版本可以从 http://wg21.link/p0479 找到,

原始属性提案可以是发现于 http://www.open-std .org/jtc1/sc22/wg21/docs/papers/2016/p0479r0.html

程序员应该更喜欢 PGO。如果应用不正确,属性很容易降低性能,或者当程序更改时属性会变得不正确。

C++20 standard will include [[likely]] and [[unlikely]] branch prediction attributes.

The latest revision of attribute proposal can be found from http://wg21.link/p0479

The original attribute proposal can be found from http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0479r0.html

Programmers should prefer PGO. Attributes can easily reduce performance if applied incorrectly or they later become incorrect when program changes.

冷…雨湿花 2024-08-11 14:43:03

根据http://www.akkadia.org/drepper/cpumemory.pdf(第57页),它仍然即使 CPU 动态预测正确,使用静态分支预测也是有意义的。
原因是如果静态预测正确,L1i 缓存的使用效率会更高。

According to http://www.akkadia.org/drepper/cpumemory.pdf (page 57), it still makes sense to use static branch prediction even if CPU predicts correctly dynamically.
The reason for that is that L1i cache will be used even more efficiently if static prediction was done right.

凉墨 2024-08-11 14:43:03

我说只是平底船

没有什么比这更好的了。有 __assume(),但不要不要使用它,它是一种不同类型的优化器指令。

实际上,gnu 内置函数被包装在宏中的原因是,如果未定义 __GNUC__ ,您可以自动删除它。这些宏没有任何必要的东西,我敢打赌您不会注意到运行时间的差异。

摘要

在非 GNU 上只需摆脱(null out)*likely即可。你不会错过的。

I say just punt

There is nothing like it. There is __assume(), but don't use it, it's a different kind of optimizer directive.

Really, the reason the gnu builtin is wrapped in a macro is so you can just get rid of it automatically if __GNUC__ is not defined. There isn't anything the least bit necessary about those macros and I bet you will not notice the run time difference.

Summary

Just get rid of (null out) *likely on non-GNU. You won't miss it.

不弃不离 2024-08-11 14:43:03

我知道这个问题是关于 Visual Studio 的,但我将尝试回答尽可能多的编译器(包括 Visual Studio)……

十年后,我们取得了进展!截至 Visual Studio 2019 MSVC 仍然不支持类似的内容(尽管它是最流行的内置/内在< /a>),但正如 Pauli Nieminen 上面提到的,C++20 有 可能 / 不太可能 属性 可用于创建可能/不可能的宏,并且 MSVC 通常会很快添加对新 C++ 标准的支持(与 C 不同),因此我希望 Visual Studio 2021 能够支持它们。

目前(2019-10-14)只有GCC支持这些属性,甚至只应用于标签,但至少做一些基本的测试就足够了。这是一个快速实现,您可以在编译器资源管理器上测试

#define LIKELY(expr) \
  ( \
    ([](bool value){ \
      switch (value) { \
        [[likely]] case true: \
          return true; \
        [[unlikely]] case false: \
          return false; \
      } \
    }) \
  (expr))
#define UNLIKELY(expr) \
  ( \
    ([](bool value){ \
      switch (value) { \
        [[unlikely]] case true: \
          return true; \
        [[likely]] case false: \
          return false; \
      } \
    }) \
  (expr))

编辑 (2022-05-02 ):MSVC 2022 支持 C++20,包括 [[likely]]/[[unlikely]],但会为此生成绝对糟糕的代码(请参阅这篇文章的评论)...不要在那里使用它。

您可能需要 #ifdef 围绕它来支持无法处理它的编译器,但幸运的是,大多数编译器都支持 __builtin_expect:

  • GCC 3.0
  • clang
  • ICC 至少从 13 开始,可能更长。
  • Oracle Development Studio 12.6+,但仅限 C++ 模式。
  • ARM 4.1
  • IBM XL C/C++ 至少从 10.1 开始,可能更长。
  • TI 自 6.1
  • TinyCC 自 0.9.27

GCC 9+ 也支持 __builtin_expect_with_probability。它在其他地方不可用,但希望有一天……在试图弄清楚是否使用 ilkely/unlikely 或不使用时需要大量的猜测——你只需设置概率,编译器(理论上)会做正确的事情。

此外,clang 支持 __builtin_unpredictable (因为3.8,但使用 __has_builtin(__builtin_unpredictable) 进行测试。由于现在很多编译器都是基于 clang 的,所以它可能也适用于它们。

如果您希望这一切都完成并准备好,您可能对我的一个项目感兴趣,Hedley。它是一个公共域 C/C++ 标头,几乎适用于所有编译器,并包含许多有用的宏,包括 HEDLEY_LIKELY HEDLEY_UNLIKELYHEDLEY_UNPREDICTABLEHEDLEY_PREDICTHEDLEY_PREDICT_TRUEHEDLEY_PREDICT_FALSE。目前还没有 C++20 版本,但应该很快就会出现

即使您不想在项目中使用 Hedley,您可能也想检查那里的实现,而不是依赖上面的列表;我可能会忘记用新信息更新这个答案,但赫德利应该始终保持最新状态。

I know this question is about Visual Studio, but I'm going to try to answer for as many compilers as I can (including Visual Studio)…

A decade later there is progress! As of Visual Studio 2019 MSVC still doesn't support anything like this (even though it's the most popular builtin/intrinsic), but as Pauli Nieminen mentioned above C++20 has likely / unlikely attributes which can be used to create likely/unlikely macros and MSVC usually adds support for new C++ standards pretty quickly (unlike C) so I expect Visual Studio 2021 to support them.

Currently (2019-10-14) only GCC supports these attributes, and even then only applied to labels, but it is sufficient to at least do some basic testing. Here is a quick implementation which you can test on Compiler Explorer:

#define LIKELY(expr) \
  ( \
    ([](bool value){ \
      switch (value) { \
        [[likely]] case true: \
          return true; \
        [[unlikely]] case false: \
          return false; \
      } \
    }) \
  (expr))
#define UNLIKELY(expr) \
  ( \
    ([](bool value){ \
      switch (value) { \
        [[unlikely]] case true: \
          return true; \
        [[likely]] case false: \
          return false; \
      } \
    }) \
  (expr))

Edit (2022-05-02): MSVC 2022 supports C++20, including [[likely]]/[[unlikely]], but generates absolutely terrible code for this (see the comments on this post)... don't use it there.

You'll probably want to #ifdef around it to support compilers that can't handle it, but luckily most compilers support __builtin_expect:

  • GCC 3.0
  • clang
  • ICC since at least 13, probably much longer.
  • Oracle Development Studio 12.6+, but only in C++ mode.
  • ARM 4.1
  • IBM XL C/C++ since at least 10.1, probably longer.
  • TI since 6.1
  • TinyCC since 0.9.27

GCC 9+ also supports __builtin_expect_with_probability. It's not available anywhere else, but hopefully one day… It takes a lot of the guesswork out of trying to figure out whether to use ilkely/unlikely or not—you just set the probability and the compiler (theoretically) does the right thing.

Also, clang supports a __builtin_unpredictable (since 3.8, but test for it with __has_builtin(__builtin_unpredictable)). Since a lot of compilers are based on clang these days it probably works in them, too.

If you want this all wrapped up and ready to go, you might be interested in one of my projects, Hedley. It's a single public-domain C/C++ header which works on pretty much all compilers and contains lots of useful macros, including HEDLEY_LIKELY, HEDLEY_UNLIKELY, HEDLEY_UNPREDICTABLE, HEDLEY_PREDICT, HEDLEY_PREDICT_TRUE, and HEDLEY_PREDICT_FALSE. It doesn't have the C++20 version quite yet, but it should be there soon

Even if you don't want to use Hedley in your project, you might want to check the the implementations there instead of relying on the lists above; I'll probably forget to update this answer with new information, but Hedley should always be up-to-date.

暖树树初阳… 2024-08-11 14:43:03

根据分支和循环重组以防止错误预测来自英特尔的文档:

为了有效地编写代码来利用这些
规则,在编写 if-else 或 switch 语句时,检查最多
首先是常见的情况,然后逐步减少到最不常见的情况。

不幸的是,您不能编写类似的内容,

#define if_unlikely(cond) if (!(cond)); else 

因为从 VS10 开始,MSVC 优化器会忽略此类“提示”。

由于我更喜欢​​首先在代码中处理错误,因此我似乎编写效率较低的代码。
幸运的是,CPU 第二次遇到分支时,它将使用其统计信息而不是静态提示。

According to Branch and Loop Reorganization to Prevent Mispredicts document from Intel:

In order to effectively write your code to take advantage of these
rules, when writing if-else or switch statements, check the most
common cases first and work progressively down to the least common.

Unfortunately you cannot write something like

#define if_unlikely(cond) if (!(cond)); else 

because MSVC optimizer as of VS10 ignores such "hint".

As I prefer to deal with errors first in my code, I seem to write less efficient code.
Fortunately, second time CPU encounters the branch it will use its statistics instead of a static hint.

吃颗糖壮壮胆 2024-08-11 14:43:03

__assume 应该类似。< /strike>

但是,如果您想做得很好,您应该使用 配置文件引导优化而不是静态提示。

__assume should be similar.

However, if you want to do this really well you should use Profile Guided Optimization rather than static hints.

灼疼热情 2024-08-11 14:43:03

现在 MS 他们已经实现了 likely/unlikely 属性

但实际上使用“likely”之间没有任何区别或不使用。

我已经编译了这些代码并产生相同的结果

    int main()
    {
        int i = rand() % 2;
        if (i) [[likely]]
        {
           printf("Hello World!\n");
        }
        else
        {
            printf("Hello World2%d!\n",i);
        }
    }
    int main()
    {
        int i = rand() % 2;
        if (i)
        {
           printf("Hello World!\n");
        }
        else [[likely]]
        {
            printf("Hello World2%d!\n",i);
        }
    }
int pdb._main (int argc, char **argv, char **envp);
0x00401040      push    ebp
0x00401041      mov     ebp, esp
0x00401043      push    ecx
0x00401044      call    dword [rand] ; pdb.__imp__rand
                                   ; 0x4020c4
0x0040104a      and     eax, 0x80000001
0x0040104f      jns     0x401058
0x00401051      dec     eax
0x00401052      or      eax, 0xfffffffe ; 4294967294
0x00401055      add     eax, 1
0x00401058      je      0x40106d
0x0040105a      push    str.Hello_World ; pdb.___C__0O_NFOCKKMG_Hello_5World__CB_6
                                   ; 0x402108 ; const char *format
0x0040105f      call    pdb._printf ; int printf(const char *format)
0x00401064      add     esp, 4
0x00401067      xor     eax, eax
0x00401069      mov     esp, ebp
0x0040106b      pop     ebp
0x0040106c      ret
0x0040106d      push    0
0x0040106f      push    str.Hello_World2_d ; pdb.___C__0BB_DODJFBPJ_Hello_5World2__CFd__CB_6
                                   ; 0x402118 ; const char *format
0x00401074      call    pdb._printf ; int printf(const char *format)
0x00401079      add     esp, 8
0x0040107c      xor     eax, eax
0x0040107e      mov     esp, ebp
0x00401080      pop     ebp
0x00401081      ret

Now MS said they have implemented likely/unlikely attributes

But in fact there isn't any different between using "likely" or not using.

I have compiled these codes and is produce same result.

    int main()
    {
        int i = rand() % 2;
        if (i) [[likely]]
        {
           printf("Hello World!\n");
        }
        else
        {
            printf("Hello World2%d!\n",i);
        }
    }
    int main()
    {
        int i = rand() % 2;
        if (i)
        {
           printf("Hello World!\n");
        }
        else [[likely]]
        {
            printf("Hello World2%d!\n",i);
        }
    }
int pdb._main (int argc, char **argv, char **envp);
0x00401040      push    ebp
0x00401041      mov     ebp, esp
0x00401043      push    ecx
0x00401044      call    dword [rand] ; pdb.__imp__rand
                                   ; 0x4020c4
0x0040104a      and     eax, 0x80000001
0x0040104f      jns     0x401058
0x00401051      dec     eax
0x00401052      or      eax, 0xfffffffe ; 4294967294
0x00401055      add     eax, 1
0x00401058      je      0x40106d
0x0040105a      push    str.Hello_World ; pdb.___C__0O_NFOCKKMG_Hello_5World__CB_6
                                   ; 0x402108 ; const char *format
0x0040105f      call    pdb._printf ; int printf(const char *format)
0x00401064      add     esp, 4
0x00401067      xor     eax, eax
0x00401069      mov     esp, ebp
0x0040106b      pop     ebp
0x0040106c      ret
0x0040106d      push    0
0x0040106f      push    str.Hello_World2_d ; pdb.___C__0BB_DODJFBPJ_Hello_5World2__CFd__CB_6
                                   ; 0x402118 ; const char *format
0x00401074      call    pdb._printf ; int printf(const char *format)
0x00401079      add     esp, 8
0x0040107c      xor     eax, eax
0x0040107e      mov     esp, ebp
0x00401080      pop     ebp
0x00401081      ret
输什么也不输骨气 2024-08-11 14:43:03

由于问题很旧,所以说 MSVC 中没有 [[likely]] / [[unlikely]] 或没有影响的答案已经过时。

最新的 MSVC 支持 /std:c++20/std 中的 [[likely]] / [[unlikely]]: c++latest 模式。

请参阅 Godbolt 编译器浏览器上的演示,了解其中的差异。

从上面的链接可以看出,if-else 语句对 x86/x64 的一个明显影响是条件向前跳转将针对不太可能的分支。在 C++20 和支持 VS 版本之前,可以通过将可能的分支放入 if 部分,将不太可能的分支放入 else 部分,根据需要否定条件来实现相同的效果。

请注意,这种优化的效果是最小的。对于紧密循环中频繁调用的代码,动态分支预测无论如何都会做正确的事情。

As the question is old, the answers saying there's no [[likely]] / [[unlikely]] in MSVC, or that there's no impact are obsolete.

Latest MSVC supports [[likely]] / [[unlikely]] in /std:c++20 and /std:c++latest modes.

See demo on Godbolt's compiler explorer that shows the difference.

As can be seen from the link above, one visible effect on x86/x64 for if-else statement is that the conditional jump forward will be for unlikely branch. Before C++20 and supporting VS version the same could be achieved by placing the likely branch into if part, and the unlikely branch into else part, negating the condition as needed.

Note that the effect of such optimization is minimal. For frequently called code in a tight loop, the dynamic branch prediction would do the right thing anyway.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文