基准测试和性能分析的区别

40

我看到术语 软件基准测试性能剖析 有时被交替使用,但据我理解它们之间有微妙的区别。

两者都与时间有关。但是,基准测试主要是确定可以与其他应用程序进行比较的某个速度得分,而剖析则提供有关应用程序在哪些地方花费大部分时间(或周期数)的确切信息。

对我来说,集成测试是基准测试的对应物,单元测试是剖析的对应物。但是微基准测试如何适合其中呢?

有人在这里陈述:这里

剖析和基准测试是同一枚硬币的两面,剖析可帮助您缩小优化最有用的范围,基准测试允许您轻松隔离优化并进行交叉比较。

还有一个人在这里谈到了剖析:

剖析在不同的时间意味着不同的事情。有时它意味着测量性能。 有时它意味着诊断内存泄漏。 有时它意味着获得多线程或其他低级别活动的可见性。

那么,这些技术在概念上是否不同,还是只是没有那么黑白分明?

4个回答

47

基准测试是衡量某个整体操作时间的东西,例如在某种工作负载下每秒 I/O 操作次数。因此,结果通常是一个单一的数字,以秒或每秒操作次数为单位。也可以是一组包含不同参数结果的数据集,这样可以绘制图表。

您可以使用基准测试来比较不同硬件上相同软件或与您的基准测试交互的其他软件的不同版本。例如,使用不同 Apache 设置基准测试每秒最大连接数。


性能分析不是用于比较不同的东西:它是用于理解程序行为的。 性能分析结果可能是每个函数所花费的时间表格,或者使用采样分析器甚至可以是每个指令。你可以通过区分基准测试和性能分析来判断,因为“那个函数所花费的时间最短,所以我们将保留它并停止使用其他函数”是没有意义的。

阅读维基百科文章以了解更多信息:https://en.wikipedia.org/wiki/Profiling_(computer_programming)

您使用性能分析来确定优化的位置。在程序花费 99% 时间的函数中获得 10% 的加速比在任何其他函数中获得 100% 的加速比更有价值。甚至更好的是,当您可以改进高级设计以减少对昂贵函数的调用时,以及使其更快。


微基准测试是基准测试的一种特定形式。这意味着您正在测试一个超级具体的东西,以单独测量它,而不是真正有用的任何东西的整体性能。

示例微基准测试结果:

非微基准结果示例:

  • 使用7-zip(具有特定选项和硬件)压缩这100MB文件集需要23秒。
  • 在某些硬件/软件组合上编译Linux内核需要99秒。

另请参见https://en.wikipedia.org/wiki/Benchmark_(computing)#Types_of_benchmarks

微基准测试是基准测试的一种特殊形式。如果你做得对,它能告诉你哪些操作是昂贵的,哪些是廉价的,这有助于你在尝试优化时。如果你做错了,你可能根本没有测量到你想要测量的东西。例如:你编写了一些C代码来测试循环和while循环,但编译器出于不同的原因生成了不同的代码,你的结果就毫无意义了。(使用现代的优化编译器,用不同的方式表达相同的逻辑几乎不会产生影响;不要浪费时间在这上面。)微基准测试很难。

另一种判断它是微基准测试的方法是通常需要查看编译器的汇编输出,以确保它正在测试你想要测试的内容(例如它没有优化重复10M次循环中的某些昂贵操作,而这个循环应该重复足够多次才能准确地测量持续时间)。

微基准测试可能会扭曲事实,因为它们使用热缓存和预取分支预测器来测试你的函数,而且在调用被测试的代码之间不运行任何其他代码。这可能使大量展开的循环看起来很好,但在一个真正的程序中,它会导致更多的缓存未命中。同样地,它使大型查找表看起来很好,因为整个查找表都在缓存中。但在完整程序中,通常会在调用函数之间脏读足够多的缓存,查找表并不总是命中缓存,所以计算某些东西通常比查找它要快。(大多数程序都是受内存限制的。重新计算不太复杂的内容通常与查找它一样快。)


感谢您抽出时间。但是我的困惑始于微基准测试 - 这是否意味着我只对程序的某个特定函数进行基准测试?那么,与仅对某个函数进行“分析”有何区别? - Jim McAdams
@JimMcAdams:是的,这正是微基准测试的全部内容:重复执行相同的工作。在分析结果中,深入到单个函数,希望能够按行或指令显示总时间的百分比。(或者按指令而非源代码来看待,因为在这种粒度下,汇编代码的样子比源代码更重要)。或者您可以记录缓存未命中而不是时钟周期进行分析。 - Peter Cordes
很好的回答,(我正在努力学习如何清晰地解释事情),你有练习过教学吗?:) - 0xc0de
1
@0xc0de。是的,我喜欢分享我的知识,无论是在我的许多(长而详细的:) SO答案中,还是在玩极限飞盘或其他事情时。 - Peter Cordes

5
一个基准测试可以帮助您观察系统在负载下的行为,确定系统的容量,了解哪些更改很重要,或查看您的应用程序如何处理不同的数据。性能分析是衡量和分析时间消耗的主要手段。性能分析包括两个步骤:测量任务和经过的时间,以及聚合和排序结果,使重要任务浮现出来。--High performance MySQL 我的理解是:基准测试是了解您的应用程序的度量标准,而性能分析是改进您的应用程序的度量标准。

感谢您抽出时间。那么微基准测试意味着您将更加了解您的应用程序?但这有什么好处呢? - Jim McAdams
我认为微基准测试意味着你可以在特定方面或关键点了解你的应用程序,而不仅仅是一点点。 - lfree

3
通常人们使用性能分析不是为了衡量程序的速度,而是为了找出如何使其更快。
通常他们这样做的假设是,通过测量特定函数或代码行所花费的时间来发现缓慢的原因是最好的方法。
有一种清晰的思考方式:如果一个函数或代码行显示出一个包含百分比的时间,那么它就是如果该函数或代码行可以被设置为零时间(通过不执行它或将其传递给一个无限快的处理器)所节省的时间的分数。
除了函数或代码行之外,还有其他可能需要时间的事情。这些是程序正在做的描述,但它们不是唯一的描述。
假设您运行了一个性能分析器,每隔N秒实际时间(而不仅仅是CPU时间)收集程序状态的样本,包括调用堆栈和数据变量。调用堆栈不仅仅是函数名称的堆栈 - 它还是调用这些函数的调用站点的堆栈,通常包括参数值。然后假设您可以检查并描述每个样本。
例如,样本的描述可以是:
  • 当需要时,例行程序X正在分配内存以初始化用于记录患者的字典,该字典由例行程序Q使用。

  • 程序正在读取dll文件以提取字符串资源,该资源将在调用堆栈中的多个级别上用于填充进度条中的文本字段,以告诉用户程序为什么需要这么长时间 :)

  • 程序正在调用带有特定参数的函数F,并且之前已经使用相同的参数调用过,得到了相同的结果。这表明可以记住先前的结果。

  • 程序正在调用函数G,该函数正在调用函数H以解密G的参数选项标志。程序员知道这些标志始终相同,因此建议使用特殊版本的G来节省时间。

  • 等等等等。

这些是可能的描述。如果它们占据了F百分比的时间,那么每个样本符合该描述的概率就是这个概率。更简单的描述如下:

  • 例程或代码行X出现在Q%的堆栈样本中,这是包含百分比
  • 例程D在R%的堆栈样本中紧接在例程E上方。该数字可以放在从D到E的调用图弧线上。
  • 堆栈序列main->A->B->C->D->E是出现在最多样本中的序列。那就是“热路径”。
  • 在堆栈底部最常出现的例程是T。那是“热点”。

大多数分析工具只提供这些简单的描述。 一些程序员理解检查样本本身的价值,以便他们可以更语义化地描述程序为什么花费时间。 如果目标是准确测量由特定描述引起的时间百分比,则必须检查大量样本。 但是,如果描述出现在少量样本的大部分分数中,则没有准确测量它,但是人们知道它很大,并且已经准确找到。 看到区别了吗? 您可以权衡测量精度和加速查找的能力。

那就是随机暂停背后的原理,统计学上的证明在这里

1

一个简介的例子

import cProfile
import re
cProfile.run('re.compile("foo|bar")')

输出

    197 function calls (192 primitive calls) in 0.002 seconds

Ordered by: standard name

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    0.000    0.000    0.001    0.001 <string>:1(<module>)
     1    0.000    0.000    0.001    0.001 re.py:212(compile)
     1    0.000    0.000    0.001    0.001 re.py:268(_compile)
     1    0.000    0.000    0.000    0.000 sre_compile.py:172(_compile_charset)
     1    0.000    0.000    0.000    0.000 sre_compile.py:201(_optimize_charset)
     4    0.000    0.000    0.000    0.000 sre_compile.py:25(_identityfunction)
   3/1    0.000    0.000    0.000    0.000 sre_compile.py:33(_compile)

https://docs.python.org/3.10/library/profile.html?highlight=profile#module-profile

性能分析模块旨在为给定程序提供执行概要,用于基准测试目的。对于基准测试,有timeit可提供相当准确的结果。这尤其适用于将Python代码与C代码进行基准测试:分析器会为Python代码引入开销,但不会为C级函数引入开销(不公平!),因此C代码似乎比任何Python代码都要快。对于大多数用户,建议使用cProfile;它是一个带有合理开销的C扩展,适用于对长时间运行的程序进行性能分析。基于lsprof。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接