【问题标题】:std::chrono::clock, hardware clock and cycle countstd::chrono::clock,硬件时钟和周期计数
【发布时间】:2018-11-25 18:53:58
【问题描述】:

std::chrono 提供多个时钟来测量时间。同时,我想 CPU 评估时间的唯一方法是计算周期数。

问题 1:除了计算周期之外,cpu 或 gpu 是否有其他方法来评估时间?

如果是这样,因为计算机计算周期的方式永远不会像原子钟那样精确,这意味着计算机的“秒”(period = std::ratio<1>)实际上可能比实际的更短或更大其次,从长远来看,导致计算机时钟和 GPS 之间的时间测量存在差异。

问题 2:正确吗?

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

问题 3: cpu 和 gpus 测量的“循环计数”是否因硬件频率而异?如果是,那么std::chrono 是如何处理的?如果不是,那么一个周期对应于什么(比如什么是“基本”时间)?有没有办法在编译时访问转换?有没有办法在运行时访问转换?

【问题讨论】:

  • Fwiw,所有现代时计都是通过计算定期发生的事件来工作的。这一趋势始于 1656 年,当时第一个摆钟“计数”了摆动摆的摆动。随着时间的推移,这将改变石英晶体振动并最终改变为原子振动。但是几个世纪以来,基本的“通过计数来测量时间”方法一直保持不变。例外:最新的进展是让一个时钟询问另一组时钟现在几点,进行对话,并就正确时间达成共识。例如。这是 NTP。

标签: c++ time cpu benchmarking chrono


【解决方案1】:

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

在现代 x86 上,内核使用的时间源(在内部以及用于clock_gettime 和其他系统调用)通常是一个固定频率的计数器,它计算“参考周期”,而不管涡轮、省电或时钟-停了闲。 (这是您从rdtsc__rdtsc() in C/C++ 获得的计数器)。

正常的std::chrono 实现将使用操作系统提供的函数,例如 Unix 上的clock_gettime。 (在 Linux 上,这可以纯粹在用户空间中运行,代码 + 比例因子数据在由内核映射到每个进程的地址空间的 VDSO 页面中。低开销时间源很好。避免用户->内核->用户往返启用 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?


一些系统没有/没有内置在 CPU 中的与挂钟等效的计数器,因此操作系统会在 RAM 中维护一个时间,它会在定时器中断时更新,或者时间查询函数会从单独的芯片读取时间。

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

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

【讨论】:

    【解决方案2】:

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

    不同的硬件可能提供不同的设施。例如,x86 PC 使用了几种硬件设施来计时:在过去十年左右的时间里,x86 CPU 有Time Stamp Counters 以它们的处理频率运行,或者 - 最近 - 一些固定频率(“恒定速率”又名“不变” TSC) ;可能有一个High Precision Event Timer,并且可以追溯到更远的可编程中断定时器(https://en.wikipedia.org/wiki/Programmable_interval_timer)。

    如果是这样,因为计算机计数周期的方式永远不会像原子钟那样精确,这意味着计算机的“秒”(周期 = std::ratio)实际上可以比实际秒短或大,导致计算机时钟和 GPS 之间的时间测量长期存在差异。

    是的,没有原子钟的计算机(它们现在可用on a chip)不会像原子钟那样准确。也就是说,Network Time Protocol 等服务允许您在一堆计算机之间保持更紧密的一致性。有时可以通过使用Pulse Per Second (PPS) 技术来辅助。更现代和更准确的变体包括 Precision Time Protocol (PTP)(通常可以在 LAN 上实现亚微秒级精度)。

    问题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 速率的机器上,这似乎也很可疑。

    【讨论】:

      猜你喜欢
      • 2017-02-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-26
      • 1970-01-01
      • 1970-01-01
      • 2019-01-30
      相关资源
      最近更新 更多