多机器架构

Perfetto 可以记录跨越多个操作系统镜像的单一 Trace——例如宿主机和一个或多个虚拟机 Guest、SoC 和协处理器、或驱动共享工作负载的测试机集群。结果是一个跨机器因果关系可见且可查询的 Timeline,而不是每台机器一个需要手动关联的 Trace。

本页解释多机器 Tracing 是什么以及各个组件如何协同工作。分步设置请参阅多机器记录

问题描述

标准的服务模型假设所有 Producer、traced 服务和 Consumer 共享同一个 OS 镜像:它们通过本地 UNIX Socket 连接 traced,共识 PID,并观察相同的 CLOCK_BOOTTIME

当 Producer 位于不同内核时,这个假设就失效了。没有共享的文件系统 Socket。PID 命名空间是独立的。启动时钟在不同时间点开始,并且各自独立漂移。在每台机器上运行单独的 traced 然后事后拼接结果 Trace 是可行的,但很脆弱,特别是对任何时间敏感的场景(如跨机器调度或 RPC 延迟)。

多机器 Tracing 在不重复每台机器的 Buffer 或 Consumer 机制的情况下解决了这个问题。

架构

配置中只有一台机器运行 traced("host")。其余每台机器运行 traced_relay,将 Producer 端 IPC 转发到 host:

远程机器 Host 机器 ┌────────────────────────┐ ┌────────────────────────────┐ │ traced_probes │ │ traced --enable-relay- │ │ + 其他 Producer │ │ endpoint │ │ │ │ │ ▲ │ │ ▼ (本地 IPC) │ TCP/vsock │ │ (本地 IPC) │ │ traced_relay ────────┼──────────────►│ relay 端点 │ └────────────────────────┘ │ ▲ │ │ │ │ │ traced_probes / 其他 │ │ 本地 Producer │ │ ▲ │ │ │ (Consumer IPC) │ │ perfetto 命令行 │ └────────────────────────────┘

traced_relay 被有意设计得很轻量:它在本地 Producer Socket 上接受 Producer 连接,与 host 交换少量元数据(见下文),然后通过 TCP 或 vsock 代理 Producer IPC 帧。它不缓冲 Trace 数据,不解析 Trace Packet,也不实现任何 Consumer 端功能。

Consumer(perfetto 命令行或 UI 的 WebSocket 桥接)只与 host 的 traced 通信。Trace 配置、Buffer 所有权和最终读取都停留在同一台机器上。

机器标识

traced_relay 首次连接到 host 时,它发送一个包含 machine_id_hintSetPeerIdentity 消息——在 Linux 上,这来源于 /proc/sys/kernel/random/boot_id(如果可用),或者以 uname(2) 加启动时间戳源的哈希作为回退。该提示在同一内核的重新连接中是稳定的,但在不同内核之间是不同的。

Host 的 traced 将每个唯一提示映射到一个小的整数 MachineId,并为从该 Relay 到达的每个 TracePacket 加盖该 ID(TracePacket 上的 machine_id 字段)。在导入时,Trace Processormachine 表中为每台机器生成一行:

描述
id Trace Processor 分配的机器 ID。host 始终为 0
raw_id Trace Packet 中的原始机器标识符(host 为 0,远程机器非零)。
sysnamereleaseversionarch 该机器的 uname(2) 字段。
num_cpus 该内核可见的 CPU 数量。
system_ram_bytessystem_ram_gb 总 RAM。
android_build_fingerprintandroid_device_manufacturerandroid_sdk_version 仅对 Android 机器填充。

具有每 CPU 或每线程维度的表(threadcpugpu_counter_track 等)携带可为空的 machine_id,以便跨机器数据可以通过 SQL 切片。UI 对每机器 Track 的支持仍在完善中,因此 machine_id JOIN 目前仍是回答跨机器问题最可靠的方式。

跨机器时钟同步

每台远程机器都有自己的 CLOCK_BOOTTIME,因此其 Producer 写入的时间戳不能直接与 host 时间戳比较。traced_relay 针对 host 的 Relay 端点运行一个轻量级 Ping 协议,发送和接收带时间戳的消息来估算每机器的时钟偏移和往返时间。Host 定期将估算的偏移作为 ClockSnapshot Packet 发出到 Trace 中。

此后一切复用时钟同步中描述的现有单机器机制:Trace Processor 将跨机器偏移折叠到它已经为 CLOCK_REALTIMECLOCK_MONOTONIC 等构建的同一时钟图中,并在导入时将每个事件解析为单一的全局 Trace 时钟。DataSource 不需要做任何额外工作。

DataSource 调度

默认情况下,traced 只将 DataSource 调度到 host 机器上的 Producer。要从远程机器收集数据,Consumer 的 TraceConfig 必须显式选择,可以通过全局设置 trace_all_machines: true,或针对每个 DataSource 设置 DataSource.machine_name_filter。没有其中之一,远程机器上的 traced_probes 仍然会注册并作为一行出现在 machine 表中,但不会被分配请求的 DataSource,因此不会有事件从中流出。

trace_all_machines 在 v54 中引入;早期版本默认匹配所有机器。远程端的机器名来自启动 traced_relay 时的 PERFETTO_MACHINE_NAME 环境变量,回退到 uname -s。字面名称 "host" 是运行 traced 的机器的同义词。

单个内核上的 Producer 不能代替"两台机器",即使用于测试。两个 traced_probes 实例会争用相同的 /sys/kernel/tracing/ 环形 Buffer,每 CPU 事件会在两个 machine_id 之间任意分区——Trace 看起来有效但实际上已被撕裂。多机器设置需要两个内核(两台机器、宿主机加 VM、具有独立内核命名空间的容器等)。

限制与约束

下一步