如何找到在Linux上运行的C++应用程序中运行缓慢的代码区域?
当前回答
我会使用Valgrind和Callgrind作为我的仿形工具套件的基础。重要的是,Valgrind基本上是一台虚拟机:
(维基百科)Valgrind本质上是虚拟的机器使用准时制(JIT)编译技术,包括动态重新编译。没有来自的内容原始程序始终运行直接在主机处理器上。相反,Valgrind首先翻译将程序转换为临时的、更简单的形式称为中间表示(IR)是处理器中性的,转换后,工具(见下文)可以自由使用无论它想要什么样的转变在Valgrind翻译之前IR返回到机器代码中主机处理器运行它。
Callgrind是一个基于此的剖析器。主要的好处是,您不必运行应用程序数小时就能获得可靠的结果。因为Callgrind是一个非探测型剖面仪,所以即使一秒钟的运行也足以获得可靠的结果。
另一个基于Valgrind的工具是Massif。我使用它来分析堆内存使用情况。它工作得很好。它的作用是为您提供内存使用情况的快照--详细信息What hold What percentage of memory,and WHO has put it there。这些信息在应用程序运行的不同时间点可用。
其他回答
您可以使用loguru这样的日志框架,因为它包括时间戳和总运行时间,可以很好地用于分析:
使用Valgrind、callgrind和kcachegrind:
valgrind --tool=callgrind ./(Your binary)
生成callgrind.out.x。使用kcachegrind读取它。
使用gprof(add-pg):
cc -o myprog myprog.c utils.c -g -pg
(对于多线程、函数指针不太好)
使用google perftools:
使用时间采样,可以发现I/O和CPU瓶颈。
英特尔VTune是最好的(出于教育目的免费)。
其他:AMD Codeanalysis(已被AMD CodeXL取代)、OProfile、“perf”工具(apt-get-install-linux工具)
事实上,没有多少人提到google/基准测试,这有点让人惊讶,虽然固定代码的特定区域有点麻烦,特别是如果代码库有点大的话,但是我发现这在与callgrind结合使用时非常有用
IMHO识别导致瓶颈的工件是这里的关键。不过,我会先尝试回答以下问题,然后根据这些问题选择工具
我的算法正确吗?有锁被证明是瓶颈吗?是否有一段特定的代码被证明是罪魁祸首?IO如何处理和优化?
valgrind与callgrind和kcachegrind的结合应该能对以上几点提供一个不错的估计,一旦确定某段代码存在问题,我建议做一个微基准测试——谷歌基准测试是一个很好的开始。
还值得一提的是
HPC工具包(http://hpctoolkit.org/)-开源,适用于并行程序,并具有一个GUI,可通过该GUI以多种方式查看结果英特尔VTune(https://software.intel.com/en-us/vtune)-如果你有英特尔编译器,这很好τ(http://www.cs.uoregon.edu/research/tau/home.php)
我使用过HPCToolkit和VTune,它们在寻找帐篷中的长极点方面非常有效,并且不需要重新编译代码(除了必须在CMake中使用-g-O或RelWithDebInfo类型的内置来获得有意义的输出)。我听说TAU的能力类似。
这是我用来加速代码的两种方法:
对于CPU绑定的应用程序:
在DEBUG模式下使用探查器来识别代码中有问题的部分然后切换到RELEASE模式,注释掉代码中有问题的部分(不加任何内容),直到看到性能的变化。
对于I/O绑定应用程序:
在RELEASE模式下使用探查器来识别代码中有问题的部分。
N.B.
如果你没有剖析器,就用穷人的剖析器。调试应用程序时单击暂停。大多数开发人员套件将使用注释的行号分解成程序集。从统计上看,你很可能会在一个消耗了大部分CPU周期的区域着陆。
对于CPU来说,在DEBUG模式下进行评测的原因是,如果您尝试在RELEASE模式下进行剖析,编译器将减少数学、矢量化循环和内联函数,这些函数在汇编代码时会使代码陷入无法映射的混乱。无法映射的混乱意味着您的探查器将无法清楚地识别所需的时间,因为程序集可能与正在优化的源代码不符。如果您需要RELEASE模式的性能(例如,对时间敏感),请根据需要禁用调试器功能以保持可用的性能。
对于I/O绑定,探查器仍然可以在RELEASE模式下识别I/O操作,因为I/O操作要么在外部链接到共享库(大多数情况下),要么在最坏的情况下会导致系统调用中断向量(探查器也很容易识别)。
推荐文章
- decltype(auto)的一些用途是什么?
- Shared_ptr转换为数组:应该使用它吗?
- Printf与std::字符串?
- 在Bash中检查变量是否存在于列表中
- 禁用复制构造函数
- 查看PS命令的全部输出
- 只接受特定类型的c++模板
- c#和Java中的泛型有什么不同?和模板在c++ ?
- Linux命令将域名转换为IP
- c++ 11中的递归lambda函数
- 在c++中指针使用NULL或0(零)吗?
- 在c++中,如何将int值附加到字符串中?
- 如何从命令行在windows中找到mysql数据目录
- 就性能而言,使用std::memcpy()还是std::copy()更好?
- 为什么布尔值是1字节而不是1位?