perfetto高阶使用:新增数据源

3,231 阅读6分钟

目录:

image.png

本篇文章通过介绍 linux.sys_stats 数据源,来看perfetto怎么添加数据源。

这应该是唯一写这方面东西的文章,当时为了搞这个功能100多个英文文档全浏览了一遍,可惜官网文档没写,接着又撸源码,搞了一周多。

前言

新增 perfetto 数据源

  • 新增 ftrace 事件看这里的文档 perfetto.dev/docs/contri…

  • 新增 atrace 看atrace相关代码即可,很多人都知道,也有很多文档介绍。

  • 对 /proc 和 /sys 等这种perfetto相对ftrace、atrace特有的数据源该怎么添加??

perfetto 对于 进程状态,内存状态,GPU\CDSP\ddr\ufs频点信息 这些数据,是通过 traced_probes 轮询 /proc 和 /sys 等内核接口轮询得到的。

通过分析 inux.sys_stats 这个数据源,可以看到 perfetto 怎么新增数据源的。

一个 linux.sys_stats 数据源的配置示例:

buffers: {
    size_kb: 63488
    fill_policy: DISCARD
}
data_sources: {
    config {
        name: "linux.sys_stats"
        sys_stats_config {
            devfreq_period_ms: 1000
        }
    }
}

duration_ms: 15000
devfreq_period_ms

看下文档 perfetto.dev/docs/refere… 说明

FieldTypeDescription
devfreq_period_msuint32Polls /sys/devfreq/*/curfreq every X ms, if non-zero. This is required to be > 10ms to avoid excessive CPU usage. This option can be used to record unchanging values. Updates from frequency changes can come from ftrace/set_clock_rate.

devfreq_period_ms 配置大于0的值后,轮询 /sys/class/devfreq/*/cur_freq 的值,并记录在 trace buffer 中

/sys/class/devfreq/*/cur_freq 的内容是什么?

是各种器件的频率,CPU0~CPU7的频率,ufs,ddr,GPU等等。

也就是说对于上面例子中的数据源配置 devfreq_period_ms,表示持续跟踪 设备中CPU0~CPU7的频率,ufs,ddr,GPU等的频率。

那么我们现在要新增一个数据,比如GPU的使用百分比,perfetto的代码中改怎么修改?

这个过程远没有想的那么简单。

已知 /sys/class/xxxx/xxxx/gpu_busy_percentage 节点表示GPU的百分比,下面手把手的讲述怎么让 perfetto 持续跟踪这个节点的数据,并在UI界面上显示出来。

正文

一、定义新的配置属性 gpu_period_ms:

新增配置属性 gpu_period_ms,配置写法如下:
cat <<EOF >  /data/misc/perfetto-configs/sys_stats && perfetto  --txt  -o /data/misc/perfetto-traces/trace  -c /data/misc/perfetto-configs/sys_stats

buffers: {
    size_kb: 63488
    fill_policy: DISCARD
}
data_sources: {
    config {
        name: "linux.sys_stats"
        sys_stats_config {
            devfreq_period_ms: 1000  // 这个 devfreq_period_ms 也带上,作为对比
            gpu_period_ms: 1000// 这个gpu_period_ms用于表示跟踪 /sys/class/xxxx/xxxx/gpu_busy_percentage 的数据
        }
    }
}

duration_ms: 15000

二、对于代码的修改围绕以下四个问题

1. 定义要抓什么数据
2. 定义数据要怎么记录存储
3. 数据怎么抓
4. 数据怎么解析
一、通过.proto文件,定义”抓什么数据“以及”数据怎么记录存储“
  • /external/perfetto/protos/perfetto/config 目录定义了抓什么数据
  • /external/perfetto/protos/perfetto/trace 目录定义了数据怎么记录存储

1、修改 /external/perfetto/protos/perfetto/config/sys_stats/sys_stats_config.proto

  • 新增配置项 gpu_period_ms
  • 这个配置文件用于 /system/bin/traced_probes
  • traced_probes 根据是否有传入的这个参数确定是否轮询 /sys/class/kgsl/kgsl-3d0/gpu_busy_percentage 节点,并记录进trace文件
  • 这部分代码”定义了抓什么数据“修改代码如下:

定义了抓什么数据.png

  • 这部分修改将编译到so库: system/lib64/libperfetto.so

2、修改 /external/perfetto/protos/perfetto/trace/sys_stats/sys_stats.proto

  • 这部分代码用于”定义数据怎么记录存储“,用于 protobuf 序列化数据为 .proto 2进制数据。

  • 新增trace数据对象,修改代码如下:

定义数据怎么记录存储.png

  • 编译到so库: system/lib64/libperfetto.so

3、执行命令:tools/gen_merged_protos

  • 这个命令会把所有的 配置文件 和 所有的 trace数据对象 文件分别合并到两个文件中:

    • protos/perfetto/config/perfetto_config.proto
    • protos/perfetto/trace/perfetto_trace.proto
    • 命令执行完后,对 sys_stats_config.proto、sys_stats.proto 的修改会merge到这两个文件中。
    • 这两个文件用于 用于 /system/bin/perfetto 的 --txt 参数。
    • 没有这个修改,perfetto 不识别新增的配置。
二、修改怎么抓trace的代码

配置文件告诉了要抓什么数据,以及数据改怎么记录

至于怎么抓trace。需要写代码去实现

  • 代码实现 src/traced/probes/sys_stats/sys_stats_data_source.cc

怎么抓trace.png

  • 代码编译到so库: system/lib64/libperfetto.so

写代码的话,需要了解 protobuf 原理。重点要了解 .proto 文件编译生成什么样的源码

protobuf 原理非常简单的简述:

  • 把 .proto 文件编译为java、c++、go、python等目标语言
  • 这个编译过程类似JavaBean,Android 的序列化对象 Parcelable。会生成getter、setter等等方法
三、修改怎么解析trace的代码

trace抓到了,但是数据怎么解析,也需要我们自己写代码处理

  • 数据解析代码在 src/trace_processor 目录下
  • 数据解析的理论知识参见:perfetto.dev/docs/analys…
    • 解析器会编译成各种各样的格式
    • 解析trace数据,形成数据库,并暴露SQL查询接口
    • 解释消息事件,根据数据生成用户友好的描述信息
    • chrome 使用 trace_processor 作为WebAssembly 的模块,从编译过程看应该叫 trace_processor_wasm
    • 对于 SysStats 数据,trace_processor 会根据原始的trace数据生成 Events、Counters、Tracks 等等信息
      • 浏览器根据这些信息生成UI界面

1、修改 src/trace_processor/importers/proto/system_probes_parser.cc

system_probes_parser.png

2、编译 浏览器UI界面

附:

编译

  • 编译 浏览器UI

    • 新增的配置,使用ui.perfetto.dev/ 无法解析。需要编译自己的 浏览器UI
  • 编译 libperfetto.so

    • sys_stats 数据源处理代码sys_stats/sys_stats_data_source.cc会编译到 libperfetto.so
    • sys_stats_config.proto 和 sys_stats.proto 生成的c++代码会被 sys_stats/sys_stats_data_source.cc调用
      • 因此对这两个 proto 文件的修改也需要重新编译 libperfetto.so
  • 编译 perfetto 命令行客户端

    • 对 sys_stats_config.proto 和 sys_stats.proto 两个配置文件修改需要编译命令行客户端工具 perfetto
      • 主要用于解析 --txt 参数的配置文件
        • /external/perfetto/protos/perfetto/config/perfetto_config.proto
        • /external/perfetto/protos/perfetto/trace/perfetto_trace.proto
## 编译命令
prebuilts/build-tools/linux-x86/bin/ninja -j32 -f out/combined-xxxx.ninja libperfetto.so perfetto -j32 


## 不用编译 traced 和 traced_probes
## sys_stats 的数据源在 traced_probes 进程中
## 但是相关源码编译到了共享库 libperfetto.so 中,bin程序文件使用 libperfetto.so。因此编译 libperfetto.so 即可
## 需要push到 system/lib64/libperfetto.so , 不用push到system/lib, 这个目录下没有

后记综述

  • perfetto 从配置文件上看,各个模块是高度耦合的。是个非常劣势的特点

  • 配置文件的修改后,需要同步更新 命令行客户端,UI浏览器工具,抓trace的进程都需要更新相应的程序文件。

    对于 linux.sys_stats 的数据源,需要更新以下程序文件:

    • 手机上system/lib64/libperfetto.so。/system/bin/traced_probes 会用到,用于抓 Ftrace, /proc, /sys 等数据
    • 手机上bin文件 perfetto(命令行客户端)
    • 桌面端浏览器UI:UI服务器程序
    • 其他不重要的程序:trigger_perfetto、trace_processor_shell 等等
  • 这个可以理解的。因为使用的 protobuf,这个的目标就是高性能,低存储。主要是极低的存储。

    • protobuf 可以看作极致压缩的json。
      • 把每种字段,变量,信息,消息等等,都使用一个数值映射,这种替代,对内存和存储进行了极致的压缩。
    • 解析端,依赖 配置文件正确的解析数据
    • perfetto 需要对传入的纯文本配置文件,转为 protobuf 二进制数据
    • 真正干活的 traced_probes 进程依赖配置文件做具体的操作
    • 这个就导致,配置文件变更,各方面的程序都要更新
  • 综上,新增一个配置项,是个复杂的工程!!!