这是Google的Android开发工程师Romain Guy刊登在个人Blog上的一篇文章。Romain Guy 作为Android图形渲染和系统优化的专家,是Android 4.1中的“黄油项目”开发者之一。这篇译文将分为上下两个部分,上部分将通过一个实际的例子来展示如何利用现有的工具来定位Android应用程序的性能瓶颈,下部分将提供一些有效的方法来解决性能问题。希望能给读者和开发者带来启发和借 鉴。
Falcon Pro
最近我在我的Nexus4上安装了Falcon Pro(下 图),一个新款的推特(Twitter)客户端。我觉得这款应用真的很赞,但我也注意到一些使用时的瑕疵:似乎在划屏滚动主界面的时间轴时,帧率并不能很 稳定。于是我利用我每天工作中所使用的工具和方法对此稍加研究,很快发现了Falcon Pro不能达到其应有性能的一些原因。
我这篇文章的主旨在于告诉你如何在一个应用中追踪和定位性能问题,甚至在没有它的源代码的情况下。你所要做的只是要获得最新的Android4.2SDK(最新的ADT工具可以帮你轻而易举的完成此事)。我强烈推荐你“能够”去下载这款有待研究的应用。不幸的是,Falcon Pro是一款付费应用,我因此只能提供一些文件的链接以便你能对照我的分析。
说说关于性能优化
Android4.1通过“黄油项目”将焦点放在性能优化上,并且它也引入了一些性能分析的工具,比如systrace。Android4.2并没有提供像systrace那样显著的工具,但也为你的工具集增加了一些很有用的功能。你将会在接下来的篇幅中发现到它们。(黄油计划 Project Butter,是Google在 Android 4.1 Jellybean版本开始启动的Android性能提升计划,其寓意为“像黄油一样顺滑”,该项目主要针对Android长期以来的饱受诟病的运行流畅度问题,通过底层的优化,确保系统设备能达到60fps的帧刷新率,从而大大提高用户体验的流畅性——译者注)
性能分析通常是一项复杂的任务,它需要大量的经验,需要对工具,硬件,API等方面的深入理解。这些经验让我在这只要几分钟就可以做出分析(你可以在我12月1日的推特(Twitter)上看到它的实况转播。)而你可能得试上几次后才能对此得心应手。
证实我的疑问
记 忆中关于性能优化最重要的一件事就是通过量化来验证你的工作。即使对我而言,Falcon Pro在的Nexus4上有着很明显的丢帧现象,我仍然得用实际的数据来证明。因此我将这款应用安装到Nexus7上,因为Nexus7比Nexus4性 能更强大,同时Nexus7在性能分析上也有着比Neux4更有意思的优势,关于这一点,我将在稍后加以讨论。
这 款应用安装到Nexus7上也没有出现多大差别,我仍然能看到丢帧的现象甚至还略差。为了量化这个问题,我决定使用“Profile GPU rendering”(GPU渲染分析),一款Android4.1所引入的工具。你可以在“设置”应用的“开发者选项”中找到这个工具。
如果开发者选项在你的Android4.2设备上不可见,你可以在“关于手机”或者“关于桌面选择”的界面底部,点击“版本号”七次。
当这个选项打开,系统将会记录画每个窗口绘画最后128帧所需要的时间。在使用这个工具前,你得先杀掉这个应用(Android未来的版本将会去掉这个要求)。
方法:
除非特别需要,在为这个分析做每一次测量时,需缓慢的滚动主界面的时间轴,让其滚动一段像素,使其能展现额外的条目。
在重新启动这个应用并滚动时间轴主界面时,我在终端上运行了下面这个命令:
$ adb shell dumpsys gfxinfo com.jv.falcon.pro
在 产生的日志中,你会发现一段标记为“Profile”的毫秒量级的数据。这段数据包含了一个有三列数据的表,应用的每个window(窗口)都有一个这样 的表。为了使用这个数据,你可以简单的将这个表拷到你最喜欢的电子制表软件中,从而生成一个数据堆叠的列图。以下这个图就是我的测量结果。
每一列给出了每一帧花在渲染上的时间估计:
“Draw”是指Java层用在创建“display lists”(显示列表)上的时间。它表明运行例如View.onDraw(Canvas)需要多少时间。
“Process”是指Android 2D渲染引擎用在执行“display lists”上的时间。你的UI层级(hierarchy)中的View数量越多,需要执行的绘画命令就越多。
“Execute”是指将一帧图像交给合成器(compositor)的时间。这部分占用的时间通常比较少
提醒:
要以60fps的帧率进行平滑的渲染,每一帧所占用的时间需要少于16ms。
关于“Execute”:
如 果Excute花费很多时间,这就意味着你跑在了系统绘图流水线的前面。Android在运行状态时最多可以用3块缓存,如果此时你的应用还需要一块缓 存,那应用就会被阻塞直到三块中的一块缓存被释放。这种情况的发生一般有两个原因。第一个原因是你的应用在Dalvik(java虚拟机)端画的太快,而 在它的Display list在GPU端执行太慢。第二个原因是你的应用花费太多时间在前几帧的渲染上,一旦流水线满了,它就跟不上,直到动画的完成。这些是我们想在下一个版 本的Android改进的地方。
以上这个图明显的证实了我的疑虑:这个应用在大部分时间运行良好,但某些时候会发生丢帧。
进一步研究
我们收集的数据显示这个应用有时绘图时间过长,但盖棺定论还为时过早。帧率也会被未调度的帧或者错过调度的帧的影响。例如,如果应用总是在16ms内完成一次绘图,但有时在帧与帧之间需要完成很长的任务,它就会因此错过一帧。
Systrace是一个很简单的工具去检查Falcon Pro是否存在这个问题。这个工具是系统级的,额外开销很低。它的时间统计是合理准确的,能给你一个整个系统运行的概况,包括你的应用。
开启Systrace,可以到开发者选项中选择“启动跟踪”,弹出一个对话框,会让你选择你想测量哪些方面的性能。我们只关注“Graphics”和“View”。
注意:
不要忘记关掉之前的GPU渲染分析选项。
使用systrace时,可以打开终端,在Android SDK的tools/systrace目录下,运行systrace.py:
$./systrace.py
这个工具默认会记录5秒钟内发生的事件。我简单的向上和向下滚动时间轴,得到了一个用HTML文档展现的结果图。
技巧:
浏览systrace的文档图,可以使用键盘上的WASD键去移动和缩放。W键是将鼠标所处位置进行放大。
systrace 的文档图显示了很多有意思的信息。例如,它可以显示一个进程是否被调度,是在哪个CPU上调度。如果你放大最后一行(叫做 10440:m.jv.falcon.pro),你可以看到这个应用正在做什么。如果你点击一个“performTraversals”块,你可以看到这 个应用花在输出一帧图像上面多长时间。
大多数的performTraversals显示在16ms临界值以下,但有一些需要更多的时间,因此也证实了之前的猜测。(在935毫秒处放大可以看到这个块。)
更 有意思的是,你可以看到这个应用有时错过一帧是因为它没有管理调度一个draw的操作。在270ms处放大,找到占用25ms的 “deliverInputEvent”块。这个块表明这个应用用了25ms来处理一个触摸事件。考虑到这个应用是使用ListView,很有可能是这个 适配器(adapter)出了问题,等会我们再来探讨这个。Systrace很有用的地方不仅在于证实这个应用花在绘图的时间上太长,也在于帮我们找到另 一个潜在的性能瓶颈。它很有用但也有局限。它只能提供高层级的数据,我们必须转向其他工具来理解此时究竟在运行什么。
可视化重绘
绘 图性能问题有很多根本的原因,但共同的一点是重绘(overdraw)。重绘发生在每次应用让系统在某个画好的地方上面再画别的。想一个最简单的应用:一 个白色背景的窗口(window),上面是一个按钮。当系统要画这个按钮时,它要画在已经画好的白色背景的上面。这就是重绘。重绘是必然的,但太多的重绘 就是个问题。设备的数据传输带宽是有限的,当重绘使得你的应用需要更多的带宽时,性能就会下降。不同的设备能够承担的重绘的代价是不同的。
最佳的准则是重绘的最大次数不能超过两次。这就意味着你可以在屏幕画第一次,然后在这个屏幕上再画第二次,最后在其中某些像素上再画第三次。
重绘的存在通常表明有这些问题:太多的View,复杂的层级,更长的inflation时间等等。
Android提供了三个工具来帮助辨别和解决重绘问题:Hierachy Viewer,Tracer for OpenGL和Show GPU overdraw。前两个可以在ADT工具或者独立的monitor工具中找到,最后一个是在开发者选项的一部分。
Show GPU Overdraw会在屏幕上画不同的颜色来辨别重绘发生在哪儿,重绘了几次。现在就开启它并且别忘了先杀掉你的应用(将来版本的Android会去掉这个要求)。
在我们查看Falcon Pro之前,让我们先看看当打开Show GPU overdraw,“设置”应用是什么样子。
如果你记得每种颜色所表示的含义,你就能很容易的知道结果是什么:
没有颜色就表示没有重绘。每个像素只画了一次。在这个例子里,你可以看到背景是完全无色的。
蓝色:表示重绘了一次。每个像素只画了两次。大块的蓝色是可以接受的。(如果整个window是蓝色的,你就可以使用一个图层(layer)。)
绿色:表示重绘了两次。每个像素画了三次。中等尺寸的绿色方块是可以接受的,但你最好尝试做出优化。
红色:表示重绘了三次。这个像素被画了四次。很小尺寸的红色方块是可以接受的。
黑色:表示重绘了四次及以上。这个像素被画了五次及以上。这个是错的,需要解决。
基于这些信息,你可以看到“设置”应用表现地很好,不需要额外的改进。只有在切换时有一点点红块,但不需要我们再做什么工作了。
透明像素:
再 仔细看看之前的截图。每一个图标都画成了蓝色。你可以看出位图(bitmap)中透明像素是解决了重绘的问题。透明像素必须由GPU处理,开销是昂贵的。 Android为了避免在图层(layer)和9-patches上绘画透明像素,做了优化,所以你只要考虑位图就行了。
重绘和GPU:
有 两种移动GPU架构。第一个使用延迟渲染,比如ImaginationTech的SGX系列。这种架构允许GPU在某些特定的场景下检查和处理重绘。(如 果你混合透明和不透明的像素,它有可能不起作用。) 第二钟架构使用及时渲染,它被NVIDIA的TegraGPU采用。这种架构不能为你优化重绘,这就是为什么我喜欢在Nexus7上测试(Nexus7使 用Tegra3)。这两种架构各有优劣。但这已经超出了本文的主题。仅仅只要知道两者都可以工作的很好就行了。现在就让我们看一下Falcon Pro…
截图上有大量的红色!最感兴趣的却是列表的背景是绿色的。这就显示在应用程序开始描绘它的内容前已经发生了两次重绘。我们这里所看到问题很有可能是和使用了许多全屏图片背景相关。但要解决这个问题通常是很繁琐的。
英文原文:http://www.curious-creature.org/docs/android-performance-case-study-1.html
原译文地址: http://www.importnew.com/3784.html