用于调用图生成和分析的最小 callgrind 命令

Des*_*o17 2 valgrind callgrind

我想使用 callgrind 来分析我的程序,但它的速度太慢了。我想要做的是使用 kcachegrind 生成一个调用图,其中每个节点显示程序在哪个函数中花费的百分比。你能告诉我我可以安全地禁用哪些功能以获得更好的性能以便仍然生成这些信息吗?

非常感谢!

小智 5

快速概览

Callgrind 本质上是一个缓存分析器(指令和数据),它以函数级粒度工作以重现调用图。分析器观察在程序执行期间触发事件的动作并更新模拟器维护的各种聚合计数器

然而,这种对缓存事件的细粒度模拟是以程序运行时间为代价的。您应该知道,即使关闭了所有分析并且没有收集到有用的数据,Callgrind 仍然会在运行时至少有大约 2-4 倍的命中率。主动收集数据时,平均会慢 10-20 倍

这个理论上的最小值是否可以满足您的要求?如果没有,您应该考虑其他分析选项 - 在此处讨论。但是,如果通过一些仔细的控制,将程序的大块、无趣的块加速到仅 2-4 倍的减速听起来合理,请继续阅读!

可用的钩子

Callgrind 对分析数据的收集提供了两种形式的控制。为了做出明智的选择,了解它们的相互依赖性很重要:

  1. 检测状态- 禁用时,不会观察到任何程序操作,因此不会触发或收集任何事件。模拟器基本上切换到“空闲”状态;这有助于您达到我上面提到的理论 2-4 倍的最小值(参见Nulgrind)。

    但请注意,这应该谨慎使用!虽然它提供了吸引人的好处,但这可能会对准确性产生重大影响。从文档

    但是,这只能以粗略的方式谨慎使用:每次模式更改都会重置模拟器状态(即,内存块是否被缓存)并刷新已检测代码块的 Valgrinds 内部缓存,从而导致切换时的延迟损失时间。

  2. 集合状态- 禁用时,不会使用触发事件更新聚合计数器。这提供了一种将收集到的数据简化到调用堆栈中有趣部分的方法。

    然而,直觉上,这并没有提供任何明显的执行时间加速。当然,需要打开检测才能启用收集。

命令

valgrind --tool=callgrind   
    --instr-atstart=<yes|no>     ;; default = yes 
    --collect-atstart=<yes|no>   ;; default = yes
    --toggle-collect=<function>  ;; Toggle collection at entry/exit of specific function
<PROGRAM> <PROGRAM_OPTIONS>
Run Code Online (Sandbox Code Playgroud)

仪表- 在开始时关闭它表示您必须在适当的时间再次打开它。2 种替代方法来做到这一点:

  1. 在程序执行期间,在适当的时间从 shell 使用以下命令。

    callgrind_control -i <on|off>
    
    Run Code Online (Sandbox Code Playgroud)

    由于部署命令的延迟,这将需要对程序执行的可见性以及对准确性的一些容忍度。当然,您可以使用一些 shell 技巧来提供帮助。

  2. 将以下宏插入您的程序代码并重新编译您的二进制文件。

    CALLGRIND_START_INSTRUMENTATION;
    CALLGRIND_STOP_INSTRUMENTATION;
    
    Run Code Online (Sandbox Code Playgroud)

集合- 同样,如果在开始时禁用,则需要围绕代码的有趣部分切换集合。2 种替代方法来做到这一点:

  1. --toggle-collect=<function>在启动期间使用该标志。根据定义,这将包括此函数内的所有子调用。如果您因此可以将特定的父函数识别为瓶颈,这可能是隔离相关数据并保持生成的调用图最小化的有用方法。

    提示:函数名中支持通配符!

  2. 在程序代码的相关部分前后使用以下宏并重新编译二进制文件。这可以为您提供更细粒度的函数控制。

    CALLGRIND_TOGGLE_COLLECT;
    
    Run Code Online (Sandbox Code Playgroud)

概括

结合上述所有想法,一个好的方法是:

#include <callgrind.h>

// Uninteresting program chunk

CALLGRIND_START_INSTRUMENTATION;

// A few extra lines to allow cache warm-up

CALLGRIND_TOGGLE_COLLECT;
// Portion to profile
CALLGRIND_TOGGLE_COLLECT;

CALLGRIND_DUMP_STATS;
CALLGRIND_STOP_INSTRUMENTATION;

// Rest of the program
Run Code Online (Sandbox Code Playgroud)

重新编译,并使用以下命令启动 Callgrind:

valgrind --tool=callgrind --instr-atstart=no --collect-atstart=no <PROGRAM> <PROGRAM_OPTIONS>
Run Code Online (Sandbox Code Playgroud)

请注意,此方法将生成 2 个 Callgrind 输出文件 - 第一个由DUMP_STATS宏创建,第二个在程序退出时。DUMP_STATS使用后将所有计数器清零,这意味着第二个日志将报告 0 个事件。

在活动检测块中,您还可以多次切换收集并转储每个块的收集统计信息。