std :: chrono ::时钟,硬件时钟和循环计数

时间:2018-06-15 23:41:27

标签: c++ time cpu benchmarking chrono

std::chrono提供几个时钟来衡量时间。与此同时,我猜cpu可以评估时间的唯一方法是计算周期。

问题1: cpu或gpu是否有任何其他方式来评估时间而不是计算周期?

如果是这种情况,因为计算机计数周期的方式永远不会像原子钟一样精确,这意味着第二个&#34;第二个&#34;计算机的(period = std::ratio<1>)实际上可能比实际的秒更短或更大,导致计算机时钟之间的长时间测量差异,让我们说GPS。

问题2:这是正确的吗?

某些硬件具有不同的频率(例如空闲模式和turbo模式)。在这种情况下,这意味着周期数会在一秒钟内发生变化。

问题3:&#34;循环计数&#34;由cpu和gpus测量,取决于硬件频率?如果是,那么std::chrono如何处理呢?如果不是,循环对应什么(比如&#34;基本&#34;时间)?有没有办法在编译时访问转换?有没有办法在运行时访问转换?

2 个答案:

答案 0 :(得分:2)

计算周期,是的,但是什么的周期?

在现代x86上,内核使用的时间源(内部和clock_gettime以及其他系统调用)通常是一个固定频率计数器,用于计算&#34;参考周期&#34;无论是涡轮增压,省电还是时钟停止空转。 (这是您从rdtsc__rdtsc() in C/C++获得的计数器。

普通std::chrono实现将在Unix上使用OS提供的函数,如clock_gettime。 (在Linux上,这可以纯粹在用户空间中运行,内核映射到每个进程的地址空间的VDSO页面中的代码+比例因子数据。低开销时间源很好。避免用户 - &gt;内核 - &gt;用户往返可以帮助解决Meltdown + Spectre缓解问题。)

分析一个没有内存限制的紧密循环可能需要使用实际的核心时钟周期,因此它对当前内核的实际速度不敏感。 (并且不必担心将CPU升级到最大涡轮增压等),例如使用perf stat ./a.outperf record ./a.out。例如Can x86's MOV really be "free"? Why can't I reproduce this at all?

有些系统没有内置等效的挂钟计数器计数器,因此操作系统会在RAM中维持时间,以便在计时器中断或时间更新时更新-query函数会从单独的芯片中读取时间。

(系统调用+硬件I / O =更高的开销,这是x86&#39; rdtsc指令从分析事物变为时钟源事物的部分原因。)

所有这些时钟频率最终都来自主板上的晶体振荡器。但是,可以调整从周期计数推断时间的比例因子,以使时钟与原子时间保持同步,通常使用网络时间协议(NTP),如@Tony指出的那样。

答案 1 :(得分:1)

  

问题1:cpu或gpu是否有任何其他方式来评估时间而不是计算周期?

不同的硬件可能提供不同的设施。例如,x86个人电脑已经采用了几种硬件设备进行计时:在过去十年左右,x86 CPU的处理频率为Time Stamp Counters,或者 - 最近 - 某些固定频率(“恒定速率”又称“不变”) TSC);可能有一个High Precision Event Timer,并且可以追溯到可编程中断定时器(https://en.wikipedia.org/wiki/Programmable_interval_timer)。

  

如果是这种情况,因为计算机计数循环的方式永远不会像原子钟一样精确,这意味着计算机的“秒”(句点= std :: ratio&lt; 1&gt;)实际上可以比实际秒更短或更大,导致计算机时钟之间的长时间测量差异,让我们说GPS。

是的,没有原子钟的计算机(它们现在可用on a chip)不会像原子钟一样准确。也就是说,像Network Time Protocol这样的服务可以让你在一堆计算机上保持更紧密的连贯性。

  

问题3:cpu和gpus测量的“循环计数”是否因硬件频率而异?

这取决于。对于TSC,较新的“恒定速率”TSC实现不会发生变化,其他情况会有所不同。

  

如果是,那么std :: chrono如何处理呢?

我希望大多数实现都能调用操作系统提供的时间服务,因为操作系统往往具有最佳的硬件知识和访问权限。有许多因素需要考虑 - 例如TSC读数是否在核心之间是同步的,如果PC进入某种睡眠模式会发生什么,在TSC采样周围需要什么样的存储器栅栏....

  

如果没有,周期对应什么(比如什么是“基本”时间)?

对于Intel CPU,请参阅this answer

  

有没有办法在编译时访问转换?有没有办法在运行时访问转换?

std::chrono::duration::count暴露了使用时间源的原始滴答计数,您可以duraction_cast到其他时间单位(例如秒)。预计C ++ 20将引入更多设施,如clock_cast。 AFAIK,没有constexpr转换可用:如果程序可能最终在TSC速率不同于编译机器的机器上运行,那么看起来也很可疑。