[授权发表]源码分析:动态分析 C 程序函数调用关系

2023-05-16

By Falcon of TinyLab.org
2015/04/15

最初发表:泰晓科技 – 聚焦嵌入式 Linux,追本溯源,见微知著!
原文链接:源码分析:动态分析 C 程序函数调用关系
评论说明:为更好地聚合大家的讨论,请到上面原文的评论区回复。


缘由

源码分析是程序员离不开的话题。无论是研究开源项目,还是平时做各类移植、开发,都避免不了对源码的深入解读。

工欲善其事,必先利其器。

之前已经介绍了如何通过 Callgraph 静态分析源代码,这里介绍如何分析程序运行时的实际函数执行情况,考虑到应用部分和内核部分有比较大的差异,该篇先介绍应用部分。

主要介绍三款工具,一款是 gprof,另外一款是 valgrind,再一款则是能够把前两款的结果导出为 dot 图形的工具,叫 gprof2dot,它的功能有点类似于我们上次介绍的 tree2dotx

准备

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

  • 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;
}

gprof

Gprof 用于对某次应用的运行时代码执行情况进行分析。

它需要对源代码采用 -pg 编译,然后运行:

$ gcc -pg -o fib fib.c
$ ./fib

运行完以后,会生成一份日志文件:

$ ls gmon.out
gmon.out

可以分析之:

$ gprof -b ./fib | gprof2dot | dot -Tsvg -o fib-gprof.svg

查看 fib-gprof.svg 如下:

[外链图片转存失败(img-Ag78wyeh-1562434670042)(http://tinylab.org/wp-content/uploads/2015/04/callgraph/fib-gprof.svg)]

可以观察到,这个图表除了调用关系,还有每个函数的执行次数以及百分比。

Valgrind s callgrind

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

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

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

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

$ ls callgrind*
callgrind.out.22737

然后用 gprof2dot 分析:

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

查看 fib-callgrind.svg 如下:

[外链图片转存失败(img-crru7pYh-1562434670043)(http://tinylab.org/wp-content/uploads/2015/04/callgraph//fib-callgrind.svg)]

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

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

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

结果如下:

[外链图片转存失败(img-CTmo7YZG-1562434670043)(http://tinylab.org/wp-content/uploads/2015/04/callgraph/fib-callgrind-all.svg)]

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

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

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

[外链图片转存失败(img-4scQ9vLs-1562434670044)(http://tinylab.org/wp-content/uploads/2015/04/callgraph//fib-callgrind-main.svg)]

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

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

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

小结

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

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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[授权发表]源码分析:动态分析 C 程序函数调用关系 的相关文章

随机推荐

  • stm32零基础应该怎么入门?

    单片机 xff08 microcontrollers xff09 是一种集成电路芯片 xff0c 是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU 多种I O口和中断系统 定时器 计数器等功能集成到一块硅片上构成的一个小而完善
  • Linux:CPU频率调节模式以及降频方法简介

    概述 cpufreq的核心功能 xff0c 是通过调整CPU的电压和频率 xff0c 来兼顾系统的性能和功耗 在不需要高性能时 xff0c 降低电压和频率 xff0c 以降低功耗 xff1b 在需要高性能时 xff0c 提高电压和频率 xf
  • Linux:rsyslog 日志丢失 messages lost due to rate-limiting

    系统日志显示 cat var log messages Apr 7 16 20 01 ngnodeb rsyslogd imjournal 154664 messages lost due to rate limiting 解决方法 修改配
  • Linux:shell 中的单行注释和多行注释

    关于 shell 中的单行注释和多行注释 单行注释 众所周知 xff0c 使用 比如想要注释 echo 34 Hello World 34 root 64 test vim test sh echo 34 Hello World 34 多行
  • Shell三剑客之sed:修改 xml

    修改前 vim config xml lt config input type verify 61 34 bool 34 name 61 34 flow bypass class 34 visible 61 34 true 34 gt fa
  • STM32串口通信

    STM32串口通信 一 基于寄存器与基于固件库编写的差异二 stm32串口通信实战1 烧录方式2 代码及效果图 三 C语言程序里全局变量 局部变量 堆 栈等概念四 stm32的堆 栈 全局变量的分配地址 一 基于寄存器与基于固件库编写的差异
  • keil下的FreeRtos多任务程序

    keil下的Freertos多任务程序 1 手动移植FreeRtos xff08 以STM32F103为例 xff09 2 直接使用野火的模板 1 手动移植FreeRtos xff08 以STM32F103为例 xff09 用该链接下载Fr
  • 随笔小记(二十七)

    神经网络中Epoch Iteration Batchsize相关理解和说明 batchsize xff1a 中文翻译为批大小 xff08 批尺寸 xff09 简单点说 xff0c 批量大小将决定我们一次训练的样本数目 batch size将
  • 手把手教物体检测——EfficientDet

    目录 摘要 训练数据 1 下载Pytoch版的EfficientDet 2 制作数据集 3 下载EfficientNets预训练模型 4 安装模型需要的包 5 放置数据集 6 修改train py中的参数 测试 注意 摘要 谷歌大脑团队 Q
  • 简化的围棋棋子规则(C++实现)

    题目 xff1a 输入棋盘 xff1a 1 1 2 3 2 3 3 3 2 3 3 3 2 2 2 3 3 3 1 2 2 2 3 3 2 1 1 2 3 1 其中1代表空 xff0c 2代表白子 xff0c 3代表黑子 xff09 输出
  • MATLAB中将图像转换为二值图像im2bw

    在MATLAB中将图像转换为二值图像 xff0c 主要运用im2bw函数 xff0c 涉及到一个灰度门槛的数值 对于灰度图像 bw 61 im2bw I level level空着的话 xff0c 默认是0 5 level一般使用grayt
  • Ubuntu 20.04 Gazebo安装 及模型库下载

    安装参考自官方教程noetic版本 xff0c 为了安装模型库 xff0c 就一起编辑了 1 设置你的电脑来接收软件 sudo sh c 39 echo 34 deb http packages osrfoundation org gaze
  • git pull强制覆盖本地修改

    有时本地代码做了修改 xff0c 但又想放弃这部分修改 xff0c 重新在新代码基础上进行开发 xff0c 这时可用如下方法覆盖先前修改 xff0c 并拉取远程仓更新本地代码 方法一 xff1a git fetch git reset ha
  • gazebo中视觉仿真怎么使用自定义贴图的问题

    gazebo中提供了很少的贴图 xff0c 场景只是用这几张贴图 xff0c 视觉SLAM仿真很容易在不该闭环的时候闭环 xff0c 导致根本没法用 那么我们怎么添加自己的贴图呢 xff1f 首先gazebo建模 使用默认贴图 xff0c
  • 传统定位方法简介--------里程计、IMU惯性传感器以及光电编码器等

    移动机器人最初是通过自身携带的内部传感器基于航迹推算的方法进行定位 xff0c 后来进一步发展到通过各种外部传感器对环境特征进行观测从而计算出移动机器人相对于整个环境的位姿 目前为止 xff0c 形成了基于多传感器信息融合的定位方法 现有移
  • 路由器接口

    深刻认识到如果不好好学习计算机网络 xff0c 对于自己学习后台的知识有很大的阻碍 所以 xff0c 这段时间好好把这方面的知识加强一下 一般路由器上的接口分为三大类 xff1a 一 用于局域网的LAN接口 二 用于广域网接入 互联的WAN
  • UART、I2C、SPI接口常见面试问题总结

    UART 定义 xff1a Universal Asynchronous Receiver Transmitter 通用异步收发传输器 特点 xff1a 速率不快 可全双工 结构上一般由波特率产生器 UART发送器 UART接收器组成 xf
  • ubuntu18.04配置ORB-SLAM3(包含ROS)完整版教程

    ORB SLAM3安装教程 ORB SLAM3安装准备1 C 43 43 11 or C 43 43 0x Compiler2 Pangolin 61 61 出现的问题 61 61 3 OpenCV安装4 Eigen安装5 boost安装6
  • 视觉里程计--视觉slam7.1/相机运动估计视觉算法

    视觉里程计 本篇文章记录了少许阅读 视觉slam14讲 的阅读整理 xff0c 不是特别全面 xff0c 只是为了本次项目中特定任务搜查资料 xff0c 时间比较紧 xff0c 文章并没有全面涵盖所有知识点 日后若时间有空闲 xff0c 将
  • [授权发表]源码分析:动态分析 C 程序函数调用关系

    By Falcon of TinyLab org 2015 04 15 最初发表 xff1a 泰晓科技 聚焦嵌入式 Linux xff0c 追本溯源 xff0c 见微知著 xff01 原文链接 xff1a 源码分析 xff1a 动态分析 C