
Perfetto Linux Cookbook端到端的 CPU、内存与内核函数追踪实战指南【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto本文是一份面向 Linux 开发者与嵌入式工程师的 Perfetto 实战手册覆盖从构建可符号化symbolizable的二进制、录制 CPU 火焰图与原生堆内存分配画像到内核函数图追踪、线程阻塞归因的完整链路。读完本文你将掌握如何用tracebox录制原始 trace、用trace_processor bundle在宿主机离线还原用户态符号并理解内核符号为何必须在录制时通过symbolize_ksyms就地解析。适用场景与阅读指引本文面向在Linux 宿主机或嵌入式 Linux 目标机包括 Yocto、QNX 等上分析原生二进制的开发者。文档中每一份菜谱recipe都是自包含的包含下载工具的命令、完整的 trace 配置textproto 格式以及事后符号化步骤。Perfetto 在 Linux 上的相关主题分散在多份指南中建议按需交叉阅读系统级 trace 录制CPU 性能分析与 perf 计数器原生堆内存分析内核函数图追踪符号化与反混淆环境准备工具下载与权限设置整份手册只需两个工具二者都是单文件、自包含的可执行程序tracebox录制引擎。它将tracedtracing 服务、traced_probes数据源采集进程以及所有数据源实现打包进一个静态链接的二进制中。从源码看tracebox 入口支持两种模式直接以traced、traced_probes、traced_perf等 applet 名调用对应子服务或在autostart模式下自动拉起并关闭这些服务——这正是本文所有命令的使用方式。curl -LO https://get.perfetto.dev/tracebox chmod x traceboxtrace_processor宿主机侧工具链。用于转换 trace更重要的是符号化。它是一个薄薄的 Python 包装脚本首次使用时按平台自动下载对应的原生二进制具体机制见 python/perfetto/prebuilts/perfetto_prebuilts.py 中的download_or_get_cached按 SHA-256 校验后缓存到~/.local/share/perfetto/prebuilts/。curl -LO https://get.perfetto.dev/trace_processor chmod x trace_processor权限设置录制 ftrace 与perf_event_open需要提权。最省事的方式是直接以 root 运行traceboxsudo ./tracebox ...。也可以选择在每次开机后授予特定权限# ftrace 类数据源调度、function_graph 等需要可写 tracefs。 sudo chown -R $USER /sys/kernel/tracing # perf / 调用栈采样linux.perf需要放开 perf_event_paranoid。 echo -1 | sudo tee /proc/sys/kernel/perf_event_paranoid # 解析内核符号名kallsyms。调用栈中的内核帧与 function_graph 菜谱都依赖它。 echo 0 | sudo tee /proc/sys/kernel/kptr_restrict需要特别说明的是kptr_restrictPerfetto不会在 trace 中存储绝对内核地址以免破坏 KASLR而是在录制设备上把符号名混淆后嵌入 trace。因此一旦权限不足内核帧就会以十六进制地址形式出现且事后无法补救只能重新录制。构建 Perfetto 能符号化的二进制Perfetto 对原生调用栈来自 CPU profiler 与 heap profiler记录的是原始指令地址。要还原成函数名、文件和行号执行符号化的宿主机需要未 strip 的 ELF 二进制且其Build ID 与目标机上运行的二进制一致。请在录制之前就完成以下准备1. 编译时加入调试信息。加-g即可。它不会改变生成的代码只是附加 DWARF 调试信息gcc -g -O2 -o myapp myapp.c # 或 clang参数相同-O2 -g是性能分析的推荐组合用优化后的代码分析的是你真正发布的版本同时保留足够的调试信息来把地址映射回源码行。2. 保留 Build ID。现代工具链默认生成 GNU Build ID可用以下命令确认readelf -n ./myapp | grep -A1 Build IDBuild ID 是 Perfetto 将磁盘上的二进制与 trace 中记录的映射相匹配的依据。两次不同构建有不同的 Build IDPerfetto 会拒绝为不匹配的符号做映射——这是一项特性可防止错误符号化。3. 可选发布 strip 版本、宿主机保留符号。你不需要把调试信息部署到目标机。可以拆分为 sidecar 文件并 strip 发布二进制匹配靠 Build ID因此两边文件名不必一致gcc -g -O2 -o myapp myapp.c # 把调试信息拆到 sidecar通过 Build ID 关联回原文件。 objcopy --only-keep-debug myapp myapp.debug objcopy --strip-debug --add-gnu-debuglinkmyapp.debug myapp # 将精简后的 myapp 部署到目标机。 # 在宿主机保留 myapp.debug或原始的未 strip 二进制。对于以独立包分发调试信息的发行版-dbg/-dbgsym/debuginfo包在宿主机安装这些包也能达到同样效果符号会出现在/usr/lib/debug下。菜谱一带完整符号的 CPU 性能分析目标得到一张展示进程 CPU 时间去向、且带真实函数名的火焰图。这是 CPU 性能分析指南 的端到端版本。1. 按上文构建可符号化的二进制一节编译带符号的程序。2. 编写配置。下面的配置按每 CPU 每秒 100 次的频率采样调用栈仅在目标进程处于 on-CPU 状态时展开栈并附加调度上下文。保存为cpu.cfg并把target_cmdline改为你进程名的子串duration_ms: 10000 buffers { size_kb: 65536 fill_policy: DISCARD } # 周期性调用栈采样限定到单个进程。 data_sources { config { name: linux.perf perf_event_config { timebase { counter: SW_CPU_CLOCK frequency: 100 timestamp_clock: PERF_CLOCK_MONOTONIC } callstack_sampling { scope { target_cmdline: myapp } # 同时展开到内核。需要降低 kptr_restrict见 Setup。 kernel_frames: true } } } } # 同一时间线上的调度上下文。 data_sources { config { name: linux.ftrace ftrace_config { ftrace_events: sched/sched_switch ftrace_events: sched/sched_waking } } } # 进程与线程名。 data_sources { config { name: linux.process_stats process_stats_config { scan_all_processes_on_start: true } } }下面对关键字段做源码级说明均可在 perf_event_config.proto 中核对timebase定义采样的事件与频率。frequency表示每 CPU 每秒采样 N 次由内核按观测到的事件速率动态调整采样周期以逼近该频率period则是严格每 N 次计数采样一次。timestamp_clock: PERF_CLOCK_MONOTONIC用于指定采样时间戳时钟。callstack_sampling.scope.target_cmdline是命令行白名单按/proc/pid/cmdline而非 comm 字符串匹配同一Scope消息中还可使用target_pid、exclude_pid、exclude_cmdline组合出更细的允许/拒绝规则。kernel_frames: true会让调用栈包含内核空间帧以kernel字符串作为映射名标识。它要求traced_perf以 root 运行或手动放开kptr_restrict该选项不会泄露 KASLR因为只输出函数名。ring_buffer_pages本配置未显式设置控制每个 CPU 的 perf 环形缓冲区大小以 4KB 页为单位必须是 2 的幂ring_buffer_read_period_ms控制 producer 读取缓冲区的周期。linux.ftrace数据源对应的完整字段定义在 ftrace_config.protolinux.process_stats的配置项见 process_stats_config.proto。3. 录制工具下载与权限见上文 Setupsudo ./tracebox -c cpu.cfg --txt -o /tmp/trace.pftrace此刻内核帧已被符号化录制设备上通过 kallsyms 就地解析但用户态帧仍是原始地址。4. 用trace_processor bundle烘焙用户态符号。它会自动发现 trace 中加载过的二进制利用 trace 里记录的绝对路径——在你本机分析时效果很好并产出一个单文件、自包含的 trace# llvm-symbolizer 必须在 $PATH 中例如sudo apt install llvm。 ./trace_processor bundle /tmp/trace.pftrace /tmp/trace.bundlebundle是推荐的符号化流程它自动搜索 AOSP 构建输出、系统标准调试目录$HOME/.debug、/usr/lib/debug以及 trace 中记录映射的绝对路径并按 Build ID 递归匹配无需重建设备上的目录布局。当符号在其他位置构建机、.debug目录、嵌入式 sysroot时用--symbol-paths指定./trace_processor bundle \ --symbol-paths /path/to/sysroot/usr/lib/debug,/path/to/build/out \ --verbose \ /tmp/trace.pftrace /tmp/trace.bundle关于 Build ID 查找顺序与 could not find library 的排障详见符号化指南。简要来说对每个搜索路径P符号化器按绝对路径 → 去掉base.apk!→ 仅文件名 → 去掉base.apk!的文件名 →P/.build-id/前两位/其余.debugFedora Build ID 布局的顺序查找第一个 Build ID 匹配的文件胜出。如果希望得到聚合的 pprof 报告./trace_processor convert profile --perf /tmp/trace.pftrace菜谱二原生堆内存分析目标找出哪个调用栈分配了最多的原生malloc内存。在 Linux 上heap_profile辅助脚本能端到端驱动整个过程包括以预加载 profiler 的方式拉起你的二进制。下载辅助脚本curl -LO https://raw.githubusercontent.com/google/perfetto/main/tools/heap_profile chmod x heap_profile在你的二进制下运行它python3 heap_profile host -- ./myapp --some-flag脚本内部参见 tools/heap_profile 的linux_main自动下载tracebox与libheapprofd_glibc_preload.so预加载库以--system-sockets模式启动内置 traced 守护进程通过--notify-fd等待会话就绪随后以LD_PRELOADlibheapprofd_glibc_preload.so环境变量启动你的程序。退出或按Ctrl-C时它会在打印出的/tmp目录中写入一份raw-trace以及每个进程的 pprof 文件。因为是本地分析匹配的二进制就在现场符号会自动解析。常用可选参数heap_profile host --help可查全量-i / --interval采样间隔字节默认 40964KiB-d / --duration分析时长毫秒0 表示运行到被中断默认-o / --output输出目录--shmem-size客户端与 heapprofd 之间的共享内存大小默认 8MiB须为 4096 的 2 的幂次倍数且至少 8192--no-block-client缓冲区满时提前结束分析而非阻塞客户端分配--block-client-timeout若启用阻塞客户端单个分配最多阻塞的时长微秒。用 Perfetto UI 打开raw-trace即可看到分配火焰图。完整的选项说明自定义预加载库、采样间隔等见原生堆分析器Linux 支持。菜谱三内核函数图追踪目标以嵌套 slice 的形式看到内核函数实际执行了哪些、各执行了多久。最常见的错误是忘记symbolize_ksyms导致所有函数都显示为十六进制地址。保存为funcgraph.cfg追踪__schedule及其所有被调用者duration_ms: 10000 buffers { size_kb: 65536 fill_policy: DISCARD } data_sources { config { name: linux.ftrace ftrace_config { # 没有它函数只会显示为十六进制地址。 symbolize_ksyms: true enable_function_graph: true function_graph_roots: __schedule function_graph_max_depth: 10 } } }录制function graph 驱动内核 tracer因此必须 rootsudo ./tracebox -c funcgraph.cfg --txt -o /tmp/funcgraph.pftrace从 ftrace_config.proto 的注释可以看出函数图数据源的设计约束enable_function_graph启用内核 function_graph tracer发出funcgraph_entry/funcgraph_exit事件要求内核编译时带CONFIG_FUNCTION_GRAPH_TRACER可查看/sys/kernel/tracing/available_tracers是否包含function_graph来确认。function_graph_roots追踪指定函数及其全部被调用者支持通配符可与function_filters限制仅追踪匹配过滤器的被调用者组合使用。function_graph_max_depth限制向下追踪的调用深度对应内核max_graph_depth只在首个启用 function_graph 的会话中生效。不加约束地开启 function_graph 会产生无法实际使用的带宽因此强烈建议用function_filters或function_graph_roots限定追踪集合此外若已有并发的非 function_graph ftrace 数据源数据源可能被拒绝内核不支持中途切换 tracer。用 UI 打开/tmp/funcgraph.pftrace调用会以每个线程的Funcgraph轨道上的嵌套 slice 呈现。内核要求CONFIG_FUNCTION_GRAPH_TRACER、过滤选项与可视化方式详见函数图数据源专题页。注意与菜谱一的关键区别这里的内核符号来自symbolize_ksyms事后无法用trace_processor bundle补上。原因是 Perfetto 刻意不在 trace 中存储绝对内核地址防止破坏 KASLR 泄露内核内存布局函数名在设备上就地混淆解析——所以忘了设symbolize_ksyms就只能重新录制。同理trace_processor bundle与离线符号化工具对 function_graph 事件无能为力符号化指南中的Kernel function names: this trace contains function_graph events ...警告即指此。菜谱四定位线程被阻塞的原因目标理解线程为何反复被抢占锁竞争、优先级反转、阻塞式系统调用。Linux 上正确的工具是由调度事件触发的调用栈采样把sched/sched_switch及sched/sched_wakingtracepoint 作为 perf 的timebase这样能在线程阻塞或唤醒的精确时刻捕获调用栈。对阻塞分析而言这远比基于时间的采样精确。⚠️ 警告Android 的blocked_function字段来自 Android cookbook 中使用的sched/sched_blocked_reasonftrace 事件是 Android 内核特性在主线/桌面 Linux 内核上通常不存在。请改用下面的调用栈采样方案。最小配置保存为blocked.cfg把comm过滤条件改为你的进程。tracepoint 的filter可防止采样器被无关线程淹没duration_ms: 10000 buffers { size_kb: 102400 fill_policy: DISCARD } data_sources { config { name: linux.perf perf_event_config { timebase { period: 1 tracepoint { name: sched/sched_switch filter: prev_comm ~ \*myapp*\ || next_comm ~ \*myapp*\ } timestamp_clock: PERF_CLOCK_MONOTONIC } callstack_sampling { kernel_frames: true } ring_buffer_pages: 2048 } } }字段说明timebase.tracepoint把采样基准从计数器换成 tracepoint——每发生一次sched/sched_switch且匹配filter就采样一次period: 1表示每 1 次事件采样一次。filter 语法与内核 Event filtering 一致perf_events.proto 中的Tracepoint.filter字段。callstack_sampling.kernel_frames: true让栈包含内核帧从而看到阻塞点在内核侧的调用路径。ring_buffer_pages: 2048把每 CPU perf 环形缓冲扩到 2048 × 4KB 8MiB避免高频事件下丢采样。录制与符号化步骤与菜谱一完全相同sudo ./tracebox -c blocked.cfg --txt -o ...然后./trace_processor bundle ...。完整的工作示例——包括同时对sched_switch与sched_waking过滤、以及如何解读捕获到的调用栈——参见调度阻塞案例研究。两条符号化路径的总结把本文涉及的两类符号化机制放在一起看脉络非常清晰符号来源解析时机工具关键配置用户态调用栈帧CPU 采样、堆分析录制后、宿主机离线trace_processor bundle--symbol-paths指定路径未 strip 二进制 匹配的 Build IDllvm-symbolizer在$PATH内核帧调用栈中的 kernel 帧录制时、设备上自动kallsymsroot 或kptr_restrict0与symbolize_ksyms无关内核 ftrace 事件function_graph 等录制时、设备上symbolize_ksyms: trueroot 或kptr_restrict0事后不可补无论哪条路径核心原则都一致符号化依赖匹配的构建产物Build ID且要按需在录制前把环境与权限准备好。这正是本文所有菜谱的第一步都是构建带符号的二进制 设置权限的原因。【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考