跟踪并打印系统事件,支持调用栈记录和火焰图生成。
- 主要用途: 实时跟踪和显示内核/用户空间事件,记录调用栈,支持联合分析,是最基础和灵活的事件分析工具。
- 适用场景: 需要实时查看事件发生的详细信息、分析事件序列、记录调用栈、生成火焰图、进行多事件联合分析等场景。
- 功能分类:
- 按事件依赖程度:自定义事件类 - 需要用户通过
-e指定事件 - 按功能领域:调试与工具 - 通用事件跟踪和调试工具
- 按分析技术:追踪分析、联合分析 - 支持多事件组合分析
- 按事件依赖程度:自定义事件类 - 需要用户通过
- 最低内核版本: 需要内核支持 perf_event 子系统 (Linux 2.6.31+)
- 依赖库: libtraceevent (事件解析), libelf (符号解析), liblzma (可选,用于 MiniDebugInfo)
- 平台支持: x86, ARM, ARM64, RISC-V, PowerPC 等主流架构
- 特殊限制:
- 需要 root 权限或 CAP_PERFMON 能力
- kprobe/uprobe 需要内核 CONFIG_KPROBES 支持
- BPF 过滤器需要较新内核支持 (4.1+)
- 参与联合分析:
- 作为联合分析主体,可以嵌入其他分析器作为事件源
- 支持通过
profiler[/option/]语法引用其他分析器
- 核心技术:
- 基于 perf_event 事件采样
- trace event 内核态过滤
- 用户态表达式过滤
- 调用栈解析和符号化
- 火焰图生成
perf-prof trace -e EVENT [--overwrite] [-g [--flame-graph file [-i INT]]]OPTION:
-i, --interval <ms>- 间隔输出,配合--flame-graph周期性输出火焰图 (默认:无间隔)--order- 按时间戳排序事件,确保事件输出的时序正确性-N, --exit-N <N>- 采样 N 个事件后退出--inherit- 子任务继承计数器,跟踪创建的子进程/线程,实验性功能
FILTER OPTION:
--user-callchain[=dwarf[,size]]- 包含用户态调用栈,no-前缀排除 (默认:包含)。=dwarf启用DWARF栈回溯,可选指定栈数据大小--kernel-callchain- 包含内核态调用栈,no-前缀排除 (默认:包含)--python-callchain- 包含 Python 调用栈
PROFILER OPTION:
-
-e, --event <EVENT,...>- 事件选择器,支持多种事件源类型- tracepoint:
sys:name[/filter/ATTR/.../]- 系统 tracepoint 事件 - profiler:
profiler[/option/ATTR/.../]- 嵌入其他分析器作为事件源 - kprobe:
kprobe:func[/filter/ATTR/.../]- 内核函数探针 - kretprobe:
kretprobe:func[/filter/ATTR/.../]- 内核函数返回探针 - uprobe:
uprobe:func@"file"[/filter/ATTR/.../]- 用户态函数探针 - uretprobe:
uretprobe:func@"file"[/filter/ATTR/.../]- 用户态函数返回探针 - 通配符: 支持
*, ?, []通配符匹配多个事件
- tracepoint:
-
-g, --call-graph- 启用调用图记录,为所有事件记录调用栈 -
--flame-graph <file>- 指定折叠栈输出文件,生成火焰图格式数据 -
--overwrite- 使用覆盖模式,避免在高负载下丢失最新事件,实验性功能 -
--ptrace- 使用 ptrace 跟踪新创建的线程,确保子线程也被监控
# 基础事件跟踪
perf-prof trace -e sched:sched_wakeup -C 0
# 多事件跟踪,带过滤器
perf-prof trace -e 'sched:sched_wakeup/prio<10/,sched:sched_switch'
# 记录调用栈并生成火焰图
perf-prof trace -e sched:sched_wakeup -C 0 -g --flame-graph wakeup.folded
# 通配符匹配多个事件
perf-prof trace -e 'sched:sched_wak*' -C 0
# kprobe 跟踪内核函数
perf-prof trace -e 'kprobe:try_to_wake_up' -C 0
# uprobe 跟踪用户态函数
perf-prof trace -e 'uprobe:printf@"/lib64/libc.so.6"' -m 64
# 联合分析:嵌入其他分析器
perf-prof trace -e 'task-state,page-faults/-N 10/,raw_syscalls:sys_enter' --order
# 覆盖模式,保留最新事件
perf-prof trace -e 'sched:sched_wakeup,sched:sched_switch' --overwrite基本定义
- 事件 (Event): 内核或用户空间发生的可观测活动点,如系统调用、进程调度、中断等
- tracepoint: 内核预定义的静态跟踪点,性能开销极低
- kprobe/uprobe: 动态插入的探针,可跟踪任意内核/用户函数
- 调用栈 (Call Chain): 函数调用序列,记录代码执行路径
- 火焰图 (Flame Graph): 可视化调用栈的统计图表,展示性能热点
数据模型
事件源 → [内核过滤] → 环形缓冲区 → [用户态过滤] → [排序] → [栈解析] → 显示/保存
- 事件源: tracepoint、kprobe、uprobe 产生原始事件
- 内核过滤: trace event filter 在内核态执行,减少数据传输
- 环形缓冲区: per-CPU 无锁缓冲区,高效收集事件数据
- 用户态过滤: ftrace_filter 表达式过滤,处理复杂逻辑
- 排序: 基于时间戳的多 CPU 事件排序 (
--order) - 栈解析: 符号化内核和用户态调用栈
- 输出: 实时打印或保存为火焰图格式
-
sample_type: 默认采样类型
PERF_SAMPLE_TID: 线程 ID (PID/TID)PERF_SAMPLE_TIME: 事件时间戳PERF_SAMPLE_ID: 事件唯一标识PERF_SAMPLE_CPU: 发生事件的 CPUPERF_SAMPLE_PERIOD: 采样周期PERF_SAMPLE_RAW: 原始事件数据PERF_SAMPLE_CALLCHAIN: 调用栈 (当-g或//stack/时启用)
-
自定义事件: trace 分析器需要用户通过
-e参数指定事件- tracepoint 事件:
sys:name[/filter/ATTR/.../]- 使用
perf-prof list列出所有可用事件 - 支持通配符:
sched:sched_wak*匹配sched_wakeup,sched_wakeup_new等
- 使用
- kprobe/kretprobe: 动态探针,需要内核支持
- uprobe/uretprobe: 用户态探针,需要指定可执行文件路径
- profiler 嵌入: 引用其他分析器作为事件源,进行联合分析
- tracepoint 事件:
trace 支持两种过滤机制:
1. trace event 过滤器 (内核态)
- 语法: 第一个
/之后,第二个/之前 - 示例:
sched:sched_wakeup/prio<10/ - 特点:
- 在内核态执行,效率高
- 支持数值比较:
==, !=, <, <=, >, >=, & - 支持字符串匹配:
==, !=, ~(通配符) - 支持逻辑组合:
&&, ||, ()
- 扩展字段:
_cpu: 事件发生的 CPU_pid: 事件发生的进程 ID (非线程 ID)
2. 用户态表达式过滤器 (ftrace_filter)
- 当内核态过滤器设置失败时,在用户态执行
- 支持完整 C 表达式语法
- 可调用内置函数:
printf(),ksymbol(),comm_get()等 - 示例:
pid<prio(比较两个字段)
通过 /ATTR/ATTR/.../ 配置事件处理行为:
stack: 为该事件启用调用栈记录max-stack=int: 设置最大栈深度 (默认: 127)alias=str: 事件别名,简化输出显示cpus=cpu[-cpu]: 指定该事件仅在特定 CPU 上采样exec=EXPR: 执行表达式,用于自定义处理逻辑,如:exec=system("/proc/%d/stat", pid)push=[IP:]PORT: 推送事件到远程服务器 (事件传播)pull=[IP:]PORT: 从远程拉取事件 (事件传播)
事件接收流程:
- 环形缓冲区读取: 从 per-CPU mmap 缓冲区读取原始事件
- 事件识别: 根据
event->header.type识别事件类型PERF_RECORD_SAMPLE: 标准采样事件PERF_RECORD_DEV: 设备转发事件 (联合分析)
- evsel 查找: 通过
id字段查找对应的perf_evsel - 事件匹配: 匹配
tp_list中的 tracepoint 定义
用户态过滤 (ftrace_filter):
long trace_ftrace_filter(struct prof_dev *dev, union perf_event *event, int instance)- 在
sample()之前执行,返回 0 则丢弃事件 - 解析原始事件数据,执行表达式程序
- 使用
tp_prog_run()运行编译后的表达式
事件打印:
void trace_sample(struct prof_dev *dev, union perf_event *event, int instance)- 解析原始数据:
__raw_size()提取事件字段 - 打印事件:
tp_print_event()格式化输出 - 执行 exec 表达式:
tp_prog_run(tp->exec_prog) - 打印调用栈:
__print_callchain()
调用栈处理:
- 不启用火焰图: 使用
callchain_ctx实时打印栈print_callchain_common(ctx->cc, &callchain, pid)
- 启用火焰图: 累积到火焰图结构
flame_graph_add_callchain_at_time(ctx->flame, &callchain, pid, comm, time, time_str)
排序处理:
- 使用
--order时,框架自动按时间戳排序 - 多 CPU 事件按时间戳归并,确保输出顺序正确
- 需要额外缓冲区延迟,适合离线分析
事件广播:
- 通过
tp_broadcast_event()推送到远程 - 支持 TCP、字符设备、文件三种方式
- 用于跨主机/跨虚拟机联合分析
覆盖模式 (overwrite):
- 环形缓冲区写满后覆盖旧数据
- 避免高负载下丢失最新事件
- 适合保留最近事件的场景
trace 分析器不处理信号,由框架统一处理:
- SIGUSR1: 无特殊操作
- SIGUSR2: 无特殊操作
标准输出格式:
[UNIX时间戳] [进程名/TID] [CPU] [时间戳] [事件名称] [字段=值 ...]
[调用栈...]
字段说明:
- UNIX时间戳: YYYY-MM-DD HH:MM:SS.microsec,由事件的perf clock转换而来,精度有损失
- 进程名/TID: 进程名称和线程 ID
- CPU: 事件发生的 CPU 编号 (0-based)
- 时间戳: 事件发生的精确时间,来自内核采样,可选格式:
- 默认: perf clock (纳秒)
--tsc: TSC 时间戳计数器--kvmclock <uuid>: Guest kvmclock--monotonic: CLOCK_MONOTONIC--clock-offset <n>: 时间偏移
- 事件名称: tracepoint、kprobe 等事件名称
- 字段=值: 事件特定字段及其值
调用栈格式:
ffffffff81xxxxxx function_name+0xoffset (kernel)
7fxxxxxxxxxxxx function_name+0xoffset (/path/to/library.so)
火焰图格式 (--flame-graph):
进程名;函数1;函数2;函数3 采样次数
进程名;函数1;函数2 采样次数
- 折叠格式,每行代表一条调用路径
- 使用
flamegraph.pl生成 SVG 可视化图表 - 支持时间切片:
-i参数周期性输出
trace 分析器主要用于定性观察事件序列,不提供聚合统计指标。关注点:
- 事件频率: 单位时间内事件发生次数,高频事件可能是性能瓶颈
- 事件延迟: 配合
multi-trace分析事件对延迟 - 调用路径: 通过调用栈识别热点函数
- 事件序列: 多事件间的时序关系和因果关系
trace 本身不设阈值,建议根据业务需求判断:
- 正常范围: 根据具体事件类型和系统负载确定基线
- 异常检测:
- 事件频率突增/突降
- 调用栈异常 (如死循环)
- 事件乱序 (未使用
--order)
- 性能影响:
- 启用调用栈会增加约 2-5% 开销
- 过滤器可显著降低数据量
1. 确定分析目标
- 明确要跟踪的事件类型
- 确定是否需要调用栈
- 评估是否需要过滤减少数据量
2. 选择事件源
# 查看可用事件
perf-prof list
# 按类别过滤
perf-prof list | grep sched:
# 查看事件字段
perf-prof trace -e sched:sched_wakeup help3. 设置过滤器
- 优先使用内核态过滤器 (效率高)
- 复杂逻辑使用用户态表达式
- 注意过滤器语法: 数值用
<, >, ==等,字符串用~通配符
4. 配置输出方式
- 实时查看: 标准输出
- 生成火焰图:
--flame-graph+-i间隔输出 - 离线分析:
--order排序 +-o输出文件
5. 调整采样范围
-C, --cpus: 限定 CPU 范围-p, --pids: 限定进程-N, --exit-N: 限制采样数量--watermark: 调整唤醒阈值
# 示例 1: 跟踪进程调度事件
perf-prof trace -e 'sched:sched_wakeup,sched:sched_switch' -C 0 -N 100
# 示例 2: 分析高优先级进程的调度路径
perf-prof trace -e 'sched:sched_wakeup/prio<10/' -g --flame-graph high_prio.folded
# 示例 3: 跟踪特定进程的系统调用
perf-prof trace -e 'syscalls:sys_enter_*' -p 1234 --order
# 示例 4: 监控内存分配热点
perf-prof trace -e 'kmem:kmalloc/bytes_alloc>1024/stack/' -m 128
# 示例 5: 覆盖模式保留最新事件
perf-prof trace -e 'irq:*' --overwrite -m 64
# 示例 6: 跟踪内核函数调用
perf-prof trace -e 'kprobe:do_sys_open' -g -N 50
# 示例 7: 联合分析任务状态和页错误
perf-prof trace -e 'task-state,page-faults/-N 10/' --order -- ./myapp# 技巧 1: 使用通配符批量跟踪事件
perf-prof trace -e 'sched:*' -C 0 -N 1000 | grep -i wakeup
# 技巧 2: 动态跟踪任意内核函数
perf-prof trace -e 'kprobe:schedule' -g --flame-graph schedule.folded
# 技巧 3: 跟踪用户态库函数调用
perf-prof trace -e 'uprobe:malloc@"/lib64/libc.so.6"' -p 1234
# 技巧 4: 周期性生成火焰图,观察时间变化
perf-prof trace -e 'sched:sched_wakeup' -g --flame-graph wakeup.folded -i 5000
# 技巧 5: 多层过滤组合
perf-prof trace -e 'sched:sched_wakeup/target_cpu==0 && prio<10/stack/max-stack=16/' -C 0
# 技巧 6: 使用表达式计算自定义字段
perf-prof trace -e 'sched:sched_stat_runtime//exec=printf("runtime: %llu us\n", runtime/1000)/' -C 0
# 技巧 7: 跨主机事件传播
# 主机 A (发送端)
perf-prof trace -e 'sched:sched_wakeup//push=192.168.1.100:8888/' -C 0
# 主机 B (接收端)
perf-prof trace -e 'sched:sched_wakeup//pull=0.0.0.0:8888/' --order
# 技巧 8: ptrace 跟踪子进程
perf-prof trace -e 'syscalls:sys_enter_*' --ptrace -- ./myapp
# 技巧 9: 时间戳转换
perf-prof trace -e 'sched:sched_wakeup' --tsc -C 0 # 使用 TSC 时间戳-
缓冲区大小:
- 默认: 2 pages (不启用调用栈),4 pages (启用调用栈)
- 高频事件:
-m 128或更大,避免丢失事件 - 低频事件:
-m 4减少内存占用 - 覆盖模式:
-m 1 --overwrite最小化内存
-
采样频率:
- trace 使用
sample_period = 1,记录每个事件 - 通过过滤器减少事件量,而非降低采样率
- 使用
-N限制采样总数,用于快速验证
- trace 使用
-
过滤器优化:
- 优先使用内核态过滤器 (
/filter/) - 简化过滤表达式,避免复杂计算
- 多条件过滤使用
&&组合,提前剔除不符合的事件 - 字符串匹配使用精确匹配 (
==) 而非通配符 (~)
- 优先使用内核态过滤器 (
-
--watermark 调优:
- 默认: 0 (使用
wakeup_events = 1) - 高频事件:
--watermark 50降低唤醒频率,减少上下文切换 - 实时性要求高: 保持默认值
- 默认: 0 (使用
-
--order 优化:
- 离线分析必选,确保事件时序正确
- 实时跟踪不推荐,增加延迟和内存占用
- 多 CPU 高频事件慎用,性能开销大
-
-m, --mmap-pages 优化:
- 必须是 2 的幂次
- 高频事件: 64-256 pages
- 中频事件: 16-64 pages
- 低频事件: 4-8 pages
- 监控多 CPU: 适当增大 (per-CPU 分配)
-
-N, --exit-N 优化:
- 快速验证:
-N 100 - 短期分析:
-N 10000 - 长期运行: 不设置 (持续运行)
- 快速验证:
-
与其他分析器配合:
# trace 嵌入 task-state 和 profile 进行联合分析 perf-prof trace -e 'task-state,profile/-F 5000/' --order -p 1234 # 先用 top 统计,再用 trace 详细跟踪 perf-prof top -e 'sched:sched_wakeup//comm=comm/' --only-comm -i 1000 # 基于 top 结果,跟踪特定进程 perf-prof trace -e 'sched:sched_wakeup/comm=="myapp"/' -g # 与 multi-trace 配合分析延迟 perf-prof trace -e 'sched:sched_wakeup,sched:sched_switch' --order | head -100 perf-prof multi-trace -e 'sched:sched_wakeup' -e 'sched:sched_switch//key=next_pid/' -k pid --order
-
多阶段分析:
# 阶段 1: 识别高频事件 perf-prof stat -e 'sched:*' -i 1000 # 阶段 2: 跟踪高频事件的调用栈 perf-prof trace -e 'sched:sched_wakeup' -g -N 1000 # 阶段 3: 过滤特定场景深入分析 perf-prof trace -e 'sched:sched_wakeup/prio<10/' -g --flame-graph high_prio.folded # 阶段 4: 生成火焰图可视化 flamegraph.pl high_prio.folded > high_prio.svg