日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++關鍵字之likely和unlikely詳解_C 語言

作者:misaka-mikoto ? 更新時間: 2022-11-25 編程語言

什么是likely和unlikely

既然程序是我們程序員所寫,在一些明確的場景下,我們應該比CPU和編譯器更了解哪個分支條件更有可能被滿足。我們是否可將這一先驗知識告知編譯器和CPU, 提高分支預測的準確率,從而減少CPU流水線分支預測錯誤帶來的性能損失呢?答案是可以!它便是likely和unlikely。在Linux內核代碼中,這兩個宏的應用比比皆是。下面是他們的定義:

#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去掉,然后反匯編,作為對照組
匯編如下,我們看到,if分支中的指令被編譯器放置于分支跳轉指令jle相鄰的位置,即CPU流水線在遇到jle指令所代表的的'岔路口'時,更傾向于走if分支

.LC0:
        .string "Positive\n"
.LC1:
        .string "Zero or Negative\n"
main:
        sub     rsp, 8
        test    edi, edi                
        jle     .L2                     ; 如果argc <= 0, 跳轉到L2
        mov     edi, OFFSET FLAT:.LC0   ; 如果argc > 0, 從這里執行
        call    puts
.L3:
        xor     eax, eax
        add     rsp, 8
        ret
.L2:
        mov     edi, OFFSET FLAT:.LC1
        call    puts
        jmp     .L3

接著我們在if分支中加上unlikely, 反匯編如下。這里的情況正好與對照組相反,if分支下的指令被編譯器放置于遠離跳轉指令jg的位置。這意味著CPU此時更傾向于走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

因此,通過對分支條件使用likely和unlikely,我們可給編譯器一種暗示,即該分支條件被滿足的概率比較大或比較小。而編譯器利用這一信息優化其機器指令,從而最大限度減少CPU分支預測失敗帶來的懲罰。

likely/unlikely的適用條件

CPU有自帶的分支預測器,在大多數場景下效果不錯。因此在分支發生概率嚴重傾斜、追求極致性能的場景下,使用likely/unlikely才具有較大意義。

C++20中的likely/unlikely

C++20之前的,likely和unlikely只不過是一對自定義的宏。而C++20中正式將likely和unlikely確定為屬性關鍵字。

int foo(int i) {
    switch(i) {
               case 1: handle1();
                       break;
    [[likely]] case 2: handle2();
                       break;
    }
}

原文鏈接:https://www.cnblogs.com/lygin/p/16793828.html

欄目分類
最近更新