现代 C++ 中有 [[likely]]
和 [[unlikely]]
属性。在 G++ 和 clang++ 中有对应的 __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 用来自(错误)预测分支的指令填充 pipeline,因为刷新 + 恢复的成本 <来自错误预测路径的 c79> 在统计上大于执行 w/o speculative execution 。
[[likely]]
或 [[unlikely]]
两个分支上的 if
和 else
属性的使用,如以下片段中的使用假设的 [[unpredictable]]
属性的等价物吗?
if (x) [[likely]] {
// "if" branch
} else [[likely]] {
// "else" branch
}
或者
if (x) [[unlikely]] {
// "if" branch
} else [[unlikely]] {
// "else" branch
}
据我所知,如果有 else
,编译器默认将 if
分支视为 [[likely]]
,如果没有 else
,则默认将其视为 [[unlikely]]
(因为它通常是不愉快的路径检查形式,提前退出当前功能)。因此,如果我只是省略任何一个属性,那么它不等同于指定假设的 [[unpredictable]]
属性。
回答1
似乎用 likely
标记 if
和 else
分支都会收到警告(unlikely
相同):
main.cpp:9:27: warning: both branches of ‘if’ statement marked as ‘likely’ [-Wattributes]
9 | if (i*j == p) [[likely]]
| ^~~~~~~~~~
10 | return 0;
11 | else [[likely]]
| ~~~~~~~~~~
所以我想这个问题仍然是假设性的。至于一个最小的完整示例,似乎 g++
支持 [[likely]]
和 [[unlikely]]
但不支持 __builtin_unpredictable
。同样, clang++
支持 __builtin_unpredictable
但不支持 [[likely]]
和 [[unlikely]]
(至少 clang 10 不支持。因此比较所有三个选项很棘手。这是一个比较 [[likely]]
与 [[unlikely]]
的最小完整示例:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
bool isPrime(int p) {
for (int i=2;i<p;i++)
for (int j=2;j<p;j++)
if (i*j == p) [[likely]]
return 0;
// else [[unlikely]] <--- gets a warning
// j++; <--- remove from for loop
return 1; }
int main(int argc, char **argv) {
int numPrimes=0;
int start=atoi(argv[1]);
int end=atoi(argv[2]);
for (int p=atoi(argv[1]);p<atoi(argv[2]);p++)
if (isPrime(p)) { numPrimes++;}
printf("There are %d primes between %d and %d",numPrimes,start,end);
}
这是评估:
$ g++ -std=c++2a -O3 main.cpp -o main
$ time ./main 2 10000
There are 1229 primes between 2 and 10000
real 1m16.083s
user 1m14.014s
sys 0m0.247s
$ sed -i "s/likely/unlikely/g" main.cpp
$ g++ -std=c++2a -O3 main.cpp -o main
$ time ./main 2 10000
There are 1229 primes between 2 and 10000
real 0m38.277s
user 0m38.100s
sys 0m0.012s