在Atom N450上,rdtsc的返回值为_always_ mod 10 == 0

Idi*_*ere 5 x86 x86-64 intel-atom systems-programming rdtsc

在我的E8200机箱上,这不会发生,但是在我的Atom N450上网本(都运行OpenSuse 11.2)上,每当我读取CPU的TSC时,返回的值是mod 10 == 0,即没有被10整除的余数.我正在使用RDTSC用于测量有趣代码片段的时间的值,但为了演示的目的,我已经编写了这个小程序:

        .text
        .global _start

_start: xorl    %ebx,%ebx
        xorl    %ecx,%ecx
        xorl    %r14d,%r14d
        movb    $10,%cl
loop:   xchgq   %rcx,%r15          # save to reg
        cpuid
        rdtsc
        shlq    $32,%rdx
        xorq    %rax,%rdx          # full 64 bit of RDTSC
        movq    %r14,%r13          # save the old value
        movq    %rdx,%r14          # copy current
        movq    %r14,%rsi          #  argv[1] of printf()
        subq    %r13,%rdx          #  argv[2] (delta)
        leaq    format(%rip),%rdi  #  argv[0]
        xorl    %eax,%eax          #  no stack varargs
        call    printf
        xchgq   %rcx,%r15
        loop    loop

0:      xorl    %eax,%eax
        movb    $0x3c,%al
        syscall

        .size   _start, .-_start

        .data
format: .asciz     "rdtsc: %#018llx = %1$llu -- delta: %llu\n"
Run Code Online (Sandbox Code Playgroud)

(我通常使用自己的例程进行转换,但是为了防止读者建议错误可能存在,我只是在这里使用printf().)

使用上面的代码,输出是(例如):

rdtsc: 0x000b88ef933ffd06 = 3246787292822790 -- delta: 3246787292822790
rdtsc: 0x000b88ef9342fcf4 = 3246787293019380 -- delta: 196590
rdtsc: 0x000b88ef93435dca = 3246787293044170 -- delta: 24790
rdtsc: 0x000b88ef9343b43c = 3246787293066300 -- delta: 22130
rdtsc: 0x000b88ef93440c34 = 3246787293088820 -- delta: 22520
rdtsc: 0x000b88ef9344604e = 3246787293110350 -- delta: 21530
rdtsc: 0x000b88ef9344b4d6 = 3246787293131990 -- delta: 21640
rdtsc: 0x000b88ef9345085a = 3246787293153370 -- delta: 21380
rdtsc: 0x000b88ef93455d96 = 3246787293175190 -- delta: 21820
rdtsc: 0x000b88ef9345b16a = 3246787293196650 -- delta: 21460
Run Code Online (Sandbox Code Playgroud)

可以很容易地看出,三角洲的数量是合理的.但显而易见的(不是说密谋;-)是最不重要的十进制数字始终为0.

我已经观察到这种现象已经两年多了,Stack Overflow并不是我公开这个问题的第一个地址.但是我还没有得到合理的答案.我们(我和其他人)提出的想法就是这样

  • TSC仅在每 10 周期递增,但随后递增10或者
  • TSC在内部正确更新,但仅在每 10 周期反映到外部,或者
  • 每个周期TSC增加10.

然而,这些要点都没有意义.我应该在E8200上实际运行这样的程序(当前是乱序的),以查看增量的数量级是否与上述输出的数量级相同或仅为十分之一.(任何志愿者?)

谷歌搜索并没有帮助,英特尔的手册也没有.

在与其他人讨论时,没有其他人经历过同样的行为.如果它与内核有关,那么至少有3个版本受到影响,但是......内核与它有什么关系呢?

我也有上网本服务,它带来了一个新的主板 - 暗示一个新的CPU,所以至少有两个单独的N450实体必须受到影响.

我还采取了针对时钟频率变化的措施(无论我将时钟固定到什么频率,数值仅在预期范围内变化(与所示相同)),并关闭HT,尽管这些实际上应该有助于获得一些其他最不重要的数字,而不是阻止它们.但只是为了确定.

好吧,如果有人想在他们的机器上运行程序,命令行是(假设您将源保存在文件中rdtsc.s):

as rdtsc.s -o rdtsc.o
ld --dynamic-linker=/lib64/ld-linux-x86-64.so.2 rdtsc.o -L /lib64 -l c -o rdtsc
Run Code Online (Sandbox Code Playgroud)

为了用gcc前端构建它,即

gcc -l c rdtsc.s -o rdtsc
Run Code Online (Sandbox Code Playgroud)

您必须添加(或替换_start:标签)main:标签并使其成为全局标签.

[更新(2012-09-15~21:15 UTC):实际上我之前也可以做到这一点:我只是让它采取前后的TSC sleep(1),这给出了一个略大于1,666,000,000的delta,这表明第三个上面列表中的点是错误的.但我仍然不知道为什么我没有得到完整的精度./更新]

twa*_*erg 2

《软件开发手册》第 3B 卷这样说:

...对于 Intel Atom 处理器...时间戳计数器以恒定速率递增。该速率可以由处理器的最大核心时钟与总线时钟比率来设置,或者可以由处理器启动时的最大解析频率来设置。最大解析频率可能与处理器的最大合格频率不同,...

这并不能完全回答为什么你会看到特定的步骤 10,但它确实指出特定的实现可以自由地增加 1 以外的值。我怀疑你必须更仔细地查看特定的实现您机器的硬件规格和 BIOS 实现,以了解为什么它恰好是 10。