商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 系统应用 > Linux怎么使用BPFTrace监控内核 Linux高级动态追踪实战详解

Linux怎么使用BPFTrace监控内核 Linux高级动态追踪实战详解

  发布于2026-05-21 阅读(0)

扫一扫,手机访问

直接上手写bpftrace脚本不难,但如果不理解探针类型和变量作用域,脚本大概率跑不起来,或者输出一片空白,让人摸不着头脑。

Linux怎么使用BPFTrace监控内核 Linux高级动态追踪实战详解

为什么执行命令没反应?

比如,你兴冲冲地敲下 bpftrace -e 'tracepoint:syscalls:sys_enter_open { printf("hit\n"); }',终端却一片寂静。这通常不是脚本错了,而是环境没准备好。

首要原因往往是权限不足或内核未启用对应的追踪点。不是所有系统调用的tracepoint都默认可用,尤其是在一些较老或特定配置的内核上。

  • 先确认点是否存在:执行 ls /sys/kernel/debug/tracing/events/syscalls/sys_enter_open/。如果目录不存在,基本可以断定内核编译时没包含这个点。
  • 必须用root权限:bpftrace需要访问内核追踪接口,记得加上 sudo
  • 检查debugfs:某些发行版(如RHEL/CentOS 8+)默认不挂载debugfs,需要手动执行:sudo mount -t debugfs none /sys/kernel/debug
  • 缩小范围:如果只想观察特定进程(比如curl),加上过滤条件会更可靠:/comm == "curl"/ { printf("open by %s\n", comm); }

kprobe和tracepoint,到底用哪个?

同样是监控读操作,kprobe:vfs_readtracepoint:syscalls:sys_enter_read 看起来相似,实则大不相同。前者是动态插桩,后者是内核预埋的静态点,实际观测中行为差异明显:

  • 覆盖范围kprobe:vfs_read 能捕获所有内核态的read路径(包括文件、管道、套接字),但可能被内联优化绕过;而 tracepoint:syscalls:sys_enter_read 只捕获从用户态发起的 read() 系统调用入口,虽然稳定,但覆盖范围较窄。
  • 参数访问kprobe 使用 arg0argN 来获取寄存器中的参数;tracepoint 则必须通过结构体字段,如 args->fdargs->count
  • 性能开销:通常 tracepoint 开销更低。kprobe 如果挂载在高频函数上(比如 schedule),很容易触发内核的采样限流机制(受 perf_event_max_sample_rate 控制)。

如何安全地测量函数耗时?

想测系统调用耗时,常见的思路是用map记录开始时间。但这里有个坑:如果不做配对清理和条件判断,很容易因为线程复用或异常退出,导致map键堆积,甚至时间戳被覆盖。

  • 防覆盖:在记录开始时间前,必须检查键是否已存在:kprobe:sys_write /!@start[tid]/ { @start[tid] = nsecs; }。否则,同一个线程的连续调用会覆盖掉前一次的时间戳。
  • 防泄漏:在返回探针中,要带非空判断再清理:kretprobe:sys_write /@start[tid]/ { @dur = hist((nsecs - @start[tid]) / 1000); delete(@start[tid]); }
  • 键的选择:别用 pid 当key。在多线程进程里,不同线程的tid不同,但共享同一个pid,用pid会导致统计完全失真。
  • 超时兜底:加一行 interval:s:10 { exit(); } 是个好习惯,能防止脚本意外卡死。

监控内存分配,为什么输出全是0?

尝试用 kprobe:__kmalloc 监控内存分配大小,却发现输出的 arg0 全是0?这很可能不是你脚本的问题,而是内核版本间的“暗坑”。

__kmalloc 函数的参数顺序在不同内核版本中可能不同。在5.10+内核里,arg0 可能是分配大小,但在4.19内核里,arg0 对应的可能是 gfp_flags。硬编码参数位置极易失效。

  • 优先用tracepoint:如果内核支持,优先使用 tracepoint:kmalloc:kmalloc,它提供了标准化的字段,如 args->bytes_alloc
  • 查证符号:如果必须用kprobe,务必查证当前内核的符号定义:sudo cat /proc/kallsyms | grep __kmalloc,再结合 objdump -t /lib/modules/$(uname -r)/build/vmlinux | grep __kmalloc 来确认参数布局。
  • 注意覆盖度:有些内存分配路径(比如SLAB分配器内部)不会经过 __kmalloc,可能需要配合 tracepoint:kmalloc:kmalloc_node 等点来补全观测。

说到底,bpftrace真正的难点,不在于写出一行脚本,而在于搞清楚你看到的每一个 arg0args->xxx@map,在当前运行的内核版本里,究竟对应着什么内存布局和生命周期。不事先查好 /sys/kernel/debug/tracing/events//proc/kallsyms 就动手,无异于蒙着眼睛调参。

本文转载于:https://www.php.cn/faq/2436871.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注