Perfetto 翻译-核心概念-trace 配置
前言:虽然有翻译软件,虽然有chatgpt,毕竟语言隔阂,对这个工具还是一知半解,因此想通过翻译的方式和大家来一起学习下Perfetto这个强大的工具
#####################以下分割线#####################
英文原文在这里
Trace configuration
与许多始终在线的日志记录系统(例如 Linux 的 rsyslog、Android 的 logcat)不同,在 Perfetto 中,所有trace的数据源默认是关闭状态,并且仅在开关开启时才记录数据。
当正在抓取一个(或多个)trace时,才会记录数据源的数据。通过调用 perfetto
cmdline 客户端并传递配置来开始抓取(请参阅适用于 Android、 Linux或Chrome on desktop 的快速入门指南)。
一个简单的跟踪配置如下所示:
duration_ms: 10000
buffers {
size_kb: 65536
fill_policy: RING_BUFFER
}
data_sources {
config {
name: "linux.ftrace"
target_buffer: 0
ftrace_config {
ftrace_events: "sched_switch"
ftrace_events: "sched_wakeup"
}
}
}
其用法如下:
perfetto --txt -c config.pbtx -o trace_file.perfetto-trace
提示:可以在 的 repo 中找到 /test/configs/一些更完整的跟踪配置示例。
TraceConfig
![](https://img.haomeiwen.com/i2972443/565d77c60ba3fec6.png)
Buffers
缓冲区部分定义tracing service拥有的内存中缓冲区的数量、大小和策略。大体结构如下:
# Buffer #0
buffers {
size_kb: 4096
fill_policy: RING_BUFFER
}
# Buffer #1
buffers {
size_kb: 8192
fill_policy: DISCARD
}
每个缓冲区都有一个填充策略,该策略是:
- RING_BUFFER (默认): 缓冲区的行为类似于环形缓冲区,缓冲区满时最新的内容将替换缓冲区中最早的跟踪数据。
- DISCARD: 缓冲区在数据满后停止接受数据。尝试写入的新数据将被丢弃。
警告:对于在trace末尾提交数据的数据源,DISCARD 可能会产生意外的副作用。
trace config必须至少定义一个缓冲区才能有效。在最简单的情况下,所有数据源都会将其跟踪数据写入同一缓冲区。
虽然这适用于大多数情况,但在不同数据源以明显不同的速率写入的情况下,它可能会出现问题。
例如,假设一个trace config同时支持:
- 内核调度程序跟踪器。在典型的 Android 手机上,这会记录 ~10000 个事件/秒,以 ~1 MB/s 的速度将trace数据写入缓冲区。
- 内存统计信息轮询。此数据源将 /proc/meminfo 的内容写入跟踪缓冲区,并配置为每 5 秒轮询一次,每个轮询间隔写入 约100 KB。
如果两个数据源都配置为写入同一缓冲区,并且该缓冲区设置为 4MB, ,则大多数trace将仅包含一个内存快照。大多数跟踪很有可能根本不包含任何内存快照,即使第二个数据源工作正常。这是因为在 5 秒的轮询间隔内,调度程序数据源最终可能会填满整个缓冲区,导致内存快照数据没有机会写入缓冲区。
动态缓冲区映射
数据源<>缓冲区映射在 Perfetto 中是动态的。在最简单的情况下,跟踪会话只能定义一个缓冲区。默认情况下,所有数据源都会将数据记录到该缓冲区中。
在上述示例中,最好将这些数据源分隔到不同的缓冲区中。这可以通过 TraceConfig target_buffer
的字段来实现。
![](https://img.haomeiwen.com/i2972443/c3a681c72e612cfc.png)
可以通过以下配置实现:
data_sources {
config {
name: "linux.ftrace"
target_buffer: 0 # <-- This goes into buffer 0.
ftrace_config { ... }
}
}
data_sources: {
config {
name: "linux.sys_stats"
target_buffer: 1 # <-- This goes into buffer 1.
sys_stats_config { ... }
}
}
data_sources: {
config {
name: "android.heapprofd"
target_buffer: 1 # <-- This goes into buffer 1 as well.
heapprofd_config { ... }
}
}
PBTX 与二进制格式
使用 perfetto
cmdline 客户端格式时,有两种方法可以传递trace config:
文本格式
它是人工驱动的工作流程和探索的首选格式。它允许直接以 PBTX(ProtoBuf TeXtual 表示)语法传递文本文件,用于 trace_config.proto中定义的模式(请参阅参考文档)
When using this mode pass the --txt
flag to perfetto
to indicate the config should be interpreted as a PBTX file: 使用此模式时,使用 --txt
参数表示应将配置解析为 PBTX 文件:
<pre mdtype="fences" cid="n299" lang="" class="md-fences md-end-block ty-contain-cm modeLoaded" spellcheck="false" style="box-sizing: border-box; overflow: visible; font-family: Consolas, Menlo, Monaco, monospace, serif; font-size: 0.9rem; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; display: block; break-inside: avoid; text-align: left; white-space: normal; position: relative !important; margin-left: 1em; padding-left: 1em; border: 1px solid rgb(221, 221, 221); padding-bottom: 8px; padding-top: 6px; margin-bottom: 1.5em; width: inherit; background-position: inherit; background-repeat: inherit;">perfetto -c /path/to/config.pbtx --txt -o trace_file.perfetto-trace</pre>
它是机器对机器 (M2M) 交互的首选格式。它将 TraceConfig 编码为 protobuf 二进制文件。这可以将 PBTX 作为输入传递给 protobuf protoc
的编译器(可在此处下载)获得。
二进制格式
警告:不要将文本格式用于机器对机器交互基准测试、脚本和工具),因为它更容易损坏(例如,如果字段被重命名或枚举被转换为整数)
注意:该 --txt
选项仅在Android 10 (Q)中引入。旧版本仅支持二进制格式。
cd ~/code/perfetto # external/perfetto in the Android tree.protoc --encode=perfetto.protos.TraceConfig \ -I. protos/perfetto/config/perfetto_config.proto \ < config.txpb \ > config.bin
然后将其传递给 perfetto,如下所示,不带 --txt
参数:
perfetto -c config.bin -o trace_file.perfetto-trace
流式处理长时间的trace
默认情况下,Perfetto 将完整的跟踪缓冲区保留在内存中,并仅在trace结束时将其写入目标文件( -o
cmdline 参数)。这是为了减少trace系统的性能侵入性。但是,这会将trace的最大大小限制为设备的物理内存大小,这通常是有限的。 在某些情况下(例如,基准测试、难以重现的案例),希望捕获比机器物理内存大得多的trace,虽然会带来额外的 I/O 开销。
为了实现这一点,Perfetto 允许使用以下 TraceConfig 字段定期将跟踪缓冲区写入目标文件(或 stdout):
-
write_into_file (bool)`:如果为 true,则定期将trace缓冲区中的数据输入到输出文件中。启用此选项后,用户空间缓冲区需要足够大,以便在两个写入周期之间保存跟踪数据。缓冲区大小取决于设备的交互活动。典型trace的数据产生速率为 ~1-4 MB/s。因此,一个 16MB 的内存缓冲区可以保持 大约4 秒的写入周期,之后就会丢失数据。
-
file_write_period_ms (uint32)`:覆盖默认耗尽周期(5 秒)。较短的时间段需要的用户空间缓冲区会较小,但会增加跟踪的性能侵入性。如果给定的周期小于 100 毫秒,则跟踪服务将使用 100 毫秒的周期。
-
max_file_size_bytes (uint64):如果设置,则在写入 N 字节后停止trace 。用于限制跟踪的大小。
有关长跟踪模式下工作跟踪配置的完整示例,请参见
/test/configs/long_trace.cfg.
摘要:要捕获长跟踪,只需设置 ,设置 write_into_file:true
一个 long duration_ms
并使用 32MB 或更大的内存缓冲区大小。
特定数据源的配置
除了跟踪范围的配置参数外,trace config还可以定义特定于数据源的行为。在原型架构级别,这在以下 DataSourceConfig
TraceConfig
部分中定义: 来自 data_source_config.proto:
message TraceConfig {
...
repeated DataSource data_sources = 2; // See below.
}
message DataSource {
optional protos.DataSourceConfig config = 1; // See below.
...
}
message DataSourceConfig {
optional string name = 1;
...
optional FtraceConfig ftrace_config = 100 [lazy = true];
...
optional AndroidPowerConfig android_power_config = 106 [lazy = true];
}
像ftrace_config
和android_power_config这样的字段是特定数据源配置的一个示范。tracing service将完全忽略这些字段的内容,并在其他地方也使用对应名字的DataSourceConfig对象(全局生效?) 该 [lazy=true]
标记在 protozero 生成器中具有特殊的含义。与标准嵌套消息不同,
关于向后/向前兼容性的说明
tracing service会将 DataSourceConfig
消息的原始二进制 blob 路由到名字匹配的数据源,而无需尝试对其进行解码和重新编码。如果跟踪配置 DataSourceConfig
的部分包含生成服务时不存在的新字段,则服务仍将传递 DataSourceConfig
到数据源。这允许引入新的数据源,而无需服务预先了解它们的任何信息。
TODO:我们知道,今天使用自定义原型扩展需要 DataSourceConfig
更改 Perfetto 存储库 data_source_config.proto
中的 perfetto,这对于外部项目来说并不理想。长期计划是为非上游扩展保留一系列字段,并为客户端代码提供通用模板化访问器。在此之前,我们接受patches upstream,为您自己的数据源引入临时配置。
多进程数据源
某些数据源是单例的。例如,在 Perfetto 在 Android 上发布的调度程序tracing的情况下, traced_probes
整个系统只有数据源,由 traced_probes
拥有。 但是,在一般情况下,多个进程可以播发同一数据源。例如,当使用 Perfetto SDK 进行用户态检测时,就是这种情况。 如果发生这种情况,则需要开始抓取trace时,在trace config中确定具体的数据来源。默认情况下,Perfetto 将要求发送该数据源的所有进程启动。
在某些情况下,可能需要进一步将数据源的启用限制为特定进程(或一组进程)。这可以通过 producer_name_filter
和 producer_name_regex_filter
.
设置这些筛选器后,Perfetto tracing service将仅在与筛选器匹配的创建者子集中激活数据源。
示范如下:
buffers {
size_kb: 4096
}
data_sources {
config {
name: "track_event"
}
# Enable the data source only on Chrome and Chrome canary.
producer_name_filter: "com.android.chrome"
producer_name_filter: "com.google.chrome.canary"
}
触发器
在大多数条件下,跟踪会话的生命周期仅与 perfetto
cmdline 客户端的调用命令匹配:跟踪数据记录在 TraceConfig 传递到 perfetto
时开始,并在已过 TraceConfig.duration_ms
时或 cmdline 客户端终止时结束。
Perfetto 支持基于触发器的启动或停止跟踪的模式。总体思路是在跟踪配置本身中声明:
-
一组触发器,它们只是格式自由的字符串。
-
给定触发器是否应导致跟踪启动或停止,以及启动/停止延迟。
为什么要使用触发器?为什么不能在需要时启动 perfetto 或杀死 (SIGTERM) 它?所有这一切的基本原理是安全模型:在大多数 Perfetto 部署环境中(例如,在 Android 上),只有特权实体(例如 adb shell)可以配置/启动/停止跟踪。从这个意义上说,应用是无特权的,它们无法控制tracing。 触发器为非特权应用提供了一种以有限方式控制跟踪tracing生命周期的方法。概念模型为:
-
特权消费者(请参阅服务模型),即通常被授权开始跟踪的实体(例如,Android 中的 adb shell),预先声明跟踪的可能触发器名称以及它们将执行的操作。
-
非特权实体(任何随机应用进程)都可以激活这些触发器。非特权实体对触发器将做什么没有控制权,它们只传达事件发生了。
可以通过 cmdline util 发出触发器信号
/system/bin/trigger_perfetto "trigger_name"
(或者也可以仅通过配置中的 activate_triggers: "trigger_name"
字段来启动独立trace抓取过程)
有两种类型的触发器:
启动触发器
启动触发器可以仅在发生某些重大事件后激活tracing。传递具有 START_TRACING
触发器的跟踪配置会导致跟踪会话保持空闲状态(即不记录任何数据),直到触发器被触发或超过 trigger_timeout_ms
时被触发。
trace_duration_ms
和有触发器的跟踪不能同时使用。
配置示例:
# If the "myapp_is_slow" is hit, the trace starts recording data and will be
# stopped after 5s.
trigger_config {
trigger_mode: START_TRACING
triggers {
name: "myapp_is_slow"
stop_delay_ms: 5000
}
# If no trigger is hit, the trace will end without having recorded any data
# after 30s.
trigger_timeout_ms: 30000
}
# The rest of the config is as usual.
buffers { ... }
data_sources { ... }
停止触发器
STOP_TRACING触发器允许在触发器触发时提前完成跟踪。在此模式下,调用 perfetto
客户端时,跟踪将立即启动(如在一般情况)。触发器发出提前结束信号。
这可用于在飞行记录器模式下使用 perfetto。通过配置RING_BUFFER
和 STOP_TRACING
触发器中的缓冲区启动跟踪,跟踪将不断循环记录 ,知道检测到罪魁祸首事件时完成。对于根本原因在最近的事件(例如,应用检测到缓慢滚动或缺少帧)而言,这很关键。
配置示例:
# If no trigger is hit, the trace will end after 30s.
trigger_timeout_ms: 30000
# If the "missed_frame" is hit, the trace is stopped after 1s.
trigger_config {
trigger_mode: STOP_TRACING
triggers {
name: "missed_frame"
stop_delay_ms: 1000
}
}
# The rest of the config is as usual.
buffers { ... }
data_sources { ... }
在 Android 上,有一些关于使用 adb shell
的提示
- Ctrl+C 通常会导致跟踪正常终止,在使用
adb shell perfetto
时并不支持,而仅在通过adb shell
使用基于 PTY 的交互式会话时支持。 - 在 Android 12 之前的非 root 设备上,由于 SELinux 规则限制性过强,配置只能作为
cat config | adb shell perfetto -c -
(-: stdin) 传递。在 Android 12及之后的版本上,/data/misc/perfetto-configs
可用于存储配置。 - O在 Android 10 之前的设备上,adb 无法直接拉取
/data/misc/perfetto-traces
.使用adb shell cat /data/misc/perfetto-traces/trace > trace
解决这个限制。
在 Android 10 之前的设备上,adb 无法直接拉取/data/misc/perfetto-traces
.用于adb shell cat /data/misc/perfetto-traces/trace > trace
解决方法。 - 捕获较长的跟踪时,例如在基准测试或 CI 的中,使用
PID=$(perfetto --background)
然后kill $PID
停止。
其他资源
- Reference TraceConfig
- [Buffers and dataflow](
#####################以上分割线#####################
后记:
1 本次主要使用百度翻译,虽然被骂,但至少翻译这个工具降低了门槛。
2 英文文档中的长难句真的是又长又难,基于百度的翻译,然后自己再调整下,水平实在有限。
3 技术背景知识不够,有些专有名词不知道怎么翻译,也不知道百度翻译的是否准确,功夫在诗外。
4 万事开头难,中间难不难,还不知道。中间的事后面再说,正确一天翻译一篇。
5 虽然可能会有人不屑,但总要有人去做不起眼的小事。
6 google 厉害,这个perfetto 工具也很厉害。君子善假于物也。
7 工具的使用是最简单的入门,背后还有更多的东西值得学习。
8 水平实在有限,闻过则喜,希望有更多的人反馈,期待更好的建议