[轉] 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
相關文章
相關標籤/搜索