模拟属性“不可预测”

Ori*_*ent 5 c++ compiler-optimization speculative-execution branch-prediction c++-attributes

现代 C++ 中有[[likely]]和属性。G++ 和 clang++ 中[[unlikely]]都有相应的__builtin_expect(x, 1)内置函数。__builtin_expect(x, 0)但也有__builtin_unpredictable(x)__builtin_expect_with_probability(x, 1, 0.5)或(同样)__builtin_expect_with_probability(x, 0, 0.5)内置函数,它告诉编译器防止 CPU 用来自(错误)预测分支的指令填充管道,因为从错误预测路径刷新+恢复管道的成本在统计上大于执行 w/o完全是投机执行。

在和分支上使用[[likely]]或同样[[unlikely]]使用属性(如以下代码片段所示)是否等同于使用假设属性?ifelse[[unpredictable]]

if (x) [[likely]] {
    // "if" branch
} else [[likely]] {
    // "else" branch
}
Run Code Online (Sandbox Code Playgroud)

或者

if (x) [[unlikely]] {
    // "if" branch
} else [[unlikely]] {
    // "else" branch
}
Run Code Online (Sandbox Code Playgroud)

据我所知,如果存在,if则编译器默认将分支视为默认情况,如果不存在(因为它通常是从当前函数提前退出的不愉快路径检查的形式)。因此,如果我只是省略任何一个属性,那么它并不等同于指定假设属性。[[likely]]else[[unlikely]]else[[unpredictable]]

Ore*_*lom 1

似乎标记ifelse分支都会likely收到警告(unlikely相同):

\n
main.cpp:9:27: warning: both branches of \xe2\x80\x98if\xe2\x80\x99 statement marked as \xe2\x80\x98likely\xe2\x80\x99 [-Wattributes]\n    9 |             if (i*j == p) [[likely]]\n      |                           ^~~~~~~~~~\n   10 |                 return 0;\n   11 |             else [[likely]]\n      |                  ~~~~~~~~~~\n
Run Code Online (Sandbox Code Playgroud)\n

所以我想这个问题仍然是假设性的。至于一个最小的完整示例,它似乎g++支持[[likely]][[unlikely]]但不支持__builtin_unpredictable。同样,clang++支持__builtin_unpredictable但不支持[[likely]][[unlikely]](至少 clang 10 不支持)。因此比较所有三个选项是很棘手的。这是一个比较[[likely]]与 的最小完整示例[[unlikely]]

\n
#include <stdio.h>\n#include <string.h>\n#include <stdlib.h>\nbool isPrime(int p) {\n    for (int i=2;i<p;i++)\n        for (int j=2;j<p;j++)\n            if (i*j == p) [[likely]]\n                return 0;\n            // else [[unlikely]] <--- gets a warning\n            //     j++; <--- remove from for loop \n    return 1; }\nint main(int argc, char **argv) {\n    int numPrimes=0;\n    int start=atoi(argv[1]);\n    int end=atoi(argv[2]);\n    for (int p=atoi(argv[1]);p<atoi(argv[2]);p++)\n        if (isPrime(p)) { numPrimes++;}\n    printf("There are %d primes between %d and %d",numPrimes,start,end);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

这是评价:

\n
$ g++ -std=c++2a -O3 main.cpp -o main\n$ time ./main 2 10000\nThere are 1229 primes between 2 and 10000\nreal    1m16.083s\nuser    1m14.014s\nsys 0m0.247s\n$ sed -i "s/likely/unlikely/g" main.cpp\n$ g++ -std=c++2a -O3 main.cpp -o main\n$ time ./main 2 10000\nThere are 1229 primes between 2 and 10000\nreal    0m38.277s\nuser    0m38.100s\nsys 0m0.012s\n
Run Code Online (Sandbox Code Playgroud)\n