gcc/linux内核中likely、unlikely和__attribute__(section(""))属性

查看linux内核源码,你会发现有不少if (likely(""))...及if (unlikely(""))...语句,这些语句实际上是编译器的一种优化方式,具体分析以下:html

likely及unlikely是一个宏定义:linux

#define likely(x)  __builtin_expect(!!(x), 1)程序员

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

 

likely()的 意思是认为这个分支最有可能发生,如if (likely(x == 0)){...},这个语句表示x等于0最有可能发生,其实语意就至关于if (x == 0){...},只不过likely针架构

对程序指令运行作了优化,不去作一些无谓的指令跳转;unlikely()意思相反,就是最不可能发生,注意if (unlikely(x == 0))仍是至关于if (x==0)的逻辑。app

 

若是须要更进一步了解likely()就必需要深刻了解__bulitin_expect(!!(x), 1)函数。ide

— Built-in Function: long __builtin_expect (long exp, long c)

    You may use __builtin_expect to provide the compiler with branch prediction information. In general, you should prefer to use actual profile feedback for this (-fprofile-arcs), as programmers are notoriously bad at predicting how their programs actually perform.
   However, there are applications in which this data is hard to collect. The return value is the value of exp, which should be an integral expression. The semantics of the built-in are that it is expected that exp == c. For example: if (__builtin_expect (x, 0)) foo (); indicates that we do not expect to call foo, since we expect x to be zero. Since you are limited to integral expressions for exp, you should use constructions such as if (__builtin_expect (ptr != NULL, 1)) foo (*ptr); when testing pointer or floating-point values.

文档连接:https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#Other-Builtins函数

 

从gcc官方文档来看,内建函数long __builtin_expect (long exp, long c)主要用于优化程序的分支预测,减小程序的指令跳转,现代处理器通常都是流水线架构,工具

不少芯片级的优化是靠流水线预取完成的,因此咱们的程序优化也是须要尽可能减小跳转。测试

 

文档也提到了因为大部分程序员根本就不了解本身程序的运行状况,因此推荐咱们在编译时加上-fprofile-arcs选项去评估咱们的程序分支运行状况;-fprofile-arcs选

项是代码覆盖率测试工具gcov使用时须要增长的编译选项,gcov可以去统计及分析咱们的程序的分支运行状况,关于gcov的使用这里不作介绍,只须要知道gcov是

一个测试统计工具,配合-fprofile-arcs工具使用,__builtin_expect 根据gcov的分析结果来作实际的分支预测优化。

 

这里能够你们还会有疑问,为何#define likely(x)  __builtin_expect(!!(x), 1)中要使用!!(x),这实际上是由于函数__builtin_expect (long exp, long c)指望是

exp == c,这时的1至关于bool值true,因此exp须要是一个bool表达式,经过!!能够变成bool表达式而不改变原有函数,这样才可以正确的与1或0(bool值)作匹配

判断;试想若是没有!!,即#define likely(x)  __builtin_expect((x), 1),那么likely(10)本来是但愿表达式是true,可是根据函数的处理逻辑10 != 1,那么优化会

以false的结果来优化,这样就阴差阳错了!!!

 

 

最后讲述一下__attribute__(section(""))属性,这个属性比较好理解,就是为某个函数或变量指定section,好比:

int __attribute__(section(".test.data")) value = 0;

这样的话变量value将会被放在.test.data段中;

void __attribute__((section(".test.text"))) func(void){}

这样函数func会被放入.test.text段中。

 

查看section信息能够经过以下命令:readelf -S xxx,能够查看可执行文件也能够是目标文件.o,关于section这里不过多介绍,只要大概知道通常咱们的代码都是

放在.text段,全局变量通常放在.data段,咱们经过__attribute__((""))定义的符号就放在咱们特定的section里面。

相关文章
相关标签/搜索