Valgrind s callgrind

本文详细介绍使用Valgrind工具集中的Callgrind进行C程序性能分析的过程,包括工具安装、典型C程序测试、调用图生成及热点分析。通过Valgrind提取详细函数调用信息,配合gprof2dot和kcachegrind展示调用图,帮助开发者理解程序运行细节,定位性能瓶颈。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

官方主页:http://valgrind.org/

最初发表:泰晓科技 – 聚焦嵌入式 Linux,追本溯源,见微知著!
原文链接:源码分析:动态分析 C 程序函数调用关系

转自:https://blog.youkuaiyun.com/tinylab/article/details/45051097

阅读:https://www.linuxidc.com/Linux/2012-06/63754.htm

【linux】Valgrind工具集详解(十五):Callgrind(性能分析图)
https://blog.youkuaiyun.com/u010168781/article/details/84303954

准备

需要事先准备好几个相关的工具。

gprof2dot: converts the output from many profilers into a dot graph

$ sudo apt-get install python python-pip
$ sudo pip install gprof2dot

graphviz: dot 格式处理

$ sudo apt-get install graphviz

gprof: display call graph profile data

$ sudo apt-get install gprof

valgrind: a suite of tools for debugging and profiling programs

$ sudo apt-get install valgrind

工具好了,再来一个典型的 C

程序,保存为:fib.c

#include <stdio.h>

int fibonacci(int n);

int main(int argc, char **argv)
{
    int fib;
    int n;

    for (n = 0; n <= 42; n++) {
        fib = fibonacci(n);
        printf("fibonnaci(%d) = %dn", n, fib);
    }

    return 0;
}

int fibonacci(int n)
{
    int fib;

    if (n <= 0) {
        fib = 0;
    } else if (n == 1) {
        fib = 1;
    } else {
        fib = fibonacci(n -1) + fibonacci(n - 2);
    }

    return fib;
}

 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

Valgrind s callgrind

Valgrind 是开源的性能分析利器。它不仅可以用来检查内存泄漏等问题,还可以用来生成函数的调用图。

Valgrind 不依赖 -pg 编译选项,可以直接编译运行:

$ gcc -o fib fib.c
$ valgrind --tool=callgrind ./fib

 
  • 1
  • 2

然后会看到一份日志文件:

$ ls callgrind*
callgrind.out.22737

 
  • 1
  • 2

然后用 gprof2dot 分析:

$ gprof2dot -f callgrind ./callgrind.out.22737 | dot -Tsvg -o fib-callgrind.svg

 
  • 1

查看 fib-callgrind.svg 如下:

Draw fibonacii by Valgrind s callgrind

需要提到的是 Valgrind 提取出了比 gprof 更多的信息,包括 main 函数的父函数。

不过 Valgrind 实际提供了更多的信息,用 -n0 -e0 把执行百分比限制去掉,所有执行过的全部展示出来:

$ gprof2dot -f callgrind -n0 -e0 ./callgrind.out.22737 | dot -Tsvg -o fib-callgrind-all.svg

 
  • 1

结果如下:

Draw fibonacii by Valgrind s callgrind (All output)

所有的调用情况都展示出来了。热点调用分支用红色标记了出来。因为实际上一个程序运行时背后做了很多其他的事情,比如动态符号链接,还有比如 main 实际代码里头也调用到 printf,虽然占比很低。

考虑到上述结果太多,不便于分析,如果只想关心某个函数的调用情况,以 main 为例,则可以:

$ gprof2dot -f callgrind -n0 -e0 ./callgrind.out.22737 --root=main | dot -Tsvg -o fib-callgrind-main.svg

 
  • 1

Draw fibonacii by Valgrind s callgrind (Only Main)

需要提到的是,实际上除了 gprof2dotkcachegrind 也可以用来展示 Valgrind's callgrind 的数据:

$ sudo apt-get install kcachegrind
$ kcachegrind ./callgrind.out.22737

 
  • 1
  • 2

通过 File --> Export Graph 可以导出调用图。只不过一个是图形工具,一个是命令行,而且 kcachegrind 不能一次展示所有分支,不过它可以灵活逐个节点查看。

小结

上文我们展示了从运行时角度来分析源码的实际执行路径,目前只是深入到了函数层次。

结果上跟上次的静态分析稍微有些差异。

  • 实际运行时,不同分支的调用次数有差异,甚至有些分支可能根本就执行不到。这些数据为我们进行性能优化提供了可以切入的热点。
  • 实际运行时,我们观察到除了代码中有的函数外,还有关于 main 的父函数,甚至还有库函数如 printf的内部调用细节,给我们提供了一种途径去理解程序背后运行的细节。

本文只是介绍到了应用程序部分(实际上是程序运行时的用户空间),下回我们将分析,当某个应用程序执行时,哪些内核接口(系统调用)被调用到,那些接口的执行情况以及深入到内核空间的函数调用情况。

### Valgrind 工具介绍 Valgrind 是一套 Linux 下开源的仿真调试工具集,遵循 GPL V2 许可证[^3]。这套工具主要用于检测程序中的内存错误、线程竞争条件以及其他性能瓶颈。 核心组件被称为 Valgrind 内核,其作用在于创建一个虚拟机环境来模拟 CPU 的行为,在此环境中运行待测应用程序。这种机制使得 Valgrind 能够监控目标应用的一切动态链接库调用和系统调用,从而实现对内存分配与释放过程的有效跟踪[^1]。 除此之外,Valgrind 还提供了多个基于该内核构建的功能模块: - **Memcheck**:这是最常用的子工具之一,专门用来查找 C/C++ 应用中存在的非法访问已分配但未初始化的数据、使用已经释放掉的空间等常见问题。 - **Cachegrind** 和 **Callgrind**:这两个工具有助于评估缓存命中率及函数调用频率,进而优化代码效率。 - **Helgrind**:专注于多线程编程领域内的竞态条件(Race Condition)检测。 - **Massif**:可以绘制堆栈大小随时间变化的趋势图,辅助分析对象生命周期管理不当引发的大规模内存占用现象。 ### Valgrind 使用方法概述 对于希望安装 Valgrind 的用户来说,通常可以通过包管理器轻松获取最新版本软件包[^2]。例如在 Debian 或 Ubuntu 发行版上只需执行命令 `sudo apt-get install valgrind` 即可完成部署工作。 当准备测试某个二进制文件时,一般会采用如下方式启动 Valgrind 并指定要使用的具体工具选项: ```bash valgrind --tool=memcheck ./your_program_name ``` 上述指令默认启用了 Memcheck 功能来进行全面细致的记忆体检查操作。如果想要查看更详细的日志输出,则可以在原有基础上增加参数如 `--leak-check=yes` 来开启泄漏检测模式,或者设置 `-v` 参数获得更加详尽的过程描述信息。 #### 实际案例展示 假设有一个简单的 C 语言编写的 hello world 程序存在潜在的风险点,那么就可以借助 Valgrind 找到这些问题所在之处。以下是具体的实践步骤: 编写一段可能存在问题的小型 C 程序并保存为 test.c 文件: ```c #include <stdio.h> int main() { char *str; str = (char *)malloc(8); strcpy(str, "hello"); printf("%s\n", str); } ``` 接着编译这段代码生成名为 a.out 的可执行文件: ```bash gcc -g -o a.out test.c ``` 最后运用 Valgrind 对刚刚产生的二进制文件做一次完整的扫描检验: ```bash valgrind --tool=memcheck --leak-check=full ./a.out ``` 此时终端将会显示出有关此次运行期间发生的任何异常状况报告,包括但不限于越界读写警告以及未能正确回收资源提示等内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值