Performance 如何准确测量c+使用的时钟周期+;功能?

Performance 如何准确测量c+使用的时钟周期+;功能?,performance,benchmarking,Performance,Benchmarking,我知道我必须使用:rdtsc。测得的函数是确定的,但结果远非可重复的(我从一次运行到另一次运行得到5%的振荡)。 可能的原因有: 上下文转换 缓存未命中 你知道其他原因吗? 如何消除它们 有关现代多核多线程多进程机器上微观基准测试差异的论述,请参见问题 尽管问题是关于Java的,但这些注意事项适用于任何语言的基准测试 另见: 另请参见:添加到原因列表中:分支预测/预测失误(这可能会受到某些芯片上具有复杂预测缓存的上下文切换的影响。预测也可能会受到程序不同输入的影响,因此两个不同数据集的时间之

我知道我必须使用:rdtsc。测得的函数是确定的,但结果远非可重复的(我从一次运行到另一次运行得到5%的振荡)。 可能的原因有:

  • 上下文转换
  • 缓存未命中
你知道其他原因吗? 如何消除它们

有关现代多核多线程多进程机器上微观基准测试差异的论述,请参见问题

尽管问题是关于Java的,但这些注意事项适用于任何语言的基准测试

另见:


另请参见:

添加到原因列表中:分支预测/预测失误(这可能会受到某些芯片上具有复杂预测缓存的上下文切换的影响。预测也可能会受到程序不同输入的影响,因此两个不同数据集的时间之间的直接比较可能会略有偏差

一般来说,几乎不可能缓解所有这些问题,但您可以做一些事情来帮助每一个问题:

  • 缓存未命中:“主”在开始计时之前先运行缓存。别忘了还有一个指令缓存也需要启动。对于小数据集,只需在不计时的情况下运行整个测试一次,然后在计时的情况下再次运行。对于大数据集,请执行此操作,但随后使用处理器的预缓存指令将第一个数据块加载回缓存
  • 上下文切换:在负载较轻的系统上使用多处理器/核心芯片,并设置进程与特定CPU(最好不是CPU 0)的关联。这也有助于解决缓存未命中(因为移动CPU意味着缓存完全丢失)和分支预测(因为它实际上是缓存的一种形式)
但是,当然,到目前为止,进行这种计时的最佳方法是在非常大的数据块上进行多次计时,这样就可以将无法控制的事物所带来的可变性降至最低。(它永远无法真正消除。)

TSCs(rdtsc使用的)在多处理器系统上通常不同步。为了将进程绑定到单个CPU,设置CPU相关性可能会有所帮助

如果可用,您还可以从中获取时间戳,这不会出现相同的问题

至于可重复性,这些差异是真实的。您可以禁用缓存,为进程提供实时优先级,和/或(如果在Linux或类似的系统上)以较低的固定计时器中断频率(进行时间切片的频率)重新编译内核.您无法完全消除差异,至少不容易消除,而且在常规的CPU+OS组合上也无法消除差异

一般来说,出于易于编码、可靠性和可移植性的原因,我建议您使用操作系统必须提供的功能。如果它提供高精度计时器,请使用适当的操作系统助手

(万一你试图对加密系统进行时间攻击,那么,你将不得不面对1.这种随机性和2.出于正当理由使系统不可预测的一般防御,因此函数在时间上可能不确定。)

编辑:增加了一段关于操作系统可以提供的定时器的内容


编辑:这指的是Linux。要将进程绑定到单个CPU(以便准确读取RDTSC),您可以使用。这是我的一个项目中的一些代码,用于其他用途(将线程映射到CPU)。这应该是您的第一次尝试。对于HPET,您可以使用常规POSIX调用,例如,只要内核和机器支持这些计时器。

为什么要消除它们?听起来您已经创建了一个现实的基准测试。在野外使用时,该代码也会有同样的可变性。可能更糟,因为您可能已经使用了消除了磁盘和CPU缓存延迟。使用Jon Skeet的方法,创造能给您带来最佳结果的条件,只会给您带来让您感觉良好但永远无法实现的结果


如果绝对数很重要,请计算中位数,而不是平均值。

大多数现代处理器都支持一组显著的低级别硬件性能计数器。
如果您真的想知道答案,包括缓存未命中和上下文切换开销的实际测量值,请抓取,然后在一些(虽然不是所有)操作系统上安装一个内核补丁,然后,再加上一些额外的努力,您就可以关机并运行了。

事实上,在较新的Linux内核中有一个新的性能子系统。例如:

$ ./perf stat du -s /tmp 94796 /tmp Performance counter stats for 'du -s /tmp': 2.546403 task-clock-msecs # 0.060 CPUs 3 context-switches # 0.001 M/sec 0 CPU-migrations # 0.000 M/sec 166 page-faults # 0.065 M/sec 2434963 cycles # 956.236 M/sec 1798092 instructions # 0.738 IPC 302969 branches # 118.979 M/sec 26197 branch-misses # 8.647 % 23217 cache-references # 9.118 M/sec 4621 cache-misses # 1.815 M/sec 0.042406580 seconds time elapsed 美元/性能统计数据单位-s/tmp 94796/tmp “du-s/tmp”的性能计数器统计信息: 2.546403任务时钟毫秒#0.060 CPU 3个上下文开关#0.001米/秒 0 CPU迁移#0.000米/秒 166页错误#0.065米/秒 2434963次循环#956.236米/秒 1798092指令#0.738 IPC 302969支#118.979米/秒 26197家分行未命中率#8.647% 23217缓存引用#9.118米/秒 4621缓存未命中#1.815米/秒
0.042406580秒elapsedmedian看起来很健壮。但我不能忽略基准测试需要花费很长时间的情况。谢谢。如何将进程绑定到一个处理器?您是否有使用HPET的示例?@ukasz Lew:在最后一段中阐明了最佳方法和HPET。如果您正在测量时钟周期,为什么要消除缓存m基准测试中的ISSE和分支预测失误?这些失误也会“在野外”发生,因此查看整个发行版而不仅仅是最佳情况非常重要。您能提供链接或某些来源吗?