多核多处理器环境下的CPU TSC获取操作

18

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

#include <sys/time.h>

int foo()
{
   timespec ts;

   clock_gettime(CLOCK_REALTIME, &ts); 
   //--snip--      
}

这个回答建议使用RDTSC指令的asm方法直接查询CPU时钟。

在多核、多处理器体系结构中,这个时钟tick/计时器值是如何在多个核心/处理器之间同步的?我的理解是存在固有的屏障。这种理解正确吗?

你能否推荐一些详细说明这一点的文档?我对Intel Nehalem和Sandy Bridge微架构很感兴趣。

编辑

将进程限制在单个核心或cpu上不是一个选项,因为该进程非常庞大(就资源消耗而言),并且希望充分利用机器上的所有资源,包括所有核心和处理器。

编辑

谢谢确认TSC在多个核心和处理器之间同步。但我的原始问题是这个同步是如何完成的?是通过某种类型的栅栏完成的吗?您是否知道任何公共文档?

结论

感谢所有的意见:以下是此讨论的结论:在多处理器/多核系统中,TSC在初始化时使用RESET在所有核心和处理器之间同步。此后,每个核心都是独立的。TSC通过相位锁定环路保持不变,该环路将规范频率变化,从而使时钟变化在给定的核心内保持同步,这就是TSC在多个核心和处理器之间保持同步的方法。


只有在Linux上,我在使用gettime()时遇到了麻烦。在我最近的测试中,它似乎仍然具有内核调用的250纳秒开销。在Windows上,我只是使用了大约1纳秒开销的rdtsc()内置函数。 - Crashworks
我不理解在这个上下文中“fencing”的含义。但是在/RESET信号之后,不会再发生显式重新同步。请注意,重新同步将违反“重新同步”TSC的“不变量”属性 - 如果需要向后跳转,它应该怎么做...但是因为TSC在每个核心上以完全相同的速度运行(它们都有一个共同的时钟源),并且在完全相同的时间开始(因为/RESET信号已同步),它们始终在每个核心上具有相同的值。 - Gunther Piez
处理器插座或甚至给定处理器插座中的核心可能会遇到不同的环境条件,例如温度,这将导致频率变化,从而导致处理器中的核心和处理器插座之间的TSC增量变化。这是我的假设。我找不到支持或反对它的文档。因此,“围栏”思想也是为了在固定间隔内保持它们同步!我认为在一定时间间隔后重新同步是必要的。 - Jay D
虽然Delta TSC可能只有几纳秒,但它可能是处理器技术本身的一部分?如果您有文档证明我错了,欢迎指出! - Jay D
1
这不是关于多个时钟源的问题,而是每个核心中的PLL单元本质上生成自己的时钟,它不仅与所有其他时钟相比具有短期周期变化,而且还具有非零的长期漂移,这与所有其他核心都不同。多核CPU每个核心使用一个PLL,它们都参考单个时钟源。但PLL仅使用该单个时钟作为参考,并且此参考过程会引入误差。 - Kuba hasn't forgotten Monica
显示剩余12条评论
4个回答

26
直接来自Intel,这里是关于最近处理器如何维护一个以恒定速率跳动的TSC(时间戳计数器)的解释,这个TSC在多核和多插槽主板上的包之间保持同步,甚至在处理器进入深度睡眠C状态时仍然可能继续跳动。具体解释请参见Vipin Kumar E K (Intel)的解释。

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. RESET
  2. 参考时钟

当您启动主板时,所有插槽同时看到RESET。所有处理器封装从外部晶体振荡器接收参考时钟信号,并且处理器内部时钟与称为锁相环(PLL)的电路保持同步(尽管通常具有高倍增器,例如25x)。最近的处理器将以处理器额定的最高频率(倍增器)时钟TSC(所谓的恒定TSC),而不管任何单个核心由于温度或功率管理节流而使用的倍增器(所谓的不变TSC)。像2008年发布的X5570这样的Nehalem处理器(以及更新的英特尔处理器)支持“Non-stop TSC”,即使在深度电源关闭C状态(C6)中节能时也会继续计时。有关不同电源关闭状态的更多信息,请参见此链接:

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

经进一步调查,我发现英特尔于2009年12月22日申请并在2011年6月23日公布的一项专利,标题为“控制多个核心和线程的时间戳计数器(TSC)偏移量”。

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

谷歌的专利申请页面(包含链接到美国专利商标局页面)。

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

根据我的了解,在uncore中有一个TSC(围绕核心的包装逻辑,但不是任何核心的一部分),其值在每个外部总线时钟上由Vipin Kumar在上面链接中指定的机器特定寄存器字段中的值递增(MSR_PLATFORM_INFO[15:8])。外部总线时钟运行在133.33MHz。此外,每个核心都有自己的TSC寄存器,由所有核心共享的时钟域驱动,并且可能与任何一个核心的时钟不同 - 因此,在核心中运行RDTSC(或RDTSCP)指令读取核心TSC时必须有某种缓冲区。例如,MSR_PLATFORM_INFO[15:8]可以设置为25,对于每个总线时钟,uncore TSC递增25,有一个PLL将总线时钟乘以25并提供此时钟给每个核心以时钟其本地TSC寄存器,从而保持所有TSC寄存器同步。因此,要将术语映射到实际硬件。
  • 常数TSC是通过使用外部总线时钟运行在133.33 MHz,该时钟乘以MSR_PLATFORM_INFO [15:8]中指定的常数乘数来实现的。
  • 不变TSC是通过将每个核心上的TSC保持在单独的时钟域中来实现的。
  • 非停TSC是通过具有未核心TSC来实现的,每次总线时钟增加MSR_PLATFORM_INFO [15:8]个滴答声,这样多核包可以进入深度电源关闭(C6状态)并可以关闭PLL……没有必要保持时钟在更高的倍频器。当一个核心从C6状态恢复时,它的内部TSC将被初始化为uncore TSC的值(未休眠的那个),如果软件写入了TSC的值,则会进行偏移调整,其详细信息在专利中解释。如果软件确实写入TSC,则该核心的TSC将与其他核心不同步,但具有恒定的偏移量(TSC时钟的频率都由常数乘数与总线参考时钟相结合)。

1
谢谢您的回答。您提供的第一个链接讨论了英特尔IPP库中的时间包装器。IPP是一种图像处理库。该链接仅重申了上述事实,即TSC在现代处理器中跨核心同步。但它没有提供原问题的原因。! - Jay D
你的第二个链接讲述了英特尔图形芯片如何报告TSC不同步以及它们如何处理Delta TSC。但是该文章并没有详细讨论TSC如何同步。 - Jay D
第三个链接讨论了 Nehalem 的特性。相位锁定环路(PLL)将规范给定核心的时钟,而不是跨核心和处理器。 - Jay D
Jay,我在这个主题上发现了一项英特尔专利,并将更新我的答案以包含该链接。感谢你的额外加分。 - amdn
我在上面的回答中添加了两个链接,分别是专利和我的解释。 - amdn

19
在较新的CPU上(i7 Nehalem+,如果我没记错),TSC在所有核心之间同步,并以恒定速率运行。因此,在单个处理器或单个套件或主板上的多个处理器中,您可以依赖于同步的TSC。
根据英特尔系统手册16.12.1:
新处理器中的时间戳计数器可能支持一种增强功能,称为不变TSC。 CPU对不变TSC的支持由CPUID.80000007H:EDX [8]指示。在所有ACPI P,C和T状态下,不变TSC将以恒定速率运行。这是未来的架构行为。
在旧处理器上,您不能依赖于恒定速率或同步。
编辑:至少在单个套件或主板上的多个处理器中,不变TSC是同步的。 TSC在/ RESET处重置为零,然后在每个处理器上以恒定速率继续前进,而无需漂移。 / RESET信号保证同时到达每个处理器。

2
请注意,此仅适用于英特尔处理器。我已经有一段时间没有在 AMD 上进行任何测试了(我测试过的最新的 AMD CPU 是 Phenom II,如果我没记错的话),但当时它们甚至在单个芯片中的多个核之间都没有同步。 - Eugene Smith

5

这本手册的17.12章节描述了新处理器中使用的不变TSC。此时间戳与rtscp指令一起提供,可以通过一个原子操作读取时间戳(不受等待状态等影响)和处理器签名。

它被认为适用于计算挂钟时间,但显然不期望值在多个处理器之间相同。所述想法是您可以查看连续读取是否来自同一CPU时钟,或进行多个CPU读取的调整。 "它也可用于调整NUMA系统中每个CPU差异的TSC值."

另请参见跨CPU核心的rdtsc准确度

然而,我不确定接受答案中的最终一致性结论是否来自于TSC可用于挂钟时间的声明。如果它是一致的,那么确定时间源的CPU的原因是什么。

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


这正是我在讨论中提出的问题。如果它是一致的,那么有什么理由去原子地确定CPU时间源呢? - Jay D
我想说的是,根据手册中的信息,有充分的理由相信时间在 CPU 状态之间是不变的,但不是在 CPU 之间。这似乎是一种被推断出来的推论,但我认为你的谨慎是有道理的。请注意,读取 CPU 签名的指令也是新的。我还建议,如果 TSC 值由内核设置,则其值(相位)即使由相同的时钟电路运行 TSC 并且具有锁定频率,也将不同。 - John S Gruber

5

RTDSC在多CPU系统中不是同步的。因此,在多处理器系统中不能依赖它。我能想到的Linux的唯一解决方法是通过设置进程的亲和力来限制其在单个CPU上运行。这可以通过使用taskset实用程序或“内部”使用sched_setaffinitypthread_setaffinity_np函数来进行外部操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接