kallsyms 不记录调用频率,仅提供静态符号地址;观测函数调用频次需依赖 ebpf(bpftrace/kprobe/tracepoint)或 perf 等运行时工具,结合计数、时间戳聚合与内核配置检查。

kallsyms 本身不记录调用频率,它只是静态符号地址表;想看内核函数调用频次走势,必须靠运行时观测,且不能直接依赖 /proc/kallsyms。
为什么不能从 /proc/kallsyms 看调用频率
/proc/kallsyms 是只读的内核符号地址快照,内容形如 ffffffff81012345 T do_syscall_64,仅含符号名、地址、类型(T 表示 text),不含任何计数或时间戳。它不是性能计数器,也不是 trace buffer —— 想从中“统计频率”等于试图从电话黄页里查通话记录。
- 该文件默认对非 root 用户不可读(
cat /proc/kallsyms报Permission denied) - 即使有权限,反复
cat /proc/kallsyms也只会得到相同结果,无时间维度 - 未导出的符号(如
__do_page_fault)在该文件中可能被标记为0000000000000000 t或直接过滤掉,无法定位
用 bpftrace + tracepoint 观测特定内核函数调用频次
真正可行的方式是:利用 eBPF 在内核态 hook 函数入口(或对应 tracepoint),每触发一次就原子计数,再按秒聚合输出趋势。前提是目标函数有对应的 tracepoint,或能通过 kprobe 安全插入。
Linux 性能分析与调优专家,覆盖 CPU、内存、磁盘 I/O、网络、内核参数、编译优化、容器/K8s。适用场景:系统卡顿/高负载、内存不足/OOM/Swap 高、CPU 异常/iowait 高。
- 优先查 tracepoint:运行
sudo cat /sys/kernel/debug/tracing/events/syscalls/看是否有sys_enter_*或sys_exit_*;对非系统调用函数(如tcp_v4_do_rcv),查sudo ls /sys/kernel/debug/tracing/events/ | grep -i net - 若无可匹配 tracepoint,改用
kprobe:sudo bpftrace -e 'kprobe:tcp_v4_do_rcv { @count = count(); } interval:s:1 { printf("%d\n", @count); @count = 0; }' - 注意:
kprobe在函数开头插桩,但某些内联函数或优化后消失的符号无法命中;需确认符号真实存在且未被编译器优化掉(grep tcp_v4_do_rcv /proc/kallsyms返回非零地址) - 输出是每秒计数,可重定向到文件后用 gnuplot 或
awk画简单折线:sudo bpftrace -e '... { @c = count(); } interval:s:1 { printf("%d\n", @c); @c = 0; }' > freq.log
用 perf 跟踪并导出时间序列数据
perf 更适合做带时间戳的采样,适合分析“某函数调用在哪些时间段密集发生”,而非单纯计数。
- 先确认函数是否可 symbolize:
sudo perf probe -F | grep do_syscall_64;若支持,加 probe:sudo perf probe do_syscall_64 - 录制 10 秒调用事件:
sudo perf record -e probe:do_syscall_64 -g -- sleep 10 - 导出带时间戳的原始事件:
sudo perf script -F time,sym > trace.csv,输出形如12345.678901: do_syscall_64 - 用
awk按秒聚合:awk '{t=int($1); c[t]++} END {for (i in c) print i, c[i]}' trace.csv | sort -n - ⚠️ 注意:
perf probe在部分发行版(如 RHEL 8.8+)默认禁用 kprobes,需检查/proc/sys/kernel/kptr_restrict是否为 0,且内核配置含CONFIG_KPROBE_EVENTS=y
容易被忽略的兼容性断点
很多教程假设函数名可直接 probe,但实际常因内核版本或编译选项失效:
-
kallsyms_lookup_name()自 5.12 起不再导出,意味着你无法在模块里动态获取未导出函数地址 ——bpftrace的kprobe依赖内核自动解析符号,而perf probe依赖 debuginfo;没vmlinux或debuginfo包,tcp_v4_do_rcv这类函数名根本不会被识别 - 某些函数被
static inline或__always_inline修饰,在/proc/kallsyms中不可见,kprobe会静默失败(无报错,但计数始终为 0) -
CONFIG_TRACEPOINTS=y必须启用,否则/sys/kernel/debug/tracing/events/下为空,所有 tracepoint 方案直接不可用










