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]]
似乎标记if和else分支都会likely收到警告(unlikely相同):
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 | ~~~~~~~~~~\nRun Code Online (Sandbox Code Playgroud)\n所以我想这个问题仍然是假设性的。至于一个最小的完整示例,它似乎g++支持[[likely]]和[[unlikely]]但不支持__builtin_unpredictable。同样,clang++支持__builtin_unpredictable但不支持[[likely]]或[[unlikely]](至少 clang 10 不支持)。因此比较所有三个选项是很棘手的。这是一个比较[[likely]]与 的最小完整示例[[unlikely]]:
#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}\nRun 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\nRun Code Online (Sandbox Code Playgroud)\n