bpftrace 单行命令教程:12个案例掌握Linux内核追踪技术
bpftrace High-level tracing language for Linux eBPF 项目地址: https://gitcode.com/gh_mirrors/bp/bpftrace
前言
bpftrace 是一个基于eBPF技术的高级追踪工具,它允许开发者通过简洁的脚本语言对Linux内核和用户空间程序进行高效追踪。本教程将通过12个精心设计的单行命令案例,由浅入深地介绍bpftrace的核心概念和使用技巧。
基础概念
在开始之前,我们需要了解几个关键术语:
- 探针(Probe):bpftrace的观测点,用于捕获事件数据
- 动作(Action):当探针触发时执行的操作
- 映射(Map):用于存储和汇总数据的特殊变量类型
- 过滤器(Predicate):条件表达式,用于筛选特定事件
课程案例
1. 探针列表查询
bpftrace -l 'tracepoint:syscalls:sys_enter_*'
这个命令展示了如何列出所有可用的探针,并使用通配符进行过滤。系统调用入口点是最常用的追踪点之一,因为它们提供了稳定的接口来监控应用程序与内核的交互。
2. Hello World示例
bpftrace -e 'BEGIN { printf("hello world\n"); }'
最简单的bpftrace程序,使用BEGIN
特殊探针在程序开始时打印欢迎信息。BEGIN
类似于awk中的BEGIN块,常用于初始化和打印标题。
3. 文件打开监控
bpftrace -e 'tracepoint:syscalls:sys_enter_openat { printf("%s %s\n", comm, str(args.filename)); }'
这个例子展示了如何追踪文件打开操作:
comm
内置变量表示当前进程名args.filename
访问系统调用参数str()
函数将指针转换为字符串
4. 进程系统调用统计
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[comm] = count(); }'
使用映射和count()
函数统计各进程的系统调用次数。映射会自动在程序结束时打印汇总结果。
5. read()字节数分布
bpftrace -e 'tracepoint:syscalls:sys_exit_read /pid == 18644/ { @bytes = hist(args.ret); }'
这个例子演示了:
- 使用过滤器(
/.../
)针对特定PID hist()
函数生成2的幂次方直方图- 分析read()系统调用的返回值分布
6. 内核动态追踪read()字节数
bpftrace -e 'kretprobe:vfs_read { @bytes = lhist(retval, 0, 2000, 200); }'
使用kretprobe
动态追踪内核函数返回:
lhist()
生成线性直方图- 相比tracepoint,kprobe/kretprobe更灵活但不稳定
7. read()操作耗时分析
bpftrace -e 'kprobe:vfs_read { @start[tid] = nsecs; } kretprobe:vfs_read /@start[tid]/ { @ns[comm] = hist(nsecs - @start[tid]); delete(@start, tid); }'
这个复杂示例展示了:
- 使用线程ID作为唯一标识
nsecs
获取高精度时间戳- 计算函数入口和返回的时间差
- 清理临时变量
8. 进程事件统计
bpftrace -e 'tracepoint:sched:sched* { @[probe] = count(); } interval:s:5 { exit(); }'
统计5秒内各种进程调度事件,使用interval
探针设置超时。
9. 内核栈采样分析
bpftrace -e 'profile:hz:99 { @[kstack] = count(); }'
99Hz频率采样内核栈:
- 99Hz避免了与其他定时活动同步
- 结果适合生成火焰图
ustack
可用于用户栈分析
10. 调度器追踪
bpftrace -e 'tracepoint:sched:sched_switch { @[kstack] = count(); }'
分析导致上下文切换的内核调用路径,对于理解系统瓶颈非常有用。
11. 块I/O大小分析
bpftrace -e 'tracepoint:block:block_rq_issue { @ = hist(args.bytes); }'
通过直方图分析块设备I/O请求大小分布,注意探针上下文可能不是预期进程。
12. 内核结构体追踪
bpftrace path.bt
其中path.bt内容:
#ifndef BPFTRACE_HAVE_BTF
#include <linux/path.h>
#include <linux/dcache.h>
#endif
kprobe:vfs_open
{
printf("open path: %s\n", str(((struct path *)arg0)->dentry->d_name.name));
}
这个高级示例展示了:
- 访问内核结构体成员
- 类型转换和指针解引用
- 条件包含头文件处理不同内核配置
总结
通过这12个案例,我们系统性地学习了bpftrace的核心功能:
- 从简单追踪到复杂分析
- 多种探针类型的使用场景
- 数据汇总和可视化技术
- 内核结构体和动态追踪
bpftrace的强大之处在于它简洁的语法和丰富的功能,使得系统级分析变得前所未有的便捷。掌握这些基础后,读者可以开始编写自己的追踪脚本,解决实际性能问题。
bpftrace High-level tracing language for Linux eBPF 项目地址: https://gitcode.com/gh_mirrors/bp/bpftrace
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考