引言
在分析perfetto文件的时候,最直观的方式就是采用网页可视化分析:
将trace文件加载进来即可按照timeline进行分析:
实际上通过perfetto ui或者perfetto提供的trace_processor工具可以让我们来按照sql的形式来操作处理trace,通过下面的链接可以下载对应平台上的trace_processor文件:
下面基于perfetto ui来进行sql查询演示,实际上为了方便更多时候是在本地利用trace_processor搭配python来实现对trace文件实现自动化分析。
简介
slice表结构
首先我们需要明确perfetto trace文件里面都有哪些表以及基础表字段是什么,使用下面的sql语句进行查询:
SELECT * FROM pragma_table_info('slice');
这里slice是trace中最核心的表,其存储用户态事件比如代码打点、方法调用等,在trace中看到的所有信息都是基于slice打印的
所有表信息
使用下面的sql语句可以查看到所有的表信息:
SELECT name FROM sqlite_master WHERE type IN ('table', 'view') ORDER BY name;
同时在perfetto ui中也支持直接查看:
核心表
- slice: 基础信息
- thread_track: slice线程信息
- thread: 线程信息
- process: 进程信息
注: slice-thread_track使用track_id来join; thread_track-thread使用utid来join; thread-process使用upid来join;
- args: slice参数
- thread_state: 线程调度信息
- sched_slice: 调度运行片
- cpu: cpu信息
使用操作
sql查询思路
一般写trace sql会按照下面的思路来:
- 先宽后窄
首先使用like搜索名字,确认切片叫什么,然后再缩小事件窗,加入depth、线程名等。
- 先确定两端时间(start ts和end ts)再下钻
这个就需要了解关联调用链,比如说binder的transaction和replay。
- 过滤时长
将无用的时间端过滤掉,缩小范围。
- limit收窄slice信息
防止打印过多信息
实例
下面举几个例子:
- 查询高德地图最耗时的10个slice
SELECT
s.name AS slice_name,
t.name AS thread_name,
s.dur / 1e6 AS dur_ms
FROM slice s
JOIN thread_track tt ON s.track_id = tt.id
JOIN thread t ON tt.utid = t.utid
JOIN process p ON t.upid = p.upid
WHERE p.name = 'com.autonavi.minimap'
ORDER BY s.dur DESC
LIMIT 10;
- 查询各个线程在不同cpu上执行时间
SELECT
process.name AS process_name,
thread.name AS thread_name,
cpu,
sum(dur) AS cpu_dur
FROM sched
JOIN thread USING (utid)
JOIN process USING (upid)
GROUP BY
process_name,
thread_name,
cpu
ORDER BY
cpu_dur DESC
LIMIT 100;
- system_server线程运行时长拆解
SELECT
t.name AS thread_name,
s.cpu,
SUM(s.dur) / 1e6 AS cpu_dur_ms
FROM sched s
JOIN thread t USING (utid)
JOIN process p USING (upid)
WHERE p.name = 'system_server'
GROUP BY t.name, s.cpu
ORDER BY t.name, cpu_dur_ms DESC;