有时我遇到的代码读取TSC rdtsc 指示,但打电话 cpuid 就在之前。

为什么打电话 cpuid 必要的?我意识到这可能与具有TSC值的不同核心有关,但是什么 确切地 当您按顺序调用这两个说明时发生?

有帮助吗?

解决方案

这是为了防止排序执行。从现在已经从网络中消失的链接(但在它消失之前都在这里复制了它),该文本来自一个约翰·埃克达尔(John Eckerdal)的题为“绩效监控”的文章:

当您对其进行编程时,Pentium Pro和Pentium II处理器支持置端执行说明可以按其他顺序执行。如果不照顾,这可能是错误的根源。

为了防止这种情况,程序员必须序列化指令队列。这可以通过在RDTSC指令之前插入诸如CPUID指令之类的序列化指令来完成。

其他提示

两个原因:

  • 正如Paxdiablo所说,当CPU看到CPUID OPCODE时,请确保执行所有先前的说明,然后执行CPUID,然后再执行任何后续说明。没有这样的指示,CPU执行管道最终可能会在您想安排的指令之前执行TSC。
  • 很大一部分机器无法同步跨核心的TSC寄存器。您想从中阅读 一种 马的嘴 - 把自己撞到 http://msdn.microsoft.com/en-us/library/ee417693%28vs.85%29.aspx. 。因此,当测量TSC读数之间的间隔时,除非将它们放在相同的核心上,否则您将有一个有效的随机但可能是恒定的(见下文)的间隔 - 即使在启动后不久,它也很容易是几秒钟(是的秒) 。这有效地反映了BIOS在单个核心上运行多长时间,然后再启动其他核心 - 如果您有任何令人讨厌的节电选项 - 增加了以不同频率运行或再次关闭的核心引起的漂移。因此,如果您还没有将读取TSC寄存器的线程钉在同一核心上补偿此偏移。这就是您可以在RDTSC并肩上看到CPUID的另一个原因,实际上,有了较新的RDTSCP,许多OS将核心ID编号存储到返回的额外TSC_AUX [31:0]数据中。 (RDTSCP可从Core i7和Athlon 64 X2获得,在所有方面都是更好的选择 - OS通常为您提供了所述的核心ID,如TSC读取, 防止指令重新排序)。

CPUID正在序列化,以防止RDTSC的级别执行。

这些天,您可以安全地使用Lfence。它被记录为在Intel 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-code-execution-execution-paper.pdf 用于使用RDTSC的方法p 这使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

也可以看看 获得CPU周期数? 有关RDTSC警告的更多信息,例如Constant_TSC和NONSTOP_TSC。

作为奖励,RDTSCP为您提供了核心ID。如果您想检查核心迁移,则可以在开始时间内使用RDTSCP。但是,如果您的CPU有 constant_tsc 功能,包装中的所有内核都应同步其TSC,因此通常在现代X86上不需要它。

正如 @Tony的答案所指出的那样,您可以从CPUID获得核心ID。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top