我一直在挖掘Linux内核的某些部分,发现这样的调用:
if (unlikely(fd < 0))
{
/* Do something */
}
Run Code Online (Sandbox Code Playgroud)
要么
if (likely(!err))
{
/* Do something */
}
Run Code Online (Sandbox Code Playgroud)
我找到了它们的定义:
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
Run Code Online (Sandbox Code Playgroud)
我知道它们是为了优化,但它们是如何工作的?使用它们可以预期性能/尺寸减少多少?至少在瓶颈代码中(当然在用户空间中)是否值得麻烦(并且可能失去可移植性).
GCC编译器支持__builtin_expect语句,该语句用于定义可能的和不太可能的宏.
例如.
#define likely(expr) (__builtin_expect(!!(expr), 1))
#define unlikely(expr) (__builtin_expect(!!(expr), 0))
Run Code Online (Sandbox Code Playgroud)
是否有Microsoft Visual C编译器的等效声明,或等效的东西?
compiler-construction optimization gcc visual-studio likely-unlikely
我在Linux内核代码中遇到了这两个宏.我知道它们是编译器(gcc)的指令,用于在分支的情况下进行优化.我的问题是,我们可以在用户空间代码中使用这些宏吗?它会进行任何优化吗?任何例子都会非常有用.
我经常发现自己编写的代码看起来像这样:
if(a == nullptr) throw std::runtime_error("error at " __FILE__ ":" S__LINE__);
Run Code Online (Sandbox Code Playgroud)
我应该更喜欢处理错误if unlikely吗?
if unlikely(a == nullptr) throw std::runtime_error("error at " __FILE__ ":" S__LINE__);
Run Code Online (Sandbox Code Playgroud)
编译器会自动推断出应该缓存代码的哪一部分,或者这实际上是否有用?为什么我看不到很多人处理这样的错误?
我正在用大致以下逻辑编写一段关键代码
if(expression is true){
//do something with extremely low latency before the nuke blows up. This branch is entered rarely, but it is the most important case
}else{
//do unimportant thing that doesnt really matter
}
Run Code Online (Sandbox Code Playgroud)
我想在表达式周围使用possible()宏,所以当它到达重要分支时,我得到最小延迟.我的问题是,使用方法与宏名称的建议完全相反,因为我选择"不太可能"的分支进行预取.在性能方面这样做有明显的缺点吗?
我如何能证明对学生的可用性likely和unlikely编译器提示(__builtin_expect)?
你能编写一个示例代码,使用这些提示比较没有提示的代码会快几倍.
简而言之:是否有一个地方可以放置属性,[[(un)likely]]以便控制流被cond2认为可能采取错误分支,而不影响分支的可能性cond1?
if (cond1) {\n do {\n foo();\n } while (cond2);\n}\nRun Code Online (Sandbox Code Playgroud)\n如果我输入[[unlikely]]or do [[unlikely]] {\ do { [[unlikely]]xef\xbc\x8c ,它会影响\xef\xbc\x9f 因为根据cppreference.com 的cond1真实分支cond1是进入循环的唯一路径,并且是始终进入循环的路径:
\n\n应用于语句,以允许编译器针对包含该语句的执行路径比不包含此类语句的任何替代执行路径的可能性较小的情况进行优化。
\n
看来是cond1受到了影响。
如果我放在[[likely]]循环之后,例如do { foo(); } while(cond2); [[likely]];,则该属性将应用于空语句。该代码不直观,并且变得更不清楚是否cond2和/或cond1受到影响。
顺便说一句,问题实际上是询问[[(un)likely]]属性的语义,而不是关于实现,也不是诸如__builtin_expect或打破 do-while 循环之类的替代方案foo(); while(cond2) [[unlikely]] foo();。
只是在linux内核中看到这个结构,我无法得到它的意思.
110 return unlikely(sl->sequence != start);
Run Code Online (Sandbox Code Playgroud)
我知道likely/ unlikely是用__builtin_expect这里描述的功能制作的:http:
//gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html
您可以使用__builtin_expect为编译器提供分支预测信息.
但是对于无条件分支,什么样的分支预测提示是可能的?
如果我有:
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
if (A)
return true;
else if (B)
return false;
...
else if (Z)
return true;
else
//this will never really happen!!!!
raiseError();
return false;
Run Code Online (Sandbox Code Playgroud)
我可以在最后一个条件检查中放置possible(),else if (likely(Z))以表示最终语句(else)非常不可能,而编译器不会影响先前检查的分支预测吗?
基本上,如果存在带分支预测器提示的单个条件语句,GCC是否会尝试优化整个if-else if块?
一些软件(通常是面向性能的,例如Linux内核、DPDK)具有用于影响分支预测的C帮助程序。
我有一个绝对简单的代码片段(假设我知道 a > b 的百分比)来表示嵌套某些逻辑时条件嵌套和应用likely/的问题:unlikely
bool foo()
{
foo1(1);
foo2(2);
/* if (unlikely(a > b)) */
/* if (a > b)*/
{
puts("Ohhh!!! Rare case");
return true;
}
return false;
}
int main(void)
{
/* if (unlikely(foo())) */
/* if (foo()) */
{
puts("Azaza");
}
}
Run Code Online (Sandbox Code Playgroud)
那么从理论角度来看,为了提高性能,哪两行应该取消注释呢?
显然有3种方法可以帮助编译器进行分支预测:
1.
if (unlikely(a > b))
...
if (unlikely(foo()))
2.
if (a > b)
...
if (unlikely(foo()))
3.
if (unlikely(a > b))
...
if (foo()) …
likely-unlikely ×10
gcc ×7
optimization ×4
c ×3
c++ ×3
linux-kernel ×3
linux ×2
built-in ×1
c++17 ×1
c++20 ×1
dpdk ×1
macros ×1
memory ×1
performance ×1