启动
-Systrace
Systrace 是 Android4.1 中新增的性能数据采样和分析工具。它可帮助开发者收集 Android 关键子系统(如 SurfaceFlinger/SystemServer/Kernel/Input/Display 等 Framework 部分关键模块、服务,View系统等)的运行信息,从而帮助开发者更直观的分析系统瓶颈,改进性能
Systrace的功能包括跟踪系统的I/O操作、内核工作队列、CPU负载以及Android各个子系统的运行状况(如surfaceflinger、WindowManagerService等Framework部分关键模块、服务)等,。
在Android平台中,它主要由3部分组成:
- 内核部分:Systrace利用了Linux Kernel中的ftrace功能。必须开启kernel中和ftrace相关的模块。
- 数据采集部分:Android定义了一个Trace类。应用程序可利用该类把统计信息输出给ftrace。同时,Android还有一个atrace程序,它可以从ftrace中读取统计信息然后交给数据分析工具来处理。
- 数据分析工具:Android 提供一个 systrace.py( python 脚本文件,位于 Android SDK目录/platform-tools/systrace 中,其内部将调用 atrace 程序)用来配置数据采集的方式(如采集数据的标签、输出文件名等)和收集 ftrace 统计数据并生成一个结果网页文件供用户查看。 从本质上说,Systrace 是对 Linux Kernel中 ftrace 的封装。应用进程需要利用 Android 提供的 Trace 类来使用 Systrace.。
关于 Systrace 的官方介绍和使用可以看这里
了解 Systrace
Systrace 概览
添加代码的跟踪方式native和java
native层用法
头文件:<utils/Trace.h>
定义ATRACE_TAG:如使用了ATRACE_TAG_GRAPHICS,表示它和Graphics相关。
ATRACE_INIT:用于统计某个变量使用的情况。ATRACE_INIT(“变量TAG”, 变量名)
ATRACE_CALL:用于统计函数的调用情况ATRACE_CALL()
app层
Trace.beginSection(“Fragement_onCreateView”);
// … 其他代码
// …
// … 结束处
Trace.endSection()
然后通过指令:python systrace.py --app=sectionName 指定APK,或者通过DDMS选择指定APK,抓取systrace分析
Java framework层
Trace.traceBegin(long traceTag, String methodName)
Trace.traceEnd(long traceTag)
打开方式:
进入Android/Sdk/platform-tools/systrace目录下
python systrace.py [options] [category1] [category2] … [categoryN]
[options]”是一些命令参数;“[category]”等是你感兴趣的系统模块,比如view代表View系统(包含绘制流程),am代表ActivityManager(包含Activity的创建过程等
如:python systrace.py --time=10 -o mynewtrace.html sched gfx view wm
要在 Pixel/Pixel XL 上调试抖动问题,请从以下命令开始:
./systrace.py sched freq idle am wm gfx view sync binder_driver irq workq input -b 96000
如果报错apt-get install python-six,请执行sudo apt-get install python-six
options:
| options | 描述 |
|---|---|
| -o < FILE > | 输出的目标文件 |
| -t N, –time=N | 执行时间,默认5s |
| -b N, –buf-size=N | buffer大小(单位kB),用于限制trace总大小,默认无上限 |
| -k < KFUNCS >,–ktrace=< KFUNCS > | 追踪kernel函数,用逗号分隔 |
| -a < APP_NAME >,–app=< APP_NAME > | 追踪应用包名,用逗号分隔 |
| –from-file=< FROM_FILE > | 从文件中创建互动的systrace |
| -e < DEVICE_SERIAL >,–serial=< DEVICE_SERIAL > | 指定设备 |
| -l, –list-categories | 列举可用的tags |
category常用取值
sched:CPU调度的信息,非常重要;你能看到CPU在每个时间段在运行什么线程;线程调度情况,比如锁信息。
gfx:Graphic系统的相关信息,包括SurfaceFlinger,VSYNC消息,Texture,RenderThread等;分析卡顿非常依赖这个。
view:View绘制系统的相关信息,比如onMeasure,onLayout等;对分析卡顿比较有帮助。
am:ActivityManager调用的相关信息;用来分析Activity的启动过程比较有效。
dalvik: 虚拟机相关信息,比如GC停顿等。
binder_driver:Binder驱动的相关信息,如果你怀疑是Binder IPC的问题,不妨打开这个。
core_services:SystemServer中系统核心Service的相关信息,分析特定问题用。
input: Input
webview : WebView
wm : Window Manager
audio: Audio
video : Video
camera : Camera
hal : Hardware Modules
res : Resource Loading
rs : RenderScript
freq : CPU Frequency
membus : Memory Bus Utilization
idle : CPU Idle
disk : Disk input and output
load : CPU Load
sync : Synchronization Manager
我们一般会把这个命令配置成Alias,配置如下:
alias st-start=‘python /sdk/platform-tools/systrace/systrace.py’
alias st-start-gfx-trace = ‘st-start -t 8 gfx input view sched freq wm am hwui workq res dalvik sync disk load perf hal rs idle mmc’
这样在使用的时候,可以直接敲 st-start 即可,当然为了区分和保持各个文件,还需要加上 -o xxx.html .上面的命令和参数不必一次就理解,只需要记住如何简单使用即可,在分析的过程中,这些东西都会慢慢熟悉的。
一般来说比较常用的是
-o : 指示输出文件的路径和名字
-t : 抓取时间
-b : 指定 buffer 大小
-a : 指定 app 包名
快捷键使用
快捷键的使用可以加快查看 Systrace 的速度,下面是一些常用的快捷键
- W : 放大 Systrace , 放大可以更好地看清局部细节
- S : 缩小 Systrace, 缩小以查看整体
- A : 左移
- D : 右移
- M : 高亮选中当前鼠标点击的段(这个比较常用,可以快速标识出这个方法的左右边界和执行时间,方便上下查看)
鼠标模式快捷切换 : 主要是针对鼠标的工作模式进行切换 , 默认是 1 ,也就是选择模式,查看 Systrace 的时候,需要经常在各个模式之间切换 , 所以点击切换模式效率比较低,直接用快捷键切换效率要高很多
- 数字键1 : 切换到 Selection 模式 , 这个模式下鼠标可以点击某一个段查看其详细信息, 一般打开 Systrace 默认就是这个模式 , 也是最常用的一个模式 , 配合 M 和 ASDW 可以做基本的操作
- 数字键2 : 切换到 Pan 模式 , 这个模式下长按鼠标可以左右拖动, 有时候会用到
- 数字键3 : 切换到 Zoom 模式 , 这个模式下长按鼠标可以放大和缩小, 有时候会用到
- 数字键4 : 切换到 Timing 模式 , 这个模式下主要是用来衡量时间的,比如选择一个起点, 选择一个终点, 查看起点和终点这中间的操作所花费的时间.
线程状态查看
Systrace 会用不同的颜色来标识不同的线程状态, 在每个方法上面都会有对应的线程状态来标识目前线程所处的状态.
通过查看线程状态我们可以知道目前的瓶颈是什么, 是 CPU 执行慢还是因为 Binder 调用, 又或是进行 IO 操作, 又或是拿不到 CPU 时间片
线程状态主要有下面几个
- 绿色 : 运行中
只有在该状态的进程才可能在CPU上运行。而同一时刻可能有多个进程处于可执行状态,这些进程的task_struct结构(进程控制块)被放入对应CPU的可执行队列中(一个进程最多只能出现在一个CPU的可执行队列中)。进程调度器的任务就是从各个CPU的可执行队列中分别选择一个进程在该CPU上运行。
作用:我们经常会查看 Running 状态的线程,查看其运行的时间,与竞品做对比,分析快或者慢的原因:
- 是否频率不够?
- 是否跑在了小核上?
- 是否频繁在 Running 和 Runnable 之间切换?为什么?
- 是否频繁在 Running 和 Sleep 之间切换?为什么?
- 是否跑在了不该跑的核上面?比如不重要的线程占用了超大核
![]()
- 蓝色 : 可运行
线程可以运行但当前没有安排,在等待 cpu 调度
作用:Runnable 状态的线程状态持续时间越长,则表示 cpu 的调度越忙,没有及时处理到这个任务:
- 是否后台有太多的任务在跑?
- 没有及时处理是因为频率太低?
- 没有及时处理是因为被限制到某个 cpuset 里面,但是 cpu 很满?
- 此时 Running 的任务是什么?为什么?
![]()
- 白色 : 休眠中
线程没有工作要做,可能是因为线程在互斥锁上被阻塞。
作用 : 这里一般是在等事件驱动
- 橘色 : 不可中断的睡眠态 IO Block
线程在I / O上被阻塞或等待磁盘操作完成,一般底线都会标识出此时的 callsite :wait_on_page_locked_killable
作用:这个一般是标示 IO 操作慢,如果有大量的橘色不可中断的睡眠态出现,那么一般是由于进入了低内存状态,申请内存的时候触发 pageFault, linux 系统的 page cache 链表中有时会出现一些还没准备好的 page(即还没把磁盘中的内容完全地读出来) , 而正好此时用户在访问这个 page 时就会出现 wait_on_page_locked_killable 阻塞了. 只有系统当 io 操作很繁忙时, 每笔的 io 操作都需要等待排队时, 极其容易出现且阻塞的时间往往会比较长.
- 紫色 : 不可中断的睡眠态
线程在另一个内核操作(通常是内存管理)上被阻塞。
作用:一般是陷入了内核态,有些情况下是正常的,有些情况下是不正常的,需要按照具体的情况取分析
进程唤醒信息分析
Systrace 会标识出一个非常有用的信息,可以帮助我们进行跨进程调用相关的分析。
一个进程被唤醒的信息往往比较重要,知道他被谁唤醒,那么我们也就知道了他们之间的调用等待关系,如果出现一段比较长的 sleep 情况,然后被唤醒,那么我们就可以去看是谁唤醒了这个线程,对应的就可以查看唤醒者的信息,看看为什么唤醒者这么晚才唤醒。
一个常见的情况是:应用进程使用 Binder 与 SystemServer 的 AMS 线程进行通信,但是恰好 AMS 的这个函数正在等待锁释放(或者这个函数本身执行时间很长),那么应用进程就需要等待比较长的时间,如果恰好是应用进程的主线程在进行等待,那么就会出现性能问题,比如响应慢或者卡顿,这就是为什么后台有大量的进程在运行,或者跑完 Monkey 之后,整机性能会下降的一个主要原因。
Systrace 可以标示出这个的一个原因是,一个任务在进入 Running 状态之前,会先进入 Runnable 状态进行等待,而 Systrace 会把这个状态也标示在 Systrace 上(非常短,需要放大进行看)
拉到最上面查看对应的 cpu 上的 taks 信息,会标识这个 task 在被唤醒之前的状态
顺便贴一下 Linux 常见的进程状态
- D 无法中断的休眠状态(通常 IO 的进程);
- R 正在可运行队列中等待被调度的;
- S 处于休眠状态;
- T 停止或被追踪;
- W 进入内存交换 (从内核2.6开始无效);
- X 死掉的进程 (基本很少見);
- Z 僵尸进程;
- < 优先级高的进程
- N 优先级较低的进程
- L 有些页被锁进内存;
- s 进程的领导者(在它之下有子进程);
- l 多进程的(使用 CLONE_THREAD, 类似 NPTL pthreads);
- 01 位于后台的进程组;
信息区数据解析
进程状态信息解析
函数 Slice 信息解析
Counter Sample 信息解析
Async Slice 信息解析
CPU Slice 信息解析
User Expectation 信息解析
位于整个 Systrace 最上面的部分,标识了 Rendering Response 和 Input Response