【问题标题】:Measuring time difference using RDTSC - results too large使用 RDTSC 测量时间差 - 结果太大
【发布时间】:2019-10-05 14:26:16
【问题描述】:

我正在尝试计算运行单个 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

编辑: 这是我的生成文件。也许我编译不正确:

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 

【问题讨论】:

  • 您总是得到错误的结果还是只是有时?尝试将您的线程固定到单个 CPU。
  • @fuz 是的,我总是得到大约 10 个数字
  • @fuz 你能告诉我怎么做吗?
  • @Piotrek 这看起来像个垃圾uint32_t (unsigned int) 号码
  • @Piotrek 这取决于您正在为什么操作系统编程。但是,正如 R.. 所说,这可能不是您的程序中真正出错的原因。

标签: c linux assembly x86 att


【解决方案1】:

cpuid clobbers ebx 和许多其他寄存器。您需要避免在此处使用 cpuid 或将值保存在不会被破坏的地方。

【讨论】:

【解决方案2】:

在不破坏开始时间的更新版本中(@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 的一些不同方法。


另请参阅Get CPU cycle count? 了解有关 RDTSC 的更多信息,尤其是它不计算核心时钟周期,只计算参考周期。所以idle/turbo会影响你的结果。

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

RDTSC 可用于为整个循环或更长的指令序列计时,大于 CPU 的 OoO 执行窗口。

【讨论】:

    猜你喜欢
    • 2013-11-12
    • 2020-05-02
    • 2023-04-10
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    • 2017-06-30
    • 2013-08-20
    • 1970-01-01
    相关资源
    最近更新 更多