CPU核心的rdtsc准确度

我从一个线程发送networking数据包,并在另一个CPU核心上运行的第二个线程上接收回复。 我的过程测量每个数据包发送和接收之间的时间(类似于ping)。 我正在使用rdtsc获得高分辨率,低开销的时间,这是我的实施所需要的。

所有测量看起来都可靠。 不过,我担心跨核心的rdtsc准确性,因为我一直在阅读一些文字,这意味着tsc在核心之间没有同步。

我在维基百科find了关于TSC的以下信息

持续的TSC行为确保了每个时钟节拍的持续时间是统一的,并且即使处理器内核改变了频率,也支持使用TSC作为挂钟定时器 这是所有英特尔处理器的架构行为。

尽pipe如此,我仍然担心跨核心的应计,这是我的问题

更多信息

  • 我在一台Intel nehalem机器上运行我的程序。
  • 操作系统是Linux。
  • 所有内核都设置了“ constant_tsc ”cpu标志。

cpuid中的X86_FEATURE_CONSTANT_TSC + X86_FEATURE_NONSTOP_TSC位(edx = x80000007,位#8;检查linux内核的unsynchronized_tsc 函数以获取更多检查)

英特尔的devise师的vol3b,第16.11.1章不变的TSC它说以下内容

“16.11.1不变的TSC

较新的处理器中的时间戳计数器可以支持被称为不变TSC的增强。 处理器对不变TSC的支持由CPUID.80000007H:EDX [8]表示。

不变的TSC将在所有ACPI P-,C-中以恒定速率运行。 和T状态。 这是build筑行为向前发展。 在支持不变TSC的处理器上,操作系统可以使用TSC作为挂钟定时器服务(而不是ACPI或HPET定时器)。 TSC读取效率更高,不会产生与环路转换或访问平台资源相关的开销。“

所以,如果TSC可以用于wallclock,它们保证是同步的。

在linux上,你可以使用clock_gettime(3)和CLOCK_MONOTONIC_RAW,这可以让你获得毫微秒的parsing度,并且不受ntp更新(如果有的话)的影响。

实际上,核心似乎并不共享TSC,请查看以下主题: http : //software.intel.com/zh-cn/forums/topic/388964

总结一下,不同的核心不共享TSC,有时如果核心改变到特定的能量状态,有时TSC可能会失去同步,但是这取决于CPU的种类,所以您需要查看英特尔文档。 似乎大多数操作系统在启动时同步TSC。
我在核心i5处理器的Linux Debian机器上检查了不同内核上的TSC与使用令人兴奋的反应algorithm之间的差异。 激励过程(在一个核心中)在共享variables中loggingTSC,当反应过程检测到该variables的变化时,它比较其值,并将其与自己的TSC进行比较。 这是我testing程序的一个输出示例:

 TSC ping-pong test result: TSC cores (exciter-reactor): 0-1 100 records, avrg: 159, range: 105-269 Dispersion: 13 TSC ping-pong test result: TSC cores (exciter-reactor): 1-0 100 records, avrg: 167, range: 125-410 Dispersion: 13 

励磁器CPU为0时的反应时间(平均159次)与励磁器CPU为1时的反应时间(167次)相同。 这表明他们很好地同步(也许有一些不同之处)。 在其他核心对上,结果非常相似。
另一方面,rdtscp汇编指令返回一个值,表示读取TSC的CPU。 这不是你的情况,但是当你想在一个简单的代码段中测量时间,并且你想确保在代码中间没有移动CPU的时候,它可能是有用的。

在最近的处理器上,你可以在同一个软件包的不同核心之间(即只有一个核心的iX处理器的系统)进行,你不能在单独的软件包(处理器)中执行它,因为它们不会共享rtc。 您可以通过cpu亲和力(将相关线程locking到特定核心)来获得它,但是这又取决于应用程序的行为方式。

在linux上,你可以检查/ proc / cpuinfo上的constant_tsc以查看处理器是否有一个对整个包有效的tsc。 原始寄存器位于CPUID.80000007H:EDX [8]

我读过的东西,但尚未得到编程确认的是,从版本11h起的AMD cpus对于这个cpuid位具有相同的含义。

我build议你不要使用rdtsc。 它不仅不可移植,而且不可靠,通常也不会工作 – 在某些系统上,rdtsc并不是一律更新(就像使用speedstep等)。 如果您需要准确的时间信息,您应该在套接字上设置SO_TIMESTAMP选项,并使用recvmsg()以(微秒分辨率)时间戳获取消息。

而且,使用SO_TIMESTAMP得到的时间戳实际上是内核获取数据包的时间,而不是在任务发生时注意到的时间。

您可以使用sched_set_affinity() API设置线程关联,以便在一个CPU内核上运行线程。