std::chrono::clock、硬件时钟和周期计数

6

std::chrono提供了几个时钟来测量时间。同时,我猜测计算机评估时间的唯一方式就是通过计数周期。

问题1:除了计数周期之外,CPU或GPU还有其他评估时间的方式吗?

如果是这种情况,因为计算机计数周期的方式永远不会像原子钟那样精确,这意味着对于计算机时钟和GPS等其他设备的时间测量,在长期内可能会存在“秒”(period = std::ratio<1>)比实际秒更短或更长的情况。

问题2:这个说法正确吗?

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

问题3:CPU和GPU测量的“周期计数”是否取决于硬件频率?如果是,那么std::chrono如何处理?如果不是,一个周期代表什么(例如什么是“基本”时间)?是否可以在编译时访问转换?是否可以在运行时访问转换?


https://superuser.com/questions/253471/how-is-time-measured-in-computer-systems - Ripi2
2
值得一提的是,所有现代计时器都通过计算定期发生的事件来工作。这种趋势始于1656年第一台摆钟,它“计数”摆动的摆动。随着时间的推移,这种计数方式会改变为石英晶体振动,最终转变为原子振动。但是,基础的“通过计数来测量时间”的方法已经保持了几个世纪。除了:最新的进展是让一个时钟询问另一组时钟现在是什么时间,进行交流,并达成正确时间的共识。例如,这就是NTP。 - Howard Hinnant
2个回答

6

计算循环次数,是的,但是循环的是什么?

在现代的x86架构中,内核使用的时间源(对于clock_gettime和其他系统调用)通常是定期读取的中断计时器或硬件定时器(例如HPET)。 (实际上我并不清楚细节; 当我写这篇文章时,我认为一切都是基于rdtsc,但我认为那并不正确。)如果有网络连接,通常会使用NTP来校正比例因子以保持系统时间正确。

细粒度计时来自一个固定频率的计数器,它计算"参考周期",无论是涡轮增压、省电还是停止闲置的时钟。 (这是你从rdtsc__rdtsc()得到的计数器,在C/C++中,更多细节请参见此处,例如在旧CPU上,它实际上确实计算了核心时钟周期,并且在睡眠状态下不会tick,因此对于墙钟时间来说没有那么有用。)

正常的std::chrono实现将使用类似于POSIX clock_gettime的操作系统提供的函数。

在Linux上,这可以在用户空间中运行。内核将VDSO页面中的代码+数据映射到每个进程的地址空间中。数据包括由计时器中断更新的粗略时间戳(CLOCK_REALTIME_COARSECLOCK_MONOTONIC_COARSE直接返回这些数据,我想),以及使用TSC获取与系统时钟最后一个tick的微调偏移量的偏移量和比例因子。低开销的时间源很好。避免用户->内核->用户的往返会有很大帮助,特别是在启用Meltdown + Spectre缓解措施后,因为这使得真正的系统调用变得更加昂贵。

对于不是内存绑定的紧密循环进行分析可能需要使用实际的核心时钟周期,以使其不受当前核心实际速度的影响。(也不必担心将CPU升级到最大涡轮增压等问题。)例如使用perf stat ./a.outperf record./ a.out 。例如x86的MOV真的可以“免费”吗?我为什么完全无法复制它?


有些系统没有/没有内置到CPU中的墙钟等价计数器,因此你只能使用更新在RAM上的粗略时间或从一个单独的芯片读取高精度时间查询函数。

(System call + 硬件I/O = 更高的开销,这也是x86的rdtsc指令从性能剖析工具变成时钟源的部分原因。) 所有这些时钟频率最终都来自主板上的晶体振荡器。 但是,用于从循环计数中推算时间的比例因子可以调整以使时钟与原子时间保持同步,通常使用网络时间协议(NTP),如@Tony所指出的那样。

2
问题1:CPU或GPU有没有其他方法来评估时间,而不是通过计算周期?
不同的硬件可能提供不同的设施。例如,x86 PC已经采用了几种硬件设施来计时:在过去的十年左右,x86 CPU使用处理频率或更近期的一些固定频率(“恒定速率”或“不变”TSC)运行时间戳计数器;可能会有高精度事件计时器,更早以前还有可编程中断计时器(https://en.wikipedia.org/wiki/Programmable_interval_timer)。
如果是这样的话,因为计算机计算周期的方式永远不会像原子钟那样精确,这意味着计算机的“秒”(周期=std::ratio<1>)实际上可能比实际秒钟短或长,导致计算机时钟和GPS等之间的时间测量在长期内存在差异。
是的,没有原子钟的计算机(现在可以使用芯片on a chip)不会像原子钟那样准确。尽管如此,诸如Network Time Protocol之类的服务使您能够在一堆计算机之间保持更紧密的协调。有时还可以辅助使用Pulse Per Second (PPS)技术。更现代和准确的变体包括Precision Time Protocol (PTP)(它通常可以在局域网上实现亚微秒的精度)。

问题3:CPU和GPU测量的“周期计数”是否因硬件频率而异?

这取决于具体情况。对于TSC,新的“恒定速率”TSC实现不会变化,其他实现则可能会变化。

如果是,则std::chrono如何处理它?

我会期望大多数实现调用操作系统提供的时间服务,因为操作系统往往具有最好的硬件知识和访问权限。需要考虑很多因素,例如TSC读数是否在核心之间同步,如果PC进入某种睡眠模式会发生什么,TSC抽样周围希望采用何种内存栅栏等等。
如若没有,一个周期对应多长时间(像是什么是“基本”时间)?
对于英特尔CPU,请参见this answer
是否有一种方法可以在编译时访问转换?是否有一种方法可以在运行时访问转换?
std::chrono::duration::count”公开了所使用的时间源的原始滴答计数,您可以使用“duration_cast”将其转换为其他时间单位(例如秒)。预计C++20将引入进一步的工具,如“clock_cast”。据我所知,没有可用的constexpr转换:如果程序可能在与编译它的机器不同的TSC速率的机器上运行,那么这似乎也是可疑的。

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