Android性能分析工具systrace的使用,能根据须要抓取trace。html
了解trace文件中数据的含义,能分析简单的性能问题。python
systrace是Android4.1版本以后推出的,对系统Performance分析的工具。chrome
systrace的功能包括跟踪系统的I/O操做、内核工做队列、CPU负载以及Android各个子系统的运行情况等。在Android平台中,它主要由3部分组成:浏览器
内核部分:Systrace利用了Linux Kernel中的ftrace
功能。因此,若是要使用systrace的话,必须开启kernel中和ftrace相关的模块。缓存
数据采集部分:Android定义了一个Trace类。应用程序可利用该类把统计信息输出给ftrace。同时,Android还有一个atrace
程序,它能够从ftrace中读取统计信息而后交给数据分析工具来处理。app
数据分析工具:Android提供一个systrace.py
(python脚本文件,位于Android SDK目录/sdk/platform-tools/systrace
中,其内部将调用atrace程序)用来配置数据采集的方式(如采集数据的标签、输出文件名等)和收集ftrace统计数据并生成一个结果网页文件供用户查看。函数
简单来讲,当机器以60帧/秒显示(也就是16.6 ms),用户会感受机器会流畅。若是出现显示时出现丢帧的状况,就须要知道系统在作什么?工具
Systrace 是用来收集系统和应用的数据信息和一些中间生成数据的细节,在Android 4.1系统和4.1以后的系统。性能
Systrace在一些分析显示的问题上特别有用,如应用画图慢,显示动做或动画时变形。优化
进入Android/Sdk/platform-tools/systrace目录下
python systrace.py -b 8000 -t 5 -o systrace.html
Google Chrome浏览器能够打开systrace,若是打不开,能够浏览器输入chrome://tracing/
,而后load systrace。
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 |
说明1:-o trace输出的文件路径
说明2:--time 配置抓取systrace的时间,一般设置5秒,并在5秒内重现问题,时间过短会致使问题重现时没有被抓到,时间太长会致使JavaHeap不够而没法保存,所以在能抓到问题点的状况下,时间越小越好。
说明3:--buf-size Buffer Size是存储systrace的size,一样的,过小会致使信息丢失,时间太长会致使Java Heap不够而没法保存,建议20480。
说明4:若是用户有本身在应用程序中加入本身的systrace log,以下:
Trace.beginSection("newInstance");
Trace.endSection("newInstance");
那么此处必须选择这个应用对应的进程名字,不然新加的systrace log不会被抓到。
在一些方法里加入trace 方便本身 跟踪调试 , 以下:
Trace.traceBegin("performTraversals");
try {
……
} finally {
Trace.traceEnd();
}
须要保证 traceBegin 与 traceEnd 必定要成对出现。 而且必定要在同一个线程里面。
加入trace的好处在于,生成的trace文件中,会在跟踪的代码段执行对应时间轴区间打上一个tag标记(好比上例中的performTraversals)
若是在代码中加入了trace,在生成trace文件时,必须指定进程为trace所在的进程。
在进程的上面有一条很细的进度条,包含了该线程的状态:
灰色: 睡眠。
蓝色: 能够运行(它能够运行,但还未被调度运行)。
绿色: 正在运行(调度程序认为它正在运行)。
红色: 不间断的睡眠(一般发生在内核锁上), 指出I / O负载,对于性能问题的调试很是有用
橙色: 因为I / O负载致使的不间断睡眠。
要查看不间断睡眠的缘由(可从sched_blocked_reason跟踪点获取),请选择红色不间断睡眠切片。
------------------------------------------------------------------------------------------------------------------------
同一个进程内按线程进行纵向拆分,每一个线程记录本身的工做。分别以包名为标识。每一个应用进程都会包含其中全部线程的记录信号,能够看到从InputEvent到RenderThread都有。
除了进程和线程运行信息,还有两个重要信息:
每一个app都有一行专门显示frame,每一帧就显示为圆圈,正常绘制是1秒60帧,大约一帧16.6毫秒,在这个值如下是正常颜色绿色,若是超过它就会变成红色、黄色。非绿色的都说明有问题。这时须要经过’w’键放大那一帧,而后按‘m’键高亮,进一步分析问题。
以分析UI Performance为例:
对于Android 5.0(API level 21)或者更高的设备,该问题主要聚焦在UI Thread
和Render Thread
这两个线程当中。对于更早的版本,则全部工做在UI Thread
。
Systrace能自动分析trace中的事件,并能自动高亮性能问题做为一个Alerts,建议调试人员下一步该怎么作。
好比对于丢帧,点击黄色或红色的Frames圆点便会有相关的提示信息;另外,在systrace的最右上方,有一个Alerts tab能够展开,这里记录着全部的的警告提示信息。
(1)当咱们点击了Alerts或者点击右边的Alerts列表中的任何一点咱们能够看到在界面的最底部会相对应的优化提示以及可能会出现优化的视频教程连接。
好比上面的提示说你View的draw绘制花的时间太长了,而后咱们能够根据Description来很明白的看到提示的内容是什么。
(2)而后咱们可以点击一块Frames中的F来查看,一样的它会生成一份跟Alerts相似的报告结果并放在界面的最底端。
(3)能够经过按下m键查看这一帧到下一帧所花费的时间以及哪一个方法被调用的最长。看到时间>16.6ms,系统要求UI的60fps水准因此系统会报出黄色的警告。照样咱们从Description中能够读出究竟是哪里出了问题。
Description :
ListView item recycling involved inflating views. Ensure your Adapter#getView() recycles the incoming View, instead of constructing a new one.
能够看出来系统提示你在getView中花费了太多时间没能颇有效的复用机制。咱们就能顺着这条路去找界面的代码哪里出现了不足从而优化完善。
(4)Alerts和Frames两栏,它们展现了经过手机来的数据而生成出来的可视化分析结果。选择最上方的alerts:
这个警告指出了,有一个View#draw()方法执行了比较长的时间。能够在下面看到问题的描述,连接,甚至是相关的视频。下面咱们看Frames这一行,能够看到这里展现了被绘制出来的每一帧,而且用绿、黄、红三颜色来区分它们在绘制时的性能。
(5)frame一栏(点击右侧Alert type的Scheduling delay):在下方显示栏,咱们看到了与这一帧所相关的一些警告。在这三个警告中,有一个是咱们上面所提到的(View#draw())。接下来咱们在这一帧处放大并在下方展开“Inflation during ListView recycling”这条警告:
可以看到警告部分的总耗时,32毫秒,远高于了咱们对保障60fps所需的16毫秒绘制时间。同时还有更多的ListView每一个条目的绘制时间,大约是6毫秒每一个条目,总共五个。而Description描述项中的内容会帮助咱们理解问题,甚至提供问题的解决方案。
(6)能够在“inflate”(某个函数方法)这一个块区处放大,而且观察究竟是哪些View在被填充过程当中耗时比较严重。
在选择了某一帧以后,按“m”键来高亮这一帧,而且在上方看到了这一部分的耗时,如图,咱们看到了这一阵的绘制总共耗时超过19毫秒。而当咱们展开这一帧惟一的一个警告时,咱们发现了“Scheduling delay”这条错误。
Scheduling delay(调度延迟)的意思就是一个线程在处理一块运算的时候,在很长一段时间都没有被分配到CPU上面作运算,从而致使这个线程在很长一段时间都没有完成工做。咱们选择这一帧中最长的一块,从而获得更加详细的信息:
在红框区域内,“Wall duration”,他表明着这一区块的开始到结束的耗时。
CPU Duration一项中显示了实际CPU在处理这一区块所消耗的时间。
很显然,两个时间的差距仍是很是大的。整个区块耗时18毫秒,而在这之中CPU只消耗了4毫秒的时间去运算。
这时候应该到最上面看Kernel中CPU在作什么操做。
(7)在这一帧中选择一个CPU,查看运行的进程和线程。
可能会因为另一个程序占用CPU,致使了咱们的程序未能得到足够的CPU资源。
可是这种状况实际上是暂时的,由于被其余后台应用占用CPU的状况并很少见,但仍有其余应用的线程或是主线程占用CPU。
(1)CPU
(2)在SurfaceFlinger上面有一个SurfaceView显示buffer的数量
(3)VSYNC信号(一帧16.67ms)分为:
VSYNC-app
VSYNC-sf
相互错位,而且SF进行图像混合的时候老是在每帧的最开始。不能超过一帧。
(4)SurfaceFlinger
在每帧的最开始,包含SurfaceFlinger模块调用的各个函数。
主要有:
acquireBuffer从BufferQueue申请buffer
releaseBuffer 释放buffer返回到BufferQueue
PS:若是Buffer数量过多,多是释放buffern以前调用到display模块的函数停滞太久。
(5)app的绘制
例如对手机camera进行拍照时抓取systrace,绘制的app就是camera。
绘制也是在一帧的开始(VSYNC-app)。
绘制中包含调用的各个函数。
主要有:
dequeueBuffer从BufferQueue申请buffer
queueBuffer返回buffer到BufferQueue
(6)LCD(HWC、display..)
显示模块,在app的下面,通常为UI thread,包含在SF进行图像混合后,将buffer传递到这个模块。
在app的一帧中绘制好后,将信息传递到SF;
在VSYNC-sf下一帧开始时,SF进行图像混合;
在SF图像混合后进行LCD显示(可能在SF混合的过程当中就已经调用到显示模块的函数,所以时间上可能会有交叉。)
例如TouchLatency,UI管道,一般包含如下阶段:
SurfaceFlinger中的EventThread唤醒了应用程序UI线程,代表如今是渲染新帧的时候了。
应用程序使用CPU和GPU资源在UI线程,RenderThread和hwuiTasks中渲染帧。这部分暂UI的大部分。
应用程序经过binder将绘制好的帧发送到SurfaceFlinger并进入睡眠状态。
SurfaceFlinger中的第二个EventThread唤醒SurfaceFlinger来触发组合和显示输出。若是SurfaceFlinger肯定没有任何工做要完成,它将返回睡眠状态。
SurfaceFlinger经过HWC / HWC2或GL处理组合。 HWC / HWC2组合更快,更低的功耗,但会受到SOC的限制。这一步一般须要4-6ms,可是能够与步骤2重叠,由于Android应用程序老是三重缓冲。 (虽然应用程序老是三重缓冲,但在SurfaceFlinger中只能有一个待处理帧,所以和双重缓存差很少。)
SurfaceFlinger通过供应商驱动程序调度最终输出,并返回睡眠状态,等待EventThread唤醒。
导航操做 |
做用 |
---|---|
w |
放大,[+shift]速度更快 |
s |
缩小,[+shift]速度更快 |
a |
左移,[+shift]速度更快 |
d |
右移,[+shift]速度更快 |
经常使用操做 |
做用 |
---|---|
f |
放大当前选定区域(放大选定的一块) |
m |
标记当前选定区域(能够显示时间长度) |
v |
高亮VSync(所在的一帧) |
g |
切换是否显示60hz的网格线(同上) |
0 |
恢复trace到初始态,这里是数字0而非字母o(缩小到初始) |
通常操做 |
做用 |
---|---|
h |
切换是否显示详情 |
/ |
搜索关键字 |
enter |
显示搜索结果,可经过← →定位搜索结果 |
` |
显示/隐藏脚本控制台 |
? |
显示帮助功能 |
Select mode: 双击已选定区能将全部相同的块高亮选中;(对应数字1)
Pan mode: 拖动平移视图(对应数字2)
Zoom mode:经过上/下拖动鼠标来实现放大/缩小功能;(对应数字3)
Timing mode:拖动来建立或移除时间窗口线。(对应数字4)
可经过按数字1~4,用于切换鼠标模式; 另外,按住alt键,再滚动鼠标滚轮能实现放大/缩小功能。