文档涵盖了Linux跟踪技术简介、静态与动态跟踪的使用方法、以及内核原理实现。笔记以简明扼要的方式提取关键点,便于记录和复习。
一、Linux Tracing 技术简介
Linux跟踪(tracing)技术用于观测系统运行状态,帮助分析性能瓶颈。它分为事件源和工具两类:
- 事件源:提供底层事件触发和数据,包括硬件事件(如CPU周期)、软件事件(如上下文切换)、tracepoint(内核静态跟踪点)、kprobe(内核动态跟踪点)、uprobe(用户态跟踪)等。
- 工具:处理事件数据,提供友好界面,如perf、ftrace、trace-cmd、eBPF、BCC、bpftrace等。火焰图是常用工具,依赖perf等采样数据。
- 跟踪时优先使用稳定的tracepoint,不足时补充kprobe。

二、内核源码跟踪方法
2.1 静态跟踪(Tracepoint)
- 原理:内核源码中预埋静态桩点(如
trace_sched_switch),未开启时开销低;开启后执行注册的钩子函数。 - 查看跟踪点:
- 使用ftrace:
ls /sys/kernel/debug/tracing/events/查看模块目录,如sched模块下的跟踪点。
- 使用ftrace:

- 使用perf:`perf list tracepoint`列出所有跟踪点(如`sched:sched_switch`)。
- 使用示例(以
sched:sched_switch为例):- ftrace方法:
- 开启跟踪点:
echo 1 > /sys/kernel/debug/tracing/events/sched/sched_switch/enable - 查看输出:
cat /sys/kernel/debug/tracing/trace_pipe(显示进程切换详情)。 - 关闭跟踪点:
echo 0 > .../enable
- 开启跟踪点:
- perf方法:
- 录制事件:
perf record -e 'sched:sched_switch' -a sleep 3 - 解析结果:
perf script(显示事件详情)。 - 记录调用栈:加
-g参数(如perf record -e 'sched:sched_switch' -a -g sleep 3),然后perf script可查看完整调用链。
- 录制事件:
- ftrace方法:
- 优点:稳定、低开销;缺点:跟踪点固定,无法覆盖所有函数。
2.2 动态跟踪(Kprobe)
- 原理:动态替换内核函数指令为断点指令(BREAKPOINT_INSTRUCTION),截胡执行跟踪函数后恢复原指令。
- 要求:内核需启用
CONFIG_KPROBE_EVENT(检查:cat /boot/config-* | grep CONFIG_KPROBE_EVENT)。 - 使用示例(跟踪
schedule函数):- ftrace方法:
- 添加跟踪点:
echo 'p:yanfei schedule' >> /sys/kernel/debug/tracing/kprobe_events - 开启跟踪:
echo 1 > /sys/kernel/debug/tracing/events/kprobes/yanfei/enable - 查看输出:
cat /sys/kernel/debug/tracing/trace_pipe
- 添加跟踪点:
- perf方法:
- 查看跟踪点:
perf probe --list(显示kprobes:yanfei)。 - 录制和解析:
perf record -e kprobes:yanfei -a -g sleep 1,然后perf script查看调用栈。
- 查看跟踪点:
- ftrace方法:
- 优点:灵活,可跟踪任意函数;缺点:影响系统性能,稳定性较低。

三、内核跟踪原理
3.1 Tracepoint 实现
- 核心机制:通过宏定义(如
DEFINE_TRACE、DECLARE_TRACE)在源码中插入钩子:- 定义
struct tracepoint对象,包含钩子函数链表。 - 执行时,若跟踪点开启,调用
__DO_TRACE遍历执行注册的钩子函数(如probe_sched_switch)。
- 定义
- 关键函数:
trace_xxx(内联函数,未开启时快速返回)和register_trace_xxx(注册钩子)。
3.2 Kprobe 实现
- 核心机制:动态指令替换:
register_kprobe函数保存原指令,替换为断点指令(x86架构使用text_poke)。- 触发断点后,执行
kprobe_int3_handler调用预定义的处理函数(如pre_handler),最后恢复原指令流。
- 示例代码(简化自内核示例):
// 注册kprobe示例
static struct kprobe kp;
static int __init my_module_init(void) {
kp.symbol_name = "write"; // 跟踪write函数
kp.pre_handler = handler_pre; // 定义处理函数
return register_kprobe(&kp);
}
四、总结
- 跟踪选择:优先使用tracepoint静态点,必要时用kprobe动态补充。
- 工具建议:perf的
-g参数可捕获调用栈,ftrace适合底层操作。 - 原理核心:tracepoint是源码钩子,kprobe是指令截胡——两者均简化了内核调试。
- 实践价值:结合代码跳转和跟踪工具,能高效分析内核行为。
此笔记提取了文档的核心技术内容,便于快速回顾。如有具体技术问题,可进一步深入讨论。

3465

被折叠的 条评论
为什么被折叠?



