繁体   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