ftrace可追踪内核函数调用频次变化趋势,需启用function tracer、限定目标函数、开启tracing并按时间戳切片统计,适合开箱即用的持续采样与时间序列分析。

用ftrace看内核函数调用频次变化趋势
ftrace是内核自带、开箱即用的方案,不需要额外安装,适合观察一段时间内某函数被调用的「次数走势」,比如sched_setaffinity或__do_page_fault是否在某个负载阶段突然飙升。
关键不是看单次快照,而是持续采样并导出时间序列数据。操作分三步:
- 启用function tracer:
echo function > /sys/kernel/debug/tracing/current_tracer - 限定目标函数(避免日志爆炸):
echo sched_setaffinity > /sys/kernel/debug/tracing/set_ftrace_filter - 开启 tracing 并运行一段时间(比如10秒):
echo 1 > /sys/kernel/debug/tracing/tracing_on;之后echo 0 > /sys/kernel/debug/tracing/tracing_on停止
注意:/sys/kernel/debug/tracing/trace里每行是一个调用事件,不是聚合计数——你要自己按时间戳(第一列)切片统计。建议用awk '{print $1}' | sort | uniq -c粗略估算单位时间调用数,再绘图。别直接 cat 大量 trace 文件,容易卡死终端。
用perf record -e cpu/event=xx/统计函数入口频次
perf更适合量化「单位时间调用次数」,尤其当你需要对比不同负载下的频率差异时。它不记录每次调用上下文,但采样稳定、开销低,且支持按时间窗口导出频次直方图。
例如统计tcp_v4_rcv每秒被调用多少次:
sudo perf record -e 'syscalls:sys_enter_recvfrom' -g --call-graph dwarf -a sleep 5
但注意:这不是直接统计函数本身,而是靠关联系统调用事件间接反映。真正统计内核函数需用perf probe先加探针:
- 查函数符号:
sudo perf probe -F | grep tcp_v4_rcv - 加动态探针:
sudo perf probe tcp_v4_rcv - 采样:
sudo perf record -e probe:tcp_v4_rcv -a sleep 10 - 导出频次:
sudo perf script | awk '{print $3}' | sort | uniq -c | sort -nr
缺点是probe添加后需重启perf record,不能热更新;且某些inline函数或编译优化过的函数可能probe失败,报No symbol found。
用bpftrace实时画调用频次折线图(需eBPF环境)
如果你需要真正的「实时走势」——比如每秒刷新一次当前调用次数,并输出到终端或管道绘图,bpftrace是最灵活的选择。它能在内核态完成计数+时间分桶,用户态只收聚合结果。
示例脚本,每秒输出do_sys_open调用次数:
sudo bpftrace -e '
kprobe:do_sys_open {
@count = count();
}
interval:s:1 {
printf("do_sys_open calls/sec: %d\n", @count);
@count = 0;
}'
常见坑:
- 函数名必须是内核符号名,不是头文件里的声明名(比如
sys_open通常不存在,要用do_sys_open或__x64_sys_open) - 某些函数被
static或inline修饰,bpftrace无法挂kprobe,会提示invalid probe - 默认只统计进入,不区分返回;如需匹配成对事件(比如open+close),得用map存PID+计数器,逻辑变复杂
为什么不能只看/proc/kallsyms或dmesg
/proc/kallsyms只列出符号地址和类型,没有调用计数;dmesg是内核日志缓冲区,除非你提前在代码里加printk,否则它不记录函数执行频次。这两者都属于静态信息源,无法反映「频率走势」这个动态指标。
真正能体现「走势」的,必须满足两个条件:带时间戳的连续采样 + 可分时段聚合。ftrace、perf、bpftrace都满足,但方式不同:ftrace原始但可控,perf适合离线分析,bpftrace适合实时监控。选哪个,取决于你手头环境有没有eBPF支持、要不要图形化、以及能否接受probe侵入式修改。


















