使用RDTSC测量时差-结果太大

时间:2019-05-18 15:12:55

标签: c linux assembly x86 att

我正在尝试计算运行单个ASM指令所需的CPU周期数。为此,我创建了以下功能:

measure_register_op:
    # Calculate time of required for movl operation

    # function setup
    pushl %ebp
    movl %esp, %ebp
    pushl %ebx
    pushl %edi

    xor %edi, %edi

    # first time measurement
    xorl %eax, %eax
    cpuid               # sync of threads
    rdtsc               # result in edx:eax

    # we are measuring instuction below
    movl %eax, %edi     

    # second time measurement
    cpuid               # sync of threads
    rdtsc               # result in edx:eax

    # time difference
    sub %eax, %edi

    # move to EAX. Value of EAX is what function returns
    movl %edi, %eax

    # End of function
    popl %edi
    popl %ebx
    mov %ebp, %esp
    popl %ebp

    ret

我正在* .c文件中使用它:

extern unsigned int measure_register_op();

int main(void)
{

    for (int a = 0; a < 10; a++)
    {
        printf("Instruction took %u cycles \n", measure_register_op());
    }

    return 0;
}

问题是:我看到的值太大。我现在得到3684414156。这里可能出什么问题了?

编辑: 从EBX更改为EDI,但结果仍然相似。一定是rdtsc本身。在调试器中,我可以看到第二个测量结果分别为0x7f61e078和第一个0x42999940,在减去后仍能得到1019758392

编辑: 这是我的makefile。也许我编译不正确:

compile: measurement.s measurement.c
    gcc -g measurement.s measurement.c -o ./build/measurement -m32

编辑: 这是我看到的确切结果:

Instruction took 4294966680 cycles 
Instruction took 4294966696 cycles 
Instruction took 4294966688 cycles 
Instruction took 4294966672 cycles 
Instruction took 4294966680 cycles 
Instruction took 4294966688 cycles 
Instruction took 4294966688 cycles 
Instruction took 4294966696 cycles 
Instruction took 4294966688 cycles 
Instruction took 4294966680 cycles 

2 个答案:

答案 0 :(得分:5)

null修饰语cpuid和许多其他寄存器。您需要避免在此处使用ebx或将值保存在不会被破坏的位置。

答案 1 :(得分:4)

在不影响开始时间的更新版本中(错误@R。指出):

sub %eax, %edi正在计算start - end。这是一个负数,即2 ^ 32以下的巨大无符号数。如果要使用%u,请在调试时习惯于将其输出解释回位模式。

您想要end - start

顺便说一句,使用lfence;它比cpuid的效率要高得多。可以确保在Intel上对指令 execution 进行序列化(无需像完整的序列化指令那样刷新存储缓冲区)。在AMD CPUs with Spectre mitigation enabled上也很安全。

另请参见http://akaros.cs.berkeley.edu/lxr/akaros/kern/arch/x86/rdtsc_test.c,以了解用于序列化RDTSC和/或RDTSCP的一些不同方法。


有关RDTSC的更多信息,另请参见Get CPU cycle count?,尤其是它不计算核心时钟周期,仅计算参考周期。因此,怠速/涡轮增压会影响您的结果。

此外,一条指令的成本不是一维的。 像这样用RDTSC计时单个指令并不是特别有用。有关如何衡量单个指令的吞吐量/延迟/微指令的更多信息,请参见RDTSCP in NASM always returns the same value

RDTSC对于定时整个循环或更长的指令序列(大于CPU的OoO执行窗口)很有用。