一般来说,我们的机器以60帧/秒显示时,用户会感觉机器很流畅,如果显示时出现丢帧的情况,需要知道当前整个系统所处的状态,这个时候Systrace便是最佳的工具选择。
Systrace是Android4.1中新增的性能数据采样和分析工具。它可帮助开发者收集Android关键子系统(如Surfaceflinger、WindowManagerService等framework部分关键模块、服务)的运行信息,从而帮助开发者更直观的分析系统瓶颈,改进性能。
Systrace在分析一些显示(performence)的问题上特别有用,如有用画图慢,显示动作或动画时变形等。
Systrace的功能包括跟踪系统的I/O操作、内核工作队列、CPU负载以及Android各个子系统的运行状况等。在Android平台中,它主要由3部分组成:
1. 内核部分:Systrace利用了Linux Kernel中的ftrace功能。所以要使用Systrace的话,必须开启kernel中和ftrace相关的模块。
2. 数据采集部分:Android定义了一个Trace类。应用程序可利用该类把统计信息输出给ftrace。同时,Android还有一个atrace程序,它可以从ftrace中读取统计信息然后交给数据分析工具来处理。
3. 数据分析工具:Android提供了一个systrace.py(Python脚步文件,位于Android SDK目录/tools/systrace中,其内部将调用atrace程序)用来配置数据采集的方式(如采集数据的标签、输出文件名等)和收集ftrace统计数据并生成一个结果网页文件供用户查看。
本质上,Systrace是对Linux Kernel中ftrace的封装,应用程序需要利用Android提供的Trace类来使用Systrace。
有三种方式抓取systrace。
首先,在手机端准备好你需要分析的过程的环境;比如假设你要分析App的冷启动过程,那就先把App进程杀掉,切换到Launcher中有你的App图标的那个页面,随时准备点击图标启动进程;假设你要分析某个Activity的卡顿情况,那就先在手机上进入到上一个Activity,随时准备点按钮切换到待分析的Activity中。因为Systrace没办法自由地控制开始和结束(下面有一个办法可以缓解),而trace得到的数据有可能非常多,因此我们需要手工缩小需要分析的数据集合;不然你可能被一堆眼花缭乱的数据和图像弄得晕头转向,然后什么有用的结论也分析不出来。
然后,打开PC端的命令行;进入systrace的目录,也即(假设$ANDROID_HOME是你Android SDK的根目录):
cd $ANDROID_HOME/platform-tools/systrace。
systrace命令行的用法如下:
python systrace.py [options] [category1] [category2] ... [categoryN]
使用上面的命令需要安装Python。其中,“[options]”是一些命令参数;“[category]”等是你感兴趣的系统模块,比如view代表View系统(包含绘制流程),am代表ActivityManager(包含Activity的创建过程等)。分析不同的问题,可以选择不同的你感兴趣的模块。
示例如下:
cd android-sdk/platform-tools/systrace
python systrace.py --time=10 -o mynewtrace.html sched gfx view wm
'systrace.py',这个脚本就是通过adb给手机发送了手机trace的通知;与此同时,切换到手机上进行你需要分析的操作,比如点击Launcher中APP的Icon启动APP。经过你指定的时间(--time=10,指定时间为10秒)后,就会有trace数据生成在当前目录(systrace所在目录),默认是‘trace.html’,上面使用‘-o mynewtrace.html’指定了生成的文件名;用Chrome浏览器打开即可。
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取值如下:
category | 描述 |
---|---|
gfx | Graphics |
input | Input |
view | View System |
webview | WebView |
wm | Window Manager |
am | Activity Manager |
sm | Sync Manager |
audio | Audio |
video | Video |
camera | Camera |
hal | Hardware Modules |
app | Application |
res | Resource Loading |
dalvik | Dalvik VM |
rs | RenderScript |
bionic | Bionic C Library |
power | Power Management |
sched | CPU Scheduling |
irq IRQ | Events |
freq | CPU Frequency |
idle | CPU Idle |
disk | Disk I/O |
mmc | eMMC commands |
load | CPU Load |
sync | Synchronization |
workq | Kernel Workqueues |
memreclaim | Kernel Memory Reclaim |
regulators | Voltage and Current Regulators |
这里看下几个比较常用的模块:
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的相关信息,分析特定问题用。
可以使用Eclipse或者Android Studio集成开发工具,切换到DDMS,如果是在Android Studio中,双击shift按钮,弹出搜索框,输入Android Device Monitor,弹出DDMS窗口;点击devices,点击Systrace按钮:
上面图中最后一个图标,点击后弹出如下图:
补充说明:
Trace.beginSection("newInstance");
Trace.endSection();
那么此处必须选择这个应用对应的进程名字,否则新加的systrace log不会被抓到。systrace没有办法在代码中控制Trace运行的开始和结束,那么,如果们要分析App的启动性能,我点了桌面图标,把Trace时间设置为10s,我怎么知道这10s中,哪段时间是我App的启动过程?如果不知道我们需要分析的时间段,那后续不是扯淡么?
我们可以用自定义Trace Label解决;有时候为了debug方便,那么我们需要自己在apk或者framework层添加trace信息。比如我们觉得Fragment的onCreateView过程有问题,那就在`onCreateView` 中加上代码:
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
Bundle savedInstanceState) {
Trace.beginSection("Fragement_onCreateView");
// .. 其他代码
// ...
// .. 结束处
Trace.endSection();
}
这样,在Trace的分析结果中就会带上`Fragement_onCreateView` 这个过程的运行时间段信息(当然你得开启 -a 选项!),如下:
我们可以在任意自己感兴趣的地方添加自定义的Label;一般来说,分析过程就是,你怀疑哪里有问题,就在那个函数加上Label,运行一遍抓一个Trace,看看自己的猜测对不对;如果猜测正确,进一步加Label缩小范围,定位到具体的自定义函数,函数最终调用到系统内部,那就开启系统相关模块的Trace,继续定位;如果猜测错误,那就转移目标,一步步缩小范围,直至问题收敛。
上面我们说的是debugable状态的APP,那么对于非Debug的APP该如何分析呢?
我们可以手动开启App的自定义Label的Trace功能,方法也很简单,调用一个函数即可;但是这个函数是SDK @hide的,我们需要反射调用:
Class> trace = Class.forName("android.os.Trace");
Method setAppTracingAllowed = trace.getDeclaredMethod("setAppTracingAllowed", boolean.class);
setAppTracingAllowed.invoke(null, true);
把这段代码放在Application的`attachBaseContext` 中,这样就可以手动开启App自定义Label的Trace功能,在非debuggable的版本中也适用!
Android SDK中提供了`android.os.Trace#beginSection`和`android.os.Trace#endSection` 这两个接,我们可以在代码中插入这些代码来分析某个特定的过程:
import android.os.Trace;
Trace.beginSection(String sectionName)
Trace.endSection()
然后通过指令:python systrace.py --app=sectionName 指定APK,或者通过DDMS选择指定APK,抓取systrace分析。
import android.os.Trace;
Trace.traceBegin(long traceTag, String methodName)
Trace.traceEnd(long traceTag)
Java framework层可以使用上面代码,抓取systrace分析。
#include
ATRACE_CALL()
native framework层可以使用上面代码,最好在函数开头声明定义,抓取systrace分析。
生成trace.html 文件后,直接在浏览器中打开就可以。
我们可以看到此界面的Frame的圆圈会显示三种颜色,绿,黄,红。一般红色就是有问题的,要优化的地方。
我们可以看到此界面的Frame的圆圈会显示三种颜色,绿,黄,红。一般红色就是有问题的,要优化的地方。
m可以显示选中方法的时间。
Systrace会自动分析信息,将性能问题直接以alerts的方式高亮显示,我们只要修改这些alerts就可以。
我们可以看到Alert的详细信息,描述和建议。这个Alert是可以定位到有问题的方法。如果我们想要知道方法的更详细信息,我们可以结合Traceview来解决问题。
导航操作 | 作用 |
---|---|
w | 放大,[+shift]速度更快 |
s | 缩小,[+shift]速度更快 |
a | 左移,[+shift]速度更快 |
d | 右移,[+shift]速度更快 |
常用操作 | 作用 |
---|---|
f | 放大当前选定区域 |
m | 标记当前选定区域 |
v | 高亮VSync |
g | 切换是否显示60hz的网格线 |
0 | 恢复trace到初始态,这里是数字0而非字母o |
一般操作 | 作用 |
---|---|
h | 切换是否显示详情 |
/ | 搜索关键字 |
enter | 显示搜索结果,可通过← →定位搜索结果 |
` | 显示/隐藏脚本控制台 |
? | 显示帮助功能 |
实例例证可参考:Systrace的工作原理及例子解读