[转] Android 性能分析案例

Android 系统的一个工程师(Romain Guy)针对Falcon Pro  应用,撰写了一个Android性能分析的文章。该文章介绍了如何分析一个应用哪里出现了性能瓶颈,致使该应用使用起来不流畅。找到缘由、并修复问题。即便没有应用源码也能分析出问题大概根源。html

须要的工具
工具很简单,只须要Android 4.2 SDK便可android

聊聊性能
Android 4.1 的Project Butter关注于性能问题,并引入了一些新的性能分析工具、例如 systrace。虽然Android 4.2没有提供如systrace同样强大的分析工具,但也提供了一些新的驾轻就熟的小工具。在该文章内会介绍一个经常使用的工具,其余有趣的内容等待读者自行探索了。性能分析常常是个复杂的任务,须要很丰富的经验和对相关领域的深刻了解,好比 硬件、API等。有了Android SDK提供的工具,分析起来应该会相对简单一些。git

先确认疑点
下图是Falcon Pro时间轴界面截图,在使用的时候滑动感受有点卡,有丢帧现象。github

Falcon Pro 的时间轴界面

Falcon Pro 的时间轴界面正则表达式

在分析性能问题的时候,很是重要的一点就是用测量工具来证明您的猜疑。尽管 Falcon Pro在Nexus 4上存在明显的丢帧现象,我仍是须要用工具确认下的。所以,我在Nexus 7上也安装了该应用,N7比N4提供shell

了不一样的分析工具。在N7上运行该应用,仍是存在丢帧现象,甚至还更严重。为了实际测量下,我决定使用在Android 4.1引入的一个新功能 — GPU呈现模式分析 — 来分析下。您能够在设置中的“开发者选项”界面找到该工具。windows

启用 GPU呈现模式分析

启用 GPU呈现模式分析安全

什么!? 在Android 4.2上您没找到“开发者选项”? 哦,别急,只须要进入“关于手机”或者“关于平板电脑”界面,在最下面的“版本号”一行上连续点击7下便可。session

启用该选项后,系统会保留每一个界面最后128帧绘制的时间信息。目前在使用该工具前,您须要先干掉要分析的应用 — 之后的Android版本将会去除该前置条件。架构

分析方法:除非有注明,不然这里的每次分析测量都是经过慢慢的上下滑动该应用的时间轴界面,最多滚动一个List项。

在启动该应用并滚动几下时间轴界面,而后运行以下命令:

$ adb shell dumpsys gfxinfo com.jv.falcon.pro

在显示的结果中,会看到一个标题为 “ Profile data in ms”的区域,下面包含了3列数字。 为了图形化显示,您能够把这些数据复制到Excel表格中,来显示一个累积柱状图。以下图:

每帧绘制的累计柱状图

每帧绘制的累计柱状图

表格文件能够到这里下载或者在线查看(Google Doc 可能须要特殊工具)

每列数据显示了渲染每一帧须要的时间:

  1. Draw 是在Java中建立显示列表所须要的时间。这个值显示了运行绘图函数用了多长时间,好比View.onDraw(Canvas)。
  2. Process 是Android 2D引擎渲染显示列表所须要的时间。在界面中View数目越多,则有越多的绘制命令须要执行。
  3. Execute 是把一帧数据送到屏幕上排版显示的时间,这个时间一般比较小。

注意:要流畅的运行60帧/秒, 则须要每帧的处理时间不超过16ms。

关于Execute:若是Execute时间过长,说明您的应用跑到图形管道(graphics pipeline)前头去了。

Android同时最多能够有3个缓冲区,若是您须要另一个,在缓冲区没有释放前应用会被阻塞住。有两种缘由会致使这种状况。第一个是您的应用在Dalvik中绘制的很快,可是在GPU中显示须要的时间比较多。

第二个是应用使用了过多的时间来显示前面几帧动画,当渲染管道填满后,若是动画不运行完则再也不接受新的请求。在将来的Android版本中会改进这个问题。

上图明显说明了个人猜疑:该应用大部分状况下表现良好,偶尔会有几帧丢失。

详细的瞅瞅

该数据目前只是代表应用程序有时候须要较长的时间来绘制界面,可是尚未告诉您是啥缘由致使的。帧率还有可能被没有计划或者错误计划的帧影响。例如,若是一个应用的绘制时间老是小于16ms,可是有时在两帧之间作长时操做,将会引发丢帧现象。

Systrace 是一个简易的工具来检查Falcon Pro中是否存在该问题。该工具是一个系统分析工具。分析结果比较精确,让你能够知道整个系统在干什么,固然也包含您的应用。

要使用Systrace,进入到“开发者选项”界面,选择“启用跟踪”。在显示的对话框中来选择您须要跟踪的类型。 这里咱们只对Graphics 和 View 感兴趣。

启用Systrace

启用Systrace

注意:不要忘记关闭“GPU呈现模式分析”选项。

要使用Systrace,打开命令行,运行 tools/systrace目录中的systrace.py:

$ ./systrace.py

须要安装Python,在windows下运行请参考这里

若是您没有安装Python,也不想安装,则能够经过Eclipse 中的ADT来使用该功能,详情见下图(使用的是ADT 21)

在ADT中使用systrace

在ADT中使用systrace

该工具默认会捕获5秒的事件。我只是简单的上下滚动下时间轴。跟踪结果是一个独立的网页文件,能够到这里下载该文件。

提示:要导航systrace文档,使用WASD键便可缩放和移动(找到打CS的感受了吧!)W会放大当前鼠标焦点。

systrace文档显示了一些很是有趣的信息。例如,显示了一个Process被分配到那个CPU去执行了。若是您放大到最后一行(10440: m.jv.falcon.pro),您能够看到该应用正在作什么。若是您点击每一个performTraversals 块,则能够看到应用绘制一帧须要多少时间。

大部分的performTraversals 都低于16ms,有些须要较多的时间,这些数据证明了前面的猜测(移动到935ms处能够看到这样的一个块)。

更有意思的是,您能够发现有时候该应用没有安排绘制操做而致使丢帧。定位到270ms处有个deliverInputEvent 占用了25ms。这个块说明该应用使用了25ms来处理一个点击事件。因为该应用使用了一个ListView,颇有可能问题就出在这个ListView的Adapter上。

Systrace不只能够帮助咱们发现一个应用须要多少时间来绘制每帧,同时还能够帮助咱们发现其余潜在的性能瓶颈所在。是个很是有用的工具,但也有限。该工具只提供了高层面的数据,咱们须要依靠其余工具

来确认问题到底出在何处。

图形化过分绘制

有多种缘由能够致使绘制性能低下,可是在Android中一个常见的缘由就是“过分绘制”。每当应用让系统在其余内容上绘制内容的时候就会致使过分绘制。想象一个简单的场景:一个带有白色背景的窗口,在该窗口上有个按钮。当系统绘制该按钮的时候是在白色背景上绘制的,这就是过分绘制。过分绘制 没法避免,可是若是太多了 则会引发性能问题。设备的内存带宽是有限的,当过分绘制致使应用须要更多的带宽(超过了可用带宽)的时候性能就会下降。带宽的限制每一个设备均可能是不同的。

一个好的参考目标就是控制过分绘制为2X;这说明您能够绘制一次屏幕,而后在上面绘制最多2次内容,

一共绘制每一个像素3次。

过分绘制一般也说明了额外的问题:太多的View了、复杂的布局、较长的inflation 时间等。

Android提供了3种工具来分析和解决过分绘制的问题: Hierarchy Viewer, Tracer for OpenGL和显示GPU过分绘制。前两个工具能够在ADT中找到,或者独立的monitor 工具(位于android-sdk-windows\tools\monitor.bat)。第三个工具是“开发者选项”中的一个功能。

显示GPU过分绘制

显示GPU过分绘制

显示GPU过分绘制 在屏幕上绘制不一样的颜色来代表过分绘制的状况。启用该选项(另外不要忘记了先干掉您的应用):

过分绘制状况的好坏经过颜色来表示,从蓝色、绿色、淡红色到红色 ,分别表明从好到坏(1x过分绘制、2x过分绘制、3x过分绘制和超过4x过分绘制)。少许的淡红色能够接受,二红色就是实现有问题,须要解决。没有颜色代表没有过分绘制。

在查看 Falcon Pro的过分绘制以前,先看看系统设置界面的过分绘制如何。以下图:

设置界面的过分绘制图形化显示

设置界面的过分绘制图形化显示

只有一两个淡红色,其余都是良好的。

关于透明像素:仔细的看看前面的截图。每一个图标上都是蓝色。这说明透明的图标也属于过分绘制。透明的图标也须要经过GPU处理,须要消耗资源。Android使用Layer和9-patches来优化透明像素的绘制,因此您只须要关注Bitmap中的透明像素。

过分绘制和GPU:目前有两种移动GPU架构。一种使用deferred rendering能够稍微优化过分绘制;另一种使用immediate rendering,没法优化过分绘制。关于这两种架构的详细优缺点请自行Google。

如今来看看 Falcon Pro的过分绘制状况:

Falcon Pro 时间轴界面的过分绘制

Falcon Pro 时间轴界面的过分绘制

哇哦,不少红色哦!List的背景为绿色也是很是有趣的。这代表在该应用还没开始绘制内容的时候已经有2x的过分绘制了。这个问题一般都是有多个全屏背景致使的,修复起了仍是很是简单的。另外在新的ADThint工具中也提供了对过分绘制的提示。

删除不相关的层级

要减小过分绘制,咱们须要先了解其产生的根源。这就要用到Hierarchy Viewer 和Tracer for OpenGL工具了。 Hierarchy Viewer能够独立使用也能够在ADT中使用,能够用来分析一个界面的View层级结构。在解决布局问题的时候很是有用,但对于定位性能问题也有必定的帮助。

重要事项: Hierarchy Viewer默认只能在非安全设备上使用,也就是工程样机或者模拟器。要是实际的设备中使用 Hierarchy Viewer,您须要在应用中添加一个开源库 ViewServer

打开ADT的Hierarchy Viewer视图,而后选择Windows tab。粗体高亮的窗口就是当前设备最上面的窗口,一般状况下就是您要分析的布局。点击选中该项,而后点击工具条上的“Load”按钮(看起来像一个蓝色方块的树)。载入View树可能须要较长的时间,因此请耐心点。 当载入完后,您将会看到一个和下图差很少的界面:

Hierarchy Viewer视图

Hierarchy Viewer视图

在工具中能够把该图导出为一个Photoshop文档。只须要点击第二个按钮便可。

Photoshop文档把该应用中的每一个View显示在一个图层上。每一个图层根据 View.getVisibility()的返回值标记为可见或者不可见。每一个图层经过View的属性android:id或者类名来命名。经过查看这些图层,很快就能够发现至少一处过分绘制:多个全屏背景。第一个是名称为 DecorView图层的背景,该View是由Android系统生成的,里面包含了在主题(theme)中设置的背景。该背景在应用中是不可见的,因此能够把它删除掉。

从DecorView 往上看,能够看到一个LinearLayout 包含另一个渐变全屏背景。这个背景和DecorView的状况同样,也能够删除掉。如今惟一可见的背景是一个名字为id/tweet_list_container的View提供的。

在Photoshop中查看处处的Hierarchy Viewer

在Photoshop中查看处处的Hierarchy Viewer

删除窗口背景:主题中定义的背景,是系统启动应用的时候来建立预览窗口的。除非您的应用是透明的,不然不要设置为Null。能够设置为您须要的颜色或者图片。或者在onCreate() 中调用getWindow().setBackgroundDrawable(null)来删除。

进一步减小过分绘制

Photoshop文档能够帮助理解应用是如何建立的,可是用了查找更小的过分绘制则比较困难。如今该Tracer for OpenGL出场了。打开ADT中“Tracer for OpenGL”透视图,而后点击工具条上的箭头图标。

使用OpenGL Traces

使用OpenGL Traces

输入您应用的包名称和启动Activity的名称,而后选择一个保存的地址后点击“Trace”按钮。

提示: OpenGL traces 文件可能会很是大而且捕获起了很是慢。为了减少文件并加速捕获,能够把DataCollection Ooptions 中的选项都取消掉。

Activity 名称:当启动一个Activity的时候 在logcat中会显该Activity的名称。

当应用启动并运行时,打开前面两个选项:
Collect Framebuffer contents on eglSwapBuffers()
Collect Framebuffer contents on glDraw*()

第一个选项用来快速定位对应的帧,第二个选项能够用来查看每帧经过每一个绘制命令绘制的。第二个选项是解决过分绘制问题的关键。

启动这两个选项后,我开始滚动时间轴界面。如今将会须要比较长的时间来捕获每帧数据,因为时间比较长,建议您下载这个数据吧。在 Tracer for OpenGL 中点击工具条上第一个按钮能够打开该文件。

打开后能够看到每一个发送给GPU的GL命令。若是您下载了我提供的分析文件,找到21帧。当选择一帧后,您能够在Frame Summary 界面中查看该帧的界面。还能够点击绘制命令(蓝色高亮显示),在Details界面中查看当前的状态。

组织结构:GL命令经过View来分组显示。重建了在 Hierarchy Viewer或者您的布局XML文件中的View树。这样很是方便查看那个Veiw执行了什么操做。

分别点击前3个绘制命令,能够发如今前面Photoshop中发现的问题– 全屏的背景绘制了3次。

进一步向下查找,能够发现更多的可优化之处。当绘制一条推特消息(一个List Item)的时候,使用一个ImageView来绘制头像。这个ImageView先绘制了一个背景,而后在其上绘制了头像。以下图:

若是您观察仔细的话会发现,这个头像的背景只是当作头像的边框来用。这样头像自己和下面被盖住的背景就照成了过分绘制。这个背景基本上所有被头像盖住了。

有一种简单的修复该问题的方法,把这个9-patch格式的背景图中间拉伸部分设置为透明的。Android 2D渲染引擎会优化9-patch图中的透明像素。这个简单的修改能够消除头像上的过分绘制。

有意思的是,在消息中的图片上也使用了一样的背景。头像尺寸较小,这点过分绘制能够不在意,可是消息中的图片可能很是大,这个地方的过分绘制就很严重了。修复方式同上。

未来的愿景:我但愿未来Android 2D渲染引擎能够自动探测过分绘制,而且在绘制的时候优化。当前Android开发团队有一些创新的想法,可是还没法肯定什么时候会实现该功能。和内置的GPU优化同样,该功能只适合彻底不透明的场景。

缩短View层级结构

如今过分绘制的问题已经解决了,再次回到Hierarchy Viewer界面。经过查看这个树形结构,咱们能够尝试发现一些非必须的View。删除这些View(特别是ViewGroup)不只仅能提升帧率还能下降对内存的消耗、同时还能加速应用的启动 等等。反正就是好处无穷。

快速扫描一眼 Falcon Pro的Hierarchy Viewer结构,就能够发现几个ViewGroup中只包含了一个View。这种ViewGroup一般是非必须的,而且很容易移除。在下图中至少有2个这种节点应该移除。

另外这个树上还有不少其余View能够移除。例如,每一个推特消息包含一个名字为 id/listElementBottom的RelativeLayout 。该布局包含了消息做者的名字、推特@操做、发布的时间以及一个图标。名字和@操做是两个TextView,这两个TextView能够用一个来实现,分别设置不一样的Style便可。后面的时间和图片分别用TextView和ImageView来实现,一样能够只用一个TextView并结合TextView组合图标来实现。

左边的划入菜单使用了几个LinearLayout+TextView+ImageView 来显示图标和文字。每一个组合均可以经过单一的TextView来实现。

如何缩短UI层级结构:在2009的Google IO中详细介绍了一些方法,演讲的标题为Turbo-charge your UI。http://www.google.com/events/io/2009/sessions/TurboChargeUiAndroidFast.html

关于输入事件

还记得前面咱们查看Systrace发现的那个点击事件吗?如今是时候来看看这个问题了,traceview则是咱们的最佳工具。

traceview是一个Dalvik分析器,该分析器记录了应用中每一个函数的执行时间。经过ADT(或者独立工具)中的DDMS透视图来使用该工具,在Devices窗口中选择您的应用进程,而后点击“Start method profiling”按钮(3个箭头带个红点的那个钮)。

启用跟踪后,我上下滚动了几下时间轴,而后再次点击下该按钮来中止跟踪。您能够从这里下载个人trace文件。 结果以下图所示:

点击#21条目,ViewRootImpl.draw()显示了绘制的时间。表格的最后一列显示了该函数执行平均须要的时间。若是您仔细的看看上面的时间轴,能够发如今连续的帧之间的缺口。

有种很简单的方式来查看这些缺口正在干什么,缩放到缺口起始位置而后点击你能够发现的最大色块。而后跟随父节点一直查找到某个您熟悉的函数为止。 对于我而言,我跟随一个Pattern.compileImpl函数调用(平均耗时0.5ms)一直到DBListAdapter.bindView。很显然该应用一直从新编译同一个正则表达式,在滚动时间轴的时候每当一个新的ListItem显示的时候,就会从新编译一次。Traceview 指出bindView消耗了38ms时间,而56%的时间都是在解析HTML文本。这代表该任务能够在后台线程中执行而不该该在UI主线程中。固然了,正则表达式无需每次都从新编译。

该你了

最后一个分析做为一个练习吧。该应用使用了左右两个滑动菜单。经过“显示GPU过分绘制”工具发如今滑动的时候过分绘制很是严重,我使用“ Tracer for OpenGL ”捕获了一些滑动的数据。下载这个数据文件, 看看您是否能够发现是啥缘由致使过分绘制的(定位到 #34帧)

提示:该应用应该经过View.setLayerType() 函数来启用硬件图层绘制。经过更明智的使用9-patch图片能够优化一些背景致使的过分绘制。剪裁也比较有用。最终,能够经过把传递给setLayerType() 的Paint上设置一个ColorFilter来移除最后一个绘制命令。

这篇文章中显示了各类能够用来分析优化应用性能的工具。若是详尽描述每一个工具则能够写成一本书了,因此详细的信息请参考Android官方网站的相关文档和Google IO上的各类Android演讲。

注:若是你没有使用eclipse和ADT,则在Android SDK中也包含了一个独立的monitor工具,最新版本的工具也是基于Eclipse RPC开发的,经过以下文件执行 android-sdk-windows\tools\monitor.bat

转自: http://blog.chengyunfeng.com/?p=458#ixzz2frrheoSi
相关文章
相关标签/搜索