代码之家  ›  专栏  ›  技术社区  ›  Alex B

“rdtsc”之前的“cpuid”

  •  18
  • Alex B  · 技术社区  · 14 年前

    有时我会遇到代码读取TSC rdtsc 指令,但调用 cpuid 就在前面。

    为什么呼叫 CPUID 必要吗?我知道它可能与具有TSC值的不同内核有关,但是 确切地 当你按顺序调用这两个指令时会发生什么?

    3 回复  |  直到 6 年前
        1
  •  18
  •   paxdiablo    6 年前

    这是为了防止无序执行。从现在已从网络上消失的链接(但在消失之前偶然复制到这里),本文来自一篇题为“性能监视”的文章,作者是John Eckerdal:

    Pentium Pro和Pentium II处理器支持无序执行指令,可以在编程时按其他顺序执行。如果不小心,这可能是错误的来源。

    为了防止这种情况发生,程序员必须序列化指令队列。这可以通过在RDTSC指令之前插入一个序列化指令(如cpuid指令)来完成。

        2
  •  6
  •   Tony Delroy    12 年前

    原因有二:

    • 正如paxdiablo所说,当CPU看到一个cpuid操作码时,它会确保在执行任何后续指令之前,执行所有先前的指令,然后执行cpuid。如果没有这样的指令,CPU执行管道可能会在您想计时的指令之前执行TSC。
    • 有相当一部分机器无法在核心间同步TSC寄存器。在你想读的时候 马的嘴-在 http://msdn.microsoft.com/en-us/library/ee417693%28VS.85%29.aspx . 所以,当测量TSC读数之间的间隔时,除非它们被放在同一个核心上,否则会有一个有效的随机但可能是恒定的(见下文)间隔——即使在启动后很快,它也可能是几秒(是秒)。这有效地反映了在启动其他内核之前,BIOS在一个内核上运行了多长时间,此外,如果您有任何令人讨厌的节能选项,还可以增加内核以不同频率运行或再次关闭所导致的漂移。因此,如果您没有将读取TSC寄存器的线程钉在同一个核心上,那么您需要构建某种跨核心增量表,并知道每个TSC样本的核心ID(由cpuid返回),以补偿这个偏移量。这也是您可以在RDTSC旁边看到cpuid的另一个原因,而且确实也是使用较新的RDTSCP,许多操作系统将核心ID号存储到返回的额外TSC_x[31:0]数据中的原因。(可从Core i7和Athlon 64 x2获得,RDTSCP在所有方面都是一个更好的选择-操作系统通常向您提供所述的核心ID,原子到TSC读取, 防止指令重新排序)。
        3
  •  1
  •   Peter Cordes    6 年前

    cpuid正在序列化,防止RDTSC的无序执行。

    现在你可以安全地使用LFENCE了。它被记录为在英特尔CPU上的指令流(但不是存储到内存)上序列化,现在在AMD上也在为Spectre更新微码后序列化。

    https://hadibrais.wordpress.com/2018/05/14/the-significance-of-the-x86-lfence-instruction/ 解释更多关于LFENCE的信息。

    也见 https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf 一种使用RDTSC的方法 这使得cpuid(或lfence)不在定时区域内:

    LFENCE     ; (or CPUID) Don't start the timed region until everything above has executed
    RDTSC           ; EDX:EAX = timestamp
    mov  ebx, eax   ; low 32 bits of start time
    
       code under test
    
    RDTSCP     ; built-in one way barrier stops it from running early
    LFENCE     ; (or CPUID) still use a barrier after to prevent anything weird
    sub  eax, ebx   ; low 32 bits of end-start
    

    也见 Get CPU cycle count? 关于RDTSC注意事项的更多信息,如常数和不间断的注意事项。

    另外,RDTSCP会给您一个核心ID。如果您想检查核心迁移,也可以在启动时使用RDTSCP。但是如果你的CPU有 constant_tsc 功能,包中的所有内核都应该同步TSC,所以在现代x86上通常不需要。

    正如@tony's answer所指出的那样,您可以从cpuid中获取核心ID。

    推荐文章