簡體   English   中英

內聯匯編代碼組織

[英]inline asm code organization

我剛剛編寫了一些小的內聯asm例程來查詢x86中的時間戳計數器,以便可以分析一小段代碼。 我真的很想將這些例程放在標頭中,以便可以在許多不同的源文件中重用它們,所以基本上我的問題是我應該只在宏中組織它們還是使它們成為內聯函數,我對內聯的懷疑是它不是必然是編譯器實際上會內聯它的情況,並且由於它是對性能敏感的調用,所以我寧願跳過函數調用的開銷,另一方面,使用宏,整個類型的安全性都會消失,為此我將嚴格需要32位int ,我認為我可以只在注釋中添加規范,但由於許多警告,我仍然盡量避免使用宏。 這是代碼:

inline void rdtsc(uint64_t* cycles)
{
    uint32_t cycles_high, cycles_low;

    asm volatile (
            ".att_syntax\n"
            "CPUID\n\t"    //Serialize
            "RDTSC\n\t"    //Read clock and cpuid
            "mov %%edx, %0 \n\t"
            "mov %%eax, %1 \n\t" 
             : "=r" (cycles_high), "=r" (cycles_low)
             :: "%edx", "%eax");

    *cycles = ((uint64_t) cycles_high << 32) | cycles_low;
}

歡迎對此提出任何建議。 我只是想弄清楚這種情況下首選的樣式。

由於您將要測量部分代碼的性能,而不必測量整個函數的性能,因此您不應嘗試內聯性能計數器。 是否有通話開銷都沒有關系。 重要的是,測量結果是一致的,這意味着您要么總是希望存在呼叫開銷,要么永遠不要。 第一個比前一個更容易實現。

讓您的代碼的每個部分都具有相同的調用開銷。

如果您真的需要在讀取TSC之前進行序列化,則可以使用LFENCE指令,該指令不會更改寄存器。

如果決定繼續使用CPUID進行序列化,則應首先將EAX設置為0(可能是0,因為您實際上並不關心輸出),並注意此指令會破壞EAX,EBX,ECX和EDX寄存器,因此您的例行程序必須說明這個事實。

總之,我傾向於這樣寫:

#include <stdint.h>
#include <stdio.h>

inline uint64_t rdtsc() {
    uint32_t high, low;
    asm volatile ( 
            ".att_syntax\n\t" 
            "LFENCE\n\t"   
            "RDTSC\n\t"   
            "movl %%eax, %0\n\t" 
            "movl %%edx, %1\n\t"
             : "=rm" (low), "=rm" (high)  
             :: "%edx", "%eax"); 
    return ((uint64_t) high << 32) | low;
}

int main() {
    uint64_t x, y;
    x = rdtsc();
    printf("%lu\n", x);
    y = rdtsc();
    printf("%lu\n", y);
    printf("%lu\n", y-x);
}

更新:

@Jester和@DavidWohlferd提出,可以通過直接將highlow分配給edxeax寄存器來消除寄存器分配。

該版本如下所示:

inline uint64_t rdtsc() {
    uint32_t high, low;
    asm volatile ( 
            ".att_syntax\n\t" 
            "LFENCE\n\t"   
            "RDTSC\n\t"   
             : "=a" (low), "=d" (high)  
             :: );
    return ((uint64_t) high << 32) | low;
}

生成的代碼(使用運行-O2的優化)(在運行Linux的64位計算機上使用gcc 4.8.3)並包括對printf的調用,如下所示:

#APP
# 20 "rdtsc.c" 1
    .att_syntax
    LFENCE
    RDTSC

# 0 "" 2
#NO_APP
    movq    %rdx, %rbx
    movl    %eax, %eax
    movl    $.LC0, %edi
    salq    $32, %rbx
    orq %rax, %rbx
    xorl    %eax, %eax
    movq    %rbx, %rsi
    call    printf

我最初發布的版本結果如下:

#APP
# 7 "rdtsc.c" 1
    .att_syntax
    LFENCE
    RDTSC
    movl %eax, %ecx
    movl %edx, %ebx

# 0 "" 2
#NO_APP
    movl    %ecx, %ecx
    salq    $32, %rbx
    movl    $.LC0, %edi
    orq %rcx, %rbx
    xorl    %eax, %eax
    movq    %rbx, %rsi
    call    printf

該版本的代碼長了一條指令。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM