likely,unlikely宏與GCC內建函數__BUILDIN_EXPECT

[轉貼]

likely,unlikely宏與GCC內建函數__builtin_expect()

http://blog.csdn.net/sahusoft/archive/2009/04/01/4041789.aspx

 

在讀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函數就是爲了優化可能性大的分支程序。

 
+++++++++++++++++++++
 
[bob]
其實, 我總結一下上面的話的意思:

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, &current->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 語言應用程序, 也可以借鑑如下:

CODE:
#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()!

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章