当我在大学项目上工作时,我使用了一个由老年学生制作的项目内部剖析器,它非常基础但很好,因为它的任务是减去代码的两点之间的时间并给出统计数据。
现在,专业的探查器如何工作?是否预先处理代码以插入检查点或类似的东西?它是否使用调试数据读取二进制代码以捕获调用函数的位置?
感谢。
答案 0 :(得分:25)
有许多不同的分析器以不同的方式工作。
常用的分析器只是定期检查正在运行的程序,以查看当前正在执行的汇编指令(程序计数器)以及调用当前函数(调用堆栈)的例程。这种采样分析器可以使用标准二进制文件,但如果您有调试符号来计算程序中给定地址的代码行,则更有用。
除了定期采样之外,您还可以使用处理器性能计数器在一定数量的事件(如高速缓存未命中)之后进行采样,这将帮助您查看程序的哪些部分因内存访问而变慢。
其他分析器涉及重新编译程序以插入指令(称为 instrumentation )来计算每个连续指令集(基本块)的执行频率,甚至可能记录基本块的顺序执行,或记录某些地方的变量内容。
仪器方法可以为您提供所需的所有精度和数据,但会降低程序的速度,从而改变其性能特征。相比之下,使用基于采样的方法,您可以根据所获得的配置文件数据的准确性,针对运行程序所需的时间长度来调整性能影响。
答案 1 :(得分:14)
有两种常见的分析策略(无论如何都适用于基于VM的语言):检测和采样。
Instrumentation插入检查点,并在每次方法启动和完成时通知探查器。这可以通过JIT /解释器或后正常编译但是执行前阶段来完成,这只是更改可执行文件。这会对性能产生非常显着的影响(从而扭曲任何时序结果)。尽管如此,这对获得准确的计数很有帮助。
采样会定期向VM询问所有线程的堆栈跟踪是什么样的,并以这种方式更新其统计信息。这通常会降低性能,但会产生较少的准确呼叫计数。
答案 2 :(得分:2)
这取决于所分析的代码类型,例如.NET CLR为代码分析器提供facility。处理托管代码时,可以重写中间代码以注入自定义钩子。您还可以分析应用程序的堆栈跟踪。操作系统可以提供分析工具,例如Windows具有performance counters。处理嵌入式代码时,您可以模拟/替换底层硬件,以有效监控系统性能。
答案 3 :(得分:2)
正如Jon Skeet上面所写,有两种策略:仪器和采样。
仪器手动和自动完成。在手动情况下:开发人员手动插入代码以跟踪感兴趣的代码区域的开始/结束。例如,简单的“StartTimer”和“EndTimer”。一些分析器工具也可以自动执行此操作 - 为此,分析器将需要对代码进行静态分析,即它解析代码并识别重要的检查点,如特定方法的开始/结束。使用支持反射的语言(例如任何.net语言)最容易实现。使用“反射”,分析器能够重建整个源代码树(以及调用图)。
采样由探查器完成,它会查看二进制代码。探查器还可以使用Hooks等技术或陷阱Windows事件/消息以进行性能分析。
仪器和采样方法都有自己的开销。开销量取决于 - 例如如果采样频率设置为高值,那么分析本身可以显着提高报告的性能。
仪器与采样: 它不像一个比另一个方法更好。两者都有自己的位置。
最好的方法是从基于采样的分析器开始,然后查看整个系统级别。这是运行采样器并查看系统范围的资源使用情况:内存,硬盘,网络,CPU。
从上面确定被窒息的资源。
通过上述信息,您现在可以在代码中添加检测功能,以指出罪魁祸首。例如,如果内存是最常用的资源,那么它将有助于检测与内存分配相关的代码。请注意,使用检测功能,您确实专注于代码的特定区域。
答案 4 :(得分:0)
对于* nix中的gprof,在编译和链接时使用-pg,将一些额外的代码注入到目标代码中。然后通过运行gprof,由注入的代码生成报告文件。