怎么统计c的代码执行中每个步骤的耗时并且生成易读的报告,最好简单点,不要大量报错,类似perf,但perf可能因为权限问题无法执行下去,手动在代码里面插桩不用考虑了,需要统计很广的范围
如果你想统计 C 代码中各个步骤的耗时,并生成易读的报告,同时避免手动插桩和 perf 的权限问题,可以考虑以下几种 轻量级、自动化 的方案:
使用perf
1. 记录函数耗时(采样)
perf record -F 99 -g ./your_program
2. 生成报告(火焰图或文本)
perf report -n --stdio # 文本模式
git clone https://github.com/brendangregg/FlameGraph.git
cd FlameGraph
方案 1:使用 gcc 的 -finstrument-functions 自动插桩
GCC 和 Clang 支持 编译时自动插桩,可以在每个函数入口/出口插入计时代码,无需手动修改源码。
2. 生成火焰图(确保在 FlameGraph 目录或指定完整路径)
perf script | ./FlameGraph/stackcollapse-perf.pl | ./FlameGraph/flamegraph.pl > flamegraph.svg
步骤
编译时启用插桩
在编译时添加 -finstrument-functions 选项:
bash
复制
gcc -finstrument-functions -o my_program my_program.c
定义插桩回调函数
在你的代码中添加以下函数,它们会在每个函数调用前后自动执行:
c
复制
#include <stdio.h>
#include <time.h>
void __cyg_profile_func_enter(void *func, void *caller) {
printf(“Enter: %p\n”, func);
}
void __cyg_profile_func_exit(void *func, void *caller) {
printf(“Exit: %p\n”, func);
}
运行程序并生成日志
bash
复制
./my_program > trace.log
解析日志生成报告
使用 addr2line 或自定义脚本将函数地址转换为函数名:
bash
复制
addr2line -e my_program -f < trace.log
优点
无需手动插桩,自动记录所有函数调用。
低侵入性,只需添加两个回调函数。
缺点
输出较原始,需要额外解析日志。
可能影响性能,频繁的函数调用会增加开销。
方案 2:使用 ltrace 跟踪库函数调用
ltrace 可以动态跟踪程序调用的库函数,并统计耗时。
步骤
安装 ltrace
bash
复制
sudo apt install ltrace # Ubuntu/Debian
sudo yum install ltrace # CentOS/RHEL
运行程序并记录耗时
bash
复制
ltrace -T -c ./my_program
-T:显示每个调用的耗时。
-c:生成汇总报告。
示例输出
复制
% time seconds usecs/call calls function
30.00 0.300000 300 1000 malloc
20.00 0.200000 200 1000 free
10.00 0.100000 100 1000 printf
优点
无需修改代码,直接运行即可。
统计库函数调用,适合分析标准库/第三方库。
缺点
只能跟踪动态库调用,无法统计内部函数。
可能影响性能,特别是高频调用的函数。
方案 3:使用 strace 跟踪系统调用
strace 可以统计系统调用的耗时,适合分析 I/O、进程等底层操作。
步骤
安装 strace
bash
复制
sudo apt install strace # Ubuntu/Debian
sudo yum install strace # CentOS/RHEL
运行程序并记录耗时
bash
复制
strace -c ./my_program
示例输出
复制
% time seconds usecs/call calls errors syscall
50.00 0.500000 500 1000 read
30.00 0.300000 300 1000 write
20.00 0.200000 200 1000 open
优点
无需修改代码,直接运行即可。
统计系统调用,适合分析文件、网络等操作。
缺点
仅限系统调用,无法统计用户态函数。
方案 4:使用 time 命令统计总耗时
如果只需要粗略统计整个程序的运行时间,可以使用 time 命令:
bash
复制
time ./my_program
输出示例:
复制
real 0m1.234s # 实际运行时间
user 0m0.987s # 用户态时间
sys 0m0.123s # 内核态时间
优点
最简单,无需任何额外工具。
适合快速评估 整体性能。
缺点
无法细化到函数级别。
方案 5:使用 gprof 生成函数级性能报告
gprof 是 GNU 的性能分析工具,可以统计函数调用关系和耗时。
步骤
编译时启用 -pg
bash
复制
gcc -pg -o my_program my_program.c
运行程序生成 gmon.out
bash
复制
./my_program
生成报告
bash
复制
gprof my_program gmon.out > report.txt
示例输出
复制
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
50.00 0.50 0.50 1000 0.50 0.50 foo
30.00 0.80 0.30 1000 0.30 0.30 bar
20.00 1.00 0.20 1000 0.20 0.20 baz
优点
函数级统计,适合分析热点函数。
无需额外运行时依赖。
缺点
需要重新编译(-pg 选项)。
不支持多线程程序(可能不准确)。
总结对比
方案 适用场景 是否需要改代码 统计粒度 易用性
-finstrument-functions 函数级统计 需添加回调函数 函数级 ⭐⭐⭐
ltrace 库函数调用统计 无需改代码 库函数级 ⭐⭐⭐⭐
strace 系统调用统计 无需改代码 系统调用级 ⭐⭐⭐⭐
time 整体耗时 无需改代码 进程级 ⭐⭐⭐⭐⭐
gprof 函数级耗时 需 -pg 编译 函数级 ⭐⭐⭐
推荐选择
如果想自动统计所有函数调用 → -finstrument-functions
如果想统计库函数调用 → ltrace
如果想统计系统调用 → strace
如果想快速查看整体耗时 → time
如果想生成函数级报告 → gprof
这些方法都不需要 perf 的高权限,且适用于大多数 Linux 环境。