哪个指标应该用于基准测试



当我对一些代码进行基准测试时,无论是在固定的输入数据集上,还是在随机性不影响控制流的随机输入上:用来评估代码性能的最佳指标是什么?

我总是在多次运行中使用最小运行时间,因为任何偏离最小运行时间的情况都是由于CPU忙于不相关的事情,但我找不到任何可靠的来源证实这是最佳实践。其他明显的选择是平均或中位数运行时间。(最大值看起来很奇怪,因为它可能会被无关的CPU峰值所主导。)有没有更好的方法来理解从几次运行中收集的统计数据?

正如paxdiablo所指出的,如果我可以直接测量CPU时间,那将是理想的。但是,当我只能基准计时时,我该怎么办呢?

正如我说的,我无法找到任何可靠的东西,但也许我只是没有找到正确的谷歌关键字,所以如果你能给我指出任何现有的,这将是一个很大的帮助。此外,请随意将其迁移到程序员。如果这个问题对SO来说太笼统了。

如果对CPU时间进行基准测试,有些系统会提供与已经过时间或超时时间无关的CPU使用情况。

你是对的,隔离时间可能会根据系统正在做的事情而变化,但这通常不会影响CPU时间。

例如,Linux(和其他类unix操作系统)中的time实用程序报告如下:

pax> time sleep 1
real    0m1.001s
user    0m0.000s
sys     0m0.000s

真正的时间是墙时间,一秒多一点。usersys时间是使用CPU的时间,在本例中是最小的,因为进程正在等待休眠结束(一个几乎不占用CPU时间的操作)。

如果你有这个设施,你应该使用它。

如果您没有这样的工具,那么您可能必须使用统计方法,例如最小化其他进程的CPU占用,并运行您自己的进程数百次以形成像样的图片。

无论你取平均值还是最小值(或者像去除异常值后的平均值这样奇怪的东西)将取决于你所遵循的统计学派。您应该选择最小值,如果您确定任何变化不是由于工作负载本身。

确保最小化其他负载非常重要。如果您有一个流氓进程占用了97%的CPU资源,那么与大多数空闲系统相比,最小值将大大向上倾斜(这就是为什么CPU时间比空闲时间好得多)。

我总是在多次运行中使用最小运行时间,因为任何偏离最小运行时间的情况都是由于CPU忙于不相关的事情,但我找不到任何可靠的来源证实这是最佳实践。其他明显的选择是平均或中位数运行时间。(最大值看起来很奇怪,因为它可能会被无关的CPU峰值所主导。)有没有更好的方法来理解从几次运行中收集的统计数据?

Chen, J. and Revels, J., 2016。噪声环境下的鲁棒基准测试。arXiv预印arXiv:1608.04295。对如何进行稳健的基准测试有一些适度广泛和数学上合理的论点。简单的版本是:使用最小值

如你所料,因为它归结为:噪音只会让东西跑得更慢,永远不会更快。因此,minimum而不是meanmedian是真实时间的最佳估计量。由于模型是true_time + noise,其中noise是非负的,因此最小的样本必须具有最小的误差(因为true_time在样本之间不会改变,只有噪声)。

通常最小值和中值应该非常相似,除非它非常嘈杂。如果您假设其他负载实际上是嘈杂的,并且不是恒定的,并且您的基准测试不是很长,它可以平均变化,那么检查这一点可以很好地告诉系统对于基准测试来说不是太嘈杂。

偶尔(特别是对于微基准测试),即使在大部分空闲的系统上,您也会发现一个低异常值。如果我手工运行几次测试,我通常会忽略这一点,并且取集群中可重复结果中最少的数字。如果系统非常嘈杂,则中位数可能不在最低的集群中,但希望是一组快速结果有点相似的集群。这就是你想要的;正如Lyndon所指出的,噪音(其他负载、中断、缓存污染)只会让事情变慢。

(虽然我认为这样的低异常值通常是真实的,就像一些快乐的巧合对齐的东西,以避免分支混叠,或巨大的页面排列良好,或IDK什么。甚至可能是CPU指令调度的某种元稳定平衡,它可能被干扰并下降到低吞吐量状态。同样,这是为了在大部分空闲的系统上获得不可重复的良好性能。


OTOH,这取决于你的基准测试,这可能没有意义。如果您的代码运行的实际条件将涉及内存带宽和缓存的竞争,和/或I/O,代码具有更差的"最佳情况";但受噪音影响更小,整体效果会更好。

。你可能会有一个非常快的算法,它真的依赖于在缓存中有20mb的热数据。如果其他内核上的其他线程通常会"污染"缓存(包括来自云主机中相同硬件上的其他虚拟机),这实际上不是最好的选择,即使它偶尔运行得非常快。

在最佳情况下使用更多CPU周期的代码(例如,通过压缩或重新计算数据,而不是巨大的查找表或未压缩的缓存)在平均现实条件下可能是最好的。

或者使用多线程或其他东西来解耦/管道一些处理步骤的代码可能会有更多的开销,在最好的情况下会更慢,但在一般情况下更能适应噪声,更好。

如果情况可能不同,请注意针对基准而不是实际系统条件进行调优。一般来说,尽量编写不过度消耗共享资源的代码,如内存带宽;例如,对于大数组的数字运算,缓存块通过在适合单个核心的L2缓存的块上执行多个步骤,因此您不会在每次传递整个数据集时从共享L3或主存重新读取。

相关内容

  • 没有找到相关文章

最新更新