likely,unlikely宏与GCC内建函数__builtin_expect()
先罗嗦几句
最
近在读linux 2.6
内核,虽然以前已经看了很多相关的知识,<>也看了2,3遍,但读2.6内核仍然感到很吃力。面对2.6如此庞大的内核,信心真的不是很足,而且好像也没有很好的、有帮助的论坛来一起探讨,哎!现在正在边看<<情景分
析>>,边看最新的内核,自<<情景分析>>出版以来,内核已经有了很多的变化,好难读啊!如果这样读下去算不算
“皓首穷经”呢,不得而知了!
言归正传
在读linux/kernel/fork.c的时候遇到了unlikely宏定义,一路追踪,最后找到了GCC内建函数__builtin_expect(),查阅GCC手册,发现其定义如下:
-
long __builtin_expect(long exp, long c) [Built-in Function]
-
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 value of c must be a compile-time constant. The semantics of the built-in are that it is expected that exp == c.
-
For example:
-
if (__builtin_expect (x, 0))
-
foo ();
-
would indicate 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))
-
error ();
-
when testing pointer or floating-point values.
大致是说,由于大部分程序员在分支预测方面做得很糟糕,所以GCC提供了这个内建函数来帮助程序员处理分支预测(见文后参考),优化程序。其第一个参数exp为一个整型表
达式,这个内建函数的返回值也是这个exp,而c为一个编译期常量,这个函数的语义是:你期望exp表达式的值等于常量c,从而GCC为你优化程序,将符合这个条件的分支放在合适的地方。
因为这个程序只提供了整型表达式,所以如果你要优化其他类型的表达式,可以采用指针的形式。
unlikely的定义如下:
#define unlikely(x) __builtin_expect(!!(x), 0)
也就是说我们期望表达式x的值为0,从而如果我们用
-
…….
-
if(unlikely(x)){
-
bar();
-
}
来测试条件的话,我们就不期望bar( )函数执行,所以该宏的名字用unlikely也就是不太可能来表示。
likely宏与此类似.
说到底__builtin_expect函数就是为了优化可能性大的分支程序。
其实, 我总结一下上面的话的意思:
if() 语句你照用, 跟以前一样, 只如果你觉得if()是1 的可能性非常大的时候, 就在表达式的外面加一个likely() , 如果可能性非常小(比如几率非常小),就用unlikely()包裹上。
看kernel代码的时候, 看到很多这样的例子, 举一个:
-
if (likely(cpu == this_cpu)) { //注意likely和unlikely的用法
-
//这里用likely说明,cpu=this_cpu的可能性非常大
-
if (!(clone_flags & CLONE_VM)) {
-
/*
-
* The VM isn't cloned, so we're in a good position to
-
* do child-runs-first in anticipation of an exec. This
-
* usually avoids a lot of COW overhead.
-
*/
-
if (unlikely(!current->array))
-
__activate_task(p, rq);
-
else {
-
p->prio = current->prio;
-
p->normal_prio = current->normal_prio;
-
list_add_tail(&p->run_list, ¤t->run_list);
-
p->array = current->array;
-
p->array->nr_active++;
-
inc_nr_running(p, rq);
-
}
-
set_need_resched();
-
} else
-
/* Run child last */
-
__activate_task(p, rq);
-
/*
-
* We skip the following code due to cpu == this_cpu
-
*
-
* task_rq_unlock(rq, &flags);
-
* this_rq = task_rq_lock(current, &flags);
-
*/
-
this_rq = rq;
-
} else {
-
......
kernel 代码,有许多看起来多余的东西,其实不多余
kernel里面的代码, 有的时候看起来,很繁琐, 冗余, 但是仔细一看 ,还真的不错。
在代码里面老能看到 BUG_ON() , WARN_ON() 这样的宏 , 类似我们日常编程里面的断言(assert) 。
bug.h:
-
QUOTE:
-
extern void __WARN_ON(const char *func, const char *file, const int line);
-
-
#ifdef CONFIG_BUG
-
#ifndef HAVE_ARCH_BUG
-
#define BUG() do { \
-
printk("BUG: failure at %s:%d/%s()!/n", __FILE__, __LINE__, __FUNCTION__); \
-
panic("BUG!"); \
-
} while (0)
-
#endif
-
-
#ifndef HAVE_ARCH_BUG_ON
-
#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
-
#endif
-
-
#ifndef HAVE_ARCH_WARN_ON
-
#define WARN_ON(condition) do { \
-
if (unlikely((condition)!=0)) \
-
__WARN_ON(__FUNCTION__, __FILE__, __LINE__); \
-
} while (0)
-
#endif
-
-
#else /* !CONFIG_BUG */
-
#ifndef HAVE_ARCH_BUG
-
#define BUG()
-
#endif
-
-
#ifndef HAVE_ARCH_BUG_ON
-
#define BUG_ON(condition) do { if (condition) ; } while(0)
-
#endif
-
-
#ifndef HAVE_ARCH_WARN_ON
-
#define WARN_ON(condition) do { if (condition) ; } while(0)
-
#endif
-
#endif
kernel 别的代码里面用到例子:
BUG_ON(unlikely(atomic_read(&(kioctx)->users) <= 0)); \
对于我们自己的c 语言应用程序, 也可以借鉴如下:
-
#include <stdio.h>
-
#include <stdlib.h>
-
-
#define likely(x) __builtin_expect(!!(x), 1)
-
#define unlikely(x) __builtin_expect(!!(x), 0)
-
-
#define BUG_ON(condition) do \
-
{
-
if (unlikely((condition)!=0)) \
-
printf("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __FUNCTION__); \
-
} while(0)
-
-
int main(void)
-
{
-
int i = 7;
-
BUG_ON(i!=10);
-
return 0;
-
}
输出如下:
BUG: failure at warn.c:18/main()!
分支预测参考二
FROM:http://blog.csdn.net/sahusoft/article/details/4041789
阅读(1545) | 评论(0) | 转发(0) |