是使用规范工作负载所花费的总时间作为基准还是计算各个操作所花费的周期/时间?



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

运行相关操作的每次迭代的时间可能很快,可能为 300-500 纳秒。

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

如果您认为运行时可能依赖于数据,并且想要查看迭代之间的差异,则可以考虑以某种方式记录时间戳。 但是在 3.3GHz CPU 上,300 ns 只是 ~1k 个时钟周期,记录时间戳需要一些时间。 因此,您绝对需要担心测量开销。


假设你在 x86 上,每个操作周围的原始rdtsc非常轻量级,但乱序执行可以对时间戳进行重新排序。 获取 CPU 周期计数?,并通过 C 函数使缓存行失效。

阻止计时在工作负载的每次迭代中重新排序lfence; rdtsc; lfence将阻止工作负载步骤的无序执行,从而扭曲事情。 (Skylake 上的无序执行窗口为 224 uops 的 ROB 大小。 每个时钟 4 个,这只是 1k 个时钟周期的一小部分,但在具有缓存未命中停滞的低吞吐量代码中,独立迭代之间可能存在显着重叠。

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


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

最新更新