您使用哪种工具来确定代码的效率?您是否使用运行统计上大量测试的本土应用程序或某些商业产品?您是否使用自己的知识来测试代码的某些区域,或者使用某种工具来分析代码中的弱点?
答案 0 :(得分:27)
INSERTED:让我们来看看“统计意义”。
假设某处有一个函数调用指令。你不一定能看到它 - 一个类,一个宏,或者编译器,可能已经把它搞砸了。 附近还有对同一函数的其他调用,但是这个调用是循环的,或者它的参数使得这个调用需要很长时间。实际上这么多时间,如果这个调用可以花费零时间,那么总执行时间会减少一些,比如说90%。 (不可能?根本没有。)时间会精确定位吗?不会。通话图是否会指出它?不会。通话计数会精确定位吗?不是。因为问题不是在功能级别,而是在呼叫指令级别。
程序在某个时间点随机停止,并检查其状态。如果指令可以“归零”,它会在90%的时间内停止吗?当然 - 概率为90%,指令将在堆栈上精确定位,等待其“工作”完成。
事实上,如果你将它随机停止20次,那么该指令将在堆栈中平均为18次,标准差为+/- 1.3倍。
这有统计意义吗?你打赌它是 你需要大量的样品吗?你打赌你没有。
假设百分比很小,例如10%或5%。 同样的原则适用。
事实上,无论采集的样本数量如何,任何> 1样本的指令都具有统计意义,并且是“热点”,“瓶颈”或任何您想要调用它的内容。如果你可以删除它,减少它,或以某种方式减少它,它将节省大量时间。 (有些你不能,比如“call _main”,但有些你可以。你只需要找到它们。)
当然我的代码永远不会那么愚蠢,不是吗?那么,证明它。
好的,现在回到故事。 。
原始回答:我听说过分析器,回过头来的时候,我认为它们必须非常整洁,但我无法访问它们/它。我正在研究一种嵌入式处理器(8086英特尔芯片),它似乎花了很长时间在显示屏上绘制一些浮点数字。硬件人员建议从他们的充足 - 添加计时器芯片,所以我可以看到事情花了多长时间。然而,在一个周末,我用英特尔“Blue Box”在线仿真器解雇了它,并让它运行起来。虽然它很慢,但我想知道“它到底做了什么?”。所以我只是停下来找出来。 PC在浮点库中(没有FP芯片)。这并不奇怪,因为它是绘制浮点数,但我想知道更多。所以我(费力地)读取十六进制内存以便跟随调用堆栈。你猜怎么着?它正在绘制数字,将其除以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
,循环速度增加了三倍!
重点是什么?如果您在程序运行缓慢时随机抽取样本,PC会告诉您它正在做什么,但调用堆栈会告诉您为什么,并直接引导您解决问题。现在,除非问题非常严重,否则您可能需要采取多个样本。任何显示在&gt; 1样本上的陈述都是您可以怀疑的陈述。请注意,它甚至可以精确定位语句,指令,而不是像函数一样的大块代码。 This technique可能“快而又脏”,但它非常有效。
增加:如果反复执行此操作,可以在同一软件中解决问题后的问题。例如,如果您获得3倍的加速,那么之前可能无关紧要的小型性能问题现在会消耗剩余时间的3倍。这使得他们更容易使用样本。您可能必须添加一个临时外部循环,以使其运行足够长的时间来进行采样。通过这种方式,我看到了more than 40 times的复合加速因子。
答案 1 :(得分:17)
这称为profiling。有许多现成的工具可以帮助您确定应用程序瓶颈的位置,适用于各种不同的语言。例如,用于Java的TPTP工具集可以显示性能瓶颈在各个方法级别下的位置(如果需要)。当然,有时您真正需要的是对系统计时器的一些读取,以便对一段代码有一个大概的了解。
答案 2 :(得分:3)
Profilers对于查看您花费最多时间的代码非常有用。有许多分析工具,通常它们特定于您所在的平台/开发环境。
对于小案例,我在代码中使用了简单的计时器(操作结束时的系统时间 - 操作开始时的系统时间)。
一条重要规则:不要假设您刚刚放入的性能优化实际上运行得更快。一定要验证!
答案 3 :(得分:2)
我确实使用工具来完成这项工作。否则我发现自己很难做到这一点......(好吧,我认为,我从未尝试过)
在Linux上我使用了Valgrind,它附带了一些有用的工具来分析你的代码。至于Valgrind主页:
它运行在以下平台上:X86 / Linux,AMD64 / Linux,PPC32 / Linux,PPC64 / Linux。
..它是免费的(如免费啤酒)和开源。
虽然我没有那么多地使用它们,但在另一个平台上你可以使用Purify/Quantify(IBM产品)。它们是商业工具。正如威尔报道的那样,它们是在PurifyPlus软件包中提供的,而Quantify将帮助您分析您的应用程序。
这就是我用过的所有......: - )
答案 4 :(得分:2)
老实说,我使用NUnit。如果我的代码花费的时间太长或者似乎没有扩展,我会编写一个模拟应用程序部分表现不佳的测试。然后我看看在代码中进行强化替换以减少运行时间并验证我没有破坏任何东西。
如果这仍然不能满足您的需求,那么您需要找到并应用一个分析器,但您至少会有一个测试用例,您可以在不必打开/加载应用程序的情况下尝试您的假设,跟踪调用应用程序的元素而不是手头的任务。
答案 5 :(得分:2)
我使用Valgrind及其工具Callgrind。这是一个很棒的工具。 Valgrind基本上是一台虚拟机:
Valgrind本质上是虚拟的 使用即时(JIT)的机器 编译技术,包括 动态重新编译。没什么 原始程序运行 直接在主处理器上。 相反,Valgrind首先翻译了 程序成一个临时的,简单的形式 称为中间代表 (IR),处理器中立, 基于SSA的表格。转换后, 一个工具(见下文)是免费的 它想要的任何转变 在Valgrind翻译之前,在IR上 IR回到机器代码并让 主处理器运行它。即使 它可以使用动态翻译(即 是,主机和目标处理器 它来自不同的架构) 没有。 Valgrind重新编译二进制文件 代码在主机和目标上运行(或 模拟)相同的CPU 架构。
Callgrind是一个构建于此的探查器。主要好处是您不必花费数小时来运行您的应用程序以获得可靠的结果。几秒钟就足够了,因为Callgrind是非探测分析器,
Valgrind的另一个工具是Massif。我用它来分析堆内存使用情况。它工作得很好,它为你提供了内存使用的快照 - 详细信息什么是内存百分比,以及世界卫生组织把它放在那里。
另一个Valgrind工具 - DRD(和Helgrind)。我使用它们来跟踪我的代码中的死锁和数据争用,以及线程API滥用。
答案 6 :(得分:1)
问题含糊不清。从运行时或内存的角度来看是否有效? 运行特定代码段的上下文,应用程序的体系结构以及可能被抛出的数据都是因素。
BTW,有人提到Purify;还有它的姐妹产品Quantify。答案 7 :(得分:1)
答案 8 :(得分:0)
对于.NET,我建议NDepend。