Jacky's blog
首页
  • 学习笔记

    • web
    • android
    • iOS
    • vue
  • 分类
  • 标签
  • 归档
收藏
  • tool
  • algo
  • python
  • java
  • server
  • growth
  • frida
  • blog
  • SP
  • more
GitHub (opens new window)

Jack Yang

编程; 随笔
首页
  • 学习笔记

    • web
    • android
    • iOS
    • vue
  • 分类
  • 标签
  • 归档
收藏
  • tool
  • algo
  • python
  • java
  • server
  • growth
  • frida
  • blog
  • SP
  • more
GitHub (opens new window)
  • tutorial
  • jetpack

  • components

  • androidx

  • 动态化
  • apm

    • apm相关概念
    • Android稳定性治理
    • Android低端机性能优化
    • monkey测试
    • bitmap
    • 大对象监控
    • android内存
    • 移动端的网络优化
    • 记一次anr问题查询ThreadedRenderer
    • 记一次shrink代码减包调研方案
    • proguard
    • R8
    • perfetto
      • custom-events
      • trace config
        • gfx
      • analysis
        • sql
      • issue
        • perfetto 查询
        • 查询 slice 名字中包含固定字符串
      • link
    • mat
  • module

  • harmony

  • tool

  • other

  • kotlin

  • 《android》
  • apm
Jacky
2023-08-01
目录

perfetto

perfetto (opens new window) is a tool that lets you collect performance information from Android devices via the Android Debug Bridge (ADB). Invoke the perfetto tool using the adb shell perfetto ... command. perfetto uses various sources to collect performance traces from your device, such as:

  • ftrace for information from the kernel
  • atrace for user-space annotation in services and apps
  • heapprofd for native memory usage information of services and apps

作为客户端开发工程师, 更多的会注重在 Android 或者 iOS 客户端的优化, 下面以 Android 为主要场景, 进行说明

# custom-events

  1. perfetto 跟参考 custom-event systrace 同样也支持自定义事件。 可以 s (opens new window)
  2. 使用 perfetto 分析自定义事件时, 你可能需要配置 atrace, 相关的内容可见: ATrace: Android system and app trace events (opens new window)

# trace config

  • 这里给出配置的 demo 定义, 将如下内容保存到文件中, 比如 config.pbtx 然后运行脚本 ./record_android_trace -o <output>.perfetto-trace -c config.pbtx.
    • script online link (opens new window)
  • 此例子参考 Quickstart: Record traces on Android (opens new window)
duration_ms: 10000

buffers {
  size_kb: 65536
  fill_policy: RING_BUFFER
}

data_sources: {
    config {
        name: "linux.ftrace"
        ftrace_config {
            ftrace_events: "sched/sched_switch"
            ftrace_events: "power/suspend_resume"
            ftrace_events: "sched/sched_process_exit"
            ftrace_events: "sched/sched_process_free"
            ftrace_events: "task/task_newtask"
            ftrace_events: "task/task_rename"
            ftrace_events: "ftrace/print"
            atrace_categories: "sched"
            atrace_categories: "freq"
            atrace_categories: "idle"
            atrace_categories: "am"
            atrace_categories: "wm"
            atrace_categories: "gfx"
            atrace_categories: "view"
            atrace_categories: "binder_driver"
            atrace_categories: "hal"
            atrace_categories: "dalvik"
            atrace_categories: "webview"
            atrace_categories: "camera"
            atrace_categories: "power"
            atrace_categories: "res"
            atrace_categories: "memory"
        }
    }
}
data_sources: {
    config {
        name: "linux.process_stats"
        target_buffer: 1
        process_stats_config {
            scan_all_processes_on_start: true
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

# gfx

atrace_categories: "gfx" 是 Perfetto 中的配置选项, 用于指定要跟踪的 Android 图形渲染相关事件的类别

在 Android 中, gfx 代表图形渲染子系统, 它负责处理应用程序的图形渲染和显示。通过启用 atrace_categories: "gfx", Perfetto 将记录与图形渲染相关的事件, 如 GPU 绘制、SurfaceFlinger 操作、GPU 状态变化等

这样的跟踪对于性能分析和图形渲染优化非常有用, 可以帮助开发人员了解图形渲染的性能瓶颈, 以及查找和解决与图形渲染相关的问题

请注意, gfx 是 Perfetto 中预定义的标签, 表示图形渲染子系统的跟踪事件。除了 gfx, 还有其他可用的预定义标签, 用于指定不同的跟踪事件类别。你可以根据需要在配置文件中添加其他标签, 以启用不同类型的跟踪数据收集

# analysis

建议查看官网 Trace analysis (opens new window) 一节

# sql

sql table (opens new window)

示例
  1. to get a list of all the threads which emitted a measure slice.

see: https://perfetto.dev/docs/analysis/trace-processor#thread-and-process-tables (opens new window)

SELECT thread.name AS thread_name
FROM slice
JOIN thread_track ON slice.track_id = thread_track.id
JOIN thread USING(utid)
WHERE slice.name = 'measure'
GROUP BY thread_name
1
2
3
4
5
6

查询逻辑解释如下:

  • FROM slice: 从 slice 表中选择数据作为查询的主要来源
  • JOIN thread_track ON slice.track_id = thread_track.id: 通过 JOIN 操作将 slice 表与 thread_track 表关联, 以获取关于线程轨迹(track_id)的信息
  • JOIN thread USING(utid): 通过 JOIN 操作将 thread 表与 thread_track 表关联, 以获取关于线程(thread.name)的信息。这里使用 USING(utid) 来指定连接的列为 utid, 表示 thread_track 表和 thread 表通过 utid 字段进行连接
  • WHERE slice.name = 'measure': 筛选 slice.name 为 'measure' 的记录, 即找到符合条件的事件
  • GROUP BY thread_name: 按照 thread_name 字段(即线程名)对结果进行分组, 以汇总每个线程中包含名为 'measure' 的事件

最终查询的结果将返回符合条件的 slice.name 为 'measure' 的事件, 并按照线程名进行分组


  1. 查询 slice name 以 jack) 开头且限定查询到的 main thread 下面的 slice rows, 并按照 slice.desc 降序排序
SELECT *
FROM slice
JOIN thread_track ON slice.track_id = thread_track.id
JOIN thread USING(utid)
WHERE slice.name LIKE 'jack)%'
AND thread.name = '<主线程名称>'
ORDER BY slice.dur DESC;
1
2
3
4
5
6
7

查询到的结果如下:

# issue

一、在 thread_track 我们查出来有一列为 utid, 上面的 26460 看起来跟 utid 又不是一个意思.如下图所示

  • TID(Thread ID): TID 是操作系统中用来唯一标识线程的数字标识符。每个线程都有一个唯一的 TID。在 Perfetto UI 的时间轴上, 你会看到类似 "xxx 26460" 这样的标签, 其中 "26460" 就是这个事件所属的线程 ID(TID)
  • utid(Unified Thread ID: utid 是 Perfetto 中使用的线程标识符, 它是在跨平台、跨内核和跨进程的场景下使用的。在某些情况下, Perfetto 可能会使用 utid 代替 TID 来唯一标识线程。utid 可以确保在线程切换和跨进程传递时保持唯一。通常, utid 会在跟踪开始时被分配, 并与 TID 相关联

因此, 虽然 "xxx 26460" 这样的标签中的 "26460" 确实代表线程 ID(TID), 但在 Perfetto 中, utid 和 TID 之间有着关联。Perfetto 使用 utid 来确保在线程切换和跨进程传递时, 正确地标识和追踪线程。在 Perfetto UI 中, 你可以根据线程的 utid 或线程 ID 来筛选和查看特定线程的事件

二、DisplayHAL jank

DisplayHAL jank refers to the case where SurfaceFlinger finished its work and sent the frame down to the HAL on time, but the frame wasn’t presented on the vsync. It was presented on the next vsync. It could be that SurfaceFlinger did not give enough time for the HAL’s work or it could be that there was a genuine delay in the HAL’s work.
1

"DisplayHAL jank" 是指 SurfaceFlinger 在规定时间内完成工作并将帧传递给硬件抽象层(DisplayHAL), 但该帧没有在垂直同步期间(vsync)被显示。而是在下一个 vsync 时刻才被显示。这可能是因为 SurfaceFlinger 没有给予 DisplayHAL 充足的时间来完成其工作, 或者可能是 DisplayHAL 的工作出现了真正的延迟

解释如下:

  1. SurfaceFlinger 是 Android 系统中负责组合和渲染所有应用程序窗口的组件。当 SurfaceFlinger 完成渲染并将帧发送给 DisplayHAL 时, 它需要根据设备的垂直同步信号来准确地显示帧
  2. 垂直同步(vsync)是一个硬件信号, 指示显示器在下一个刷新周期开始时显示帧。设备通常以固定的帧速率刷新显示, 比如 60 Hz。当帧被错过, 会导致显示延迟, 即 "DisplayHAL jank"
  3. "DisplayHAL jank" 可能是由于 SurfaceFlinger 没有给予 DisplayHAL 充足的时间来完成帧的显示准备。这可能导致帧错过当前的 vsync 时刻, 被推迟到下一个 vsync 时刻
  4. 另一种可能是由于 DisplayHAL 本身的处理过程出现了延迟, 导致帧无法及时被显示

为了解决 "DisplayHAL jank", 需要进一步分析和优化 SurfaceFlinger 和 DisplayHAL 之间的交互和工作流程。通过减少处理时间、优化资源利用和避免冲突, 可以降低 "DisplayHAL jank" 的发生频率, 从而提高 Android 设备的流畅性和显示性能

# perfetto 查询

SELECT track.type
FROM slice
JOIN track ON track.id = slice.track_id
WHERE slice.name = 'measure'
1
2
3
4

这个 SQL 查询语句用于从 Perfetto 数据库中获取与名称为 'measure' 的切片(slice)关联的跟踪(track)的类型(type)

解析查询语句:

  • SELECT track.type: 这是查询的目标, 表示要从结果中选择跟踪的类型字段
  • FROM slice: 这是查询的主要数据表, 表示要从 "slice" 表中检索数据
  • JOIN track ON track.id = slice.track_id: 这是一个 JOIN 操作, 它将 "slice" 表与 "track" 表进行关联。它将使用 "track" 表中的 "id" 字段与 "slice" 表中的 "track_id" 字段进行匹配, 从而获取与切片相关联的跟踪信息
  • WHERE slice.name = 'measure': 这是一个过滤条件, 表示只选择 "slice" 表中 "name" 字段值为 'measure' 的记录。这将限制查询结果仅包含名称为 'measure' 的切片

因此, 该 SQL 查询的结果将返回与名称为 'measure' 的切片关联的跟踪的类型(type)。你将获得与 'measure' 切片相关联的跟踪类型的信息, 这对于了解跟踪数据中不同类型的跟踪信息非常有帮助

# 查询 slice 名字中包含固定字符串

SELECT * FROM slice JOIN thread_track ON thread_track.id = slice.track_id WHERE slice.name LIKE 'jack)%'
1

# link

  • android 官网给出的 perfetto command line 介绍 (opens new window)
  • Perfetto (opens new window)
    • Reference-Trace Config proto (opens new window)
  • perfetto-ui (opens new window)
  • android system trace 概览 (opens new window)
  • Perfetto 分析进阶-CSDN (opens new window)
#perfetto#sql
上次更新: 2025/10/09, 23:53:03
R8
mat

← R8 mat→

最近更新
01
npx 使用指南
10-12
02
cursor
09-28
03
inspect
07-20
更多文章>
Theme by Vdoing | Copyright © 2019-2025 Jacky | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式