分析代码以提高效率?

14

你使用哪些工具来确定代码的效率?你使用自己编写的应用程序运行大量测试,还是使用商业产品?你使用自己的知识来测试代码的某些部分,还是使用分析代码弱点的工具?

9个回答

34

插入内容: 让我们来看看"统计学意义"。

假设有一个函数调用指令。您可能看不到它 - 一个类,或者一个宏,或者编译器可能已经添加了它。附近还有其他对同一函数的调用,但是这次的调用在一个循环中,或者其参数使得该调用需要较长时间才能完成。实际上,如果可以使该调用时间为零,那么总执行时间将减少一定量,比如90%。(不可能吗?完全不是这样。) 时间可以确定它吗?不能。调用图可以确定它吗?不能。调用计数可以确定它吗?不能。因为问题不在函数级别上,而在调用指令级别上。

不知何故程序在某个时间点随机停止,并检查其状态。它是否会在那90%节省下来的时间内停止?当然会 - 有90%的概率,而该指令将被定位在堆栈上等待“工作”的完成。

事实上,如果您随机停止20次,该指令将平均出现18次,标准偏差为+/-1.3倍。

这是否具有统计学意义呢?当然有。
您是否需要大量样本?当然不需要。

假设比例很小,例如10%或5%。相同的原则适用。

事实上,无论采取多少样本,任何出现在>1个样本中的指令都具有统计学意义,并且是“热点”、“瓶颈”或其他任何您想称之为的东西。如果可以删除它、减少调用次数或以某种方式减少它,则节省大量时间。(像“call _main”这样的一些你无法处理,但对于其他一些,你只需要找到它们。)

当然,我的代码永远不会如此愚蠢,是吗?那好吧,证明一下

好了,现在回到故事中...

原始回答:我很早以前就听说过分析器,认为它们一定很棒,但我没有使用它们/它。当时我正在处理嵌入式处理器(8086英特尔芯片),似乎在屏幕上绘制一些浮点数需要很长时间。硬件工程师建议我提供计时器芯片,以便我可以看到所需时间。然而,有一个周末我使用英特尔“蓝盒子”电路模拟器启动了它并使其运行。在它运行缓慢时,我想知道“它到底在做什么?”。因此,我将其暂停以查明情况。PC位于浮点库中(没有FP芯片)。这不足为奇,因为它正在绘制浮点数,但我想要更多信息。因此,我费力地读取HEX存储器以跟踪调用堆栈。你猜怎么着?它正在处理数字以绘制下一个数字,即除以10,转换为整数,再转换为浮点数,然后相减,等等。只是为了获取下一个要绘制的数字。不用说,有更好的方法来做那件事,结果加快了约10倍。 那是通过一个(1)样本发现的!

另一次,在68K芯片上,出现了一些缓慢。同样,没有分析器可用,但有调试器“adb”,所以在它运行缓慢时,我暂停了几次。PC位于数学库中,实际上在32位整数乘法例程中。查找堆栈,我发现了这段代码:

struct {...} a[...];

int i;
for (i = 0; i < ...; ++i){ ... a[i] ... }

这里并没有调用乘法,到底发生了什么?原来,对于 a[i],编译器必须将 i 乘以数组元素大小。由于 i 是一个 32 位的变量(在该编译器中),它会生成一个调用 32 位乘法例程的指令,并且堆栈会定位到该调用指令。通过将 i 声明为 short,循环的速度增加了三倍!

有什么意义呢?如果你在程序运行缓慢时随机取样,计算机会告诉你它在做什么,但是调用堆栈会告诉你 为什么,并直接引导你找到问题所在。现在,除非问题真的很严重,你可能需要进行多次采样。出现在 >1 个样本中的任何语句都是可疑的语句。请注意,它定位到的是 语句、甚至是 指令,而不是像函数那样的大块代码。虽然这种技术可能有些 "快速而肮脏",但确实非常有效。 这种技术

添加:如果你反复这样做,可以在同一个软件中解决问题。例如,如果你获得了 3 倍的速度提升,可能以前不重要的小性能问题现在会消耗剩余时间的三倍。这使得它们更容易被采样到。你可能需要添加一个临时的外部循环,以使其运行足够长的时间进行采样。通过这种方式,我曾经看到过超过 40 倍的增速因子


8
这项技术确实有效。我是通过另一个Stack Overflow的帖子https://dev59.com/n3RC5IYBdhLWcg3wOOL1在本周发现它的,并在我所开发的一个被许多内部和外部用户使用的应用程序上进行了尝试。在第一次迭代中,结果是整体加速了7倍(!) - 在一个特定的(典型)数据集上,从16.5分钟缩短到2.2分钟。 - Peter Mortensen
1
@Peter:你需要采集多少个堆栈样本才能找到问题?如果你实现了七倍的加速,那么每个样本至少有六七的概率显示它。 - Mike Dunlavey
2
@Mike Dunlavey: 我只需要3-4个。当时已经很清楚了。在下一轮迭代中,我试了20个,这给了我一个想法进行更改,导致应用程序中另一种操作模式(事实上是整个应用程序中最耗时的操作)的速度提升了3.3倍 (http://msquant.sourceforge.net/)。 - Peter Mortensen
@Peter:看起来这是一个非常有趣的产品。 - Mike Dunlavey

17

这被称为性能分析。有许多现成的工具可用于帮助您确定应用程序中各种不同语言的瓶颈在哪里。例如,针对Java编写的TPTP工具集,如果需要,可以显示性能瓶颈在单个方法级别上的位置。当然,有时候您只需要多次读取系统计时器,就可以对代码段进行大致估计。


3

性能分析工具非常有用,可以帮助你看出你花费最多时间的代码。通常情况下,有许多专门针对特定平台/开发环境的性能分析工具。

对于小规模的情况,我使用了简单的计时器来测量代码执行时间(动作结束时系统时间减去动作开始时系统时间)。

一个重要的原则是:不要假设你刚刚优化的性能一定会更快。一定要进行验证!


2
我使用Valgrind及其工具Callgrind。这是一个很棒的工具。Valgrind基本上是一个虚拟机:
Valgrind本质上是一种虚拟机,使用即时编译(JIT)技术,包括动态重新编译。原始程序中的任何内容都不会直接在主机处理器上运行。相反,Valgrind首先将程序转换为称为中间表示(IR)的临时、更简单的形式,这是一种处理器中立的、基于SSA的形式。在转换之后,一个工具(见下文)可以在IR上执行任何所需的转换,然后Valgrind将IR重新转换为机器代码,并让主机处理器运行它。尽管它可以使用动态翻译(即,主机和目标处理器来自不同的架构),但它并没有这样做。Valgrind重新编译二进制代码以在相同架构的主机和目标(或模拟)CPU上运行。
Callgrind是建立在此基础上的性能分析器。其主要优点在于您无需运行应用程序数小时即可获得可靠的结果。几秒钟就足够了,因为Callgrind是一种非侵入式分析器。
另一个建立在Valgrind之上的工具是Massif。我用它来分析堆内存使用情况。它非常出色,可以给您提供内存使用的快照--详细信息包括谁占用了多少内存以及是谁将其放在那里。
还有一个Valgrind工具--DRD(和Helgrind)。我用它们来跟踪代码中的死锁和数据竞争,以及线程API的滥用。

2

我使用工具来完成这项工作。否则,我发现自己用手很难完成...(好吧,这是我的观点,我实际上从未尝试过)

在Linux上,我使用Valgrind,它带有一些有用的工具来分析您的代码。就Valgrind主页而言:

它可以运行在以下平台上:X86/Linux、AMD64/Linux、PPC32/Linux、PPC64/Linux。

而且它是免费的(就像免费啤酒一样),并且是开放源代码的。

虽然我没有太多使用过它们,但在另一个平台上,您可以使用Purify/Quantify(IBM产品)。它们是商业工具。正如Will所报道的那样,它们包含在PurifyPlus软件包中,Quantify将帮助您分析应用程序性能。

这就是我使用的全部内容... :-)


我认为 Purify 与 Quantify 相关,Quantify 是一种分析器。尽管我不确定,但它们都是 PurifyPlus 的一部分。 - Will Mc
好的点子。谢谢你,威尔!我会用你的评论更新问题。 - yves Baumes

2
说实话,我使用 NUnit。如果我的代码运行时间过长或似乎不够可扩展,我会编写一个测试来模拟应用程序中表现不佳的部分。然后我会考虑在代码中进行强大的替换,以减少运行时间,并验证我没有破坏任何东西。
如果这仍然无法满足您的需求,那么您需要找到并应用性能分析器,但至少您将拥有一个测试用例,可以在不必打开/加载应用程序的情况下尝试您的假设,并跟踪与任务无关的元素的调用。

1
你可以使用MbUnit来精确计算每个测试执行所需的时间。然而,对于运行时分析,ANTS Performance Profiler比任何单元测试框架都更有效。 - Vadim
是的,我同意你需要两个工具。一个用来识别热点,另一个用来确保减少计算量的变化不会导致操作失误。 - MikeJ

1

我听说Yourkit在Java性能分析方面很不错。对于网站,我尝试过JMeter,它具有简单参数化分析的基本功能。


1
问题含糊不清。是从运行时间还是内存占用的角度来看“效率”?特定代码片段的运行环境、应用程序的架构以及可能传递给它的数据也都是影响因素。
另外顺带一提,有人提到了Purify;此外还有它的姐妹产品Quantify。

0

对于.NET,我建议使用NDepend


我原本认为NDepend更适用于静态代码分析。现在它也具备了运行时性能检测的功能? - MikeJ
@MikeJ,你说得对,NDepend用于静态代码分析。 我认为问题并不特定于运行时。顺便说一下,在我的工作中,我们使用ANTS性能分析器(http://www.red-gate.com/products/ants_performance_profiler/index.htm)进行运行时分析。 - Vadim

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