likely()和unlikely()

CPU流水线:

CPU的工作也可以大致分为指令的获取、解码、运算和结果的写入四个步骤,
如果不采用流水线工作方式,依次进行工作,后面的部件等待前面的部件工作的完成,
当一部分工作的时候,其余的三部分会空闲,这是对资源的极大的浪费
直接影响到CPU的工作效率

define likely(x) __builtin_expect(!!(x), 1)

define unlikely(x) __builtin_expect(!!(x), 0)

likely(x)宏传入__builtin_expect(!!(x), 0)的第一个参数为!!x,这样写是因为__builtin_expect的第一个参数需要为long型,而我们如果想传入指针或字符串类型,则需要使用!!x将x变成long型,例如,如果一个指针ptr==NULL,则!ptr=1,而!!ptr=0。

这个函数无论在linux内核还是在一些系统开发中经常看到,实际上是用来做分支预测的,分支预测的意义如下:

CPU的流水线的工作模式,决定在执行一条指令时顺便会把接下来要执行的指令读取

当执行到if这样的分支的时候,决定是取if下面的指令,还是其他分支的指令

我们取出被执行可能性最大的那个分支的指令序列,这样就可以提升执行的效率;
反之,如果预测不准确,那么提前被读取的指令就没有意义,需要重新读取其他分支的指令。

类似于这样的代码:

if( likely(expr) )
{
	//将这部分代码编译到前面,利于CPU取指
}
else
{
}
一般认为表达式expr在绝大多数情况下是成立的

if(unlikely(expr))
{
}
else
{
	//将这部分代码编译到前面,利于CPU取指
}
一般认为表达式expr在绝大多数情况下是不成立的

#define likely(x) __builtin_expect(!!(x), 1)也就是说明x==1是“经常发生的”或是“很可能发生的”。
使用likely ,执行if后面语句的可能性大些,编译器将if{}中的内容编译到前面,

使用unlikely ,执行else后面语句的可能性大些,编译器将else{}里的内容编译到前面。这样有利于cpu预取,提高预取指令的正确率,因而可提高效率。

总结:
likely与unlikely互换或不用都不会影响程序的正确性,但可能会影响程序的效率。
参考链接:
https://blog.csdn.net/jasonchen_gbd/article/details/44968395
https://blog.csdn.net/tommy_wxie/article/details/7384641

你可能感兴趣的:(linux,性能优化入门)