首页 > 解决方案 > 周期计数本身在程序时间上是否可靠?

问题描述

我目前正在尝试开发一个判断系统,它不仅可以测量时间和内存使用情况,还可以测量更深层次的信息,例如缓存未命中等,我认为硬件计数器(使用 perf)非常适合它。

但是对于计时部分,我想知道纯粹使用循环计数来确定执行速度是否足够可靠?希望了解这个决定的利弊。

标签: performance-testingtimingperf

解决方案


所以你建议测量CPU周期,而不是秒?听起来有些合理。

对于一些很好的微基准测试,主要考虑了由于 CPU 频率变化引起的变化。(如果你只计算用户空间周期,如果你正在对一个不进行系统调用的循环进行微基准测试,那么由于中断而导致的延迟。只有中断的次要影响是可见的,即序列化管道并可能驱逐你的一些来自缓存 / TLB 的数据。)

但是内存(可能还有 L3 缓存)在 CPU 频率变化时保持恒定速度,因此缓存未命中的相对成本会发生变化:相同的响应时间(以纳秒为单位)是更少的核心时钟周期,因此乱序 exec 可以隐藏更多它更容易。 相对于内核可以使用的内存带宽,可用内存带宽更高。 所以硬件预取更容易跟上。

例如,在 4.3GHz 时,在 L2 缓存中丢失但在 Skylake 服务器上的 L3 中命中的负载可能具有大约 79 个核心时钟周期的总延迟。(https://www.7-cpu.com/cpu/Skylake_X.html - i7-7820X(Skylake X),8 核)。

在 800MHz 空闲时钟速度下,L2 高速缓存未命中仍为 14 个周期(因为它以核心速度运行)。但是,如果另一个内核将 L3 缓存(以及一般的非内核)保持在高时钟速度,则该往返请求的非内核部分将需要更少的内核时钟周期。

例如,我们可以通过假设 L3 命中与 L2 命中的所有额外时间都花费在非核心而不是核心中来进行粗略计算,并且需要固定的纳秒数。由于我们以 4.3GHz 时钟周期计算,因此计算得出14 + (79-14)*8/43的 L3 命中周期为 800MHz = 26 个周期,低于 79 个周期。

这个粗略的计算实际上与 7-cpu.com 的数字相匹配,相同的 CPU 具有 3.6GHz 的内核:L3 缓存延迟 = 68 个周期。 14 + (79-14)*36/43 = 68.4.

请注意,我选择了“服务器”部分,因为不同的内核可以以不同的时钟速度运行。在 i7-6700k 这样的“客户端”CPU 中,情况并非如此。非核心(L3、互连等)可能仍然能够独立于核心而变化,例如为 GPU 保持高位。此外,服务器部件在核心之外具有更高的延迟。(例如,禁用 turbo 的 4GHz Skylake i7-6700k 的 L3 延迟只有 42 个核心时钟周期,而不是 68 或 79。)

另请参阅为什么 Skylake 在单线程内存吞吐量方面比 Broadwell-E 好得多?了解 L3 和内存延迟为何/如何影响最大可能的单核内存带宽


当然,如果您通过允许一些预热来控制 CPU 频率,或者对于运行时间超过微不足道的任务,这没什么大不了的。

(虽然请注意,Skylake 有时会在非常受内存限制时降低时钟速度,不幸的是,这会进一步损害带宽,默认为 energy_performance_preference = balance_power,但“balance_performance”或“performance”可以避免这种情况。 通过强制降低 CPU 频率记忆压力

请注意,仅计算周期不会消除上下文切换的成本(切换回此线程后额外的缓存未命中,并且耗尽 ROB 很糟糕)。或者来自其他内核对内存带宽的竞争。

例如,在同一物理内核的另一个逻辑内核上运行的另一个线程通常会严重降低 IPC。总体吞吐量通常会增加一些,具体取决于任务,但单个每个线程的吞吐量会下降。

Skylake 有一个用于跟踪超线程竞争的性能事件:cpu_clk_thread_unhalted.one_thread_active- IIRC,当您的任务正在运行并且拥有全部核心时,事件计数会以 24MHz 的速度递增。因此,如果您看到的比这少,您就知道您遇到了一些竞争,并且花了一些时间来处理 ROB 分区并与另一个线程交换前端周期。


所以有一堆效果,由你决定它是否有用。 按核心时钟周期排序结果听起来很合理,但您可能应该在结果中包括 CPU 秒(任务时钟)和平均频率,以帮助人们发现异常值/故障。


推荐阅读