本项目是一个基于Linux perf_event
子系统的高性能采样分析器。它能够实时地将运行时指令地址(IP)转换为具体的函数符号,从而帮助开发者精确地定位用户态和内核态的性能热点。
常态化火焰图,解决的是性能抖动难以复现的问题。 在线服务面对以下问题,现有排查工具通常无法及时定位问题现场:
- 偶发性抖动,来不及部署工具。
- 极小粒度的竞争问题。
- 进程频繁启动来不及指定pid。
- 网络偶发性抖动。
- 无法分粒度查看。
偶发延迟,怎么查,是网络,还是应用。 目前暂未实现抓网络重传的延迟,会持续更新下去。
- 全栈符号化: 同时支持用户态(ELF符号)和内核态(kallsyms符号)的地址解析。
- 异步符号解析: 与采集线程分离,
main_loop
生产,handler
消费。 - 实时符号化: 采样地址到函数名的转换延迟极低,小于1毫秒。
- 系统级监控: 能够监控系统上的所有进程,提供全局性能视图。
- 三级核心缓存: 进程、ELF文件和内核符号三级缓存,最大化减少重复IO和解析开销。
- 高可靠栈回溯: 可选LBR或Frame Pointer模式,用于生成高度精确的调用栈和火焰图。
- 内存安全: 通过引用计数和定期清理机制,确保零内存泄漏。
┌──────────────────────────────────────────────────────────────────────────────┐
│ 应用层 (main.c)
│ ├── 配置解析: parse_command_line()
│ ├── 生命周期: initialize_system() → main_loop() → cleanup()
│ └── 错误处理: 完善的错误恢复和资源清理
├──────────────────────────────────────────────────────────────────────────────┤
│ 配置层 (config.c + config.h)
│ └── 采样参数与过滤策略: sampling_frequency, use_lbr, filter_mode 等
├──────────────────────────────────────────────────────────────────────────────┤
│ 事件循环层 (main_loop.c)
│ ├── mmap环形缓冲区消费: perf_event_consume_ring_buffer()
│ ├── 采样分发(生产者): dispatch_sample_event() → queue_push(symbolizer_queue)
│ └── 定期清理: cleanup_dead_processes()
├──────────────────────────────────────────────────────────────────────────────┤
│ 采样源 / Perf 层 (perf.c)
│ ├── 事件配置: build_perf_attr() [LBR/软件调用栈]
│ ├── sample_type: IP/TID/TIME/CALLCHAIN 或 BRANCH_STACK + REGS_USER
│ └── exclude_kernel/idle, mmap环形缓冲区
├──────────────────────────────────────────────────────────────────────────────┤
│ 采样与符号化层 (handler.c)
│ ├── 符号化消费(消费者): queue_pop(symbolizer_queue) → symbolize_sample()
│ ├── 地址空间判断与过滤: FILTER_USER / FILTER_KERNEL
│ ├── 内核符号解析: find_kernel_symbol() [kernel]
│ ├── 用户符号解析: find_new_process() → find_vma_from_process()
│ │ → find_or_create_elf() → find_symbol_name_from_elf()
│ ├── PID复用检测与降级: [process_recycled] / [unknown_*]
│ └── 构建折叠栈: process_name[pid];func1;func2;… → db_writer_push_stack()
├──────────────────────────────────────────────────────────────────────────────┤
│ 数据持久化层 (database.c + database.h, SQLite)
│ └── 按小时分库写入: db_writer_push_stack()
├──────────────────────────────────────────────────────────────────────────────┤
│ 实时服务层 (http_server.c + http_server.h)
│ └── 实时数据查询/输出
├──────────────────────────────────────────────────────────────────────────────┤
│ 查询与可视化层
│ ├── 历史/实时查询: config/query_tool.c
│ ├── 辅助脚本: smart_query.sh → flamegraph.pl
│ └── 可视化输出: profile.svg
├─────────────────┬────────────────────┬──────────────────────┬──────────────────┤
│ELF解析层 进程管理 数据结构与工具层 内核符号解析层
│ elf.c process.c utils kernel_symbol.c
│ ├── ELF解析 ├── 进程创建 ├── 红黑树操作 ├── kallsyms解析
│ ├── 符号提取 ├── VMA管理 ├── 哈希表实现 └── 内核符号缓存
│ └── ELF缓存 └── 死进程清理 ├── 核心缓存与内存池
└─────────────────┴────────────────────┴──────────────────────┴──────────────────┘
在编译前,请确保已安装以下必要的开发库和符号包。
以Debian/Ubuntu为例:
sudo apt-get update
sudo apt-get install build-essential libelf-dev libsqlite3-dev libmicrohttpd-dev libcjson-dev libcurl4-openssl-dev
build-essential
: 提供gcc
和make
等基础编译工具。libelf-dev
: ELF文件解析所需的核心库。libsqlite3-dev
: 用于数据存储功能(SQLite)。libmicrohttpd-dev
: 轻量级 HTTP 服务器库,用于内置管理/查询接口。libcjson-dev
: 用于解析/构造 JSON 数据(配置、接口输出等)。libcurl4-openssl-dev
: 查询工具query_tool
的 HTTP 访问能力(下载/接口调用等)。
可选(符号包/调试符号):
- 为了获得更完整的用户态/系统库符号,建议安装系统调试符号包(例如 libc 的 dbgsym/dbg、libstdc++ 的 dbgsym/dbg 等)。
- 未安装符号包时,程序仍可工作。
- 内核符号默认来自
/proc/kallsyms
,通常无需额外安装。
git clone <https://github.com/Vivy33/Profiling.git>
cd <Profiling>
直接运行 make
命令即可编译生成可执行文件。
make
安装历史数据库(7天)定时清理任务
sudo ./auto_manager.sh install
重要提示: 运行本工具需要 root
权限,因为它依赖于 perf_event_open
系统调用,需要root内核栈才可以解析。
场景1: 标准性能分析 (默认软件采样) 此模式适用于快速定位消耗CPU时间最长的“热点”函数。
# 以100Hz的频率监控所有进程(默认30hz)
sudo ./auto_manager.sh start --frequency=100
场景2: 高精度调用栈分析 (LBR硬件采样) 此模式使用CPU的LBR硬件功能,以极高的精度追踪函数调用路径,是生成可靠火焰图的首选。
# 启用LBR模式进行高精度分析
sudo ./auto_manager.sh start --frequency=100 --lbr
场景3: 只分析内核空间
# 仅对内核函数进行采样
sudo ./auto_manager.sh start --frequency=100 --filter=kernel
场景4: 火焰图生成
LBR模式是生成高质量火焰图的首选。为了生成火焰图,profiling_tool
的输出需要被处理成flamegraph.pl
脚本所要求的折叠堆栈格式(folded stack format),即每一行都是一个完整的调用栈,以分号分隔,最后是一个空格和样本数。
# 1. 使用分析器采集数据
# 注意:为了生成火焰图,您需要修改分析器使其输出折叠堆栈格式。
sudo ./smart_query.sh --time "last 10 minutes" --flame > folded_stacks.txt
”last“ 通过http服务查询内存数据
其他格式 走sqlite数据库查询已经落盘的数据
# 2. 使用 flamegraph.pl 生成 SVG 火焰图
./flamegraph.pl folded_stacks.txt > profile.svg
auto_manager.sh
是一个统一的性能分析管理脚本,简化了性能分析工具的启动、停止、状态查询和数据清理等操作。
核心命令:
start
: 启动性能分析(带自动清理)。- 选项:
--dir <PATH>
,--frequency <HZ>
,--filter <TYPE>
,--cleanup <SEC>
,--stack-depth <NUM>
,--lbr
- 选项:
stop
: 停止性能分析及后台清理守护进程。status
: 查看性能分析工具、后台清理守护进程和 systemd 定时任务的状态。cleanup
: 手动清理旧数据。- 选项:
--days <NUM>
,--dry-run
- 选项:
install
: 安装 systemd 定时任务,用于定期清理数据库旧数据。uninstall
: 卸载 systemd 定时任务。logs
: 查看profiling_tool
的实时日志。
示例:
# 默认启动性能分析(30Hz采样,所有空间,自动清理)
sudo ./auto_manager.sh start
# 以100Hz频率启动,只分析用户态,启用LBR
sudo ./auto_manager.sh start --frequency 100 --filter user --lbr
# 查看当前系统状态
./auto_manager.sh status
# 手动清理超过3天的旧数据(只显示不删除)
./auto_manager.sh cleanup --days 3 --dry-run
# 安装systemd定时任务,实现自动定期清理
sudo ./auto_manager.sh install
smart_query.sh
提供了一个人性化的接口来查询 profiling_tool
收集到的性能数据。它支持灵活的时间范围选择和多种过滤条件。
选项:
--dir <目录>
: 指定数据库目录 (默认:./tmp
)。--time <时间段>
: 人性化时间格式,支持多种表达方式。- 示例:
"15:10-15:30"
,"2023-09-22 15:10-15:30"
,"today 15:10"
,"last 20 minutes"
,"09:00-"
,"-15:30"
- 示例:
--pid <pid>
: 按进程ID过滤。--name <名称>
: 按进程名过滤。--flame
: 输出火焰图兼容格式(调用链 计数)。--detailed
: 输出详细的调用栈信息。
示例:
# 查询今天15:10到15:30的性能数据
./smart_query.sh --time "15:10-15:30"
# 查询最近30分钟内,进程ID为1234的性能数据
./smart_query.sh --time "last 30 minutes" --pid 1234
# 查询最近5分钟内,进程名为nginx的性能数据,并输出火焰图兼容格式
./smart_query.sh --time "last 5 minutes" --name nginx --flame > flame_data.txt
# 查询最近10分钟内,输出详细调用栈信息
./smart_query.sh --time "last 10 minutes" --detailed