經做者受權,發表Tieto某青年牛的一篇《程序員》大做。 html
在軟件開發過程當中,想必不少讀者都遇到過系統性能問題。而解決系統性能問題的幾個主要步驟是: java
由上述步驟可知,性能優化的目標對象是hotspot。若是找到的hotspot並不是真正的熱點,則性能優化的結果必然是事倍功半甚至竹籃打水一場空。因此,做爲Android性能調優相關知識的第一部分,本篇首先將向讀者介紹Android平臺中三個重要的性能測試工具,它們能很好得幫助開發者找到hotspot。 python
Traceview是Android平臺特有的數據採集和分析工具,它主要用於分析Android中應用程序的hotspot。Traceview自己只是一個數據分析工具,而數據的採集則須要使用Android SDK中的Debug類或者利用DDMS工具。兩者的用法以下: linux
圖1-1 DDMS中Traceview使用示意圖 android
點擊圖1-1中所示按鈕便可以採集目標進程的數據。當中止採集時,DDMS會自動觸發Traceview工具來瀏覽採集數據。 程序員
下面,咱們經過一個示例程序向讀者介紹Debug類以及Traceview的使用。 瀏覽器
示例程序運行時的界面如圖1-2所示: 性能優化
圖1-2 示例界面圖 架構
圖1-2中: composer
該示例的關鍵代碼如圖1-3所示:
圖1-3示例代碼
由圖1-3可知:
如今,咱們用Traceview工具將測試結果文件TraceviewDemo.trace打開。
Traceview界面比較複雜,其UI劃分爲上下兩個面板,即Timeline Panel(時間線面板)和Profile Panel(分析面板)。圖1-4所示爲Timeline Panel界面:
圖1-4 Traceview Timeline Panel示意圖
圖1-4中的Timeline Panel又可細分爲左右兩個Pane:
如今來看Traceview的Profile Panel界面,如圖1-5所示:
圖1-5 TraceviewProfile Panel界面
Profile Panel是Traceview的核心界面,其內涵很是豐富。它主要展現了某個線程(先在Timeline Panel中選擇線程)中各個函數調用的狀況,包括CPU使用時間、調用次數等信息。而這些信息正是查找hotspot的關鍵依據。因此,對開發者而言,必定要了解Profile Panel中各列的含義。筆者總結了其中幾個重要列的做用,如表1-1所示:
表1-1 Profile Panel各列做用說明
列名 |
描述 |
Name |
該線程運行過程當中所調用的函數名 |
Incl Cpu Time |
某函數佔用的CPU時間,包含內部調用其它函數的CPU時間 |
Excl Cpu Time |
某函數佔用的CPU時間,但不含內部調用其它函數所佔用的CPU時間 |
Incl Real Time |
某函數運行的真實時間(以毫秒爲單位),內含調用其它函數所佔用的真實時間 |
Excl Real Time |
某函數運行的真實時間(以毫秒爲單位),不含調用其它函數所佔用的真實時間 |
Call+Recur Calls/Total |
某函數被調用次數以及遞歸調用佔總調用次數的百分比 |
Cpu Time/Call |
某函數調用CPU時間與調用次數的比。至關於該函數平均執行時間 |
Real Time/Call |
同CPU Time/Call相似,只不過統計單位換成了真實時間 |
另外,每個Time列還對應有一個用時間百分比來統計的列(如Incl Cpu Time列對應還有一個列名爲Incl Cpu Time %的列,表示以時間百分比來統計的Incl Cpu Time)。
瞭解完Traceview的UI後,如今介紹如何利用Traceview來查找hotspot。
通常而言,hotspot包括兩種類型的函數:
首先,咱們來查找hotspot 1。
在Profile Panel中,選擇按Cpu Time/Call進行降序排序(從上之下排列,每項的耗費時間由高到低),獲得如圖1-6所示的結果:
圖1-6 按CPU Time/Call降序排列數據
圖1-6中:
相對來講,類型1的hotspot比較好找,步驟是先按降序對時間項進行排列(能夠是時間百分比、真實時間或CPU時間),而後查找耗費時間最多的函數。通常而言,先應對應用程序本身實現的函數進行排查,Framework的函數也有多是hotspot,但主因通常仍是在應用自己(例如設置複雜的界面,致使對應XML解析很是慢)。
如今,咱們來看如何查找類型2的hotspot。
點擊Call/Recur Calls/Total列頭,使之按降序排列。關注點放在那些調用頻繁而且佔用資源較多的函數。圖1-7爲降序排列的結果圖。
圖1-7類型2 Hotspot查找過程示意之一
圖1-7所示的運行最頻繁的幾個函數中,咱們發現了幾個懷疑點,由圖中的1和2箭頭標示。
第一次查找的潛在點被排除後,繼續瀏覽數據,獲得如圖1-8所示的結果。
圖1-8 類型2 Hotspot查找過程示意之二
在圖1-8中:
找到hotspot以後,開發者就須要結合代碼來進行對應的優化了。關於Java代碼優化,讀者可參考以下資料:http://developer.android.com/training/articles/perf-tips.html
整體而言,Hotspot的查找是一個細緻的工做,須要開發者對目標程序的代碼,以及Traceview工具都比較熟悉才行。
Traceview工具是Android平臺應用程序性能分析的利器。不過筆者以爲它的UI仍是有些複雜。而且使用時感受流暢度不夠好。
Google官方關於Traceview的介紹可參考如下連接,不過其內容以及較久未更新了。http://developer.android.com/tools/debugging/debugging-tracing.html。
Systrace是Android4.1中新增的性能數據採樣和分析工具。它可幫助開發者收集Android關鍵子系統(如surfaceflinger、WindowManagerService等Framework部分關鍵模塊、服務)的運行信息,從而幫助開發者更直觀的分析系統瓶頸,改進性能。
Systrace的功能包括跟蹤系統的I/O操做、內核工做隊列、CPU負載以及Android各個子系統的運行情況等。在Android平臺中,它主要由3部分組成:
從本質上說,Systrace是對Linux Kernel中ftrace的封裝。應用進程須要利用Android提供的Trace類來使用Systrace。Android 4.1爲系統中的幾個關鍵進程和模塊都添加了Systrace功能。以顯示系統中重要模塊Hwcomposer爲例,其代碼中使用Systrace的方法如圖2-1所示:
圖2-1 Hwcomposer模塊Systrace使用示例
圖2-1中,應用程序只要經過三個宏就可以使用Systrace了:
因爲篇幅關係,關於Trace使用更多的信息請讀者閱讀frameworks/native/include/utils/Trace.h或者android.os.Trace類。下面,咱們經過一個示例來展現Systrace的使用。
首先,在PC機上運行以下命令以啓動Systrace,如圖2-2所示:
圖2-2 Systrace操做步驟
執行上述命令後,將獲得一個名爲trace.html的文件(trace.html是默認文件名,讀者也可在命令行中指定其餘文件名)。經過瀏覽器打開此文件,結果如圖2-3所示:
圖 2-3 trace.html內容示意
圖2-3中所示的trace.html頁面內容和Traceview的Timeline Panel很是相似。圖中包含的內容以下:
圖2-1中,CPU信息如下的行就是經過Trace.h提供的宏而添加的統計信息,其中:
表2-1所示爲CPU狀態取值信息:
表2-1 CPU狀態
C-state |
描述 |
C-0 |
RUN MODE,運行模式。 |
C-1 |
STANDBY,就位模式,隨時準備投入運行 |
C-2 |
DORMANT,休眠狀態,被喚醒投入運行時有必定的延遲 |
C-3 |
SHUTDOWN,關閉狀態,須要有較長的延遲才能進入運行狀態,減小耗電 |
整體來講,Systrace比Traceview用途更普遍,它支持對CPU、Native進程甚至Kernel線程進行性能數據採樣,可幫助開發者對整個系統的性能狀況進行一個詳盡的分析。不過其用法比Traceview要複雜,並且還須要對Kernel作一些配置調整。
Android官方對Systrace也有一些介紹,請讀者閱讀:
http://developer.android.com/tools/debugging/systrace.html
Oprofile是另外一個功能更強大的性能數據採集和分析工具,其工做原理以下:
Android默認提供了對Oprofile的支持,其組成包括:
表3-1 opcontrol經常使用選項
opcontrol選項 |
功能 |
--list-events |
列出當前CPU所支持的事件 |
--setup |
對測評進行設置,好比關閉舊的守護進程、掛載oprofilefs |
--vmlinux= |
設置將要分析的Android內核鏡像文件 |
--callgraph |
設置跟蹤函數調用的層數 |
--kernel-range=start,end |
內核二進制文件起始和結束的虛擬地址 |
--start/--stop |
開始/中止採樣 |
--event=name:count:unitmask:kernel:user |
設置對某事件進行採樣。 Name:事件的名字 Count:採樣時事件發生的次數Unitmask:事件的掩碼(CPU支持的事件以及掩碼見oprofile的文檔) Kernel:是否採樣內核事件 User:是否採樣用戶事件 |
表3-2 opreport經常使用選項
opreprt選項 |
功能 |
-l |
顯示函數調用的符號名字 |
-g |
以調試的形式打印函數符號,包括函數所在文件及行數等。 |
-c |
顯示函數調用堆棧 |
-o |
報告輸出到指定文件 |
另外,Android提供了一個特別的工具opimport_pull。它可把採樣數據從手機中pull到PC上,並對數據進行一些簡單處理以供opreport使用。因此,在Android平臺上,開發者只要使用opimport_pull了就能夠了。
如今,咱們來看Oprofile的使用實例。
Oprofile的使用大致能夠分紅如下三步:
下面分別來看這三個步驟:
以下所示爲內核配置的示例,如圖3-1所示:
圖3-1 Oprofile內核配置示意
運行Oprofile須要root權限,因此目標設備中最好運行的是userdebug或者engineer版本的Android OS。
Oprofile用戶空間配置的示例如圖3-2所示。假設當前目錄爲Android源碼根目錄,而且已經初始化Android編譯環境(執行完畢build/envsetup.sh和lunch)。
圖3-2 Oprofile用戶空間配置示意
用戶空間的配置主要經過執行opcontrol命令來完成。而opcontrol內部是經過往oprofilefs傳遞對應的控制參數來完成的。例如圖3-2中「opcontrol --callgraph=16」命令也可經過「echo 16> /dev/oprofile/backtrace_depth」來實現。
在上一步中,咱們已經獲取了測評採樣的數據。如今,就可使用它們來生成採樣報告了,方法如圖3-3所示:
圖3-3 oprofile生成採樣報告方法示意
圖3-4爲報告的一部份內容:
圖3-4 Oprofile測評報告概要
圖3-4中,咱們發現libc.so調用的採樣數爲117299,排第4位。那麼libc.so中哪一個函數調用次數最多呢?開發者可經過以下命令獲取libc.so的更爲詳細的信息。方法如圖3-5所示:
圖3-5 opreport使用示例
執行上述命令後的結果如圖3-6所示:
圖3-6 Oprofile關於libc的詳細結果
由圖3-6可知,memcpy()函數佔用最多的CPU資源。因此能夠考慮優化memcpy()。
此處,筆者針對Cortex-A9雙核SMP處理器,使用ARM彙編的方法對memcpy進行了優化。優化後的結果如圖3-7所示。對比圖3-6和圖3-7可明顯看出,優化後的memcpy對資源的佔用下降了2.7個百分點。
圖3-7 優化memcpy()後的測試結果
在性能分析中,Oprofile無疑是一個使用最普遍、功能最強大的測評工具。對於Android平臺開發者來講,它能夠採集和分析整個系統的運行狀態信息,對於分析查找系統瓶頸進而優化系統具備重大意義。
性能調優向來是一件「高深莫測」的任務,但打破它們神祕面紗的工具就是上文所述的工具了。因此,對有志開展這方面工做的讀者而言,首要一步的工做就是先了解各個工具的做用及優缺點。
除了本文介紹的這三個工具外,Android系統還支持其餘一些更有針對性的測試工具,例如用於測評系統總體功能的lmbench,lttng、測試系統啓動性能的bootchart、測試文件系統性能的iozone等。因爲篇幅關係,筆者就再也不一一介紹它們了。
[1]關於VSYNC的詳情,讀者可參考http://blog.csdn.net/innost/article/details/8272867,「Android Project Butter分析「一文。