App优化 Systrace

时间:2021-02-17 21:29:46

简介

trace [tres] vt.跟踪,追踪; 追溯,探索; 探索; 查找;   n.痕迹; 痕迹,踪迹; 微量,极少量;
1
1
 
1
trace [tres] vt.跟踪,追踪; 追溯,探索; 探索; 查找;   n.痕迹; 痕迹,踪迹; 微量,极少量;

Systrace是Android4.1中新增的性能数据采样和分析工具,它可帮助开发者收集Android关键子系统(如SurfaceFlinger、WindowManagerService等Framework部分关键模块、服务、View系统等)的运行信息,从而帮助开发者更直观的分析系统瓶颈,改进性能。


Systrace允许你监视和跟踪Android系统的行为,它会告诉你系统都在哪些工作上花费时间、CPU周期都用在哪里,甚至你可以看到每个线程、进程在指定时间内都在干嘛。它同时还会突出观测到的问题,从垃圾回收到渲染内容都可能是问题对象,甚至提供给你建议的解决方案。

Systrace的功能包括跟踪系统的I/O操作、内核工作队列、CPU负载以及Android各个子系统的运行状况等。在Android平台中,它主要由3部分组成:
  • 内核部分:Systrace利用了Linux Kernel中的ftrace功能,所以,如果要使用Systrace的话,必须开启kernel中和ftrace相关的模块。
  • 数据采集部分:Android定义了一个Trace类,应用程序可利用该类把统计信息输出给ftrace。同时,Android还有一个atrace程序,它可以从ftrace中读取统计信息然后交给数据分析工具来处理。
  • 数据分析工具:Android提供一个systrace.py(python脚本文件,位于Android SDK目录/tools/systrace中,其内部将调用atrace程序)用来配置数据采集的方式(如采集数据的标签、输出文件名等)和收集ftrace统计数据并生成一个结果网页文件供用户查看。从本质上说,Systrace是对Linux Kernel中ftrace的封装。应用进程需要利用Android提供的Trace类来使用Systrace。

启动Systrace

Systrace是Android4.1中新增的,所以要求要生成Trace的手机在Android 4.1以上。
Systrace工具可以在sdk/platform-tools/ 中找,源码位于external/chromium-trace下面。

Systrace可以通过命令行,Eclipse,Android Studio等方式启动。
【Using  Android Studio】
  • 1.In Android Studio, open an Android application project. 1.Open the Device Monitor by selecting Tools > Android > Monitor.
  • 2.In the Devices tab, select the device on which to run a trace. If no devices are listed, make sure your device is connected via USB cable and that debugging is enabled on the device.
  • 3.Click the Systrace icon at the top of the Devices panel to configure tracing.
  • 4.Set the tracing options and click OK to start the trace.
App优化 Systrace

【Using Eclipse】

  • 1.In Eclipse, open an Android application project. 1.Switch to the DDMS perspective, by selecting Window > Perspectives > DDMS.
  • 2.In the Devices tab, select the device on which to run a trace. If no devices are listed, make sure your device is connected via USB cable and that debugging is enabled on the device.
  • 3.Click the Systrace icon at the top of the Devices panel to configure tracing.
  • 4.Set the tracing options and click OK to start the trace.
App优化 Systrace

【Using Device Monitor】
  • 1.Navigate to your SDK tools/ directory. 1.Run the monitor program.
  • 2.In the Devices tab, select the device on which to run a trace. If no devices are listed, make sure your device is connected via USB cable and that debugging is enabled on the device.
  • 3.Click the Systrace icon at the top of the Devices panel to configure tracing.
  • 4.Set the tracing options and click OK to start the trace.

生成Trace分析文档

生成Trace分析文档的步骤如下:
  • 打开手机调试模式,连接手机,运行APP
  • 启动Systrace
  • 手机准备好你要进行抓取的界面
  • 配置文件路径、抓取时间等
  • 点击确定后开始操作手机,在时间到了后会自动生成报表(这个文件至少也有好几兆)
  • 使用Chrome(其他浏览器很可能打不开)将这个文件打开进行分析

Systrace的一些配置
App优化 Systrace
  • duration:抓取时间,通常设置5秒,并在5秒内重现问题,时间太短会导致问题重现时没有被抓到,时间太长会导致JavaHeap不够而无法保存。因此在能抓到问题点的情况下,时间越小越好。
  • Buffer Size:存储Systrace的size,同样太小会导致信息丢失,太长会导致Java Heap不够而无法保存,建议【20480】。如果检测结果有异常,请调整Buffer Size的大小试试。
  • Application:检测的应用,默认选择none
  • Commonly Used Tag:常用标签,这部分TAG全部使能上。只关注显示情况的话 ,只选取Graphics和View System就可以。
  • Advanced Options:高级选项。如果设备root了,可以看到更多的TAG,如eMMC commands/ Synchonization/Kernel Workqueues。

测试时发现,5.1的华为手机点击确定后报以下误:
Unexpected error while collecting system trace.
Unable to find trace start marker 'TRACE:':error opening /sys/kernel/debug/tracing/options/overwrite: No such file or directory
2
2
 
1
Unexpected error while collecting system trace.
2
Unable to find trace start marker 'TRACE:':error opening /sys/kernel/debug/tracing/options/overwrite: No such file or directory
而7.0的三星手机正常

打开Trace文档

可以用Chrome浏览器打开生成的trace文件。浏览时可以使用w/s/a/d快捷键来放大、缩小、移动等操作。可以点击右上角的?号来查看等多的操作。
Key Description
w Zoom into the trace timeline.
s Zoom out of the trace timeline.
a Pan left on the trace timeline.
d Pan right on the trace timeline.
e Center the trace timeline on the current mouse
location.
g Show grid at the start of the currently selected
task.
Shift+g Show grid at the end of the currently selected task.
Right Arrow Select the next event on the currently selected
timeline.
Left Arrow Select the previous event on the currently selected
timeline.
双击
Zoom into the trace timeline.
Shift+双击 Zoom out of the trace timeline.

分析Trace文档--简介
纵轴代表着时间线,事件记录按照进程分组,同一个进程内按线程进行纵向拆分,每个线程记录自己的工作,可收缩/展开。

在本例中,一共有三个组:Kernel, SurfaceFlinger, App,他们分别以包名为标识。每个应用进程都会包含其中所有线程的记录信号,你可以看到从InputEvent到RenderThread都有。
除了进程和线程运行信息,还有两个重要信息:
【Frame】
在每个app进程,都有一个Frames行,正常情况以绿色的圆点表示。当圆点颜色为黄色或者红色时,意味着这一帧超过16.6ms(即发现丢帧),这时需要通过放大那一帧进一步分析问题。对于Android 5.0(API level 21)或者更高的设备,该问题主要聚焦在UI Thread和Render Thread这两个线程当中。对于更早的版本,则所有工作在UI Thread。

【Alerts】
Systrace能自动分析trace中的事件,并能自动高亮性能问题作为一个Alerts,建议调试人员下一步该怎么做。
比如对于丢帧时,点击黄色或红色的Frames圆点便会有相关的提示信息;另外,在systrace的最右侧,有一个Alerts tab可以展开,这里记录着所有的的警告提示信息。
当我们点击了Alerts或者点击右边的Alerts列表中的任何一点,我们可以看到,在界面的最底部,会有相对应的优化提示,以及可能会出现优化的视频教程链接。

比如上面的提示说你View的draw绘制花的时间太长了,然后我们可以根据Description来很明白的看到提示的内容是什么。
App优化 Systrace

然后我们可以点击一块Frames中的F来查看,同样的它会生成一份跟Alerts类似的报告结果并放在界面的最低端。
我们可以通过按下m键查看这一帧到下一帧所花费的时间以及哪个方法被调用的最长。
App优化 Systrace
可以明显看到这时间>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.
//ListView项目回收涉及inflating视图。 确保您的Adapter#getView() 循环使用传入的View,而不是构建新的View。
 
1
Description :ListView item recycling involved inflating views. Ensure your Adapter#getView() recycles the incoming View, instead of constructing a new one.
2
//ListView项目回收涉及inflating视图。 确保您的Adapter#getView() 循环使用传入的View,而不是构建新的View。
根据系统提示,我们就能顺着这条路去找界面的代码哪里出现了不足从而优化完善。

当然Systrace无法帮你定位到代码里面的具体到某一行代码,但是我们可以通过Alerts和Frames来能基本上优化了不足的地方,然后我们可以根据TraceView来分析具体函数花了多长时间来进一步优化代码提高性能。

分析Trace文档--案例
上面介绍了Systrace中不同区域的功能,当然最有趣的还是Alerts和Frames两栏,让我们来选择最上方的Alerts瞧瞧:
App优化 Systrace
这个警告指出了,有一个View#draw()方法执行了比较长的时间。我们可以在下面看到问题的描述、链接,甚至是相关的视频。
下面我们看Frames这一行,可以看到这里展示了被绘制出来的每一帧,并且用绿、黄、红三颜色来区分它们在绘制时的性能。我们选一个红色帧来瞅瞅:
App优化 Systrace
在最下方,我们看到了与这一帧所相关的一些警告。
在这三个警告中,有一个是我们上面所提到的(View#draw())。接下来我们在这一帧处放大并在下方展开“Inflation during ListView recycling”这条警告:
App优化 Systrace
我们可以看到警告部分的总耗时32毫秒,远高于了我们对保障60fps所需的16.6毫秒绘制时间。同时还有更多的ListView每个条目的绘制时间,大约是6毫秒每个条目,总共五个。而Description描述项中的内容会帮助我们理解问题,甚至提供问题的解决方案。回到我们上一张图片,我们可以在“inflate”这一个块区处放大,并且观察到底是哪些View在被填充过程中耗时比较严重。

下面是另外一个渲染过慢的实例:
App优化 Systrace
在选择了某一帧之后,我们可以按“m”键来高亮这一帧,并且在上方看到了这一部分的耗时,如图,我们看到了这一阵的绘制总共耗时大约19毫秒。而当我们展开这一帧唯一的一个警告时,我们发现了“Scheduling delay”这条错误。
Scheduling delay(调度延迟)的意思就是一个线程在处理一块运算的时候,在很长一段时间都没有被分配到CPU上面做运算,从而导致这个线程在很长一段时间都没有完成工作。我们选择这一帧中最长的一块,从而得到更加详细的信息:
App优化 Systrace

在红框区域内,我们看到了“Wall duration”,他代表着这一区块的开始到结束的耗时。之所以叫作“Wall duration”,是因为他就像是墙上的一个时钟,从线程的一开始就为你计时。
而CPU Duration一项中显示了实际CPU在处理这一区块所消耗的时间。
很显然,两个时间的差距还是非常大的。整个区块耗时18毫秒,而在这之中CPU只消耗了4毫秒的时间去运算。这就有点奇怪了,所以我们应该看一下在这整个过程之中,CPU去干吗了。
App优化 Systrace
可以看到,所有四个线程都非常的繁忙。
选择其中的一个线程会告诉我们是哪个程序在占用他,在这里是一个包名为com.udinic.keepbusyapp的程序。在这里,由于另外一个程序占用CPU,导致了我们的程序未能获得足够的CPU资源。
但是这种情况其实是暂时的,因为被其他后台应用占用CPU的情况并不多见,但仍有其他应用的线程或是主线程占用CPU。而Systrace也只能为我们提供一个概览,他的深度是有限的。所以要找到我们app中到底是什么让我们的CPU繁忙,我们还要借助另一个工具——Traceview。

通过Trace类跟踪应用案例

Trace类能够让你在任何时候跟踪应用的一举一动。在你获取trace的过程中,Trace.beginSection()与Trace.endSection()之间代码工作会一直被追踪。
比如,我们在recyclerview的bindview中使用sleep模拟耗时操作,滚动时会出现明显卡顿
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override
public void onBindViewHolder(StaggredAdapter.MyHolder holder, int position) {
holder.mivItem.setImageResource(mlstPics.get(position)); Trace.beginSection("aaa");//生成的trace文件中,会在跟踪的代码段执行对应时间轴区间打上一个tag标记
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Trace.endSection();//Trace的begin与end必须在同一线程之中执行
}
x
 
1
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
2
@Override
3
public void onBindViewHolder(StaggredAdapter.MyHolder holder, int position) {
4
    holder.mivItem.setImageResource(mlstPics.get(position));
5

6
    Trace.beginSection("aaa");//生成的trace文件中,会在跟踪的代码段执行对应时间轴区间打上一个tag标记
7
    try {
8
        Thread.sleep(1000);
9
    } catch (InterruptedException e) {
10
        e.printStackTrace();
11
    }
12
    Trace.endSection();//Trace的begin与end必须在同一线程之中执行
13
}

使用systrace跟踪,生成如下分析图
App优化 Systrace
找到分析进程对应的ui线程,线程的纵向信息记录的是调用关系,横向信息记录的是调用顺序,代码中的标记“aaa”标记了sleep的时间段,可以按m键高亮显示这个标记对应的时间段,可以看出以下信息:
  • 丢帧,在aaa标记时段的前面,有一帧标红的frame,它跟下一个frame之间间隔事件很长(代码sleep中)
  • 调用关系,RV滚动 ---> bindview ---> aaa(sleep)

2017-10-20