有时我会遇到使用指令读取 TSC 的代码,但在此之前rdtsc
调用。cpuid
为什么需要打电话cpuid
?我意识到这可能与具有 TSC 值的不同内核有关,但是当您按顺序调用这两条指令时究竟会发生什么?
这是为了防止乱序执行。来自一个现在已经从网络上消失的链接(但在消失之前偶然被复制到这里),这段文字来自 John Eckerdal 的一篇题为“性能监控”的文章:
Pentium Pro 和 Pentium II 处理器支持乱序执行指令可以在您对它们进行编程时以另一个顺序执行。如果不加以注意,这可能是错误的根源。
为了防止这种情况,程序员必须序列化指令队列。这可以通过在 RDTSC 指令之前插入像 CPUID 指令这样的序列化指令来完成。
两个原因:
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-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。