ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Perfetto 多 Trace 合并深入解析:全局时钟图、对齐回退策略与机器归属模型

Perfetto 多 Trace 合并深入解析:全局时钟图、对齐回退策略与机器归属模型 Perfetto 多 Trace 合并深入解析全局时钟图、对齐回退策略与机器归属模型【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfettoPerfetto 的 Trace Processor 可以一次打开多个 trace 文件将它们合并到一条共享时间线上来自不同设备、同一设备的不同进程、甚至格式完全不同的 trace 都可以共存于一次分析中。本文以 Trace Merging 概念文档 为主线结合仓库中的时钟同步引擎clock_synchronizer、ClockTracker与 trace manifest 解析器源码讲清楚独立文件中的事件如何获得可比较的时间戳、数据又如何始终归属于它来源的机器。读完之后你能够独立配置跨设备合并、诊断合并时的事件丢弃并理解合并底层的时间转换机制。问题本质同时录制的两个文件并不共享时间基两个同时录制的 trace 文件其时间戳在一般情况下并不可直接比较。每个文件里的时间戳都是某个时钟的读数一部手机上的BOOTTIME、Chrome 渲染进程内部的MONOTONIC或者像 Chrome JSON 这类格式根本没有绝对时钟。不同机器上的时钟会各自漂移同一台机器上不同的时钟域例如BOOTTIME与REALTIME也有不同的零点。如果只是把文件简单拼接就会把互不相关的刻度放到同一条轴上。因此合并必须为每个事件回答两个问题这个时间戳是从哪个时钟读出的这个时钟与合并后 trace 用作时间线的那个时钟即 trace time是什么关系这就是整个合并机制要解决的核心问题下文的所有机制都是围绕它展开的。时钟的作用域机器 文件Perfetto 在单个 trace 内部就已经建模了多时钟域并借助ClockSnapshot数据包在域之间做转换详见 时钟同步概念文档。合并把这个模型扩展到跨文件、跨机器每一个时钟不仅由其域domain标识还由它所属的机器标识必要时还由它出自哪个文件标识。手机上的BOOTTIME和手表上的BOOTTIME是两个不同的时钟两个无时钟 JSON 文件各自的私有时间线也是如此。从源码结构看这一模型落实在 ClockId 结构体 中它由四个字段共同构成一个时钟的全局身份struct ClockId { uint32_t clock_id 0; // 时钟域内置钟、序列钟或文件私有钟 uint32_t seq_id 0; // 序列作用域时钟的序列号 uint32_t trace_file_id 0; // 归档中隔离各文件的状态 uint32_t machine_id 0; // 时钟所属的机器0 表示宿主机 };machine_id用来区分同一个文件里来自不同机器的数据一条多机器 proto trace 只对应一个trace_file_idtrace_file_id则用来隔离同一机器上不同文件的时钟状态。每次转换前ClockTracker::ToTraceTime 都会先通过ClockId::Qualify把时钟打上(machine, file)标签再交给转换引擎——这正是时钟按机器和文件限定作用域在代码层面的直接体现。全局时钟图及其三条边的来源所有这些时钟都存在于一张全局时钟图中节点是时钟边是两条时钟之间已知的对应关系每条边表达当时钟 A 读数为 X 时时钟 B 读数为 Y。转换一个时间戳时Trace Processor 就在这张图上从源时钟寻路到 trace-time 时钟沿途逐条应用边上的换算。边的来源有三类trace 文件内部的ClockSnapshot数据包录制期完成的时钟同步例如 多机器录制 所用的 ping 协议remote_clock_synctrace manifest 中的条目允许用户断言一条 trace 自身并不包含的对应关系可选带固定偏移。转换引擎 ClockSynchronizer 对每次AddSnapshot调用增量构建这张无权重有向图Convert时用 BFS 查找最短转换路径允许跨多种快照类型多跳例如 A→C 经由快照 S1、C→E 经由快照 S2。一个值得注意的实现细节是每条进入图的边都会写入clock_snapshot表见 ClockTracker::AddSnapshot 的注释Every edge entering the graph is recorded this way因此实际用于转换的整张图都可以用 SQL 完全检查——这是排查合并问题的关键入口。文件间毫无共同时钟时如何摆放三级回退策略如果某个文件的时钟在图上有通往 trace time 的路径直接走这条路即可。否则 Trace Processor 按以下优先级回退源码对应 ClockTracker::BridgeToTraceTime 的分支逻辑1. REALTIME 会合rendezvous。REALTIME墙钟时间假定在所有机器上读数相同——实际中机器都通过 NTP 同步它。如果文件所在机器与 trace-time 机器都能关联到REALTIME文件就经由它定位。这正是两部手机各自独立录制的 trace 能够按真实墙钟位置自动对齐的原理。源码中该分支的实现是把本机的REALTIME节点与 trace-time 所在机器的REALTIME全局会合节点以零偏移边相连再让源时钟经本机REALTIME到达 trace time。2. 同域假设。不同机器或文件上的同域时钟例如两个BOOTTIME在没有更好的证据时以零偏移关联类似地文件的私有按文件时钟BUILTIN_CLOCK_TRACE_FILE也可以被固定在零偏移上。从源码看这是最后手段分支且仅当两端之一是文件私有钟、或两端是同域时钟时才注入这条零偏移边——这是一种猜测只适用于来自同一机器同一开机周期的文件。3. 丢弃Drop。两个不同的真实时钟域比如这边的BOOTTIME和那边的REALTIME永远不会被盲目等同。无法与 trace time 关联的时钟其事件被丢弃并记入 trace 的错误统计见下文如何验证结果。源码注释对此表述很明确we do not fabricate a relationship: the conversion fails so the events are dropped and logged rather than silently misplaced。修复方式是录制时记录时钟快照或在 manifest 中断言该对应关系。注意REALTIME 会合的精度取决于各机器的墙钟。如果 NTP 没有同步它们trace 之间会相差一个偏移量已知的偏差可以用 manifest 的offset_ns修正。Trace time 与时间边界合并后的 trace 只有一个时钟充当时间线。规则是第一个声明 trace-time 时钟的文件获胜。TraceTimeState::TrySetClock 的所有权语义即首个声明者获胜其他声明者被忽略。由于 manifest 总是最先被处理其 importer 描述符设置了archive_priority -1和is_manifest true见 PerfettoManifestImportermanifest 里的trace_time字段优先于各 trace 自身声明的任何内容。合并 trace 的时间边界是所有 (机器, 文件) 对录制区间的并集。因此相隔几分钟录制的两个 trace 合并后会得到一条很长的时间线两端各有一簇活动——合并是把文件放到它们真实的相对位置上而不是把它们叠加在一起。时间戳若被转换到 trace time 起点之前将无法表示同样被丢弃并记入错误统计。在合并 trace 中最常见的原因是 manifest 里的offset_ns把文件移得太远。机器Machine合并数据保持来源归属合并后的数据始终归属于它来源的机器。一台机器是一个设备或操作系统实例手机、服务器、虚拟机。在 trace 模型中机器是machine表的一行process、thread、cpu、sched等机器作用域的表都带machine_id列引用它。这与 live 多机器录制 使用同一模型合并时数据来源有三类trace 内嵌的机器 id。通过 traced_relay 录制、或 SDK producer 通过TracingInitArgs::machine_id配置了机器 id 的数据包会携带TracePacket.machine_id每个不同的 id 成为一台机器。如果一条 trace 的数据完全来自这样的一台机器它会被收养adopted到宿主机器行上——因此单机器 trace 恰好只有一台机器而不是空宿主 一台远程。manifest 声明。manifest 可以把整个文件归属到命名机器也可以重命名多机器文件内嵌的 id。命名单独说明manifest 命名机器获得从 2^32 开始的合成raw_id源码常量kFirstManifestMachineId 1ll 32落在 32 位内嵌 id 空间之外多个文件使用相同名字即表示同一台共享机器。SystemInfo.machine_name。producer 可以在自己的SystemInfo包中设置人类可读名字填入machine.name列。没有任何东西会自动设置它缺省时且 manifest 未命名UI 会回退到 machine 2 之类的数字标签。注意machine.id表行 id在 Perfetto 版本之间不稳定。查询中识别机器应使用machine.raw_id或machine.name。与 live 多机器录制的关系合并是获得跨多机器 trace 的三种方式之一另外两种发生在录制期将多个 producer 中继到单个tracedtraced_relay或在 SDK producer 中预先打上机器 id。三种方式产生的是同一套模型上文描述的时钟图 机器表并且事后的合并还可以组合它们的输出——例如合并两条来自不同宿主机、各自用 relay 录制的 trace。三种方案的适用场景与选择依据见 多机器录制文档。已知限制自身包含多个 trace 的归档不能再嵌套进另一次合并不支持递归同步。应直接合并叶子文件。把合并后的多机器 trace 导出为 legacy JSON 时只会导出宿主机器上的第一个 trace。UI 构造合并输入时使用内存中的 TAR因此单个文件大小受限于能用 12 位八进制编码的长度约 8 GB归档成员名长度上限为 99 个字符。实战构建归档、写 manifest 与验证结果概念文档偏重机制任务导向的完整指南见 命令行合并指南 与 UI 合并指南。这里给出可直接复制的最小实操闭环。归档 manifest 模型trace_processor只接受一个 trace 文件参数合并的入口是一个归档ZIP 或 TAR其中装有待合并的文件。util merge子命令是构建这种归档的便捷工具实现位于 util_subcommand.cctrace_processor util merge -o merged.tar trace_a.pftrace trace_b.pftrace trace_processor merged.tar归档是普通的 TAR/ZIPtar cf merged.tar ...完全等效util merge额外处理归档布局并把--manifest指定的文件固定命名为perfetto_manifest.json--strict还能把校验警告变成非零退出码适合 CI。用 manifest 保留两台设备的数据分离默认情况下两个看起来像同一台设备的 trace 会合并到一台机器上。给文件命名机器可以让各自的进程、线程、CPU 保持分组{ perfetto_manifest: { version: 1, files: [ {path: device_a.pftrace, machine: {name: device-a}}, {path: device_b.pftrace, machine: {name: device-b}} ] } }trace_processor util merge -o merged.tar --manifest manifest.json \ device_a.pftrace device_b.pftrace trace_processor merged.tar把无时钟 trace 钉到系统 trace 上Chrome JSON、Gecko、Instruments 等格式没有绝对时钟自身无法与系统 trace 对齐。manifest 的clocks块可以把文件钉到另一个文件的时钟上可选固定偏移{ perfetto_manifest: { version: 1, trace_time: {clock: BOOTTIME}, files: [ {path: system_trace.pftrace}, { path: app_trace.json, clocks: { sync_to: {file: system_trace.pftrace, clock: BOOTTIME}, offset_ns: 100000000 } } ] } }offset_ns的语义与 PerfettoManifestReader::ParseClocks 的实现一致在同一时刻源文件时钟读 T 时参考时钟读 T offset_ns因此正值会把文件在时间线上向后移动。注意sync_to.file必须本身是files数组中的一项。另外两个源码可确认的约束manifest 目前仅支持version: 1版本校验clocks块中可写的时钟名只接受REALTIME、REALTIME_COARSE、MONOTONIC、MONOTONIC_COARSE、MONOTONIC_RAW、BOOTTIME六个ParseClockName。用 SQL 验证合并结果合并过程是自描述的合并后直接查询-- 合并后的机器以及各自的数据量 SELECT m.name, m.raw_id, (SELECT COUNT(*) FROM thread t WHERE t.machine_id m.id) AS threads FROM machine m; -- 输入文件及其处理顺序 SELECT name, trace_type, size FROM trace_file; -- 合并中被丢弃或错位的事件结果为空说明每个事件都成功落入时间线 SELECT name, value, machine_id, trace_id FROM stats WHERE severity error AND value 0;合并时值得盯的统计项clock_sync_unrelatable_clock_domains与clock_sync_failure_no_path统计无法与时间线关联的时钟上的事件对策录制时钟快照或添加 manifestclocks条目trace_sorter_negative_timestamp_dropped统计被offset_ns移出时间线起点之前的事件。逐文件的元数据可通过metadata表的trace_id列或更高层的traceinfo.tracestdlib 模块中的_metadata_by_trace视图获取。延伸阅读Trace manifest 格式参考手动合并配置的完整字段说明、默认值与错误目录。命令行合并指南构建合并归档、manifest 自动化的完整流程与 CI 建议。UI 中合并 trace交互式配置对齐与机器归属并可一键导出 manifest 或自包含 .tar。时钟同步单 trace 内的ClockSnapshot模型即本文合并机制所构建的基础。【免费下载链接】perfettoProduction-grade client-side tracing, profiling, and analysis for complex software systems.项目地址: https://gitcode.com/GitHub_Trending/pe/perfetto创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表