关于java:如何编写探查器?

How to write a profiler?

我想知道如何写一个分析器?推荐哪些书籍和/或文章?有人能帮我吗?

有人已经做过类似的事情了吗?


我们不鼓励焊料:)

profilers不是太硬,如果你想让一个程序在合理的开支大部分时间它。如果你没有在高精度和最小中断的东西,很难得到。

所以如果想答案A永裕Profiler会给你一个别人有,去写。如果你要找的智力挑战,为什么没有一个在写作水平?

我已经写了几个,一个运行时环境,一年之间无关。

有两个方法

  • 添加一些你的函数或其他重要的点,它是时间和日志。

  • 如果要关闭定时器定期存款和聚醚醚酮是在目前的程序。

《JVMPI版本似乎是第一个孩子的链接提供的报告显示,它uzhin CAN或看东西湖段数1.3)。你这样做是得到执行,因此,分析影响性能的CAN(如果你是一个网站分析什么是轻量级但功能通常被称为,它可以mislead)。

如果你能得到一个定时/计数器中断程序告诉你该在什么时间的中断,你可以使用调试符号表信息的功能,它解决的是在一个时间。这提供了信息,但不可以不破坏性。一位获得更多的信息可以从调用堆栈中callers步行到最后等我的想法是不可能的,如果没有基础的Java…

保罗。


我写过一篇文章,主要是为了让"深度采样"更容易使用。当您手动执行该方法时,这里将对其进行解释。它是基于抽样,而不是采取大量的小样本,你采取少量的大样本。好的。

例如,它可以告诉您,指令I(通常是一个函数调用)花费了总执行时间的百分之十,或多或少,因为它出现在样本的百分之十的堆栈上。好的。

考虑一下,因为这是一个关键点。只要程序运行,调用堆栈就存在。如果一个特定的调用指令I在堆栈x%的时间上,那么如果该指令可以消失,那么x%的时间就会消失。这不取决于执行I的次数,也不取决于函数调用需要多长时间。所以定时器和计数器都没有达到目的。在某种意义上,所有指令都是调用指令,即使它们只调用微码。好的。

采样器是基于这样一个前提:准确地知道指令I的地址(因为这正是你要找的)比准确地知道数字x%更好。如果你知道你可以通过重新编码节省大约30%的时间,你真的在乎你可能会减少5%的时间吗?你还是想把它修好。它实际节省的时间不会因为你精确地知道X而减少或增加。好的。

因此,可以将样本从计时器中取出,但坦率地说,我发现用户同时按下两个SHIFT键来触发中断同样有用。因为20个样本通常都是足够的,这样您就可以确保在相关的时间(即,在等待用户输入的时候)采集样本,这是非常充分的。另一种方法是只在用户按住两个SHIFT键(或类似的键)的情况下进行计时器驱动的采样。好的。

我并不担心采样可能会减慢程序的速度,因为目标不是测量速度,而是找到最昂贵的指令。修好后,整个加速过程很容易测量。好的。

分析器提供的主要内容是一个UI,这样您就可以轻松地检查结果。从采样阶段出来的是调用堆栈样本的集合,其中每个样本都是指令地址列表,其中除最后一个之外的每个指令都是调用指令。用户界面主要是所谓的"蝴蝶视图"。它有一个当前的"焦点",这是一个特殊的指令。在左边,调用指令显示在该指令的正上方,从堆栈样本中剔除。如果focus指令是一个调用指令,那么下面的指令会出现在右边,就像从样本中选择的那样。焦点指令上显示一个百分比,即包含该指令的堆栈的百分比。同样,对于左边或右边的每条指令,百分比也按每条指令的频率进行分解。当然,指令由文件、行号和它所在函数的名称表示。用户可以通过点击任何一条指令来轻松地浏览数据,使其成为新的焦点。好的。

这个用户界面上的一个变体将蝴蝶视为二部分,由交替的函数调用指令层和包含它们的函数组成。这可以让每个函数花费的时间更加清晰。好的。

也许这并不明显,所以值得一提这项技术的一些特性。好的。

  • 递归不是一个问题,因为如果一个指令在任何给定的堆栈样本上出现多次,它仍然只计为包含它的一个样本。它的删除所节省的估计时间是它所在堆栈的百分比,这仍然是正确的。好的。

  • 注意这与调用树不同。不管调用树中有多少个不同的分支,它都会给您一条指令的开销。好的。

  • UI的性能不是问题,因为示例的数量不需要很大。如果一个特定的指令i是焦点,那么很容易找到样本如何包含它,对于每个相邻的指令,包含i的样本中有多少也包含它旁边的相邻指令。好的。

  • 如前所述,采样速度不是问题,因为我们不测量性能,我们正在诊断。抽样不会使结果产生偏差,因为抽样不会影响整个程序的工作。一个需要n个指令来完成的算法,即使它被停止了任意次数,仍然需要n个指令。好的。

  • 我经常被问到如何对一个在毫秒内完成的程序进行采样。简单的答案是将它包装在一个外环中,以使它需要足够长的时间来取样。你可以找出需要x%的时间,去掉它,让x%加速,然后去掉外循环。好的。

我称之为Yapa(又一个性能分析器)的这个小分析器是基于DOS的,并且做了一个很好的小演示,但是当我有很认真的工作要做时,我会回到手工方法上。这主要是因为调用堆栈本身常常没有足够的状态信息来告诉您为什么要使用特定的周期。您可能还需要了解其他状态信息,这样您就可以更完整地了解程序当时在做什么。因为我觉得手工方法很满意,所以我把工具搁置起来了。好的。

在谈论分析时经常忽略的一点是,您可以反复进行分析以发现多个问题。例如,假设指令I1在堆栈上占时间的5%,而I2在堆栈上占时间的50%。20个样本很容易找到I2,但可能不是I1。所以你修复了I2。然后你再做一次,但是现在I1需要10%的时间,所以20个样本可能会看到它。这种放大效应允许重复应用轮廓来实现大的复合加速因子。好的。好啊。


我会看看这些开源项目的第一。

  • Eclipse tptp(http:/ / / / www.eclipse.org tptp)
  • visualvm(http:/ / / visualvm.dev.java.net)

然后,我会看JVMTI(JVMPI遇险)

  • http:/ / / / / java.sun.com开发者technicalarticles JVMTI /编程/

JVMPI规格:http:////java.sun.com J2SE 1.5.0 /文档/指南/ jvmpi.html JVMPI

你的勇气和bravery i礼炮

编辑:当用户说:"boune,JVMTIhttp:/ / / / / java.sun.com开发者technicalarticles JVMTI /编程/


作为另一个答案,我只是看看SourceForge上的Lukestackwalker。它是一个很好的、很小的堆栈采样器示例,如果您想编写一个分析器,它是一个很好的开始位置。

在我看来,这是正确的做法:

  • 它对整个调用堆栈进行采样。

叹息…那么近,那么远。这里,imo,它(和其他堆栈取样器,如xperf)应该做的是:

  • 它应该保留原始堆栈样本。事实上,它在函数级别上作为示例进行了总结。这将丢失定位有问题的呼叫站点的密钥行号信息。

  • 如果储存是一个问题,它不需要取那么多的样品。由于典型的性能问题的成本从10%到90%,20-40个样本将非常可靠地显示出来。数百个样本提供了更高的测量精度,但它们不会增加定位问题的概率。

  • 用户界面应该用语句而不是函数来概括。如果保留原始样品,这很容易做到。附加到语句的关键度量是包含该语句的样本的分数。例如:

    5/20 myfile.cpp:326用于(i=0;i

这说明myfile.cpp中的326行在调用strlen的过程中出现在20个样本中的5个。这是非常重要的,因为您可以立即看到问题,并且您知道解决问题的速度有多快。如果用s[i]替换strlen(s),它将不再花时间在该调用中,因此不会出现这些样本,加速将大约为1/(1-5/20)=20/(20-5)=4/3=33%。(感谢David Thornley提供的示例代码。)

  • 用户界面应该有一个显示语句的"蝴蝶"视图。(如果它也显示函数,那没关系,但是语句才是真正重要的。)例如:

    3/20 myfile.cpp:502 myfunction(myargs)2/20 hisfile.cpp:113 myfunction(hisargs)

    5/20 myfile.cpp:326用于(i=0;i

    5/20 Strlen.asm:23…一些程序集代码…

在本例中,包含for语句的行是"关注焦点"。发生在5个样本上。上面的两行显示,在这些样本中,有3个是从MyFile.cpp:502中调用的,其中2个是从HisFile.cpp:113中调用的。下面的一行显示,在所有5个样本中,它都在strlen中(这并不奇怪)。一般来说,焦点线将有一棵"父母"树和一棵"孩子"树。如果由于某种原因,焦距线不是你能修复的,你可以上下移动。目标是找到尽可能多的样本上可以修复的行。

重要提示:不应将分析视为您曾经做过的事情。例如,在上面的示例中,通过修复一行代码,我们得到了4/3的加速。当这个过程被重复的时候,其他有问题的代码行应该以4/3的频率出现,这样更容易找到。我从来没有听说有人在谈论重复分析过程,但这对于获得全面的复杂加速至关重要。

另外,如果一个语句在一个样本中出现多次,这意味着存在递归。这不是问题。它仍然只算作一个包含语句的示例。这种情况下,报表的成本仍然是由包含它的样本的分数来近似的。