最好使用规范工作负载所花费的总时间作为基准,还是计算单个操作所花费的 cycles/time?

Is it preferable to use the total time taken for a canonical workload as a benchmark or count the cycles/time taken by the individual operations?

我正在为关键系统操作设计基准。理想情况下,基准可用于检测性能回归。我正在争论是使用传递给操作的大工作负载的总时间还是计算操作所用的周期作为基准的测量标准。

运行 所讨论操作的每次迭代的时间很快,可能是 300-500 纳秒。

总时间更容易准确/可靠地测量,并且测量开销无关紧要。这是我推荐的,只要你确定你可以阻止你的编译器对你正在测量的任何迭代进行优化。 (必要时检查生成的 asm)。

如果您认为 运行 时间可能依赖于数据并且想要研究迭代之间的变化,那么您可能会考虑以某种方式记录时间戳。但是 300 ns 在 3.3GHz CPU 上只有约 1k 个时钟周期,并且记录时间戳需要一些时间。所以你肯定需要担心测量开销。


假设您使用的是 x86,围绕每个操作的原始 rdtsc 非常轻量级,但乱序执行可以重新排序工作的时间戳。 Get CPU cycle count?, and .

lfence; rdtsc; lfence 停止在工作负载的每次迭代中重新排序的计时将阻止工作负载步骤的无序执行,从而扭曲事物。 (Skylake 上的乱序执行 window 是 224 微指令的 ROB 大小。每个时钟 4 个,这只是 1k 时钟周期的一小部分,但在低吞吐量代码中,缓存未命中可能会出现停顿独立迭代之间的显着重叠。)

像 C++ std::chrono 这样的任何标准计时函数通常会调用最终使用 rdtsc 的库函数,但有许多额外的指令。或者更糟的是,将进行一个实际的系统调用 enter/leave 内核,并且在启用 Meltdown+Spectre 缓解措施的情况下会花费超过一百个时钟周期。


但是,可能有用的一件事是使用 Intel-PT (https://software.intel.com/en-us/blogs/2013/09/18/processor-tracing) 来记录所采用分支的时间戳。在完全不阻塞无序执行的情况下,您仍然可以获得有关重复循环中的循环分支何时执行的时间戳。这很可能与您的工作量无关,并且能够 运行 在其发布到核心的无序部分后不久,但这只能在最旧的尚未退休的指令之前发生有限的距离.