CPU TSC获取操作,尤其是在多核多处理器环境中

时间:2012-06-06 19:53:57

标签: c assembly multicore cpu-registers microprocessors

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

#include <sys/time.h>

int foo()
{
   timespec ts;

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

This answer建议采用asm方法直接使用RDTSC指令查询cpu时钟。

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

您能否建议一些可以详细解释此问题的文档?我对Intel Nehalem和Sandy Bridge微体系结构很感兴趣。

修改

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

修改

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

结论

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

4 个答案:

答案 0 :(得分:22)

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

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. 参考CLOCK
  3. 当您为主板供电时,所有插座都会同时看到RESET,所有处理器封装都会从外部晶体振荡器接收参考时钟信号,并且处理器中的内部时钟保持同相(尽管通常具有高倍频器,如25x)带有称为锁相环(PLL)的电路。最近的处理器将以处理器额定的最高频率(乘数)为TSC提供时钟(所谓的恒定TSC),而不管任何单个核心由于温度或功率管理限制而使用的乘数(所谓的不变TSC)。像2008年发布的X5570(以及更新的英特尔处理器)这样的Nehalem处理器支持“不间断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寄存器同步。所以将术语映射到实际硬件

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

答案 1 :(得分:14)

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

从英特尔系统手册16.12.1

  

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

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

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

答案 2 :(得分:5)

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

答案 3 :(得分:5)

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

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

另见rdtsc accuracy across CPU cores

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

N.B。 TSC信息已从英特尔手册的第11章移至第17章。