超越堆栈采样:C ++ Profiler

黑客的故事

这个date是12/02/10。 圣诞节前的日子正在stream逝,我几乎是一个Windows程序员打了一个主要的路障。 我一直在使用AQTime,我试过困,有光泽,很困,而且正如我们所说,VTune正在安装。 我试图使用VS2008分析器,这是积极的惩罚,以及往往不知情。 我使用了随机暂停技术。 我已经检查了一些调用树。 我发射了function痕迹。 但是令人痛心的事实是,我正在使用的应用程序有超过一百万行代码,可能还有另外一百万行第三方应用程序。

我需要更好的工具。 我读过其他主题。 我已经尝试了每个主题中列出的每个分析器。 只要有一些比这些垃圾和昂贵的select更好的东西,或者可笑的工作量几乎没有收获。 更复杂的是,我们的代码是高度线程化的,并且运行了一些Qt事件循环,其中一些是非常脆弱的,由于时间延迟,它们在沉重的仪器下崩溃。 不要问我为什么要运行多个事件循环。 没有人能告诉我。

Valgrind在windows环境下有更多的select吗?
有没有什么比我已经尝试过的那些破碎的工具更好?
是否有任何devise与Qt集成,可能与队列中的事件有用的显示?

我试过的工具的完整列表,以及那些在斜体中非常有用的工具:

  • AQTime:相当好! 深度recursion有一些问题,但在这些情况下调用图是正确的,可以用来清除你可能有的任何混淆。 不是一个完美的工具,但值得尝试。 这可能适合你的需求,大部分时间对我来说确实够好。
  • debugging模式下的随机暂停攻击:没有足够的信息足够的时间。
    一个好工具,但不是一个完整的解决scheme
  • 平行工作室:核select。 突兀,怪异,疯狂的强大。 我认为你应该进行30天的评估,并确定它是否合适。 它也很酷。
  • AMD Codeanalyst:精彩,易于使用,非常容易崩溃,但我认为这是一个环境问题。 我build议尝试一下,因为它是免费的。
  • Luke Stackwalker:在小型项目上工作得很好,有点试图让它在我们的工作。 一些好的结果,但它绝对取代了我的个人任务的睡眠。
  • PurifyPlus:不支持Win-x64环境,最显眼的是Windows 7。 我在其他部门的一些同事发誓。
  • VS2008 Profiler:以所需的分辨率在function跟踪模式下产生100 +演出范围内的输出。 从正面来看,产生稳固的结果。
  • GProf:要求海湾合作委员会甚至适度有效。
  • VTune:VTune的W7支持犯罪分子。 否则优秀
  • 个人识别码:我需要破解我自己的工具,所以这是不得已而为之的。
  • 昏昏欲睡\ VerySleepy:有用的小型应用程序,但在这里失败。
  • EasyProfiler:不错,如果你不介意一些手动注入的代码来指示在哪里工具。
  • Valgrind:只有nix,但是当你在这个环境里时,它是非常好的。
  • OProfile:仅限Linux。
  • Proffy:他们拍野马。

我还没有尝试过的build议工具:

  • XPerf:
  • Glowcode:
  • Devpartner:

注意:目前的英特尔环境。 VS2008,增强库。 Qt 4+。 而他们所有人的猥琐手段:通过trolltech进行Qt / MFC集成。


现在:差不多两个星期后,看起来我的问题已经解决了。 感谢各种工具,包括名单上的几乎所有东西以及我个人的一些技巧,我们发现了主要的瓶颈。 但是,我将继续testing,探索和尝试新的分析器以及新技术。 为什么? 因为我欠你们,因为你们摇滚。 它确实减慢了一些时间表,但我仍然非常高兴不断尝试新的工具。

概要
在许多其他问题中,最近一些组件被切换到不正确的线程模式,由于下面的代码突然不再是multithreading的,所以造成了严重的困扰。 我不敢多说,因为它违背了我的NDA,但我可以告诉你,这不可能通过临时检查或甚至通过正常的代码审查发现。 没有configuration文件,电话号码和随机的暂停,我们仍然会在美丽的蓝色天空中尖叫我们的愤怒。 值得庆幸的是,我和一些我见过的最好的黑客合作过,而且我可以使用一个非常棒的工具和伟大的人物。

绅士,我非常欣赏这一点,只有遗憾的是我没有足够的代表来奖励你们每个人。 我仍然认为这是一个重要的问题,以获得比我们目前为止所得到的更好的答案。

结果,在接下来的三个星期的每个星期里,我会把我能负担得起的最大的奖金,并用最好的工具奖给我,我认为这不是常识。 三个星期后,如果你能原谅我的唠叨,我们希望已经积累了一个定型者的明确资料。

带走
使用一个分析器。 对里奇,凯尼根,本特利和克努特来说,这已经足够了。 我不在乎你以为你是谁。 使用一个分析器。 如果你有一个不工作,find另一个。 如果找不到,请input一个。 如果你不能编码,或者是一个小的挂断,或者你只是卡住,使用随机暂停。 如果一切都失败了,请雇一些研究生来敲打一个分析器。


更长远的观点
所以,我认为写一些回顾可能是不错的。 我select与Parallel Studios广泛合作,部分原因是它实际上是build立在PIN工具之上的。 与一些研究人员进行了学术交stream后,我觉得这可能是一些质量的标志。 谢天谢地,我是对的。 虽然graphics用户界面有点恐怖,但是我发现IPS非常有用,尽pipe我不能很好地向大家推荐它。 至关重要的是,没有明显的方法可以获得行级命中计数,AQT和其他一些分析器提供的东西,而且我发现在分支select率等方面非常有用。 在networking上,我也喜欢使用AQTime,并且我发现他们的支持非常有效。 再次,我必须限定我的推荐:他们的许多function不能很好地工作,其中一些function在Win7x64上非常容易崩溃。 XPerf的performance也令人钦佩,但对于在某些应用中获得良好的读取所需的采样细节,却感到痛苦不堪。

现在,我不得不说,我不认为在W7x64环境中分析C ++代码是一个明确的select,但肯定有一些选项不能执行任何有用的服务。

第一:

时间采样分析器比CPU采样分析器更稳健。 我不是很熟悉Windows开发工具,所以我不能说哪个是哪个。 大多数configuration文件是CPU采样。

CPU采样分析器每N条指令抓取一个堆栈跟踪。
这种技术将揭示你的代码是CPU绑定的部分。 如果这是你的应用程序的瓶颈,那真棒。 如果您的应用程序线程花费大部分时间在互斥体上进行争夺,那就不是那么好。

时间采样分析器每N微秒捕获一次堆栈跟踪。
这种技术将在“慢”代码中归零。 无论原因是CPU绑定,阻止IO绑定,互斥锁绑定,还是高速caching抖动代码段。 简而言之,任何一段代码都会减慢应用程序的性能。

因此,尽可能使用时间采样分析器,特别是在分析线程代码时。

第二:

采样分析器产生大量的数据。 这些数据是非常有用的,但往往太多,很容易使用。 configuration文件数据可视化器在这里帮助非常大。 我发现的用于configuration文件数据可视化的最佳工具是gprof2dot 。 不要让名称骗你,它处理各种采样分析器输出(AQtime,Sleepy,XPerf等)。 一旦可视化指出了有问题的function,就跳回到原始的configuration文件数据,以获得更好的提示。

gprof2dot工具生成一个点图描述 ,然后将其input到graphviz工具中。 输出基本上是一个调用函数,其function是通过对应用程序的影响进行颜色编码的。 替代文字

一些提示让gprof2dot生成很好的输出。

  • 我在图上使用了0.001的--skew ,所以我可以很容易地看到热门的代码path。 否则, int main()主宰graphics。
  • 如果你对C ++模板做了什么疯狂的事情,你可能需要添加--strip 。 Boost尤其如此。
  • 我使用OProfile来生成我的采样数据。 为了获得良好的输出,我需要configuration它来加载我的第三方和系统库的debugging符号。 一定要这样做,否则你会看到,当真正发生的事情是malloc的时候,CRT正在占用你应用程序20%的时间,正在捣毁这个堆,吃掉了15%。

当你尝试随机暂停时发生了什么? 我一直使用它在一个怪物的应用程序。 你说它没有提供足够的信息,而且你build议你需要高分辨率。 有时候人们需要一些帮助来理解如何使用它。

我在VS下做的是configuration堆栈显示,所以它不会显示函数参数,因为这会使堆栈显示完全不可读,IMO。

然后, 在我等待的时候,我通过点击“暂停”大约10个样本。 我用^ A,^ C和^ V将它们复制到记事本中,以供参考。 然后我研究每一个,试图找出当时正在努力完成的过程。

如果它试图在2个或更多的样本上完成某件事情,而这件事情不是绝对必要的,那么我发现了一个现实问题,我大概知道它将会节省多less修复。

有些东西你并不需要知道,比如精确的百分比并不重要,第三方代码里面发生的事情并不重要,因为你不能做任何事情。 你可以做些什么是你可以在每个堆栈样本上显示的代码中丰富的调用点。 那是你的快乐狩猎场

我发现的东西的例子:

  • 在启动过程中,尝试从DLL资源中提取国际化string的过程中,可能会有30层左右的深度。 如果检查实际的string,很容易发现string不需要被国际化,就像用户从来没有看到过的string一样。

  • 在正常的使用过程中,有些代码会在一些对象中无辜地设置Modified属性。 这个对象来自一个超级类,捕捉变化,并触发通知,在整个数据结构中涟漪,操纵UI,以难以预料的方式创build和删除obects。 这可能发生很多 – 通知的意外后果。

  • 逐行填写工作表,逐个单元格。 事实certificate,如果您从一系列值中一次构build行,速度会快很多。

PS如果你是multithreading的,当你暂停时,所有线程暂停。 看看每个线程的调用堆栈。 机会是,其中只有一个是真正的罪魁祸首,其他人是空转的。

我在AMD CodeAnalyst上取得了一些成功。

你有一个MFC的OnIdlefunction? 在过去,我有一个接近实时的应用程序,我不得不解决的问题是,以19.2K的速度下载串行数据包,这是PentiumD应该能够跟上的。 OnIdlefunction是什么东西被杀。 我不确定QT是否有这个概念,但是我也会检查一下。

重新VS探查器 – 如果它产生这样的大文件,也许你的采样间隔过于频繁? 尝试降低它,因为你可能有足够的样本。

理想的情况下,确保你没有收集样本,直到你实际上行使问题领域。 因此,从收集暂停开始,让您的程序做“缓慢的活动”,然后开始收集。 您最多只需要20秒的收集时间。 之后停止收集。

这应该有助于减less您的示例文件大小,并只捕获什么是您的分析所必需的。

我成功地使用了PurifyPlus for Windows。 虽然IBM并不便宜,但它提供了一个稍微有点缺陷的试用版本。 所有你需要量化分析是pdb文件和链接/ FIXED:NO。 唯一缺点:不支持Win7 / 64。

Easyprofiler – 我还没有看到它在这里提到,所以不知道你是否已经看过它。 它收集度量数据的方式略有不同。 使用其编译时间configuration文件方法的缺点是您必须对代码库进行更改。 因此,您需要了解缓慢的地方,并在其中插入分析代码。

尽pipe你最近的评论,听起来你至less有一些进展。 也许这个工具可能会为你提供一些有用的指标。 如果没有别的,它有一些真正的purdy图表和图片:P

两个更多的工具build议。

Luke Stackwalker有一个可爱的名字(即使它尝试了一下我的口味),它不会花费你任何东西,而且你得到了源代码。 它声称也支持multithreading程序。 所以这当然值得一提。

http://lukestackwalker.sourceforge.net/

还有Glowcode,我已经指出,值得使用:

http://www.glowcode.com/

不幸的是,我有一段时间没有做任何PC工作,所以我没有尝试过这些。 我希望这些build议无论如何都是有帮助的。

结帐XPerf

这是由MS提供的免费,非侵入性和可扩展的分析器。 它是由Microsoft开发的,用于分析Windows。

如果您怀疑事件循环,可以覆盖QCoreApplication :: notify()和dosome手动分析(发送者/事件的一个或两个映射到计数/时间)?

我在想你首先logging事件types的频率,然后仔细检查这些事件(哪个对象发送它,包含什么等)。 线程间的信号隐式排队,所以它们最终在事件循环中(显然也是显式的排队连接)。

我们已经做到了在事件处理程序中捕获和报告exception,所以每一个事件都经过这里。

只是一个想法。

编辑:我现在看到你在你的第一篇文章中提到这个。 该死的,我从来没有想过我会是那个人。

您可以使用Pin以更精细的方式来testing您的代码。 我认为Pin会让你创build一个工具来计算你进入一个函数的次数,或者你在那里花了多less时钟,大概模仿VTune或者CodeAnalyst。 然后,您可以剥离哪些function得到检测,直到您的计时问题消失。

我可以告诉你我每天都在用什么。

a)AMD代码分析师

  • 这很容易,它会让你快速了解正在发生的事情。 大部分时间都可以。
  • 使用AMD CPU,它会告诉你关于CPUpipe道的信息,但是只有当你有很重的循环时才需要这个,比如在graphics引擎,video编解码器等等。

b)VTune。

  • 它很好地集成在vs2008中

  • 在知道了热点之后,你不仅需要对时间进行抽样,还需要对其他事情进行抽样,比如caching未命中和内存使用。 这非常重要 。 设置一个采样会话,并编辑属性。 我总是抽样的时间,内存读取/写入和caching未命中(三个不同的运行)

但是,不仅仅是工具,你需要获得分析的经验。 这意味着了解CPU /内存/ PCI如何工作…所以,这是我的第三select

c)unit testing

如果您正在开发一个需要巨大性能的大型应用程序,这一点非常重要。 如果你不能分割一些应用程序,将很难跟踪CPU使用情况。 我不testing所有的案例和类,但我已经硬编码执行和重要function的input文件。

我的build议是在几个小testing中使用随机抽样,并尝试标准化一个configuration文件策略。

我刚刚完成了CxxProf的第一个可用版本, CxxProf是一个用于C ++的便携式手动检测分析库。

它实现了以下目标:

  • 易于集成
  • 在编译时轻松删除lib
  • 在运行时轻松删除lib
  • 支持multithreading应用程序
  • 支持分布式系统
  • 保持最低限度的影响

这些点来自项目的维基百科 ,看看有更多的细节。

免责声明:我是CxxProf的主要开发者

我使用xperf / ETW来处理所有的分析需求。 它有一个陡峭的学习曲线,但是非常强大。 如果你在Windows上分析,那么你必须知道xperf。 我经常使用这个分析器来查找我的代码和其他人的代码中的性能问题。

在我使用它的configuration中:

  • xperf从每个执行代码的每个核心每ms获取CPU采样。 采样率可以提高到8KHz,采样包括用户模式和内核代码。 这允许找出线程正在运行的过程
  • xperflogging每个上下文切换(允许每个线程使用多less时间的完美重构),加上线程切换时的调用堆栈,以及调用另一个线程的调用堆栈,允许跟踪等待链并找出为什么线程没有运行
  • xperflogging所有进程的所有文件I / O
  • xperflogging所有进程的所有磁盘I / O
  • xperflogging哪个窗口处于活动状态,CPU频率,CPU电源状态,UI延迟等。
  • xperf还可以logging来自一个进程的所有堆分配,所有进程的所有虚拟分配以及更多。

对于所有进程来说,这些数据都是在一个时间线上。 Windows上没有其他的分析器可以做到这一点。

我已经广泛地讨论了如何使用xperf / ETW。 这些博客文章,以及一些专业质量的培训video,可以在这里find: http : //randomascii.wordpress.com/2014/08/19/etw-training-videos-available-now/

如果你想知道如果你不使用xperf会发生什么事,请阅读这些博客文章: http : //randomascii.wordpress.com/category/investigative-reporting/这些是我在其他人的代码中发现的性能问题的故事,这应该是开发者find的。 这包括将mshtml.dll加载到VC ++编译器中,VC ++查找文件中的拒绝服务,令人惊讶的客户机中的热限制,Visual Studio中的单步缓慢,硬拷贝中的4 GB分配,磁盘驱动程序,一个PowerPoint的性能错误,等等。

只是抛出它,即使它不是一个完整的探查器:如果你所有的事情都挂起事件循环,需要很长时间处理一个事件,一个临时工具在Qt中是简单的事情。 这种方法可以很容易地扩展到跟踪每个事件需要处理多长时间,以及这些事件是什么等等。 这不是一个通用的分析器,而是一个以事件为中心的分析器。

在Qt中,所有跨线程信号槽调用都是通过事件循环传递的,如定时器,networking和串口通知以及所有用户交互。 因此,观察事件循环是理解应用程序花费时间的重要一步。

DevPartner最初由NuMega开发,现在由MicroFocus分发,曾经是分析和代码分析(例如内存和资源泄漏)的解决scheme。 我最近没有试过,所以我不能保证它会帮助你; 但是我曾经有过很好的结果,所以这是我们考虑在代码质量过程中重新安装的替代scheme(他们提供了14天的试用期)

虽然你的操作系统是WIN7,程序不能在XP下运行? 如何在xp下进行configuration,结果应该是win7提示。

这里列出了大量的configuration文件,我自己尝试了其中的一些configuration文件,但是我最终根据自己的需要编写了自己的configuration文件:

http://code.google.com/p/high-performance-cplusplus-profiler/

当然,这需要你修改代码库,但是这对于缩小瓶颈是完美的,应该适用于所有的x86(可能是多核心盒子的问题,也就是使用rdtsc,但是这纯粹是指示性的时间 – 所以我觉得这足以满足我的需要..)