Perfetto 应用内追踪(In-App Tracing)实战:C++ 埋点、采集、可视化与 PerfettoSQL 分析

发布时间:2026/9/17 18:38:48
Perfetto 应用内追踪(In-App Tracing)实战:C++ 埋点、采集、可视化与 PerfettoSQL 分析 Perfetto 应用内追踪In-App Tracing实战C 埋点、采集、可视化与 PerfettoSQL 分析【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto本文基于 Perfetto 官方入门指南docs/getting-started/in-app-tracing.md展开系统讲解如何用 Perfetto SDK 在 C 应用中添加自定义追踪点track events、录制应用内 trace、在 Perfetto UI 中可视化并用 PerfettoSQL 做程序化分析最后演示如何将应用事件与系统级事件如 ftrace、CPU 调度融合到同一条时间线上。读完本文你将能够独立完成从“引入 SDK、写埋点”到“录制、查询、做全栈性能分析”的完整链路。一、Perfetto SDK 与两种追踪模式Perfetto SDK 是一个 C17 库用于在用户态应用中记录 trace 事件。这些事件可以被 Perfetto UI 与 Trace Processor 可视化和分析。从官方 Tracing SDK 文档可以看到SDK 使用时需要先回答两个问题只记录应用自身事件还是需要叠加系统事件调度、syscall 等——这决定使用 in-process 后端还是 system 后端只需要简单的时间轴事件slices、counters还是需要强类型自定义数据源。SDK 的两种后端模式如下可同时启用模式初始化方式特点与限制进程内模式args.backends \| perfetto::kInProcessBackend服务与数据源全部托管在应用进程内不连接系统traced守护进程无需特殊系统权限应用自己控制会话生命周期支持 Android、Linux、macOS、Windows系统模式args.backends \| perfetto::kSystemBackend数据源通过 UNIX socket 上的 IPC 连接外部traced服务可与 ftrace 等系统事件融合成同一时间线要求traced守护进程运行Android 9/Pie 及以上随平台内置值得注意的是在系统模式下追踪会话必须由外部控制——用perfetto命令行客户端见 docs/reference/perfetto-cli.md或 UI 启停因为生产者不允许读回 trace 数据以避免泄露其他进程信息、防范侧信道攻击。两种模式产出的 trace 文件格式完全一致。二、添加第一处插桩2.1 获取 SDK 源文件从 Perfetto 最新 release 下载perfetto-cpp-sdk-src.zip并解压。SDK 只有两个文件——perfetto.h与perfetto.cc——它们是 Client API 的 amalgamation合并版自包含、仅依赖 C17 标准库极易接入现有构建系统。将其拷入项目的perfetto/sdk目录即可。仓库内的示例项目examples/sdk/README.md还给出了另一条开发期获取途径在仓库根目录运行tools/gen_amalgamated --output sdk/perfetto本地生成 SDK 文件然后cd examples/sdk cmake -B build cmake --build build2.2 CMake 集成参考仓库 examples/sdk/CMakeLists.txt 的写法把 SDK 编译为静态库并链接cmake_minimum_required(VERSION 3.13) project(Example) # Find the thread library, which is a dependency of Perfetto. find_package(Threads) # Add the Perfetto SDK source files to a static library. include_directories(perfetto/sdk) add_library(perfetto STATIC perfetto/sdk/perfetto.cc) # Add your applications source files to an executable. add_executable(example example.cc) # Link the Perfetto library and the thread library to your executable. target_link_libraries(example perfetto ${CMAKE_THREAD_LIBS_INIT}) # Windows-specific settings. if (WIN32) # The Perfetto library contains many symbols, so it needs the big object format. target_compile_options(perfetto PRIVATE /bigobj) # Disable legacy features in windows.h. add_definitions(-DWIN32_LEAN_AND_MEAN -DNOMINMAX) # On Windows, we need to link to the WinSock2 library. target_link_libraries(example ws2_32) endif (WIN32) # Enable standards-compliant mode when using the Visual Studio compiler. if (MSVC) target_compile_options(example PRIVATE /permissive-) endif (MSVC)仓库示例还展示了 Android 交叉编译通过 NDK 的android.toolchain.cmake-DANDROID_ABIarm64-v8a以及在 Android 上额外链接log库的细节具体可对照 examples/sdk/CMakeLists.txt。2.3 定义追踪类别并初始化在程序中初始化 Perfetto并定义追踪类别category。类别是事件归属的分组可以在录制时独立开关。来自官方指南的初始化代码如下#include perfetto.h PERFETTO_DEFINE_CATEGORIES( perfetto::Category(rendering) .SetDescription(Events from the graphics subsystem), perfetto::Category(network) .SetDescription(Network upload and download statistics)); PERFETTO_TRACK_EVENT_STATIC_STORAGE(); int main(int argc, char** argv) { perfetto::TracingInitArgs args; args.backends | perfetto::kInProcessBackend; perfetto::Tracing::Initialize(args); perfetto::TrackEvent::Register(); //... }仓库示例 examples/sdk/trace_categories.h 演示了更丰富的类别定义类别名可以带点号层级如network.debug还可以通过.SetTags(debug)打标签供录制时按标签过滤PERFETTO_DEFINE_CATEGORIES( perfetto::Category(rendering) .SetDescription(Rendering and graphics events), perfetto::Category(network.debug) .SetTags(debug) .SetDescription(Verbose network events), perfetto::Category(audio.latency) .SetTags(verbose) .SetDescription(Detailed audio latency metrics));其中PERFETTO_TRACK_EVENT_STATIC_STORAGE()为类别保留内部静态存储通常放在单独一个.cc文件中见 examples/sdk/trace_categories.cc多个翻译单元共享同一份定义。2.4 三大核心宏TRACE_EVENT / TRACE_EVENT_BEGIN·END / TRACE_COUNTER宏语义适用场景TRACE_EVENT(cat, name, ...)作用域事件宏调用时开始、当前作用域结束如函数返回时结束底层基于 C RAII测量函数执行时长最常用TRACE_EVENT_BEGIN/TRACE_EVENT_END显式配对事件不依赖函数作用域TRACE_EVENT_END默认结束同一线程最近开始的事件也可跨线程、跨进程见 Track Event 文档追踪跨越多个函数的操作TRACE_COUNTER(cat, name, value)在某个时间点记录数值快照追踪内存占用、队列长度、帧率等官方指南的示例代码void DrawPlayer(int player_number) { TRACE_EVENT(rendering, DrawPlayer, player_number, player_number); // ... } void DrawGame() { TRACE_EVENT_BEGIN(rendering, DrawGame); DrawPlayer(1); DrawPlayer(2); TRACE_EVENT_END(rendering); // ... TRACE_COUNTER(rendering, Framerate, 120); }仓库中的完整实现 examples/sdk/example.cc 还展示了其他细节自定义进程名perfetto::ProcessTrack::Current()SetTrackDescriptor写入TrackDescriptor见 examples/sdk/example.cc瞬时事件TRACE_EVENT_INSTANT(rendering, Event1)——只记录一个时间点、没有时长结束录制前先perfetto::TrackEvent::Flush()确保最后一个事件被闭合examples/sdk/example.cc。提示TRACE_EVENT_END不需要事件名因为它自动关闭同一线程上最近开始的、尚未结束的事件——同一线程上的所有事件共享同一个“栈”。因此不建议把配对的 BEGIN/END 分散在两个函数里否则无关事件可能意外终结原事件跨函数的事件最好放到独立 track 上详见 docs/instrumentation/track-events.md。三、录制第一条应用内 trace应用内录制通过TracingSessionAPI 完成完整流程分为配置 → 启动 → 运行 → 停止 → 读回 → 落盘六步。3.1 构造 TraceConfigperfetto::TraceConfig描述缓冲区、数据源等录制参数// Create a trace configuration object. This is used to define the buffers, // data sources, and other settings for the trace. perfetto::TraceConfig cfg; // Add a buffer to the config. Traces are written to this buffer in memory. cfg.add_buffers()-set_size_kb(1024); // 1 MB // Add a data source to the config. This specifies what kind of data to collect. // In this case, were collecting track events. auto* ds_cfg cfg.add_data_sources()-mutable_config(); ds_cfg-set_name(track_event); // Configure the track event data source. We can specify which categories of // events to enable or disable. perfetto::protos::gen::TrackEventConfig te_cfg; te_cfg.add_disabled_categories(*); // Disable all categories by default. te_cfg.add_enabled_categories(rendering); // Enable our rendering category. ds_cfg-set_track_event_config_raw(te_cfg.SerializeAsString());TrackEventConfig的匹配规则详见 docs/instrumentation/track-events.md值得展开每个列表项都是 glob类别按“精确命中 enabled → 精确命中 tags → 精确命中 disabled → 精确命中 disabled tags → 模式匹配……”的固定顺序依次判定默认情况下所有非 debug、非 slow 类别都是开启的而带debug更啰嗦的调试输出或slow可能影响交互性能标签的类别默认关闭。常用组合如下目标需要的配置只开特定类别enabled_categories [foo, bar, baz]disabled_categories [*]开所有非 slow 类别enabled_categories [*]只开特定标签disabled_tags [*]enabled_tags [foo, bar]3.2 会话生命周期启动、停止、保存// Create a new tracing session. std::unique_ptrperfetto::TracingSession tracing_session perfetto::Tracing::NewTrace(); // Set up the tracing session with the configuration. tracing_session-Setup(cfg); // Start tracing. This will block until the trace is stopped. tracing_session-StartBlocking(); // The tracing_session object must be kept alive for the duration of the trace.停止并保存// Stop the tracing session. This will block until all tracing data has been flushed. tracing_session-StopBlocking(); // Read the trace data from the session. std::vectorchar trace_data(tracing_session-ReadTraceBlocking()); // Write the trace data to a file. std::ofstream output; output.open(example.pftrace, std::ios::out | std::ios::binary); output.write(trace_data.data(), std::streamsize(trace_data.size())); output.close();仓库示例 examples/sdk/example.cc 把以上逻辑封装成了StartTracing()/StopTracing()两个函数可直接对照阅读。两点工程建议长 trace 直接写文件TracingSession::Setup()支持传入文件描述符Setup(cfg, fd)由 Perfetto 直接向文件写数据避免长时间录制占用内存examples/sdk/example.cc 注释也提到这一点异步变体带Blocking后缀的 API 会挂起调用线程直至操作完成需要非阻塞时使用对应的异步版本Setup/Start/Stop 回调。四、在 Perfetto UI 中可视化 trace把生成的example.pftrace拖入 Perfetto UIui.perfetto.dev即可在时间线上看到插桩点捕获的事件。指南中的示例可视化结果如下仓库示例生成的 traceexample.perfetto-trace同样可直接在 UI 打开效果参见 examples/sdk/example.png。若本地不便打开 UI也可以先用命令行工具转成文本查看例如仓库示例注释中给出的./tools/traceconv text example.pftrace或trace_processor convert text file见 examples/sdk/README.md。五、用 PerfettoSQL 程序化分析 trace除时间线可视化外Perfetto 还支持用 SQL 查询 trace。最便捷的方式是直接使用 UI 内嵌的查询引擎在 Perfetto UI 左侧菜单点击 “Query (SQL)” 标签页窗口分为上下两部分上部分写 PerfettoSQL 查询下部分查看结果按 Ctrl/Cmd Enter 执行。运行以下查询即可看到DrawPlayer插桩点被命中的次数、每次执行耗时纳秒以及player_number注解SELECT dur AS duration_ns, EXTRACT_ARG(slice.arg_set_id, debug.player_number) AS player_number FROM slice WHERE slice.name DrawPlayer;TRACE_EVENT中附加的player_number, player_number调试注解会被存进 slice 的arg_set_id关联的 debug args因此用EXTRACT_ARG(slice.arg_set_id, debug.player_number)取回——这也解释了为什么注解名带debug.前缀。帧率计数器则落在counter表SELECT ts AS timestamp_ns, value AS frame_rate FROM counter JOIN track ON track.id counter.track_id WHERE name Framerate;这里counter表保存计数器时间序列track表保存其名称等元数据两者通过track_id关联。关于 Trace Processor 表结构的更多细节可参考 docs/analysis/trace-processor.md。六、应用内 系统级融合追踪应用内 trace 的威力在于与系统级 trace 融合把应用事件和 CPU 调度、内存、I/O 等系统事件叠加在同一条时间线上形成“应用行为 × 系统环境”的完整视图。6.1 改造应用代码两点改动初始化改为连接系统后端kSystemBackend让 SDK 把事件发给中央系统追踪服务而不是应用内采集删除所有会话管理代码perfetto::Tracing::NewTrace()、tracing_session-Setup()、StartBlocking()等——应用从此只扮演数据生产者启停由外部系统工具控制。改造后的main函数#include perfetto.h // Define your categories as before. PERFETTO_DEFINE_CATEGORIES( perfetto::Category(rendering) .SetDescription(Events from the graphics subsystem), perfetto::Category(network) .SetDescription(Network upload and download statistics)); PERFETTO_TRACK_EVENT_STATIC_STORAGE(); int main(int argc, char** argv) { // Connect to the system tracing service. perfetto::TracingInitArgs args; args.backends | perfetto::kSystemBackend; perfetto::Tracing::Initialize(args); // Register your track event data source. perfetto::TrackEvent::Register(); // Your application logic goes here. // The TRACE_EVENT macros will now write to the system trace buffer // when tracing is enabled externally. // ... }仓库示例 examples/sdk/example_system_wide.cc 展示了系统模式的进阶用法——TrackEventSessionObserver应用通过WaitForTracingStart()阻塞等待外部开始录制后再执行被测逻辑并用perfetto::TrackEvent::Flush()保证事件闭合examples/sdk/example_system_wide.cc。这是配合“先启动录制、再跑业务”的测试/压测场景的标准模式。6.2 录制系统 trace应用运行后按照录制系统 trace 指南录制。配置 trace 时除了系统数据源如linux.ftrace必须额外启用track_event数据源应用的自定义事件才会被包含进来。仓库自带的 examples/sdk/system_wide_trace_cfg.pbtxt 是一个完整的融合配置示例同时采集了进程统计、系统统计、ftrace 事件和应用 track eventbuffers: { size_kb: 8960 fill_policy: DISCARD } data_sources: { config { name: linux.process_stats process_stats_config { scan_all_processes_on_start: true } } } data_sources: { config { name: linux.sys_stats sys_stats_config { stat_period_ms: 1000 stat_counters: STAT_CPU_TIMES stat_counters: STAT_FORK_COUNT } } } data_sources: { config { name: linux.ftrace ftrace_config { ftrace_events: sched/sched_switch ftrace_events: sched/sched_wakeup ftrace_events: sched/sched_waking ftrace_events: power/cpu_frequency ftrace_events: power/cpu_idle ftrace_events: task/task_newtask ftrace_events: task/task_rename } } } data_sources: { config { name: track_event } } duration_ms: 5000结合 examples/sdk/README.md 的 Android 实测步骤完整的录制链路是把示例与配置推到设备 → 通过perfetto命令行后台启动录制 → 运行被测程序 → 拉回 trace 文件adb push build_android/example_system_wide system_wide_trace_cfg.pbtxt /data/local/tmp/ adb shell \ cd /data/local/tmp; \ rm -f /data/misc/perfetto-traces/example_system_wide.perfetto-trace; \ cat system_wide_trace_cfg.pbtxt | \ perfetto --config - --txt --background \ -o /data/misc/perfetto-traces/example_system_wide.perfetto-trace; \ ./example_system_wide adb pull /data/misc/perfetto-traces/example_system_wide.perfetto-trace其中--config - --txt表示从标准输入读取文本格式的 protobuf 配置--background让录制在后台进行。打开生成的 trace即可看到应用自定义 track 与系统级 trackCPU 频率、内核调度信息等并列展示效果参考 examples/sdk/example_system_wide.png。需要更多数据源时也可以直接用 Perfetto UI 的 Record 页面生成新的配置。七、进阶类别过滤、事件参数与会话观察7.1 类别的更多玩法多类别事件一个事件可同时属于多个类别TRACE_EVENT(rendering,benchmark, ...)对应需要在注册表中声明perfetto::Category::Group(rendering,benchmark)动态类别类别名只能在运行时确定时如 WebView 里的 JS 插桩用perfetto::DynamicCategory dynamic_category{nodejs.something}配合宏使用见 docs/instrumentation/track-events.md启用查询if (TRACE_EVENT_CATEGORY_ENABLED(rendering))可高效判断某类别当前是否开启测试专用类别PERFETTO_DEFINE_TEST_CATEGORY_PREFIXES(test, dontship)限定带这些前缀的类别仅用于测试不进入生产二进制。7.2 事件参数TRACE_EVENT支持丰富参数组合签名概览详见 docs/instrumentation/track-events.mdTRACE_EVENT(cat, name[, track][, timestamp] (, debug_name, debug_value |, TrackEvent::kFieldName, value)* [, lambda]);常用形态包括携带 lambda 写自定义TrackEvent字段、任意数量的调试注解arg, value、指定perfetto::Track(1234)覆盖默认线程 track、传递自定义时间戳等。复杂结构化参数还可以通过定义自定义 protobuf 消息并用 lambda 写入ctx.event()-set_xxx()也可以声明为 TrackEvent 扩展以避开改动 Perfetto 本体见 docs/instrumentation/extensions.md。7.3 会话观察者实现perfetto::TrackEventSessionObserver并调用perfetto::TrackEvent::AddSessionObserver(this)即可在OnSetup/OnStart/OnStop回调中感知 trace 会话的启停注意所有回调都在 Perfetto 内部线程上触发典型用途就是前面系统模式示例中的“等待录制开始”examples/sdk/example_system_wide.cc。7.4 自定义数据源当数据不适合 track 模型、或数据量很大需要强类型 schema 压缩体积时可以继承perfetto::DataSourceCustomDataSource实现自定义数据源重写OnSetup/OnStart/OnStop生命周期回调用PERFETTO_DECLARE/DEFINE_DATA_SOURCE_STATIC_MEMBERS管理静态存储用DataSourceDescriptor命名并注册最后通过CustomDataSource::Trace([](TraceContext ctx) { ... })在启用时同步写入 trace packet示例见 examples/sdk/example_custom_data_source.cc完整说明见 docs/instrumentation/tracing-sdk.md。注意自定义数据源需要配套的 Trace Processor 改动才能被导入分析。八、延伸阅读Tracing SDK 深入指南SDK 全部特性含可选的 zlib/zstd 压缩与 RE2 正则优化开关Track Events 详解slices / counters / flows 三类事件及 track、interning、时钟对齐等进阶主题PerfettoSQL 入门 与 Trace Processor更多表结构与查询能力系统追踪入门录制融合 trace 的完整方法【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询