如何编写一个简单的代码分析器?
Posted
技术标签:
【中文标题】如何编写一个简单的代码分析器?【英文标题】:How to write a simple code profiler? 【发布时间】:2011-07-28 15:32:05 【问题描述】:我想知道像 quantify 这样的产品如何在不修改代码的情况下测量函数/方法所花费的时间。有人知道吗?
您有描述如何开始编写自己的工具的网页吗?
【问题讨论】:
嗯,你说得对,我还没有接受答案,不是我认为他们不好,而是更不幸的是他们没有完全回答“如何编写简单的代码分析器” .我得到了有趣的答案,但不知道如何真正开始使用该工具。我认为不关闭问题会让更多人回答。 @Dave:写了一个分析器之后,让我建议一个开始的方法。我的方法是从获取随机时间堆栈样本开始。pstack
、jstack
或 lsstack
可以做到。你不需要很大的数字。 (我这样做的粗略方式完全是手动的 - 在调试器中暂停,然后回溯。)然后,如果您愿意,您可以编写一个程序来处理该数据并让用户浏览它。
@Mike:听起来我是一个明智的开始方式。会试一试的。
@Dave:祝你好运,看看 Zoom。我不使用任何分析器的原因是我实际上发现了完全手动的方法,而更多的工作,更有效。也许这就是我,but I'm not alone。
@Mike:我同意,这就是为什么我试图提高我对这些通常没有记录的技术的了解。由于我正在使用相同的代码库,因此额外的工作是一次性的,并且与它可以提供的东西相比绝对值得。
【参考方案1】:
非侵入式分析器可以通过分析器将代码编译成可执行形式。此格式不需要与操作系统所需的实际执行格式相匹配。这类似于 Java 的虚拟机。
分析器使用基本单位(例如时钟周期)来衡量性能。确定周期数后,可以将总和乘以一个常数,得出一个近似的时间单位。该值是近似值,因为程序不是直接在处理器上运行,而是在“虚拟”处理器上运行。
其他分析器修改代码以在需要进行分析的地方(通常在函数的开始和结束处)调用“开始测量”和“结束测量”。
JTAG 调试器和其他仿真器在找到特定地址时调用测量函数。
从嵌入式系统的角度来看,最准确的性能测量技术是找到一个未使用的引脚或测试点,然后向该引脚发送“开始”脉冲,然后再发送“结束脉冲”,然后使用示波器进行测量确切的时差。高级示波器可以提供这个时间差的直方图。
【讨论】:
【参考方案2】:你问了一个非常大的问题。但是,据我所见,分析器在许多情况下确实会修改代码。例如,EQUATEC 会为您的可执行文件和已检测的库创建一个副本。其他人将在分析器运行时创建代码的缓存和副本。因此,他们不一定会在您正在使用的代码中编写任何检测,但他们会检测代码或 IL 的副本。
【讨论】:
【参考方案3】:我的猜测是 CPU 进入了“单步模式”。
【讨论】:
什么是“单步模式”? 这是 x86 处理器的一个特性。请参阅以下内容:en.wikipedia.org/wiki/Trap_flag【参考方案4】:我能猜到。通常,分析器在构建阶段或执行时“检测”您的代码。他们可以将测量调用放在每个函数的开头和结尾。并做很多其他的事情。
【讨论】:
【参考方案5】:我不知道 quatify,但一种常见的技术是使用 随机采样:每 100 微秒左右中断一次,并保存 当前指令指针。然后从符号表中计算出来 哪个函数在里面,并把它们汇总起来。
大多数分析器做得更多,并且还会在某些情况下检测代码 方式,以便提供更多信息。
【讨论】:
第一段i正是prof and gprof所做的。只使用指令指针就像试图用只有秒针的时钟来告诉时间。【参考方案6】:分析器可能具有以下属性:
一个调试器,它会注意到目标进程中的调试事件(如线程创建、DLL 加载、线程退出等)。 具有一组挂钩(Windows 挂钩、标准函数调用挂钩等)的进程,可用于“分析”。 也可以作为服务运行,它会注意到内核(环 0)级别的事件。这可能需要也可能不需要从 Bios 进行硬件虚拟化。【讨论】:
【参考方案7】:另一种在嵌入式领域有用的技术,类似于 Thomas Matthews 所描述的技术,是将频率发生器连接到将产生 NMI(即不可屏蔽中断)的引脚。然后对作为中断帧的一部分存储在堆栈中的程序计数器进行采样。这将为您的应用程序提供非常准确的统计视图,而对您的应用程序的更改最少。
当然这只适用于特殊情况。
【讨论】:
【参考方案8】:记住这一点很有帮助:
分析器的一个重要目的是帮助程序员通过在他/她的代码中定位占用大量时间并且可以在更短的时间内完成的活动来使他/她的程序尽可能高效。李>这听起来很明显,对吧?但请注意:
它说的是定位,而不是测量。测量可能是最终定位的一种手段,但实际上是非常间接的。 它说的是活动,而不是函数/方法,也不一定是热点。大多数情况下,这些是函数调用点,它们花费的时间比预期的要多,实际上不需要完成。 上面写着在他/她的代码中。这是程序员可以修改的唯一代码。知道在某些系统例程上花费了很多时间是没有好处的。 它说的是 时间,而不是 CPU 时间。如果程序由于 I/O 或其他系统功能而花费大量时间阻塞,这与 CPU 时间一样重要。 它说的是相当大的百分比,而不是精确的时间。如果找到了一项成本高昂的活动,重要的是它的位置,而不是它的成本有多高的不确定性。 (如果您正在寻找金块,您会先测量一个,然后再找到它吗?)因此,不仅仅是任何旧的采样器或仪器都可以达到这个目的。
恕我直言,最有效的方法是收集堆栈样本,而不仅仅是程序计数器,并在随机挂钟时间采样,而不仅仅是 CPU 时间,并且不仅按函数报告,而且按代码行报告,包含该行的样本百分比。 Zoom 就是这样一个分析器。
换句话说 a) 不要取大量的小样本并将它们混合成数字。 b) 一定要采集少量的大样本,并了解他们告诉您的内容。
作为一个极端的例子,如果只取三个堆栈样本,如果一个特定的语句(或指令)出现在其中两个的某个地方,那么该语句的成本是多少? 嗯,可以想象这只是一个巧合 - 一个误报,但平均而言,它将节省 (2+1)/(3+2) = 60%整体运行时间。 就“物超所值”而言,很难超越。
这里是the issues的更详细摘要。
【讨论】:
以上是关于如何编写一个简单的代码分析器?的主要内容,如果未能解决你的问题,请参考以下文章