C++關(guān)鍵字之likely和unlikely詳解
什么是likely和unlikely
既然程序是我們程序員所寫(xiě),在一些明確的場(chǎng)景下,我們應(yīng)該比CPU和編譯器更了解哪個(gè)分支條件更有可能被滿足。我們是否可將這一先驗(yàn)知識(shí)告知編譯器和CPU, 提高分支預(yù)測(cè)的準(zhǔn)確率,從而減少CPU流水線分支預(yù)測(cè)錯(cuò)誤帶來(lái)的性能損失呢?答案是可以!它便是likely和unlikely。在Linux內(nèi)核代碼中,這兩個(gè)宏的應(yīng)用比比皆是。下面是他們的定義:
#define likely(x) __builtin_expect(!!(x), 1) #define unlikely(x) __builtin_expect(!!(x), 0)
likely,用于修飾if/else if分支,表示該分支的條件更有可能被滿足。而unlikely與之相反
以下為示例。unlikely修飾argc > 0分支,表示該分支不太可能被滿足。
#include <cstdio>
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
int main(int argc, char *argv[])
{
if (unlikely(argc > 0)) {
puts ("Positive\n");
} else
{
puts ("Zero or Negative\n");
}
return 0;
}likely/unlikely的原理
接下來(lái),我們從匯編指令分析likely/unlikely到底是如何起作用的?
首先我們將上述代碼中的unlikely去掉,然后反匯編,作為對(duì)照組
匯編如下,我們看到,if分支中的指令被編譯器放置于分支跳轉(zhuǎn)指令jle相鄰的位置,即CPU流水線在遇到j(luò)le指令所代表的的'岔路口'時(shí),更傾向于走if分支
.LC0:
.string "Positive\n"
.LC1:
.string "Zero or Negative\n"
main:
sub rsp, 8
test edi, edi
jle .L2 ; 如果argc <= 0, 跳轉(zhuǎn)到L2
mov edi, OFFSET FLAT:.LC0 ; 如果argc > 0, 從這里執(zhí)行
call puts
.L3:
xor eax, eax
add rsp, 8
ret
.L2:
mov edi, OFFSET FLAT:.LC1
call puts
jmp .L3
接著我們?cè)趇f分支中加上unlikely, 反匯編如下。這里的情況正好與對(duì)照組相反,if分支下的指令被編譯器放置于遠(yuǎn)離跳轉(zhuǎn)指令jg的位置。這意味著CPU此時(shí)更傾向于走else分支。
.LC0:
.string "Positive\n"
.LC1:
.string "Zero or Negative\n"
main:
sub rsp, 8
test edi, edi
jg .L6
mov edi, OFFSET FLAT:.LC1
call puts
.L3:
xor eax, eax
add rsp, 8
ret
.L6:
mov edi, OFFSET FLAT:.LC0
call puts
jmp .L3因此,通過(guò)對(duì)分支條件使用likely和unlikely,我們可給編譯器一種暗示,即該分支條件被滿足的概率比較大或比較小。而編譯器利用這一信息優(yōu)化其機(jī)器指令,從而最大限度減少CPU分支預(yù)測(cè)失敗帶來(lái)的懲罰。
likely/unlikely的適用條件
CPU有自帶的分支預(yù)測(cè)器,在大多數(shù)場(chǎng)景下效果不錯(cuò)。因此在分支發(fā)生概率嚴(yán)重傾斜、追求極致性能的場(chǎng)景下,使用likely/unlikely才具有較大意義。
C++20中的likely/unlikely
C++20之前的,likely和unlikely只不過(guò)是一對(duì)自定義的宏。而C++20中正式將likely和unlikely確定為屬性關(guān)鍵字。
int foo(int i) {
switch(i) {
case 1: handle1();
break;
[[likely]] case 2: handle2();
break;
}
}到此這篇關(guān)于C++關(guān)鍵字之likely和unlikely詳解的文章就介紹到這了,更多相關(guān)C++ likely和unlikely內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
c++統(tǒng)計(jì)文件中字符個(gè)數(shù)代碼匯總
本文給大家匯總介紹了3種使用C++實(shí)現(xiàn)統(tǒng)計(jì)文件中的字符個(gè)數(shù)的方法,非常的簡(jiǎn)單實(shí)用,有需要的小伙伴可以參考下。2015-09-09
基于C++中常見(jiàn)編譯錯(cuò)誤的總結(jié)詳解
本篇文章是對(duì)C++中的常見(jiàn)編譯錯(cuò)誤進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
程序員都不知道C語(yǔ)言中的這些小細(xì)節(jié)
本文通過(guò)7到實(shí)例題目給大家展示C語(yǔ)言中的一些小細(xì)節(jié),很少有朋友真正的掌握,感興趣的朋友跟隨小編一起看看吧2021-05-05
C++實(shí)現(xiàn)LeetCode(133.克隆無(wú)向圖)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(133.克隆無(wú)向圖),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C++中strstr函數(shù)的實(shí)現(xiàn)方法總結(jié)
這篇文章主要介紹了C++中strstr函數(shù)的實(shí)現(xiàn)方法總結(jié)的相關(guān)資料,希望通過(guò)本文能幫助到大家,讓大家掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10
C語(yǔ)言學(xué)習(xí)之標(biāo)識(shí)符的使用詳解
C語(yǔ)言標(biāo)識(shí)符是用于表示變量、函數(shù)、常量、類型等程序元素的名稱,這篇文章將通過(guò)一些簡(jiǎn)單的示例為大家介紹一下C語(yǔ)言標(biāo)識(shí)符的使用,需要的可以參考一下2023-05-05
C++實(shí)現(xiàn)LeetCode(35.搜索插入位置)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(35.搜索插入位置),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07

