代码之家  ›  专栏  ›  技术社区  ›  Mike Dunlavey

可以使用分析器,但为什么不停止程序呢?[闭门]

  •  44
  • Mike Dunlavey  · 技术社区  · 17 年前

    如果某个东西使一个单线程程序花费的时间是它应该花费的时间的10倍,那么您可以在其上运行探查器。你也可以用一个“暂停”按钮来停止它,你会看到它在做什么。

    即使它只比它应该的慢10%,如果你停止它更多次,不久你就会看到它重复做不必要的事情。通常问题是函数调用在堆栈中间的某个地方,而不是真正需要的。这并不能衡量问题的严重程度,但它肯定能找到问题所在。

    编辑:反对意见大多假设您只取一个样本。如果你是认真的,拿10块。平均而言,任何导致一定百分比浪费的代码行(如40%)都会出现在该部分样本的堆栈上。瓶颈(在单线程代码中)无法隐藏。

    编辑:为了说明我的意思,许多反对意见的形式是“没有足够的样本,所以你看到的可能完全是假的”——关于机会的模糊想法。但是如果 任何可辨认的描述 ,而不仅仅是在例行程序中或例行程序处于活动状态,在30%的时间内有效,那么在任何给定样本中看到它的概率是30%。

    那么假设只采集了10个样本。在10个样本中发现问题的次数如下 binomial distribution

    在这种情况下,在10个样本中看到它的几率是86%。如果有14%的人看不到,那就多拿些样品,直到你看到为止。(如果样本数量增加到20个,看到它两次或两次以上的几率会增加到99%以上)因此它没有被精确测量,但它已经被精确地找到了,重要的是要理解它可能是探查器无法实际发现的东西,例如涉及数据状态的东西,不是程序计数器。

    17 回复  |  直到 14 年前
        1
  •  53
  •   Peter Mortensen Pieter Jan Bonestroo    15 年前

    在Java服务器上,快速完成2-3个任务始终是一个巧妙的技巧 Ctrl键 - 打破 s并获取所有运行线程的2-3个线程转储。只需查看所有线程的“所在”位置,就可以非常快速地找出性能问题所在。

    这种技术比我所知道的任何其他技术都能在2分钟内揭示更多的性能问题。

        2
  •  33
  •   Paul Tomblin    17 年前

        3
  •  27
  •   JesperE    17 年前

    手动执行此操作实际上不能称为“快速”或“有效”,但有几种分析工具可以自动执行此操作;亦称为 statistical profiling .

        4
  •  15
  •   Peter Mortensen Pieter Jan Bonestroo    14 年前

    为什么? 正在调用一个函数。我经常使用它,但我使用自动化工具,例如 Luke Stackwalker OProfile 和各种硬件供应商提供的东西。

    statistical power . 当一个函数占用运行时间的40%时,手动获取十个样本是可以的,因为平均而言,您将在其中获得四个样本,并且始终至少有一个。但是,如果您有一个平面配置文件,有数百个叶函数,没有一个占用超过运行时1.5%的时间,那么您需要更多的示例。

    假设你有一个湖里有许多不同种类的鱼。如果湖中有40%的鱼是鲑鱼(还有60%是“其他所有的”),那么你只需要钓到10条鱼就知道湖中有很多鲑鱼。但如果你有数百种不同种类的鱼,而且每种鱼的数量都不超过1%,那么你需要捕到更多的鱼才能说“这个湖有0.8%的鲑鱼和0.6%的鳟鱼。”

    malloc ),但大多数都没有,而且在任何情况下,没有一片叶子每帧占用超过1000μs。

    我可以看一下 大旅行箱 函数,看,“我们在碰撞上花费了10%的时间”,但这并没有多大帮助:我需要确切地知道 哪里 在碰撞中,我知道要挤压哪些函数。只是“减少碰撞”只会让你走到这一步,尤其是当它意味着扔掉特性的时候。我更愿意知道“我们平均每帧花费600微秒在缓存的窄段丢失上 the octree 因为魔法导弹移动得如此之快,接触到许多细胞,“因为这样我就可以追踪到确切的修复方法:要么是更好的树,要么是更慢的导弹。

    stricmp

    但卢克·斯塔克沃克(Luke Stackwalker)所做的本质是你所描述的:大约每毫秒,它就会停止程序并记录调用堆栈(包括调用的精确指令和行号) IP ).有些程序只需要成千上万个样本就可以有效地分析。

        5
  •  10
  •   andy SKK    17 年前

    我知道很多程序员(包括我自己)都使用这种方法。它只会真正有助于发现最明显的性能问题,但它速度快、脏而且有效。

    但我不会真的告诉其他程序员去做,因为我要花很长时间来解释所有的警告。基于这种方法很容易得出不准确的结论,而且在很多领域根本不起作用。(例如,该方法不会显示由用户输入触发的任何代码)。

        6
  •  10
  •   Peter Mortensen Pieter Jan Bonestroo    15 年前

    评测是很棒的,而且当您能够做到这一点时,它肯定是一种更精确、更精确的方法。有时候你做不到,有一个可靠的后援是很好的。暂停技术就像当电动工具太远或电池耗尽时使用的手动螺丝刀。

    Process Explorer ,我们可以看到线程堆栈的快照。您可以浏览堆栈的顶部,用enter键将其关闭,然后用另一次鼠标单击获取另一个快照。你可以很容易地每隔一秒钟左右得到一个样品。

    不需要很长时间就可以看到堆栈的顶部通常位于数据库客户机库DLL(等待数据库)中,还是位于另一个系统DLL(等待系统操作)中,或者实际上位于应用程序本身的某些方法中。在本例中,如果我没记错的话,我们很快注意到10次中有8次应用程序在系统DLL文件调用中读取或写入网络文件。确实,最近的“升级”改变了文件共享的性能特征。没有一个快速的、肮脏的(系统管理员认可的)方法来查看应用程序在做什么 生产中 ,我们会花更多的时间来衡量问题,而不是纠正问题。

    另一方面,当性能要求超出“足够好”以真正达到极限时,探查器就变得至关重要,这样您就可以尝试从所有紧密联系的前十或二十个热点中剔除周期。即使您只是在项目过程中试图保持适度的性能要求,当您能够获得正确的工具来帮助您进行测量和测试,甚至将它们集成到您的自动化测试过程中时,它也会非常有用。

    但是当电源断了(可以说)电池没电时,知道如何使用手动螺丝刀就好了。

        7
  •  8
  •   Peter Mortensen Pieter Jan Bonestroo    15 年前

    如果我们问“为什么它不更为人所知?”那么答案将是主观的。可能是因为评测提供了一个长期的解决方案,而不是当前的问题解决方案。它对于多线程应用程序无效,对于花费大量时间渲染的游戏等应用程序无效。

    如果您有良好的检测代码,那么您可以检查的不仅仅是特定方法的使用时间;你可以看到所有的方法。

    使用配置文件:

    • 然后,您可以在每次更改后重新运行场景,以确定性能改进/回归的程度。

    • 您可以让初级开发人员更容易地可视化他们对代码所做更改的影响,因为他们可以在您离开海滩或酒吧(或两者兼而有之)的六个月内重新分析代码。海滩酒吧,ftw。

    由于企业代码应该 总是 具有一定程度的剖析能力,因为它能在较长时间内为组织带来好处。代码越重要,进行的评测和测试就越多。

    您的方法是有效的,并且是开发人员工具箱中的另一项。它只是被分析压倒了。

        8
  •  7
  •   Vineet Reynolds    17 年前

    如果您必须避免使用探查器,更好的选择是使用记录器,然后将减速因子应用于“猜测”真正的问题所在。然而,分析器是更好的猜测工具。

    在调试模式下点击暂停按钮可能无法给出应用程序行为的真实画面,原因是调试器引入了额外的可执行代码,这会减慢应用程序的某些部分。可以参考 Mike Stall's blog post 调试环境中应用程序速度减慢的可能原因。这篇文章揭示了某些原因,如断点太多、创建异常对象、未优化代码等。关于未优化代码的部分很重要,“调试”模式将导致大量优化(通常是代码排列和重新排序)被抛出窗口,以启用调试主机(运行代码的进程)和IDE来同步代码执行。因此,在“调试”模式下反复点击暂停可能是个坏主意。

        9
  •  7
  •   Peter Mortensen Pieter Jan Bonestroo    14 年前

    1. 您正在使用少量线程监视运行时。最好是一个。
    2. 每个线程的调用堆栈深度相对较小(以减少收集样本时令人难以置信的开销)。
    3. 您只关心挂钟时间,而不关心其他仪表或资源瓶颈。
    4. 无论内在成本(不包括被调用方)实际上是否为零,您都错误地认为删除堆栈帧是一种有效的性能改进策略
    5. 您不必费心学习如何在日常工作中应用软件性能工程
        10
  •  6
  •   Thorbjørn Ravn Andersen    17 年前

    堆栈跟踪快照仅允许您查看应用程序的频闪x射线。你可能需要更多的知识积累,而档案员可能会给你。

        11
  •  6
  •   Tim    15 年前

    这些必须是一些琐碎的示例,您正在使用这些示例来使用您的方法获得有用的结果。我想不出哪一个项目的评测是有用的(无论采用何种方法),而您的“快速有效”方法能够获得令人满意的结果。启动和停止某些应用程序所需的时间已经使您的“快速”断言受到质疑。

    同样,对于非平凡的程序,您提倡的方法是无用的。

    编辑: 关于“为什么不更为人所知”?

    根据我的经验,代码审查可以避免质量低劣的代码和算法,而分析也会发现这些问题。如果你想继续你的方法,那是很好的——但我认为对于大多数专业人士来说,这是一个很难尝试的事情,它永远不会得到积极的强化,因为这是一个很好的时间利用。

    对于小样本集来说,这似乎是非常不准确的,而获取大样本集则需要花费大量时间,而这些时间本可以更好地用于其他有用的活动。

        12
  •  5
  •   Peter Mortensen Pieter Jan Bonestroo    14 年前

    如果程序在运行中怎么办 生产 同时被付费客户或同事使用。探查器允许您在没有干扰的情况下进行观察(同样多,因为根据 Heisenberg principle ).

    分析还可以为您提供更丰富、更详细、更准确的报告。从长远来看,这会更快。

        13
  •  4
  •   Mike Dunlavey    17 年前

    不知何故,这种想法在英国流行开来,即绩效问题是通过衡量绩效来发现的。这是手段与目的的混淆。不知何故,很久以前我通过单步执行整个程序来避免这种情况。我并没有责备自己把它慢到了人的速度。我试着看看它是做错了还是做了不必要的事情。这就是如何使软件快速-查找并删除不必要的操作。

    我


    这就是为什么对调用堆栈进行采样不能给出错误的答案,以及为什么不需要很多样本。

    在感兴趣的时间间隔内,当程序花费的时间超过您希望的时间时,调用堆栈将持续存在,即使您没有对其进行采样。

    如果指令出现在M=2个或更多样本上,则在N个样本中,其P(I)约为M/N,且绝对有效。

    因此,性能调优的过程很简单,只需挑选指令(主要是函数调用指令),这些指令通过打开调用堆栈的多个样本来提高性能。 那些是森林里的高大树木。

    请注意,我们不必关心调用图,也不必关心函数需要多长时间,调用多少次,也不必关心递归。

    您可以谈论林和树,但是对于任何可以通过修改代码来解决的性能问题,您需要修改指令,特别是具有高P(I)的指令。所以你需要知道他们在哪里,最好不要扮演福尔摩斯。堆栈采样告诉您它们的确切位置。

    这种技术很难在多线程、事件驱动或生产系统中使用。如果剖析器能够报告P(I),那么这就是他们真正能够提供帮助的地方。

        14
  •  4
  •   Peter Mortensen Pieter Jan Bonestroo    14 年前

    单步执行代码对于查看细节和故障排除算法非常有用。这就像是近距离观察一棵树,然后逐个跟踪树皮和树枝的每一条纹理。

    通过分析,您可以看到全局,并快速确定问题点——比如向后退一步,看看整个森林,注意到最高的树。通过按执行时间长度对函数调用进行排序,可以快速识别出故障点所在的区域。

        15
  •  4
  •   Peter Mortensen Pieter Jan Bonestroo    14 年前

    Commodore 64 BASIC 很多年以前。令人惊讶的是,它工作得如此之好。

        16
  •  3
  •   T.E.D.    17 年前

    我通常在超过时间片的实时程序上使用它。您不能手动停止和重新启动每秒必须运行60次的代码。

    我还使用它来跟踪我编写的编译器中的瓶颈。你不想尝试手动破坏这样一个程序,因为你真的没有办法知道你是在瓶颈所在的地方破坏,还是仅仅在瓶颈之后,当操作系统被允许返回停止它时。另外,如果主要的瓶颈是你不能做任何事情,但你想摆脱系统中所有其他巨大的瓶颈怎么办?当您没有关于瓶颈位置的良好数据时,如何确定首先攻击哪些瓶颈的优先级 全部的 是,以及它们各自的相对影响是什么?

        17
  •  3
  •   mseery    17 年前

    程序越大,分析器就越有用。如果您需要优化包含数千个条件分支的程序,那么探查器是必不可少的。输入最大的测试数据样本,完成后将分析数据导入Excel。然后根据实际数据检查关于可能热点的假设。总有惊喜。