如果 profiler 不是答案,我们还有啥其他选择?
Posted
技术标签:
【中文标题】如果 profiler 不是答案,我们还有啥其他选择?【英文标题】:If profiler is not the answer, what other choices do we have?如果 profiler 不是答案,我们还有什么其他选择? 【发布时间】:2011-05-22 05:37:52 【问题描述】:看完 Joshua Bloch 的演讲“Performance Anxiety”后,我阅读了他在演讲"Evaluating the Accuracy of Java Profilers" 中建议的论文。引用结论:
我们的结果令人不安,因为它们表明分析器不正确是普遍存在的——发生在我们的七个基准测试和两个生产 JVM 中的大多数中——并且很重要——所有四个 最先进的剖析器会产生不正确的剖析。不正确 配置文件很容易导致性能分析师花时间优化对性能影响最小的冷方法。 我们展示了一个不使用产量的概念验证分析器 采样点不存在上述问题
论文的结论是,我们不能真正相信分析器的结果。但是,使用分析器的替代方法是什么。我们是不是应该回去只凭感觉做优化?
更新:讨论中似乎遗漏的一点是观察者效应。我们能否构建一个真正无“观察者效应”的分析器?
【问题讨论】:
【参考方案1】:哦,伙计,从哪里开始?
首先,我很惊讶这是新闻。其次,问题不在于分析器不好,而在于 一些 分析器不好。 作者构建了一个他们认为很好的模型,只是避免了他们在评估的错误中发现的一些错误。 由于一些持久的myths about performance profiling,错误很常见。
但让我们保持积极的态度。 如果想找到加速的机会,其实很简单:
采样应该与程序的状态不相关。 这意味着发生在真正随机的时间,无论程序是在 I/O(用户输入除外)还是在 GC 中,还是在紧密的 CPU 循环中,或者其他什么。
采样应该读取函数调用堆栈,
以确定哪些语句在采样时是“活跃的”。
原因是每个调用站点(调用函数的点)的百分比成本等于它在堆栈上的时间分数。
(注意:本文完全关注自时间,忽略了大型软件中可避免的函数调用的巨大影响。事实上,最初的gprof
背后的原因是帮助找到这些调用。)
报告应按行显示百分比(而不是按功能)。 如果识别出一个“热”函数,仍然需要在其中寻找占时间的“热”代码行。该信息在样本中!为什么要隐藏它?
一个几乎普遍的错误(论文分享的)是过于关注测量的准确性,而对位置的准确性却不够关注。 例如,这是一个example of performance tuning 其中发现并修复了一系列性能问题,实现了 43 倍的复合加速。 在解决每个问题之前,不一定要准确知道每个问题的大小,但要知道它的位置。 性能调优的一个现象是修复一个问题,通过减少时间,放大了剩余问题的百分比,因此更容易找到。 只要发现并解决了任何问题,就会朝着发现并解决所有问题的目标前进。 不必按尺寸递减的顺序修复它们,但必须确定它们。
关于测量的统计准确度,如果调用点在堆栈上的某个百分比时间 F(如 20%),并且取 N(如 100)个随机时间样本,则显示调用点是二项分布,均值 = NF = 20,标准差 = sqrt(NF(1-F)) = sqrt(16) = 4。所以显示它的样本百分比将为 20% +/ - 4%。 那准确吗?不是真的,但是问题找到了吗?没错。
事实上,就百分比而言,问题越大,定位它所需的样本就越少。例如,如果采集了 3 个样本,其中 2 个样本出现了呼叫点,则很可能成本非常高。 (具体来说,它遵循 beta 分布。如果您生成 4 个统一的 0,1 随机数,并对它们进行排序,则第 3 个的分布就是该调用点的成本分布。 它的平均值是 (2+1)/(3+2) = 0.6,所以这是给定这些样本的预期节省。) 插入:您获得的加速因子由另一个分布控制,BetaPrime,其平均值为 4。因此,如果您取 3 个样本,请在其中 2 个样本上发现问题,然后消除该问题,平均而言,您将使程序快四倍。
现在是时候让我们的程序员在剖析问题上大惊小怪了。
免责声明 - 论文未能引用我的文章:Dunlavey,“Performance tune with instruction-level cost derived from call-stack sampling”,ACM SIGPLAN Notices 42, 8(2007 年 8 月),第 4-8 页。
【讨论】:
不错的答案。虽然我不完全同意这一点:发现并解决任何问题,朝着发现并解决所有问题的目标取得进展。不是所有的问题都可以解决,有时性能瓶颈是应用程序的属性,这意味着其他问题不会被放大。这肯定是个大问题。 @nanda:这就是我说“并修复”的原因。基本上,如果存在问题 A、B、C、D 和 E,无论它们的相对大小如何,您找到并解决的任何问题,无论顺序如何,都会放大其他问题。如果有一个你无法修复,它不会,但你仍然可以继续处理其他的。 @nanda:这里有一个关于这个主题的有趣数学:en.wikipedia.org/wiki/Rule_of_succession【参考方案2】:如果我没看错的话,这篇论文只讨论了基于样本的分析。许多分析器还进行基于检测的分析。它的速度要慢得多,并且还有一些其他问题,但它不应该受到论文中提到的偏见的影响。
论文的结论是,我们 不能真的相信结果 分析器。但是,那是什么 替代使用分析器。
没有。论文的结论是,当前轮廓仪的测量方法存在特定缺陷。他们提出了一个修复方案。这篇论文是最近的。我希望分析器最终会实施此修复程序。在那之前,即使是有缺陷的分析器仍然比“感觉”好得多。
【讨论】:
第二个原因:“观察者效应”呢?任何分析器都会遇到这个问题,消除观察者效应的唯一方法是移除观察者,即不使用任何分析器 @nanda:但很明显,不使用任何分析器,因为它会影响性能,就像不吃馅饼一样,因为它的味道可能会很糟糕。没有任何观察是不可能了解热点的(除了可能在不依赖用户输入的人为示例中),但是如果你在不知道它在哪里产生显着影响的情况下尝试优化,那么你的几率在 80- 20 规则。 "最终实施此修复" 这将是进步,但仍然不够。在我看来,重点需要从测量转变为发现。 Here's a very short explanation of what I mean.【参考方案3】:除非您正在构建需要每个 CPU 周期的前沿应用程序,否则我发现分析器是查找代码中 10% 最慢部分的好方法。作为一名开发人员,我认为这应该是您在几乎所有情况下真正关心的全部内容。
我有使用http://www.dynatrace.com/en/ 的经验,我可以告诉你它非常擅长寻找低悬的果实。
Profiler 与任何其他工具一样,它们也有自己的怪癖,但我相信它们总比人类更容易找到您应用中要查看的热点。
【讨论】:
+1 我同意找到应用程序中最糟糕的部分通常有助于将性能提高到可接受的水平。大多数性能提升并不是通过使小方法更快来实现的,而是通过优化高级代码而不调用它们来实现的。 @Daniel:链接到的论文提出了一个令人信服的案例,即分析器通常无法正确识别代码中最慢的部分。 @Michael:我的错!我想写的是找到你的应用程序中最糟糕的部分,即使使用分析器,也会向你展示最慢的部分。我的结论是,解决问题通常不是几毫秒的问题,但通常可以通过根本不调用(可能是错误测量的)方法来实现。 @Michael:我试图用“Profilers 就像任何其他工具一样,它们有自己的夸克”来涵盖这一点。在实践中,我发现它们“足够好” “分析器是找到代码中 10% 最慢部分的好方法”。这是否意味着您获得了 10% 的加速?这说明了两件事之一。 1) 代码一开始就几乎是最佳的,如果 10% 就够了,或者 2) 代码中还有其他探查器没有发现的问题。我见过人们假设 1。【参考方案4】:如果您不信任分析器,那么您可以通过使用面向方面编程、包装应用程序中的每个方法,然后使用记录器记录每个方法调用来进入偏执模式。
您的应用程序确实会变慢,但至少您可以准确计算每个方法被调用的次数。如果您还想查看每个方法执行所需的时间,请环绕每个方法perf4j。
将所有这些统计信息转储到文本文件后,使用一些工具提取所有必要的信息,然后将其可视化。我想这可以让您很好地了解您的应用程序在某些地方的运行速度。
【讨论】:
-1 这并不比像 JProfiler (ej-technologies.com/products/jprofiler/overview.html) 这样的带有代理工具的优秀分析器已经做的更好。 @Daniel:如果您不信任分析器,它仍然是另一种使用分析器的方法。 是的,但是如果你不相信性能分析器的性能结果(方法调用在这里不计算,因为它们仍然由分析器可靠地测量),那么结合使用 AspectJ 和 perf4j 的方法更具误导性。【参考方案5】:实际上,最好在数据库级别进行分析。大多数企业数据库都能够显示一段时间内的热门查询。开始处理这些查询,直到顶部的查询下降到 300 毫秒或更短,您将取得很大的进步。分析器对于显示堆的行为和识别阻塞的线程很有用,但我个人在识别热方法或大型对象方面从未与开发团队获得太多关注。
【讨论】:
这里的目标不是数据库,也不是所有 Java 应用都与数据库交互。以上是关于如果 profiler 不是答案,我们还有啥其他选择?的主要内容,如果未能解决你的问题,请参考以下文章
XMLHttpRequest.open();第一个参数post,get有啥不同,啥时候选啥,还有其他的,都有啥区别