超越堆栈采样:C ++ Profiler


146

黑客的故事

日期是2010年12月2日。圣诞节前的日子不多了,作为Windows程序员,我几乎遇到了一个主要障碍。我一直在使用AQTime,尝试过困倦,发亮和非常困倦,而正如我们所说的,VTune正在安装。我曾尝试使用VS2008 Profiler,但它一直在积极地惩罚着人们,而且常常是不明智的。我使用了随机暂停技术。我已经检查了呼叫树。我已经解雇了功能痕迹。但令人悲伤的事实是,我正在使用的应用程序超过一百万行代码,可能还有价值一百万行的第三方应用程序。

我需要更好的工具。 我已经阅读了其他主题。 我已经尝试了每个主题中列出的每个事件探查器。简直就是必须有比这些笨拙而昂贵的选择更好的东西,或者可笑的工作量几乎没有收益。更复杂的是,我们的代码具有大量线程,并运行许多Qt Event循环,其中某些循环如此脆弱,以至于它们由于时序延迟而在繁重的测试中崩溃。不要问我为什么我们要运行多个事件循环。没有人能告诉我。

在Windows环境中,Valgrind还有更多选择吗?
有没有比我已经尝试过的一堆破烂的工具更好的东西了?
是否有任何旨在与Qt集成的东西,也许可以在队列中显示有用的事件?

我尝试过的工具的完整列表,以及在斜体中真正有用的工具:

  • AQTime:很好!深度递归会遇到一些麻烦,但是在这些情况下,调用图是正确的,并且可以用来消除您可能遇到的任何混乱。不是一个完美的工具,但是值得尝试。它可能适合您的需求,并且在大多数情况下对我来说已经足够了。
  • 调试模式下的随机暂停攻击:没有足够的时间信息。
    一个好的工具,但不是一个完整的解决方案。
  • 并行工作室: 核选项。引人入胜,古怪而疯狂。我认为您应该进行30天的评估,并确定是否合适。这也太酷了。
  • AMD Codeanalyst:很棒 ,易于使用,非常容易崩溃,但是我认为这是环境问题。我建议您尝试一下,因为它是免费的。
  • 卢克·斯塔克沃克(Luke Stackwalker):在小型项目上运行良好,这是在尝试使其在我们的项目上运行。虽然有一些不错的结果,但是它绝对可以代替Sleepy来完成我的个人任务。
  • PurifyPlus:不支持Win-x64环境,最主要的是Windows7。否则,它非常出色。我在其他部门的许多同事对此表示肯定。
  • VS2008 Profiler:在功能跟踪模式下以所需的分辨率产生100 + gigs范围的输出。从好的方面来说,产生可靠的结果。
  • GProf:要求GCC还要适度有效。
  • VTune:VTune的W7支持犯罪分子的边界。否则优秀
  • PIN:我需要破解我自己的工具,所以这是最后的选择。
  • Sleepy \ VerySleepy:对于较小的应用程序很有用,但在这里让我失望。
  • EasyProfiler:如果您不介意使用一些手动注入的代码来指示要检测的位置,那还不错。
  • Valgrind:仅* nix,但在那种环境下非常好。
  • OProfile:仅Linux。
  • 亵渎:他们射击野马。

我没有尝试过的建议工具:

  • XPerf:
  • 发光代码:
  • 开发伙伴:

注意:目前是 Intel环境。VS2008,增强库。Qt 4+。而所有这些令人沮丧的杂物:通过trolltech进行Qt / MFC集成。


现在:大约两周后,看来我的问题已解决。借助各种工具,包括列表中的几乎所有内容以及我的一些个人技巧,我们找到了主要的瓶颈。但是,我将继续测试,探索和尝试新的探查器以及新技术。为什么?因为我欠你们,因为你们摇滚。它确实使时间线放慢了一点,但是我仍然很高兴继续尝试新工具。

简介
在许多其他问题中,最近将许多组件切换到了错误的线程模型,由于下面的代码突然不再是多线程的,导致了严重的问题。我不能说太多,因为它违反了我的NDA,但是我可以告诉您,通过偶然检查甚至常规代码检查都不会发现它。如果没有探查器,通话记录和随机暂停的共同作用,我们仍然会对天空的美丽蓝色弧线大怒。值得庆幸的是,我与一些我见过的最好的黑客一起工作,而且我可以接触到一个充满了强大工具和才华横溢的“诗篇”。

绅士们,我非常感谢您,很遗憾,我没有足够的代表来奖励你们每个人。我仍然认为,这是一个重要的问题,比到目前为止我们在SO上获得的答案更好。

因此,在接下来的三周中,每周我将尽我所能提供最大的赏金,并用我认为并不常见的最好的工具将其奖励给答案。三个星期后,希望您能对我的探查器有一个完整的了解,请原谅。

外卖
使用探查器。对于Ritchie,Kernighan,Bentley和Knuth来说,它们足够好。我不在乎你以为你是谁。使用探查器。如果找到的那个不起作用,请找到另一个。如果找不到,请编码一。如果您无法编写一个代码,或者是一个小的挂断,或者只是被卡住,请使用随机暂停。如果其他所有方法都失败了,请雇用一些研究生来进行探查。


更长的视野
因此,我认为撰写回顾展可能会很好。我选择与Parallel Studios进行广泛合作,部分原因是它实际上是基于PIN工具构建的。与一些研究人员进行过学术往来后,我觉得这可能是某种品质的标志。幸运的是,我是对的。虽然GUI有点令人恐惧,但我发现IPS非常有用,尽管我不能为所有人推荐它。至关重要的是,没有明显的方法来获取行级命中数,这是AQT和许多其他探查器提供的,并且我发现对于检查分支选择率等非常有用。在网络上,我也很喜欢使用AQTime,而且我发现他们的支持非常有效。同样,我必须符合我的建议:它们的许多功能不能很好地工作,其中一些在Win7x64上非常容易崩溃。XPerf的性能也令人赞叹,但对于在某些类型的应用程序上获得良好读取所需的采样细节而言,它的速度实在令人沮丧。

现在,我不得不说,我认为在W7x64环境中没有确定的C ++代码概要分析选项,但是肯定有一些选项根本无法执行任何有用的服务。


18
您是否考虑过要换一份工作?:)
Nikolai Fetissov 2010年

10
我还能在哪里解决难题呢?我想我可以回到内核黑客攻击上,但这还不算什么。
杰克·库泽

3
@Kos我认为gprof不能有任何用途,您必须使用-pg编译的gcc工具集,否则它不会产生gprof.out文件。在OP的情况下,听起来好像他正在使用msvc,但排除了使用gprof的情况。再说一次,我不认为如果名单上的其他人都无法满足他的需要
那么

2
@Marc Gravell我想这很公平....对我来说,似乎很奇怪,最保养得当的帖子突然进入了社区领域,有效地产生了这样一种情况:您更新和维护问题或答案的次数越多,从整个社区的角度来看,您从维护工作中获得的收益就越少。我应该把它带到meta吗?
杰克·库泽

2
鉴于我现在对探查器的了解,有人想要回顾吗?
杰克·库泽

Answers:


65

第一:

时间采样探查器比CPU采样探查器更强大。我对Windows开发工具不是很熟悉,所以我不能说哪个是哪个。大多数探查器都是CPU采样。

CPU采样探查器每N条指令就抓取一次堆栈跟踪。
此技术将揭示代码中受CPU约束的部分。如果这是您应用程序中的瓶颈,那就太好了。如果您的应用程序线程大部分时间都在为互斥体而战,那就不是很好。

时间采样分析器每N微秒捕获一次堆栈跟踪。
该技术将在“慢速”代码上归零。原因是CPU绑定,阻塞IO绑定,互斥体绑定还是代码的缓存颠簸部分。简而言之,无论哪段代码都会减慢您的应用程序的性能。

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

第二:

采样分析器会生成数据块。数据是非常有用的,但往往有太多不容易使用的数据。个人资料数据可视化工具在这里大有帮助。我发现用于概要文件数据可视化的最佳工具是gprof2dot。不要让这个名字愚弄您,它会处理各种采样探查器输出(AQtime,Sleepy,XPerf等)。可视化文件指出了有问题的功能后,请跳回原始配置文件数据以获得有关真正原因的更好提示。

gprof2dot工具生成一个点图描述,然后将其输入到graphviz工具中。输出基本上是一个调用图,其功能根据对应用程序的影响进行了颜色编码。 替代文字

一些提示让gprof2dot生成漂亮的输出。

  • --skew在图表上使用0.001,因此我可以轻松查看热代码路径。否则,将int main()主导图形。
  • 如果您要对C ++模板进行疯狂的操作,则可能需要添加--strip。Boost尤其如此。
  • 我使用OProfile生成采样数据。为了获得良好的输出,我需要对其进行配置以从我的第3方和系统库中加载调试符号。一定要这样做,否则您会发现CRT占用了应用程序20%的时间,而真正发生的事情是浪费malloc堆并吞噬了15%。

虽然我不知道这是我所遇到问题的完整答案,但gprof2dot已进入我庞大的兵工厂,并迅速成为最受欢迎的地点。我认为这值得悬赏!
杰克·库泽

2
我问了这个问题,它是基于Linux时间样本的探查器。OProfile最终被认为是基于获取时间的采样。它们产生非常高质量的输出,因此一旦添加了该功能,我就将使用它们。除此之外,我还有一个朋友一起破解了gdb + backtrace解决方案来进行性能分析。非常hacky,但确实找到了瓶颈。
deft_code 2012年

@deft_code:“一起破解gdb + backtrace解决方案以进行概要分析。非常hacky,但确实找到了瓶颈。” 您正在确认我的观点:)有些人希望外观漂亮,但如果结果是您所需要的,那就去用有效的方法,而不是好用的方法
Mike Dunlavey 2014年

我同意Mike Dunlavey的观点。XPerf / WPA之类的东西看起来非常漂亮而且功能强大,但是弄清楚如何使用这些工具需要花费一些时间,最终,随机暂停非常容易,并且可以提供更好的信息来解决问题。似乎更多的自动化解决方案往往会过滤掉解决瓶颈所需的关键信息。
JDiMatteo 2014年

16

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

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

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

如果它试图在两个或两个以上的样本上完成某项任务,而该任务并非绝对必要,那么我发现了一个实际问题,并且我大致知道可以节省多少固定费用。

还有,你并不真的需要知道,像精确的百分比并不重要,什么那张里面的第三方代码并不重要,因为你不能做任何事情的事情。你可以做一些什么是你的代码的丰富的呼叫点可以在每个堆栈样本上显示的修改。那就是你快乐的狩猎场。

我发现的种类的例子:

  • 在启动过程中,尝试从DLL资源提取国际化字符串的过程中,它的深度可能约为30层。如果检查了实际的字符串,可以很容易地发现这些字符串实际上并不需要进行国际化,就像它们是用户实际上从未看到过的字符串一样。

  • 在正常使用期间,某些代码会无辜地在某些对象中设置Modified属性。该对象来自一个超类,该类捕获更改并触发通知,这些通知在整个数据结构中起伏不定,操纵UI,以难以预料的方式创建和破坏对象。这可能会发生很多-通知的意外后果。

  • 逐行,逐单元填写工作表。事实证明,如果您一次从一个值数组构建所有行,则速度要快得多。

PS:如果您是多线程的,则在暂停它时,所有线程都会暂停。看一下每个线程的调用堆栈。机会是,其中只有一个是真正的罪魁祸首,而其他人则在闲置。


2
注释?注释?这是斯巴达!我...对不起,不知道那是哪里来的。不,该代码使Klingon Opera看起来可读性强,并且它的文档记录也差不多。其实,我认为它的文献记载还很少。
杰克·库泽

3
QTMFC集成?哦,太好了,您变得非常复杂邪恶,甚至还没有使用过针对特定应用程序的代码。
Ben Voigt 2010年

5
QT / MFC?难道这不会产生三个脑袋摇晃的变异孩子,同时呼唤他们听到过最愚蠢的想法时会来回摇摆吗?Errr ...我离题了...如果您使用任何MFC Socket类,请立即重写您的套接字代码,然后进行概要分析。我发现在CSocket代码中有很多地方使用消息循环版本的WaitForSingleObject,这会降低性能。为了我的生命,我不记得等待功能的名称...:/
JimR 2010年

2
噢,天哪,请相信我,这完全像您想的那样棘手。
杰克·库泽

3
@杰克:没有太多的安慰,但这就是图灵普遍性的荣耀。任何语言,无论级别高低,都具有被滥用的无限能力。
Mike Dunlavey 2010年

8

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


目前,英特尔环境。不过我会记住的!:)
Jake Kurzer 2010年

4
@杰克:我不确定你在那里的意思。AMD CodeAnalyst不需要AMD芯片,它应该可以在大多数x86或x64(aka x86-64 / IA-64 / AMD64)芯片上运行,包括Intel芯片。
亚当·罗森菲尔德

1
显然,我是文盲!那真是个好消息。我明天会尝试并更新问题。
杰克·库泽

到目前为止,以我需要的分辨率进行采样时非常不稳定。
杰克·库泽

@Adam:最近我在intel pentium IV机器上尝试了代码分析器,它仅提供基于时间的采样,没有有关线程使用的信息,也没有与线程相关的信息……我得到的信息量确实很少。此外,它还导致Visual Studio的qt集成崩溃。.我不满意:(
smerlin 2010年

7

您有MFC OnIdle函数吗?过去,我有一个近乎实时的应用程序,我必须解决的问题是,当设置为19.2K速度时,PentiumD应该能够跟上串行数据包的丢失。OnIdle函数是杀死事物的原因。我不确定QT是否具有该概念,但我也会对此进行检查。


2
我们实际上确实有一个OnIdle,并且由于我们的QTMFC集成,它正在QT ev..e ... eve ... event循环中流动。哦,天哪。
杰克·库泽

事实证明,这直接导致了我们的解决方案,因此,尽管这不是对问题的完美答案,但我认为该问题无法回答。
杰克·库泽

4

重新使用VS Profiler-如果它生成如此大的文件,也许您的采样间隔太频繁了?尝试降低它,因为您可能仍然有足够的样本。

理想情况下,请确保您没有在实际锻炼问题区域之前收集样本。因此,从暂停的收集开始,使程序执行“缓慢的活动”,然后开始收集。您最多只需要20秒的收集时间。此后停止收集。

这应有助于减少样本文件的大小,并且仅捕获分析所需的内容。


我明天再试一下。
杰克·库泽

4

我已经成功地将PurifyPlus用于Windows。尽管它并不便宜,但是IBM提供的试用版有些残缺。您只需使用pdb文件和/ FIXED:NO链接进行量化分析,就可以了。唯一的缺点:不支持Win7 / 64。


不幸的是,我们的主要目标是Win7。我会将这些信息添加到主要帖子中。
杰克·库泽

1
当前的PurifyPlus版本支持Win7 / 64。
hmuelner 2013年

3

Easyprofiler在这里我还没有看到它,所以不确定您是否已经看过它。它在收集度量标准数据方面采用了稍微不同的方法。使用其编译时概要文件方法的一个缺点是您必须对代码库进行更改。因此,您需要对慢速可能在哪里有所了解,然后在其中插入性能分析代码。

不过,按照您的最新评论看来,您至少正在取得一些进展。也许此工具可能为您提供了一些有用的指标。如果没有别的,它有一些非常纯正的图表和图片:P


3

另外两个工具建议。

卢克·斯塔克沃克(Luke Stackwalker)的名字很可爱(即使我想尝试一下也很努力),它不会花费您任何钱,而且您会获得源代码。它声称也支持多线程程序。因此,无疑值得一试。

http://lukestackwalker.sourceforge.net/

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

http://www.glowcode.com/

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


3

结帐XPerf

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


3

如果您怀疑事件循环,可以覆盖QCoreApplication :: notify()并进行手动配置(一两个发送者/事件到计数/时间的映射)?

我认为您首先要记录事件类型的频率,然后更仔细地检查那些事件(哪个对象发送了它,它包含了什么,等等)。线程中的信号被隐式地排队,因此它们最终会进入事件循环(显然,显式排队连接也是如此)。

我们已经完成它捕获和报告异常在我们的事件处理程序,所以真的,事件都通过该。

只是个主意。


好主意!我不习惯QT环境,从现在到现在都完成了pyGTK的大部分工作。谢谢!
杰克·库泽

您是否有推荐的方法来寻找和解决给定信号的性质?
杰克·库泽

我只用QStateMachine :: SignalEvent来完成信号,这似乎并不相同。源仍应为QObject* object参数。也许MetaCall是所有信号的类型(似乎很可能),但是我不确定。这超出了我的经验,但是窥探Qt源可能会收集一些真相。(或者,在SO ..上问一个更尖锐的问题wrt排队信号调用:)
Macke 2010年

2

编辑:我现在看到您在第一篇文章中提到了这一点。该死,我从没想过我会成为那个家伙。

您可以使用Pin来细化代码。我认为Pin可以让您创建一个工具,以大致模拟VTune或CodeAnalyst之类的功能来计算输入函数的次数或在其中花费的时钟次数。然后,您可以精简安装哪些功能,直到时序问题消失。


其实,PIN是我最先接触到的。实际上有一种叫做PIN Play的东西会很完美,但是它不适合在Intel之外发布。我不确定我是否足够记得使用PIN来组合一些非常好的东西,但是……
Jake Kurzer 2010年

2

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

a)AMD代码分析师

  • 这很容易,它将使您快速了解正在发生的事情。在大多数情况下都可以。
  • 使用AMD CPU,它将告诉您有关cpu管道的信息,但是只有在循环很重的情况下(例如图形引擎,视频编解码器等),才需要此信息。

b)VTune。

  • 它与vs2008很好地集成在一起

  • 在了解了热点之后,您不仅需要采样时间,还需要采样其他内容,例如缓存未命中和内存使用情况。这很重要。设置采样会话,然后编辑属性。我总是采样时间,内存读/写和缓存未命中(三种不同的运行)

但是,除了工具之外,您还需要获得配置方面的经验。这意味着了解CPU /内存/ PCI的工作原理...所以,这是我的第三个选择

c)单元测试

如果您正在开发需要巨大性能的大型应用程序,那么这非常重要。如果您无法将应用分成几部分,将很难跟踪CPU的使用情况。我没有测试所有情况和类,但是我对执行代码和具有重要功能的输入文件进行了硬编码。

我的建议是在几个小型测试中使用随机抽样,并尝试标准化配置文件策略。


AMD Code Analyst在我的开发环境中不稳定,并且VTune明确不支持它。:S
Jake Kurzer 2010年

2

我将xperf / ETW用于所有性能分析需求。它具有陡峭的学习曲线,但是功能强大。如果要在Windows上进行概要分析,则必须了解xperf。我经常使用此探查器在我的代码和其他人的代码中查找性能问题。

在我使用它的配置中:

  • xperf从每毫秒执行代码的每个内核中获取CPU样本。采样率可以提高到8 KHz,并且采样包括用户模式和内核代码。这允许找出线程在运行时在做什么
  • xperf记录每个上下文切换(允许完美地重建每个线程使用多少时间),以及何时接通线程的调用堆栈,以及为哪个线程准备了另一个线程的调用堆栈,从而允许跟踪等待链并找出线程的原因没有运行
  • xperf记录来自所有进程的所有文件I / O
  • xperf记录所有进程的所有磁盘I / O
  • xperf记录哪个窗口处于活动状态,CPU频率,CPU电源状态,UI延迟等。
  • xperf还可以记录来自一个进程的所有堆分配,来自所有进程的所有虚拟分配等等。

在一个时间轴上,所有流程都包含大量数据。Windows上没有其他探查器可以做到这一点。

我已经在博客中广泛介绍了如何使用xperf / ETW。这些博客文章以及一些专业质量的培训视频可以在以下位置找到:http : //randomascii.wordpress.com/2014/08/19/etw-training-videos-available-now/

如果您想了解如果不使用xperf将会发生什么,请阅读以下博客文章:http : //randomascii.wordpress.com/category/investigative-reporting/ 这些都是我在其他人的代码中发现的性能问题的故事,开发人员应该已经找到了。其中包括将mshtml.dll加载到VC ++编译器中,拒绝VC ++的文件查找服务,在数量惊人的客户计算机中进行热调节,在Visual Studio中执行缓慢的单步执行,在硬编码中分配4 GB磁盘驱动程序,PowerPoint性能错误等。


1

我刚刚完成了CxxProf的第一个可用版本是用于C ++的便携式手动检测概要文件库。

它实现了以下目标:

  • 易于整合
  • 在编译时轻松删除lib
  • 在运行时轻松删除库
  • 支持多线程应用
  • 支持分布式系统
  • 尽量减少影响

这些要点已从项目Wiki中删除,请查看那里以了解更多详细信息。

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


1

即使它不是一个完善的探查器,也要把它扔掉:如果您只需要挂起的事件循环,这会花费很长时间来处理事件,那么这是一个临时工具在Qt中,很简单。可以轻松扩展该方法,以跟踪每个事件需要花费多长时间以及这些事件是什么,等等。它不是通用的探查器,而是一个以事件循环为中心的探查器。

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


0

DevPartner最初由NuMega开发,现在由MicroFocus分发,曾经是分析和代码分析(例如内存和资源泄漏)的首选解决方案。我最近没有尝试过,所以不能保证会给您带来帮助。但是我曾经获得过出色的结果,因此我确实考虑将其重新安装到我们的代码质量流程中(他们提供14天的试用期)


0

虽然您的操作系统是win7,但程序无法在XP下运行?如何在xp下配置它,结果应该是win7的提示。


当然可以,但是那将需要购买可能永远无法很好地支持所需开发环境的产品的许可证,或者可能需要花费数年的时间。1.5k是一笔很大的赌注,加上成像和部署XP盒的时间成本。
杰克·库泽

0

这里列出了许多探查器,我自己尝试了其中的一些探查器-但是我最终基于此编写了自己的探查器:

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

当然,确实需要修改代码库,但是它非常适合缩小瓶颈,应该在所有x86上都可以使用(多核处理器可能是个问题,即它使用rdtsc,但是,这纯粹是用于指示性时序-因此我发现它足以满足我的需求。)



By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.