性能工具

Traceview / Systrace 的基础操作


Traceview

https://developer.android.google.cn/studio/profile/generate-trace-logs?hl=zh-cn#java

1
2
3
Debug.startMethodTracing("sample");
……
Debug.stopMethodTracing();

Device File Explorer中可以找到trace文件,直接打开,可以看到火焰图

Traceview 已弃用。如果您使用的是 Android Studio 3.2 或更高版本,应改为使用 CPU 性能分析器来执行

  1. 事件时间轴
    显示应用中的 activity 在其生命周期内不断转换经历各种不同状态的过程,并指示用户与设备的交互,包括屏幕旋转事件。
  2. CPU 时间轴
    显示应用的实时 CPU 使用率(以占总可用 CPU 时间的百分比表示)以及应用当前使用的线程总数。此时间轴还会显示其他进程(如系统进程或其他应用)的 CPU 使用率,以便您可以将其与您应用的 CPU 使用率进行对比。您可以通过沿时间轴的横轴方向移动鼠标来检查历史 CPU 使用率数据。
  3. 线程活动时间轴
    列出属于应用进程的每个线程,并使用下面列出的颜色在时间轴上指示它们的活动。记录轨迹后,您可以从此时间轴上选择一个线程,以在轨迹窗格中检查其数据。
  • 绿色:表示线程处于活动状态或准备使用 CPU。也就是说,线程处于正在运行或可运行状态。
  • 黄色:表示线程处于活动状态,但它正在等待一项 I/O 操作(如磁盘或网络 I/O),然后才能完成它的工作。
  • 灰色:表示线程正在休眠且没有消耗任何 CPU 时间。 当线程需要访问尚不可用的资源时,就会出现这种情况。在这种情况下,要么线程主动进入休眠状态,要么内核将线程置于休眠状态,直到所需的资源可用。

TraceView试图收集某个阶段所有函数的运行信息,开销过大

Systrace的思路是反过来的,在不清楚问题的情况下,通过假设-分析-验证 的过程找出问题


Systrace

https://zhuanlan.zhihu.com/p/27331842

  1. 进入systrace目录:
    cd /Users/stew/Library/Android/sdk/platform-tools/systrace
  2. 执行命令:
    ./systrace.py -t 10 sched gfx view wm am app webview -a
  3. 生成trace.html目录:
    /Users/stew/Library/Android/sdk/platform-tools/systrace
  4. 在chrome中查看trace.html
    chrome://tracing/trace.html
  5. 操作:
    W : 放大 Systrace , 放大可以更好地看清局部细节
    S : 缩小 Systrace, 缩小以查看整体
    A : 左移
    D : 右移
    M : 高亮选中当前鼠标点击的段

Systrace 是对 Linux Kernel中 ftrace 的封装

内核部分:Systrace 利用了 Linux Kernel 中的 ftrace 功能

数据采集部分:Android 定义了一个 Trace 类。应用程序可利用该类把统计信息输出给ftrace。同时,Android 还有一个 atrace 程序,它可以从 ftrace 中读取统计信息然后交给数据分析工具来处理

数据分析工具:Android 提供一个 systrace.py

线程状态主要有下面几个

  • 绿色 : 运行中(Running)
    只有在该状态的线程才可能在 cpu 上运行
  • 蓝色 : 可运行(Runnable)
    线程可以运行但当前没有安排,在等待 cpu 调度
    作用:Runnable 状态的线程状态持续时间越长,则表示 cpu 的调度越忙,没有及时处理到这个任务
  • 白色 : 休眠中(Sleep)
    线程没有工作要做,可能是因为线程在互斥锁上被阻塞。
    作用 : 这里一般是在等事件驱动
  • 橘色 : 不可中断的睡眠态 (Uninterruptible Sleep - IO Block)
    线程在I / O上被阻塞或等待磁盘操作完成
  • 紫色 : 不可中断的睡眠态(Uninterruptible Sleep)
    一般是陷入了内核态,有些情况下是正常的,有些情况下是不正常的,需要按照具体的情况去分析

应用的启动动画由 Launcher 和应用自己的第一帧组成,点击图标启动应用的时候,由于 App 还在启动,Launcher 首先启动一个 StartingWindow,等 App 的第一帧绘制好了之后,再切换到 App 的窗口动画

与 AMS 相关的 Trace 一般会用 TRACE_TAG_ACTIVITY_MANAGER 这个 TAG,在 Systrace 中的名字是 ActivityManager

与 WMS 相关的 Trace 一般会用 TRACE_TAG_WINDOW_MANAGER 这个 TAG,在 Systrace 中 WindowManagerService 在 SystemServer 中多在对应的 Binder 中出现,在 Window 的各种场景一般都会有对应的 Trace 点来记录,比如大家熟悉的 relayoutWIndow、performLayout、prepareToDisplay 等

Input 是 SystemServer 线程里面非常重要的一部分,主要是由 InputReader 和 InputDispatcher 这两个 Native 线程组成

android.bg,BackgroundThread 在系统中使用比较多,许多对性能没有要求的任务,一般都会放到 BackgroundThread 中去执行

App 部分 -> BufferQueue 部分 -> SurfaceFlinger 部分 -> HWComposer 部分

  1. App 部分
    1)Vsync 信号的接收和处理
    2)RenderThread 的 dequeueBuffer
    dequeue 有出队的意思,dequeueBuffer 顾名思义,就是从队列中拿出一个 Buffer,这个队列就是 SurfaceFlinger 中的 BufferQueue。
    3)RenderThread 的 queueBuffer
    queue 有入队的意思,queueBuffer 顾名思义就是讲 Buffer 放回到 BufferQueue,App 处理完 Buffer 后(写入具体的 drawcall),会把这个 Buffer 通过 eglSwapBuffersWithDamageKHR -> queueBuffer 这个流程,将 Buffer 放回 BufferQueue

  2. BufferQueue 部分
    dequeue、queue、acquire、release

  3. SurfaceFlinger 部分
    收到 Vsync 信号后开始工作,MessageQueue::INVALIDATE主要是执行 handleMessageTransaction 和 handleMessageInvalidate 这两个方法,MessageQueue::REFRESH — 主要是执行 handleMessageRefresh 方法

  4. HWComposer 部分
    1)SurfaceFlinger 向 HWC 提供一个完整的层列表,并询问“您希望如何处理这些层?”
    2)HWC 的响应方式是将每个层标记为叠加层或 GLES 合成。
    3)SurfaceFlinger 会处理所有 GLES 合成,将输出缓冲区传送到 HWC,并让 HWC 处理其余部分。

Input
InputReader 和 InputDispatcher 是跑在 SystemServer 里面的两个 Native 线程,负责读取和分发 Input 事件

Vsync
Vsync Offset 我们指的是 VSYNC_APP 和 VSYNC_SF 之间有一个 Offset,即上图中 phase-sf - phase-app 的值,这个 Offset 是厂商可以配置的。如果 Offset 不为 0,那么意味着 App 和 SurfaceFlinger 主进程不是同时收到 Vsync 信号,而是间隔 Offset (通常在 0 - 16.6ms 之间)
目前大部分厂商都没有配置这个 Offset,所以 App 和 SurfaceFlinger 是同时收到 Vsync 信号的.

android studio terminal中执行:adb shell dumpsys SurfaceFlinger
结果截取:可见offset=0
app phase: 1000000 ns SF phase: 1000000 ns
early app phase: 1000000 ns early SF phase: 1000000 ns
GL early app phase: 1000000 ns GL early SF phase: 1000000 ns
next VSYNC threshold: 9223372036854775807 ns
present offset: 0 ns VSYNC period: 16666666 ns

不是每次申请 Vsync 都会由硬件产生 Vsync,只有此次请求 vsync 的时间距离上次合成时间大于 500ms,才会通知 hwc,请求 HW_VSYNC

HW_VSYNC 主要是利用最近的硬件 VSYNC 来做预测,最少要 3 个,最多是 32 个,实际上要用几个则不一定, DispSync 拿到 6 个 VSYNC 后就会计算出 SW_VSYNC,只要收到的 Present Fence 没有超过误差,硬件 VSYNC 就会关掉,不然会继续接收硬件 VSYNC 计算 SW_VSYNC 的值,直到误差小于 threshold.