可以使用一个分析器,但为什么不停止程序呢?
如果某个单线程程序需要执行10倍的时间,那么可以在其上运行一个分析器。 你也可以用“暂停”button停下来,你会看到它到底在做什么。
即使只比应该慢10%,如果再多停一下,不久你就会看到它多次做不必要的事情。 通常这个问题是一个函数调用,在堆栈中间的地方并不是真正需要的。 这不是衡量问题,但它确实find它。
编辑:反对意见主要假设你只采取1个样本。 如果你认真的话,就拿10分。任何造成一定百分比的代码,如40%的代码,都会平均出现在这部分样本上。 瓶颈(在单线程代码中)不能隐藏起来。
编辑:为了表明我的意思,许多反对意见的forms是“没有足够的样本,所以你看到的可能是完全虚假的” – 关于机会的模糊想法。 但是,如果有任何可识别的描述 ,不仅仅是例行活动或者例行活动,在30%的时间内是有效的,那么在任何给定的样本上看到它的概率是30%。
那么假设只有10个采样。 在10个样本中将出现问题的次数遵循二项分布 ,并且看到0次的概率是0.028。 看1次的概率是.121。 2次,概率是.233,3次是.267,之后下降。 由于看不到两次的概率是.028 + .121 = .139,这意味着看到它两次或更多次的概率是1 – .139 = .861。 一般的规则是如果你看到一些你可以修复两个或更多的样本,这是值得修复的。
在这种情况下,在10个样本中看到的机会是86%。 如果你有14%的人没有看到它,那么只需要更多的样本,直到你做。 (如果样本数量增加到20个,则看到它的次数增加到99%以上)。所以它没有被精确地测量,但是它被精确地find了,而且了解这一点很重要它可能很容易成为一个分析器实际上找不到的东西,比如涉及数据状态的东西,而不是程序计数器。
在Java服务器上执行2-3快速Ctrl – 连续中断并获得所有正在运行的线程的2-3个线程转储总是非常简单。 只要看看所有线程在哪里,就可以非常快速地找出你的性能问题。
这种技术可以在2分钟内揭示更多的性能问题,比我知道的任何其他技术。
因为有时候它有效,有时会给你完全错误的答案。 分析器有更好的loggingfind正确答案,而且通常会更快。
这样做手动不能真正被称为“快速”或“有效”,但有几个分析工具自动执行此操作; 也被称为统计分析 。
调用堆栈抽样是一种非常有用的分析技术,特别是在查看可能花费时间在任何地方的庞大而复杂的代码库时。 它具有测量CPU使用情况的好处,这是对于交互性至关重要的,并且每个样本的调用堆栈都可以让你明白为什么调用一个函数。 我使用了很多,但我使用了自动化工具,比如Luke Stackwalker和OProfile以及各种硬件供应商提供的东西。
我所喜欢的自动化工具比手工抽样的原因是统计功效 。 当你有一个function占用40%的运行时间时,手动抓取10个样本是很好的,因为平均来说,你会得到4个样本,总是至less有一个样本。 但是当你有一个扁平的configuration文件时,你需要更多的样本,有数百个叶函数,没有超过1.5%的运行时间。
假设你有一个有许多不同种类的鱼的湖。 如果湖中40%的鱼是三文鱼(60%是其他所有的东西),那么你只需要捕捉十条鱼,知道湖中有很多鲑鱼。 但如果你有几百种不同的鱼种,每种鱼种不超过1%,你就需要捕捉十多条鱼才能说“这个湖是三文鱼0.8%,鳟鱼0.6% “。
同样,在我所从事的游戏中,有几个主要的系统,每个系统都会在数百个不同的实体中调用数十个函数,而这一切都发生在每秒60次。 其中一些函数的时间漏斗到常见的操作(如malloc
),但其中大部分时间没有,并且在任何情况下没有单帧,每帧占用超过1000微秒。
我可以看看后备箱的function,看看“我们花费了10%的时间来处理碰撞”,但这不是很有帮助:我需要知道碰撞的确切位置 ,所以我知道哪些function需要挤压。 只是“减less碰撞”只会让你感到满意,特别是当它意味着抛弃function。 我宁愿知道“因为魔法导弹移动得太快而碰到很多细胞,所以我们在八叉树的狭窄阶段平均花费了600微秒/帧的时间”,因为那时我可以find确切的修正:要么是更好的树,要么是更慢的导弹。
如果stricmp
有20%的大块,手动采样就可以,但是我们的configuration文件并不是这样。 相反,我有数百个function,我需要从0.6%的框架到0.4%的框架。 我需要每隔50微秒的function,每秒300次刮掉10微秒。 为了获得这种精度,我需要更多的样本。
但是,Luke Stackwalker所做的就是描述你所描述的:每一毫秒左右,它停止程序并logging调用堆栈(包括IP的精确指令和行号)。 一些程序只需要成千上万的样本进行有效的分析。
(当然,我们之前已经讨论过这个问题,但我认为这是一个总结辩论的好地方。)
程序员实际上做的事情和他们推荐的其他事情是有区别的。
我知道很多程序员(包括我自己)实际上使用这种方法。 它只能真正帮助find最明显的性能问题,但它是快速和肮脏的,它的工作原理。
但是我不会告诉其他程序员这么做,因为解释所有的注意事项需要我很长的时间。 根据这种方法做出一个不准确的结论是非常容易的,而且有很多地方根本不起作用。 (例如,该方法不会显示任何由用户input触发的代码)。
所以就像在法庭上使用谎言探测器或“goto”声明一样,我们并不build议你这样做,尽pipe它们都有其用途。
我对双方的宗教色调感到惊讶。
性能分析是非常好的,当你可以做到的时候,性能确实更加精确和精确。 有时你不能,而且有一个可靠的备份是很好的。 暂停技术就像您使用的电动工具太远或者餐馆已经停止使用的手动螺丝刀。
这是一个简短的真实故事。 一个应用程序(一批批处理任务)已经在生产中运行了六个月,突然间,运营商开始调用开发人员,因为它“太慢”了。 他们不打算让我们在生产中附加采样分析器! 你必须使用已经安装的工具。 在不停止生产过程的情况下,只要使用Process Explorer (操作员已经安装在机器上),我们可以看到线程堆栈的快照。 您可以浏览堆栈的顶部,使用回车键解除它,并通过另一次鼠标点击获得另一个快照。 你可以很容易地得到一个样本,每秒左右。
不需要很长时间就可以看到堆栈的顶端是最经常在数据库客户端库DLL(等待数据库)中,还是在另一个系统DLL(等待系统操作)中,或者实际上在某些方法中应用本身。 在这种情况下,如果我没有记错的话,我们很快就注意到,应用程序中有8次是在系统DLL文件中调用读取或写入networking文件。 当然,最近的“升级”已经改变了文件共享的性能特征。 如果没有一个快速和肮脏的(系统pipe理员认可的)方法来看看应用程序在生产中做了什么,我们将花费更多时间来衡量问题,而不是纠正问题。
另一方面,如果性能要求超出“足够好”的程度来推动信封,那么一个分析器就变得至关重要,所以你可以试着从所有紧密联系在一起的十几个或二十个热点中进行循环。 即使您只是试图在项目中保持适度的性能要求,当您可以将正确的工具排列起来以帮助您进行测量和testing,甚至将它们整合到自动化testing过程中时,它可以非常有帮助。
但是,当电源(可以这么说),电池已经死了,很高兴知道如何使用手动螺丝刀。
所以直接的答案是:知道你可以从停止程序中学到什么,但也不要害怕精密工具。 最重要的是知道哪些工作需要哪些工具。
如果我们回答这个问题:“为什么不知名?” 那么答案将是主观的。 据推测,为什么它不是更好的知道是因为分析提供了一个长期的解决scheme,而不是目前的问题的解决scheme。 它对multithreading应用程序无效,对于花费大量时间渲染的游戏等应用程序无效。
此外,在单线程应用程序中,如果你有一个方法,你希望消耗最多的运行时间,并且你想减less所有其他方法的运行时间,那么将很难确定哪些次要方法来集中你的努力首先。
您的分析过程是一个可以接受的方法,可以工作,但分析为您提供了更多的信息,并可以向您显示更详细的性能改进和回归。
如果你的代码很好,那么你可以检查一个特定方法的时间长度; 你可以看到所有的方法。
通过分析:
-
然后,您可以在每次更改后重新运行您的scheme,以确定性能改进/回归的程度。
-
您可以在不同的硬件configuration上分析代码,以确定您的生产硬件是否足够。
-
您可以在负载和压力testing场景下对代码进行剖析,以确定信息量如何影响性能
-
您可以使初级开发人员更轻松地将其更改对代码的影响可视化,因为他们可以在六个月的时间内在海滩或酒吧,或两者兼而有之的情况下重新调整代码。 海滩酒吧,ftw。
分析被赋予更多的权重,因为企业代码应该总是具有一定程度的分析,因为它给组织带来了长时间的好处。 代码越重要,越是进行性能分析和testing。
您的方法是有效的,另一个项目是开发人员的工具箱。 它只是被分析所压倒。
在“debugging”模式下执行程序期间按暂停button可能不会提供正确的数据来执行任何性能优化。 说穿了,这是一个简单的概况分析。
如果您必须避免使用分析器,最好的方法是使用logging器,然后将减速因子应用于真正问题所在的“猜测”。 Profiler是更好的猜测工具。
在debugging模式下点击暂停button的原因可能不会给出应用程序行为的真实情况,因为debugging器会引入额外的可执行代码,从而可能会减慢应用程序的某些部分。 可以参考Mike Stall的博客文章 ,了解在debugging环境中应用程序减速的可能原因。 这篇文章阐明了一些原因,比如断点太多,创buildexception对象,未经优化的代码等等。有关未优化代码的部分非常重要 – “debugging”模式会导致很多优化(通常是代码内嵌和重新编译)sorting)被抛出窗口,使debugging主机(进程运行您的代码)和IDE同步代码执行。 因此,在“debugging”模式下重复暂停可能是一个坏主意。
采样分析器只有在使用时才有用
- 您正在使用less量的线程监视运行时。 最好是一个。
- 每个线程的调用堆栈深度相对较小(以减less收集样本的难以置信的开销)。
- 你只关心挂钟时间而不关心其他仪表或资源瓶颈。
- 您还没有安装代码进行pipe理和监视(因此堆栈转储请求)
- 你错误地认为,去除堆栈框架是一种有效的性能改进策略,无论其固有成本(不包括被调用者)是否几乎为零
- 在工作中,你不能为学习如何应用软件性能工程而忙碌
- ….
堆栈跟踪快照只允许您查看应用程序的频闪X射线。 你可能需要更多的知识,分析师可能会给你。
诀窍是认识你的工具,并select最好的工作。
这些必须是一些微不足道的例子,你正在用你的方法来获得有用的结果。 我不能想象一个项目,通过你的“快速和有效的”方法,分析是有用的(不pipe是哪种方法),都可以得到体面的结果。 启动和停止某些应用程序所需的时间已经使您对“快速”的断言成为疑问。
再次,用非平凡的程序,你所提倡的方法是无用的。
编辑:关于“为什么不是更好的了解”?
根据我的经验,代码审查避免了质量差的代码和algorithm,分析也会发现这些。 如果你想继续你的方法,那就太好了 – 但是我认为对于大多数专业人士来说,这是一个很不错的select,因为这是一个很好的利用时间的方法。
对于小样本集似乎相当不准确,并且要获得大样本集需要很多时间,而这些时间本可以更好地用于其他有用的活动。
如果该节目正在制作中 ,并且通过付费客户或同事同时使用,该怎么办? 一个分析器可以让你观察而不会干扰(同样,因为按照海森堡的原则 ,它也会有一点点的打击)。
分析也可以为您提供更丰富,更详细的准确报告。 从长远来看,这将更快。
编辑2008/11/25:好的,Vineet的回应终于让我看到了这个问题。 迟到总比不到好。
不知怎的,这个想法在性能问题被发现的土地上变得松散了。 这是令人困惑的手段与目的。 不知何故,我很久以前就通过单步执行整个程序来避免这种情况。 我没有责备自己放慢速度。 我试图看看是否做错了或不必要的事情。 这就是如何使软件快速find并删除不必要的操作。
目前还没有人有足够的耐心,但最好的办法是随机挑选几个周期,问问他们的原因是什么。 (这就是调用堆栈经常可以告诉你的。)如果他们中有很大比例的人没有很好的理由,你可以做一些事情。
现在比较困难,线程和asynchronous是什么,但这就是我调整软件的方法 – find不必要的循环。 不是看它有多快 – 最后我这样做。
这就是为什么抽样调用栈不能给出错误的答案,为什么不需要很多样本。
在感兴趣的时间间隔内,当程序花费的时间超过了你想要的时间时,即使你不采样,调用堆栈也会持续存在。
- 如果一个指令是在那个时间的分数P(I)的调用堆栈上,如果可以的话,将它从程序中删除,将会节省很多。 如果这不明显,就给一点思考。
如果指令在M = 2或更多的样本上出现,则在N之中,其P(I)大约是M / N,并且肯定是显着的。
你看不到指令的唯一方法就是在指令不在调用堆栈上的时候,把所有的样本神奇地计时。 一个简单的事实,它是存在的一小部分时间是什么暴露给你的探针。
所以性能调优的过程很简单,只需调出指令(主要是函数调用指令),通过打开调用堆栈的多个样本来抬起头来。 那些森林里的高大的树木。
请注意,我们不必关心调用图,函数需要多less时间,或者调用了多less次或recursion。
我反对混淆,而不是针对个人档案。 他们给你很多统计资料,但大多数不给P(I),大多数用户不知道这是重要的。
You can talk about forests and trees, but for any performance problem that you can fix by modifying code, you need to modify instructions, specifically instructions with high P(I). So you need to know where those are, preferably without playing Sherlock Holmes. Stack sampling tells you exactly where they are.
This technique is harder to employ in multi-thread, event-driven, or systems in production. That's where profilers, if they would report P(I), could really help.
Stepping through code is great for seeing the nitty-gritty details and troubleshooting algorithms. It's like looking at a tree really up close and following each vein of bark and branch individually.
Profiling lets you see the big picture, and quickly identify trouble points — like taking a step backwards and looking at the whole forest and noticing the tallest trees. By sorting your function calls by length of execution time, you can quickly identify the areas that are the trouble points.
I used this method for Commodore 64 BASIC many years ago. It is surprising how well it works.
I've typically used it on real-time programs that were overrunning their timeslice. You can't manually stop and restart code that has to run 60 times every second.
I've also used it to track down the bottleneck in a compiler I had written. You wouldn't want to try to break such a program manually, because you really have no way of knowing if you are breaking at the spot where the bottlenck is, or just at the spot after the bottleneck when the OS is allowed back in to stop it. Also, what if the major bottleneck is something you can't do anything about, but you'd like to get rid of all the other largeish bottlenecks in the system? How to you prioritize which bottlenecks to attack first, when you don't have good data on where they all are, and what their relative impact each is?
The larger your program gets, the more useful a profiler will be. If you need to optimize a program which contains thousands of conditional branches, a profiler can be indispensible. Feed in your largest sample of test data, and when it's done import the profiling data into Excel. Then you check your assumptions about likely hot spots against the actual data. There are always surprises.