15

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

#include <sys/time.h>

int foo()
{
   timespec ts;

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

这个答案提出了asm一种使用指令直接查询 cpu 时钟的方法RDTSC

在多核、多处理器架构中,这个时钟滴答/定时器值如何在多个内核/处理器之间同步?我的理解是,内在的围栏正在完成。这种理解正确吗?

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

编辑

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

编辑

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

结论

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

4

4 回答 4

25

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

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

这是 Intel 讨论跨内核同步 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(和更新的 Intel 处理器)支持“不间断 TSC”,即使在深度掉电 C 状态 (C6) 中保存功率时,它也会继续运行。

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

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

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

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

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

据我所知,非核心中有一个 TSC(封装中围绕核心但不属于任何核心的逻辑),它在每个外部总线时钟上按 Vipin Kumar 指定的机器特定寄存器字段中的值递增在上面的链接中 (MSR_PLATFORM_INFO[15:8])。外部总线时钟运行在 133.33MHz。此外,每个内核都有自己的 TSC 寄存器,由所有内核共享的时钟域提供时钟,并且可能与任何一个内核的时钟不同 - 因此当 RDTSC 读取内核 TSC 时必须有某种缓冲区(或 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 时钟的频率都通过恒定乘数与总线参考时钟相关联)。
于 2012-06-16T03:45:01.787 回答
18

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

来自英特尔系统手册 16.12.1

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

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

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

于 2012-06-06T20:47:55.203 回答
5

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

于 2012-06-06T20:05:23.383 回答
5

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

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

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

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

NB 英特尔手册中的 TSC 信息已从第 11 章移至第 17 章。

于 2012-06-14T00:56:43.333 回答