網(wǎng)站首頁 編程語言 正文
什么是likely和unlikely
既然程序是我們程序員所寫,在一些明確的場(chǎng)景下,我們應(yīng)該比CPU和編譯器更了解哪個(gè)分支條件更有可能被滿足。我們是否可將這一先驗(yàn)知識(shí)告知編譯器和CPU, 提高分支預(yù)測(cè)的準(zhǔn)確率,從而減少CPU流水線分支預(yù)測(cè)錯(cuò)誤帶來的性能損失呢?答案是可以!它便是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的原理
接下來,我們從匯編指令分析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
因此,通過對(duì)分支條件使用likely和unlikely,我們可給編譯器一種暗示,即該分支條件被滿足的概率比較大或比較小。而編譯器利用這一信息優(yōu)化其機(jī)器指令,從而最大限度減少CPU分支預(yù)測(cè)失敗帶來的懲罰。
likely/unlikely的適用條件
CPU有自帶的分支預(yù)測(cè)器,在大多數(shù)場(chǎng)景下效果不錯(cuò)。因此在分支發(fā)生概率嚴(yán)重傾斜、追求極致性能的場(chǎng)景下,使用likely/unlikely才具有較大意義。
C++20中的likely/unlikely
C++20之前的,likely和unlikely只不過是一對(duì)自定義的宏。而C++20中正式將likely和unlikely確定為屬性關(guān)鍵字。
int foo(int i) {
switch(i) {
case 1: handle1();
break;
[[likely]] case 2: handle2();
break;
}
}
原文鏈接:https://www.cnblogs.com/lygin/p/16793828.html
相關(guān)推薦
- 2023-04-24 Python?argparse中的action=store_true用法小結(jié)_python
- 2022-04-28 python實(shí)現(xiàn)簡(jiǎn)單的學(xué)生成績(jī)管理系統(tǒng)_python
- 2024-02-28 UNI-APP,text、rich-text控件顯示字符串,當(dāng)字符串過長(zhǎng)時(shí),實(shí)現(xiàn)自動(dòng)換行
- 2022-07-27 Python中的數(shù)據(jù)可視化matplotlib與繪圖庫模塊_python
- 2023-04-24 Android?集成Google?Cast?異常問題解析_Android
- 2023-07-10 SpringBoot AOP+注解方式實(shí)現(xiàn)多數(shù)據(jù)源切換可能遇到的問題
- 2022-05-22 Flutter利用Canvas繪制精美表盤效果詳解_Android
- 2022-09-14 iOS開發(fā)多線程下全局變量賦值崩潰原理詳解_IOS
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡(jiǎn)單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支