一、DDMS
二、SysTrace
SysTrace是一款性能分析工具,通过捕获应用程序进程和其他Android进程的执行时间来分析应用程序的性能问题。该工具组合了Android内核的数据,例如==CPU调度程序,磁盘活动和应用程序线程==,以生成一个HTML报告,显示给定时间段内Android设备系统进程的整体画面。
SysTrace特别适合检测App的卡顿问题。==SysTrace会收集整个系统的运行过程信息==,因此当发现卡顿、失帧时,可以使用SysTrace检测出具体位置。
2.1 SysTrace的用法
2.1.1 前置条件
- Android SDK tools 20或者以上版本
- python 2.7(不可是其他版本)
- 使用USB连接的Android 4.1以上版本的debugging测试机
要使用SysTrace必须同时满足上面三个条件。SYSTrace有两种启动方式:控制台和Android Device Monitor。
2.1.2Android Device Monitor
- Android Studio --> Tools --> Android --> Android Device Monitor / 。
- sdk/tools/ Run monitor / Select a device / Android Device Monitor /
2.1.3 控制台
Android 4.3及以上设备与Android4.2及以下设备使用CMD启动SysTrace略有不同。我们先介绍一种通用的方案 通用方案
cd /sdk/platform-tools/systrace
python systrace.py -a packageName -o trace.html
复制代码
该方法会在/sdk/platfoorm-tools/systrace/目录下生成trace.html文件
2.2 使用SysTrace对UI进行性能分析
打开trace.html之后,我们得到下图所示页面。在Alerts中显示出检测到的所有问题。如果没有看到Alerts条目,则证明没有问题。
一般而言,ALert对应的时间点上App都发生了丢帧,从而引发了UI性能问题。
接下来我们逐帧分析问题所在:
点击Alert A点之后,查看其报告为
Alert Scheduling delay
Running
17.167 ms
Sleeping
2.626 ms
Not scheduled, but runnable
0.577 ms
Uninterruptible Sleep | WakeKill - Block I/O
13.315 ms
Blocking I/O delay
2.865 ms
Frame
Description
Work to produce this frame was descheduled for several milliseconds,
contributing to jank. Ensure that code on the UI thread doesn't block on work
being done on other threads, and that background threads (doing e.g. network
or bitmap loading) are running at android.os.Process#THREAD_PRIORITY_BACKGROUND
or lower so they are less likely to interrupt the UI thread. These background
threads should show up with a priority number of 130 or higher in the
scheduling section under the Kernel process.
复制代码
B点的报告为:
Alert Long View#draw()
Time spent
3.053 ms
Record View#draw() took 3.05ms
Frame
Description
Recording the drawing commands of invalidated Views took a long time. Avoid
significant work in View or Drawable custom drawing, especially allocations
or drawing to Bitmaps.
Video Link Android Performance Patterns: Invalidations, Layouts, and Performance
Video Link Android Performance Patterns: Avoiding Allocations in onDraw()
复制代码
C点报告为:
Alert Scheduling delay
Running
17.576 ms
Sleeping
17.805 ms
Not scheduled, but runnable
4.108 ms
Frame
Description
Work to produce this frame was descheduled for several milliseconds,
contributing to jank. Ensure that code on the UI thread doesn't block on work
being done on other threads, and that background threads (doing e.g. network
or bitmap loading) are running at android.os.Process#THREAD_PRIORITY_BACKGROUND
or lower so they are less likely to interrupt the UI thread. These background
threads should show up with a priority number of 130 or higher in the
scheduling section under the Kernel process.
复制代码
Scheduling delay说明这个处理特定时间片的线程很长时间没有被CPU调度,因此这个线程花了很久才完成。为什么会出现这种状况呢?可能是因为开启了太多的线程和UI线程竞争CPU资源,导致UI线程迟迟不能执行。
E点报告:
▶Alert Long View#draw()
Time spent
3.053 ms
Record View#draw() took 3.05ms
Frame
Description
Recording the drawing commands of invalidated Views took a long time.
Avoid significant work in View or Drawable custom drawing, especially
allocations or drawing to Bitmaps.
Video Link Android Performance Patterns: Invalidations, Layouts, and Performance
Video Link Android Performance Patterns: Avoiding Allocations in onDraw()
▶Alert Scheduling delay
Running
17.167 ms
Sleeping
2.626 ms
Not scheduled, but runnable
0.577 ms
Uninterruptible Sleep | WakeKill - Block I/O
13.315 ms
Blocking I/O delay
2.865 ms
Frame
Description
Work to produce this frame was descheduled for several milliseconds, contributing to jank. Ensure that code on the UI thread doesn't block on work
being done on other threads, and that background threads (doing e.g. network
or bitmap loading) are running at android.os.Process#THREAD_PRIORITY_BACKGROUND
or lower so they are less likely to interrupt the UI thread. These background
threads should show up with a priority number of 130 or higher in the
scheduling section under the Kernel process.
复制代码
G点报告为:
▶Alert Expensive Bitmap uploads
Pixels uploaded
"2.25 million"
Time spent
15.256 ms
Upload 3000x750 Texture took 15.26ms
Frame
Description
Bitmaps that have been modified / newly drawn must be uploaded to the GPU.
Since this is expensive if the total number of pixels uploaded is large,
reduce the amount of Bitmap churn in this animation/context, per frame.
▶Alert Scheduling delay
Running
17.576 ms
Sleeping
17.805 ms
Not scheduled, but runnable
4.108 ms
Frame
Description
Work to produce this frame was descheduled for several milliseconds,
contributing to jank. Ensure that code on the UI thread doesn't block on work
being done on other threads, and that background threads (doing e.g. network
or bitmap loading) are running at android.os.Process#THREAD_PRIORITY_BACKGROUND
or lower so they are less likely to interrupt the UI thread. These background
threads should show up with a priority number of 130 or higher in the
scheduling section under the Kernel process.
复制代码
总结如下表所示:
帧头 | 帧间 | 帧尾 |
A: Scheduling Delay | B: Long Draw | C:scheduling delay |
E: long Draw, scheduling delay | G:Extensive bitmap upload, scheduling delay |
经过对比,B点描述了该帧的UI性能问题:在draw方法中做了太多的事情,在G点描述了该事件是Extensive bitmap upload。
API中也提供了以下方法检测UI性能:
Trace.beginSection("sectionName");
try {
doSomething();
}finally {
Trace.endSection();
}
复制代码
注意:必须在同一个线程调用beginSection和endSection,且仅支持Android 4.3及以上版本。
但是通过上述方法只能知道有哪些UI性能问题,但是并不知道在哪儿发生了性能问题。我们可以使用另一个TraceView来跟踪代码,发现错误。
三、TraceView
Android自带的TraceView堪比java的性能调优工具visualvm线程视图,可以方便的查看线程的执行情况,某个方法执行时间、调用次数、在总体中的占比等,从而定位性能点。
3.1、生成日志,运行TraceView
运行TraceView有两种方式
a、调用Debug类
在开始调试的地方,如Activity的onCreate函数,添加
Debug.startMethodTracing("tracefilename");
复制代码
结束调试的地方,如Activity的onDestroy函数,添加
Debug.stopMethodTracing();
复制代码
之后运行你的app一段时间并退出会在/android/data/packageName/files/生成tracefilename.trace这个log文件,记录这段时间内的运行信息。 将日志文件pull到PC端,cmd到android sdk tools文件夹内(或绑定sdk tools目录到系统path内),运行traceview tracefilename.trace即可打开TraceView分析界面,如下
示例代码如下:
Debug.startMethodTracing("summaryTraceForMain");
spannString();
Debug.stopMethodTracing();
复制代码
b. 使用DDMS
打开devices窗口,选择某个进程,点击右上角的start method profiling
运行app一段时间后,再点击已变成stop method profiling的该按钮。eclipse会自动弹出debug的标签(可通过菜单File->save as保存数据)。界面同上面。 这种方式不需要修改代码,所以对于没有源码的程序同样可以进行排查。同时可以方便的进行全局性能排查。
3.2、TraceView界面信息介绍
TraceView界面包括时间面板和方法面板
(1) 时间面板(Timeline Panel)
时间面板展示了每个线程的执行情况,其中main即为ui主线程。 移动到某个位置可以查看该点对应的方法的执行信息,点击方法面板则会选中相应的方法。 可以左键按住不放选中区域放大局部精细查看,不同方法用不同颜色标注
(2) 方法面板(Profile Panel)
方法面板展示了所有方法的执行情况,点击某个方法可以查看在对应线程上的执行时间区域,并会显示其父方法及子方法。 每个方法包括如下信息列,可点击某列进行排序,从而确定产生性能问题的函数: Incl Cpu Time, Excl Cpu Time, Incl Real Time, Excl Real Time, Incl Cpu Time%, Excl Cpu Time%, Incl Real Time%, Excl Real Time%, Calls+RecurCalls/Total, Cpu Time/Call, Real Time/Call 所有的Time都是以毫秒计算。每列具体含义及作用如下:
a. Incl表示将所有子函数耗时也计算在内,Excl则表示不包括子函数的调用时间。对比可以确定耗时操作发生是自身还是子函数中。
b. Cpu Time表示占用cpu执行的时间,Real Time包括Cpu Time以及等待、切换的时间等,所以一般都大于Cpu Time。对比可以判断耗时操作是否在cpu执行段内。
c. 上面四个指标对应的%表示函数在总时间的占比。方便查看某个函数的时间占比。
d. Calls+RecurCalls/Total表示被外部调用次数+递归次数/总次数。可以查看调用次数是否符合自己预期。
e. Cpu Time/Call, Real Time/Call表示总的Cpu Time及Real Time与总调用次数的比例。查看每次调用的耗时,一般可通过简单此项确定每个函数的性能。