內核中的 likely() 與 unlikely()

在 2.6 內核中,隨處可以見到 likely() 和 unlikely() 的身影,那么為什么要用它們?它們之間有什么區別?
首先要明確:

??????????? if(likely(value)) 等價于 if(value)

??????????? if(unlikely(value)) 也等價于 if(value)

也就是說 likely() 和 unlikely() 從閱讀和理解代碼的角度來看,是一樣的!!!
這兩個宏在內核中定義如下:

#define likely(x)?????? __builtin_expect((x),1)
#define unlikely(x)???? __builtin_expect((x),0)

__builtin_expect() 是 GCC (version >= 2.96)提供給程序員使用的,目的是將“分支轉移”的信息提供給編譯器,這樣編譯器可以對代碼進行優化,以減少指令跳轉帶來的性能下降。

__builtin_expect((x),1) 表示 x 的值為真的可能性更大;
__builtin_expect((x),0) 表示 x 的值為假的可能性更大。

也就是說,使用 likely() ,執行 if 后面的語句的機會更大,使用unlikely(),執行else 后面的語句的機會更大。
例如下面這段代碼,作者就認為 prev 不等于 next 的可能性更大,

if (likely(prev != next)) {
?????? next->timestamp = now;
??????? ...
} else {
??????? ...;
}
通過這種方式,編譯器在編譯過程中,會將可能性更大的代碼緊跟著起面的代碼,從而減少指令跳轉帶來的性能上的下降。


下面以兩個例子來加深這種理解:

第一個例子: example1.c

int testfun(int x)
{
??????? if(__builtin_expect(x, 0)) {
????????????????????????????? ^^^--- We instruct the compiler, "else" block is more probable
??????????????? x = 5;
??????????????? x = x * x;
??????? } else {
??????????????? x = 6;
??????? }
??????? return x;
}
在這個例子中,我們認為 x 為0的可能性更大

編譯以后,通過 objdump 來觀察匯編指令,在我的 2.4 內核機器上,結果如下:

# gcc -O2 -c example1.c
# objdump -d example1.o

Disassembly of section .text:

00000000 <testfun>:
?? 0:?? 55????????????????????? push?? %ebp
?? 1:?? 89 e5?????????????????? mov??? %esp,%ebp
?? 3:?? 8b 45 08??????????????? mov??? 0x8(%ebp),%eax
?? 6:?? 85 c0?????????????????? test?? %eax,%eax
?? 8:?? 75 07?????????????????? jne??? 11 <testfun+0x11>
?? a:?? b8 06 00 00 00????????? mov??? $0x6,%eax
?? f:?? c9????????????????????? leave
10:?? c3????????????????????? ret
11:?? b8 19 00 00 00????????? mov??? $0x19,%eax
16:?? eb f7?????????????????? jmp??? f <testfun+0xf>
可以看到,編譯器使用的是 jne (不相等跳轉)指令,并且 else block 中的代碼緊跟在后面。

8:?? 75 07?????????????????? jne??? 11 <testfun+0x11>
a:?? b8 06 00 00 00????????? mov??? $0x6,%eax


第二個例子: example2.c
int testfun(int x)
{
??????? if(__builtin_expect(x, 1)) {
????????????????????????????? ^^^ --- We instruct the compiler, "if" block is more probable
??????????????? x = 5;
??????????????? x = x * x;
??????? } else {
??????????????? x = 6;
??????? }
??????? return x;
}
在這個例子中,我們認為 x 不為 0 的可能性更大

編譯以后,通過 objdump 來觀察匯編指令,在我的 2.4 內核機器上,結果如下:

# gcc -O2 -c example2.c
# objdump -d example2.o
Disassembly of section .text:

00000000 <testfun>:
?? 0:?? 55????????????????????? push?? %ebp
?? 1:?? 89 e5?????????????????? mov??? %esp,%ebp
?? 3:?? 8b 45 08??????????????? mov??? 0x8(%ebp),%eax
?? 6:?? 85 c0?????????????????? test?? %eax,%eax
?? 8:?? 74 07?????????????????? je???? 11 <testfun+0x11>
?? a:?? b8 19 00 00 00????????? mov??? $0x19,%eax
?? f:?? c9????????????????????? leave
10:?? c3????????????????????? ret
11:?? b8 06 00 00 00????????? mov??? $0x6,%eax
16:?? eb f7?????????????????? jmp??? f <testfun+0xf>


這次編譯器使用的是 je (相等跳轉)指令,并且 if block 中的代碼緊跟在后面。

?? 8:?? 74 07?????????????????? je???? 11 <testfun+0x11>
?? a:?? b8 19 00 00 00????????? mov??? $0x19,%eax

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/445077.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445077.shtml
英文地址,請注明出處:http://en.pswp.cn/news/445077.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

python外卷(12)-sort(),sorted(),ord(),chr()

Python內置函數1.sort()&#xff0c;sorted()2.ord(), chr()1.sort()&#xff0c;sorted() sort() 是list的方法&#xff0c;對已經存在的列表進行操作&#xff0c;無返回值 a[3,2,4,1] b["c","a","b"] print (a.sort(),b.sort()) # 輸出 (Non…

利用posix_fadvise清理系統中的文件緩存

利用posix_fadvise清理系統中的文件緩存leoncom c/c,unix2011-08-03當我們需要對某段讀寫文件并進行處理的程序進行性能測試時&#xff0c;文件會被系統cache住從而影響I/O的效率&#xff0c;必須清理cache中的對應文件的才能正確的進行性能測試。通常清理內存可以采用下面的這…

空間分配

目前主流的垃圾收集器都會采用分代回收算法&#xff0c;因此需要將堆內存分為新生代和老年代&#xff0c;這樣我們就可以根據各個年代的特點選擇合適的垃圾收集算法。 大多數情況下&#xff0c;對象在新生代中 eden 區分配。當 eden 區沒有足夠空間進行分配時&#xff0c;虛擬…

關于uint32_t uint8_t uint64_t 的問題

怎么又是u又是_t的?u代表的是unsigned相信大家都知道,那么_t又是什么呢?我認為它就是一個結構的標注,可以理解為type/typedef的縮寫,表示它是通過typedef定義的,而不是其它數據類型。 uint8_t,uint16_t,uint32_t等都不是什么新的數據類型,它們只是使用typedef給類型起…

學點數學(4)-協方差矩陣

協方差矩陣協方差矩陣&#xff08;從隨機變量講起&#xff09;隨機變量x&#xff1a;表示隨機試驗各種結果的 實值 單值函數&#xff0c;就是說隨機變量x是一個函數映射&#xff0c;其取值為標量。隨機變量有離散型和連續型&#xff0c;離散型&#xff1a;拋10次硬幣&#xff…

RedLock

概念 Redis 官方站這篇文章提出了一種權威的基于 Redis 實現分布式鎖的方式名叫 Redlock&#xff0c;此種方式比原先的單節點的方法更安全。它可以保證以下特性&#xff1a; 安全特性&#xff1a;互斥訪問&#xff0c;即永遠只有一個 client 能拿到鎖避免死鎖&#xff1a;最終…

GCC中常用的優化的參數

-pipe 的作用&#xff1a; 使用管道代替編譯中臨時文件&#xff0c; -pipe 加速編譯 gcc -pipe foo.c -o foo 加速 在將源代碼變成可執行文件的過程中,需要經過許多中間步驟,包含預處理、編譯、匯編和連接。這些過程實際上是由不同的程序負責完成的。大多數情況下 GCC 可以為 …

Linux與時間相關的結構體及相關用法

1. Linux下與時間有關的結構體 struct timeval { int tv_sec; int tv_usec; }; 其中tv_sec是由凌晨開始算起的秒數&#xff0c;tv_usec則是微秒(10E-6 second)。 struct timezone { …

算法(3)-數據結構-數組和字符串

leetcode-explore-learn-數據結構-數據結構-數組和字符串1. 一維數組1.0 概況1.1 尋找數組的中心索引1.2 搜索插入位置1.3 合并區間1.4 至少是其他數字兩倍大的最大數1.5 加一2. 二維數組2.1旋轉矩陣本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處…

redis的入門/原理/實戰大總結

入門 Redis是一款基于鍵值對的NoSQL數據庫&#xff0c;它的值支持多種數據結構&#xff1a; 字符串(strings)、哈希(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等。 ? Redis將所有的數據都存放在內存中&#xff0c;所以它的讀寫性能十分驚人&#xff0c;用作數…

創建與打開IPC通道的POSIX和SYSTEM V方法

先說&#xff30;&#xff2f;&#xff33;&#xff29;&#xff38;的吧&#xff1a; mq_open&#xff0c;sem_open&#xff0c;shm_open著三個函數用于創建或者打開一個IPC通道。 由此可見&#xff0c;消息隊列的讀寫權限是任意的&#xff0c;然而信號燈就沒有&#xff0c;…

算法(4)-leetcode-explore-learn-數據結構-數組2

leetcode-explore-learn-數據結構-數組21.簡述2.例題2.1 二維數組的對角線遍歷2.2 螺旋遍歷2.3 楊輝三角本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處&#xff0c;請參考leetcode官網&#xff1a;https://leetcode-cn.com/explore/learn/card/ar…

軟件測試基礎知識

第一章 1.1 軟件測試背景知識和發展史 互聯網公司職位架構&#xff1a;產品 運營 技術 市場 行政軟件測試&#xff1a;使用人工或自動化手段&#xff0c;來運行或測試某個系統的過程&#xff0c;其目的在于檢驗它是否滿足規定的需求或弄清預期結果與實際結果之間的差別&#…

key_t IPC鍵和ftok函數詳解和剖析

統建立IPC通訊&#xff08;如消息隊列、共享內存時&#xff09;必須指定一個ID值。通常情況下&#xff0c;該id值通過ftok函數得到。 ftok原型如下&#xff1a; key_t ftok( char * fname, int id ) fname就時你指定的文件名(該文件必須是存在而且可以訪問的)&#xff0c;id是子…

算法(5)-leetcode-explore-learn-數據結構-字符串

leetcode-explore-learn-數據結構-數組3-字符串1.簡述2.例題2.1 二進制求和2.2實現strStr()2.3最長公共前綴本系列博文為leetcode-explore-learn子欄目學習筆記&#xff0c;如有不詳之處&#xff0c;請參考leetcode官網&#xff1a;https://leetcode-cn.com/explore/learn/card…

ipcs命令查看管道,消息隊列,共享內存

修改消息隊列大小&#xff1a; root&#xff1a;用戶&#xff1a; /etc/sysctl.conf kernel.msgmnb 4203520 #kernel.msgmnb 3520 kernel.msgmni 2878 保存后需要執行 sysctl -p ,然后重建所有消息隊列 ipcs -q : 顯示所有的消息隊列 ipcs -qt : 顯示消息隊列的創建時…

Jmeter-基礎篇

常用壓力測試工具對比 1、loadrunner 性能穩定&#xff0c;壓測結果及細粒度大&#xff0c;可以自定義腳本進行壓測&#xff0c;但是太過于重大&#xff0c;功能比較繁多 2、apache ab(單接口壓測最方便) 模擬多線程并發請求,ab命令對發出負載的計算機…

消息隊列接口API(posix 接口和 system v接口)

消息隊列 posix API消息隊列&#xff08;也叫做報文隊列&#xff09;能夠克服早期unix通信機制的一些缺點。信號這種通信方式更像\"即時\"的通信方式&#xff0c;它要求接受信號的進程在某個時間范圍內對信號做出反應&#xff0c;因此該信號最多在接受信號進程的生命…

算法(6)-leetcode-explore-learn-數據結構-數組字符串的雙指針技巧

leetcode-explore-learn-數據結構-數組4-雙指針技巧1.雙指針技巧--適用情形11.1概述1.2 例題1.2.1 反轉字符串1.2.2數組拆分1.2.3 兩數之和22雙指針技巧-適用情形22.1概述2.2例題2.2.1 移除元素2.2.2 最大連續1的個數2.2.3長度最小的子數組本系列博文為leetcode-explore-learn子…

POSIX和SYSTEM的消息隊列應該注意的問題

首先看看POSIX的代碼&#xff1a; 1.posix_mq_server.c #include <mqueue.h> #include <sys/stat.h> #include <string.h> #include <stdio.h> #define MQ_FILE "/mq_test" #define BUF_LEN 128 int main() { mqd_t mqd; char b…