C语言 CPU TSC 提取操作,尤其是在多核多处理器环境中



在Linux世界中,要获得纳秒精度计时器/时钟滴答声,可以使用:

#include <sys/time.h>
int foo()
{
   timespec ts;
   clock_gettime(CLOCK_REALTIME, &ts); 
   //--snip--      
}

这个答案提出了一种asm方法,可以使用RDTSC指令直接查询 CPU 时钟。

在多核、多处理器架构中,此时钟周期/计时器值如何在多个内核/处理器之间同步?我的理解是,固有的围栏正在做。这种理解正确吗?

你能建议一些详细解释这一点的文档吗?我对Intel Nehalem和Sandy Bridge微架构感兴趣。

编辑

进程限制为单个内核或 CPU 不是一种选择,因为该过程确实很大(就消耗的资源而言),并且希望以最佳方式利用机器中的所有资源,包括所有内核和处理器。

编辑

感谢您确认 TSC 在内核和处理器之间同步。但我最初的问题是这种同步是如何完成的?是用某种击剑吗?你知道任何公共文件吗?

结论

感谢您的所有输入:以下是本次讨论的结论:TSC 在初始化时使用 RESET 进行同步,该重置发生在多处理器/多核系统中的内核和处理器之间。在那之后,每个核心都是独立的。TSC通过锁相环保持不变,锁相环将使频率变化归一化,从而规范给定内核内的时钟变化,这就是TSC在内核和处理器之间保持同步的方式。

直接来自英特尔,以下是最新的处理器如何保持以恒定速率滴答作响的 TSC 的解释,在多插槽主板上的内核和封装之间同步,甚至可能在处理器进入深度睡眠 C 状态时继续滴答作响,特别是参见 Vipin Kumar E K(英特尔)的解释:

http://software.intel.com/en-us/articles/best-timing-function-for-measuring-ipp-api-timing/

这是英特尔讨论跨内核同步 TSC 的另一个参考资料,在这种情况下,他们提到了 rdtscp 允许您以原子方式读取 TSC 和处理器 ID 的事实,这在跟踪应用程序时很重要......假设您要跟踪可能从一个内核迁移到另一个内核的线程的执行,如果您在两个单独的指令(非原子)中执行此操作,那么您不确定线程在读取时钟时位于哪个内核。

http://software.intel.com/en-us/articles/intel-gpa-tip-cannot-sychronize-cpu-timestamps/

主板上的所有插槽/封装都接收两个外部公共信号:

  1. 重置
  2. 参考时钟

当您为主板供电时,所有插槽都会同时看到 RESET 信号,所有处理器封装都从外部晶体振荡器接收参考时钟信号,处理器中的内部时钟保持相位(尽管通常使用高乘法器,如 25x),电路称为锁相环 (PLL)。 最新的处理器将以处理器额定的最高频率(乘法器)对 TSC 进行计时(所谓的恒定 TSC),而不管任何单个内核由于温度或电源管理节流(所谓的不变 TSC)而可能使用的乘法器如何。 Nehalem处理器,如2008年发布的X5570(以及更新的英特尔处理器)支持"不间断TSC",即使在深度掉电C状态(C6)中节省功率,它也会继续滴答作响。 有关不同关断状态的更多信息,请参阅此链接:

http://www.anandtech.com/show/2199

经过进一步的研究,我发现了英特尔于 2009 年 12 月 22 日提交并于 2011 年 6 月 23 日发布的专利,标题为"控制多核和线程的时间戳计数器 (TSC) 偏移"

http://www.freepatentsonline.com/y2011/0154090.html

谷歌此专利申请的页面(带有指向USPTO页面的链接)

http://www.google.com/patents/US20110154090

据我收集,非内核中有一个TSC(围绕内核的封装中的逻辑,但不是任何内核的一部分),它在每个外部总线时钟上按Vipin Kumar在上面的链接中指定的机器特定寄存器字段中的值递增(MSR_PLATFORM_INFO[15:8])。 外部总线时钟的工作频率为133.33MHz。 此外,每个内核都有自己的TSC寄存器,由所有内核共享的时钟域时钟,并且可能与任何一个内核的时钟不同 - 因此,当内核TSC由内核中运行的RDTSC(或RDTSCP)指令读取时,必须有某种缓冲区。 例如,封装上的MSR_PLATFORM_INFO[15:8]可以设置为25,非内核TSC的每个总线时钟递增25,有一个PLL将总线时钟乘以25,并将该时钟提供给每个内核以为其本地TSC寄存器提供时钟,从而使所有TSC寄存器保持同步。 因此,将术语映射到实际硬件

  • 恒定TSC通过使用运行在133.33 MHz的外部总线时钟来实现,该时钟乘以MSR_PLATFORM_INFO中指定的常数乘法器[15:8]
  • 不变TSC
  • 是通过将每个内核中的TSC保持在单独的时钟域上来实现的
  • 不间断 TSC 是通过在每个总线时钟上增加 MSR_PLATFORM_INFO[15:8] 滴答声的非内核 TSC 来实现的,这样多核封装就可以进入深度掉电状态(C6 状态),并可以关闭 PLL...没有必要将时钟保持在较高的乘数。 当内核从 C6 状态恢复时,其内部 TSC 将被初始化为非内核 TSC(未进入睡眠状态的那个)的值,并在软件将值写入 TSC 的情况下进行偏移调整,其详细信息在专利中。 如果软件确实写入了TSC,则该内核的TSC将与其他内核异相,但偏移量恒定(TSC时钟的频率都通过恒定乘法器与总线参考时钟相连)。

在较新的CPU(i7 Nehalem+ IIRC)上,TSC在所有内核之间同步并以恒定速率运行。因此,对于单个处理器,或单个封装或主板上的多个处理器(! 您可以依赖同步的 TSC。

摘自英特尔系统手册 16.12.1

较新处理器中的时间戳计数器可能支持增强功能, 称为不变 TSC。处理器对固定 TSC 的支持是 由 CPUID.80000007H:EDX 表示[8]。固定 TSC 将在 所有 ACPI 中的恒定速率 P-、C-。和 T 状态。这是 向前发展的体系结构行为。

在较旧的处理器上,您不能依赖恒定速率或同步。

编辑:至少在单个封装或主板中的多个处理器上,不变的TSC是同步的。TSC 在/RESET 处复位为零,然后在每个处理器上以恒定速率向前滴答,没有漂移。/RESET 信号保证同时到达每个处理器。

RTDSC 不会在 CPU 之间同步。因此,您不能在多处理器系统中依赖它。对于 Linux,我能想到的唯一解决方法是通过设置其亲和力来实际限制进程在单个CPU上运行。这可以使用taskset实用程序在外部完成,也可以使用sched_setaffinity或pthread_setaffinity_np函数"内部"完成。

本手册第 17.12 章描述了最新处理器中使用的不变 TSC。Nehalem 提供此时间戳以及 rtscp 指令,允许人们在一个原子操作中读取时间戳(不受等待状态等的影响)和处理器签名。

据说它适用于计算挂钟时间,但它显然不希望处理器之间的值相同。陈述的想法是,您可以查看连续读取是针对同一 CPU 时钟,还是针对多个 CPU 读取进行调整。"它还可用于调整 NUMA 系统中 TSC 值的每个 CPU 差异。

另请参阅跨 CPU 内核的 rdtsc 准确性

但是,我不确定接受答案中的最终一致性结论是否来自tsc可用于挂钟时间的声明。如果它是一致的,那么以原子方式确定当时的CPU源有什么理由。

:注:TSC 信息已从该英特尔手册的第 11 章移至第 17 章。

相关内容

  • 没有找到相关文章

最新更新