Android性能分析工具systrace的使用,能根據須要抓取trace。html
瞭解trace文件中數據的含義,能分析簡單的性能問題。python
systrace是Android4.1版本以後推出的,對系統Performance分析的工具。chrome
systrace的功能包括跟蹤系統的I/O操做、內核工做隊列、CPU負載以及Android各個子系統的運行情況等。在Android平臺中,它主要由3部分組成:瀏覽器
內核部分:Systrace利用了Linux Kernel中的ftrace
功能。因此,若是要使用systrace的話,必須開啓kernel中和ftrace相關的模塊。緩存
數據採集部分:Android定義了一個Trace類。應用程序可利用該類把統計信息輸出給ftrace。同時,Android還有一個atrace
程序,它能夠從ftrace中讀取統計信息而後交給數據分析工具來處理。app
數據分析工具:Android提供一個systrace.py
(python腳本文件,位於Android SDK目錄/sdk/platform-tools/systrace
中,其內部將調用atrace程序)用來配置數據採集的方式(如採集數據的標籤、輸出文件名等)和收集ftrace統計數據並生成一個結果網頁文件供用戶查看。函數
簡單來講,當機器以60幀/秒顯示(也就是16.6 ms),用戶會感受機器會流暢。若是出現顯示時出現丟幀的狀況,就須要知道系統在作什麼?工具
Systrace 是用來收集系統和應用的數據信息和一些中間生成數據的細節,在Android 4.1系統和4.1以後的系統。性能
Systrace在一些分析顯示的問題上特別有用,如應用畫圖慢,顯示動做或動畫時變形。優化
進入Android/Sdk/platform-tools/systrace目錄下
python systrace.py -b 8000 -t 5 -o systrace.html
Google Chrome瀏覽器能夠打開systrace,若是打不開,能夠瀏覽器輸入chrome://tracing/
,而後load systrace。
options |
描述 |
---|---|
-o < FILE > |
輸出的目標文件 |
-t N, –time=N |
執行時間,默認5s |
-b N, –buf-size=N |
buffer大小(單位kB),用於限制trace總大小,默認無上限 |
-k < KFUNCS >,–ktrace=< KFUNCS > |
追蹤kernel函數,用逗號分隔 |
-a < APP_NAME >,–app=< APP_NAME > |
追蹤應用包名,用逗號分隔 |
–from-file=< FROM_FILE > |
從文件中建立互動的systrace |
-e < DEVICE_SERIAL >,–serial=< DEVICE_SERIAL > |
指定設備 |
-l, –list-categories |
列舉可用的tags |
說明1:-o trace輸出的文件路徑
說明2:--time 配置抓取systrace的時間,一般設置5秒,並在5秒內重現問題,時間過短會致使問題重現時沒有被抓到,時間太長會致使JavaHeap不夠而沒法保存,所以在能抓到問題點的狀況下,時間越小越好。
說明3:--buf-size Buffer Size是存儲systrace的size,一樣的,過小會致使信息丟失,時間太長會致使Java Heap不夠而沒法保存,建議20480。
說明4:若是用戶有本身在應用程序中加入本身的systrace log,以下:
Trace.beginSection("newInstance");
Trace.endSection("newInstance");
那麼此處必須選擇這個應用對應的進程名字,不然新加的systrace log不會被抓到。
在一些方法里加入trace 方便本身 跟蹤調試 , 以下:
Trace.traceBegin("performTraversals");
try {
……
} finally {
Trace.traceEnd();
}
須要保證 traceBegin 與 traceEnd 必定要成對出現。 而且必定要在同一個線程裏面。
加入trace的好處在於,生成的trace文件中,會在跟蹤的代碼段執行對應時間軸區間打上一個tag標記(好比上例中的performTraversals)
若是在代碼中加入了trace,在生成trace文件時,必須指定進程爲trace所在的進程。
在進程的上面有一條很細的進度條,包含了該線程的狀態:
灰色: 睡眠。
藍色: 能夠運行(它能夠運行,但還未被調度運行)。
綠色: 正在運行(調度程序認爲它正在運行)。
紅色: 不間斷的睡眠(一般發生在內核鎖上), 指出I / O負載,對於性能問題的調試很是有用
橙色: 因爲I / O負載致使的不間斷睡眠。
要查看不間斷睡眠的緣由(可從sched_blocked_reason跟蹤點獲取),請選擇紅色不間斷睡眠切片。
------------------------------------------------------------------------------------------------------------------------
同一個進程內按線程進行縱向拆分,每一個線程記錄本身的工做。分別以包名爲標識。每一個應用進程都會包含其中全部線程的記錄信號,能夠看到從InputEvent到RenderThread都有。
除了進程和線程運行信息,還有兩個重要信息:
每一個app都有一行專門顯示frame,每一幀就顯示爲圓圈,正常繪製是1秒60幀,大約一幀16.6毫秒,在這個值如下是正常顏色綠色,若是超過它就會變成紅色、黃色。非綠色的都說明有問題。這時須要經過’w’鍵放大那一幀,而後按‘m’鍵高亮,進一步分析問題。
以分析UI Performance爲例:
對於Android 5.0(API level 21)或者更高的設備,該問題主要聚焦在UI Thread
和Render Thread
這兩個線程當中。對於更早的版本,則全部工做在UI Thread
。
Systrace能自動分析trace中的事件,並能自動高亮性能問題做爲一個Alerts,建議調試人員下一步該怎麼作。
好比對於丟幀,點擊黃色或紅色的Frames圓點便會有相關的提示信息;另外,在systrace的最右上方,有一個Alerts tab能夠展開,這裏記錄着全部的的警告提示信息。
(1)當咱們點擊了Alerts或者點擊右邊的Alerts列表中的任何一點咱們能夠看到在界面的最底部會相對應的優化提示以及可能會出現優化的視頻教程連接。
好比上面的提示說你View的draw繪製花的時間太長了,而後咱們能夠根據Description來很明白的看到提示的內容是什麼。
(2)而後咱們可以點擊一塊Frames中的F來查看,一樣的它會生成一份跟Alerts相似的報告結果並放在界面的最底端。
(3)能夠經過按下m鍵查看這一幀到下一幀所花費的時間以及哪一個方法被調用的最長。看到時間>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.
能夠看出來系統提示你在getView中花費了太多時間沒能頗有效的複用機制。咱們就能順着這條路去找界面的代碼哪裏出現了不足從而優化完善。
(4)Alerts和Frames兩欄,它們展現了經過手機來的數據而生成出來的可視化分析結果。選擇最上方的alerts:
這個警告指出了,有一個View#draw()方法執行了比較長的時間。能夠在下面看到問題的描述,連接,甚至是相關的視頻。下面咱們看Frames這一行,能夠看到這裏展現了被繪製出來的每一幀,而且用綠、黃、紅三顏色來區分它們在繪製時的性能。
(5)frame一欄(點擊右側Alert type的Scheduling delay):在下方顯示欄,咱們看到了與這一幀所相關的一些警告。在這三個警告中,有一個是咱們上面所提到的(View#draw())。接下來咱們在這一幀處放大並在下方展開「Inflation during ListView recycling」這條警告:
可以看到警告部分的總耗時,32毫秒,遠高於了咱們對保障60fps所需的16毫秒繪製時間。同時還有更多的ListView每一個條目的繪製時間,大約是6毫秒每一個條目,總共五個。而Description描述項中的內容會幫助咱們理解問題,甚至提供問題的解決方案。
(6)能夠在「inflate」(某個函數方法)這一個塊區處放大,而且觀察究竟是哪些View在被填充過程當中耗時比較嚴重。
在選擇了某一幀以後,按「m」鍵來高亮這一幀,而且在上方看到了這一部分的耗時,如圖,咱們看到了這一陣的繪製總共耗時超過19毫秒。而當咱們展開這一幀惟一的一個警告時,咱們發現了「Scheduling delay」這條錯誤。
Scheduling delay(調度延遲)的意思就是一個線程在處理一塊運算的時候,在很長一段時間都沒有被分配到CPU上面作運算,從而致使這個線程在很長一段時間都沒有完成工做。咱們選擇這一幀中最長的一塊,從而獲得更加詳細的信息:
在紅框區域內,「Wall duration」,他表明着這一區塊的開始到結束的耗時。
CPU Duration一項中顯示了實際CPU在處理這一區塊所消耗的時間。
很顯然,兩個時間的差距仍是很是大的。整個區塊耗時18毫秒,而在這之中CPU只消耗了4毫秒的時間去運算。
這時候應該到最上面看Kernel中CPU在作什麼操做。
(7)在這一幀中選擇一個CPU,查看運行的進程和線程。
可能會因爲另一個程序佔用CPU,致使了咱們的程序未能得到足夠的CPU資源。
可是這種狀況實際上是暫時的,由於被其餘後臺應用佔用CPU的狀況並很少見,但仍有其餘應用的線程或是主線程佔用CPU。
(1)CPU
(2)在SurfaceFlinger上面有一個SurfaceView顯示buffer的數量
(3)VSYNC信號(一幀16.67ms)分爲:
VSYNC-app
VSYNC-sf
相互錯位,而且SF進行圖像混合的時候老是在每幀的最開始。不能超過一幀。
(4)SurfaceFlinger
在每幀的最開始,包含SurfaceFlinger模塊調用的各個函數。
主要有:
acquireBuffer從BufferQueue申請buffer
releaseBuffer 釋放buffer返回到BufferQueue
PS:若是Buffer數量過多,多是釋放buffern以前調用到display模塊的函數停滯太久。
(5)app的繪製
例如對手機camera進行拍照時抓取systrace,繪製的app就是camera。
繪製也是在一幀的開始(VSYNC-app)。
繪製中包含調用的各個函數。
主要有:
dequeueBuffer從BufferQueue申請buffer
queueBuffer返回buffer到BufferQueue
(6)LCD(HWC、display..)
顯示模塊,在app的下面,通常爲UI thread,包含在SF進行圖像混合後,將buffer傳遞到這個模塊。
在app的一幀中繪製好後,將信息傳遞到SF;
在VSYNC-sf下一幀開始時,SF進行圖像混合;
在SF圖像混合後進行LCD顯示(可能在SF混合的過程當中就已經調用到顯示模塊的函數,所以時間上可能會有交叉。)
例如TouchLatency,UI管道,一般包含如下階段:
SurfaceFlinger中的EventThread喚醒了應用程序UI線程,代表如今是渲染新幀的時候了。
應用程序使用CPU和GPU資源在UI線程,RenderThread和hwuiTasks中渲染幀。這部分暫UI的大部分。
應用程序經過binder將繪製好的幀發送到SurfaceFlinger並進入睡眠狀態。
SurfaceFlinger中的第二個EventThread喚醒SurfaceFlinger來觸發組合和顯示輸出。若是SurfaceFlinger肯定沒有任何工做要完成,它將返回睡眠狀態。
SurfaceFlinger經過HWC / HWC2或GL處理組合。 HWC / HWC2組合更快,更低的功耗,但會受到SOC的限制。這一步一般須要4-6ms,可是能夠與步驟2重疊,由於Android應用程序老是三重緩衝。 (雖然應用程序老是三重緩衝,但在SurfaceFlinger中只能有一個待處理幀,所以和雙重緩存差很少。)
SurfaceFlinger通過供應商驅動程序調度最終輸出,並返回睡眠狀態,等待EventThread喚醒。
導航操做 |
做用 |
---|---|
w |
放大,[+shift]速度更快 |
s |
縮小,[+shift]速度更快 |
a |
左移,[+shift]速度更快 |
d |
右移,[+shift]速度更快 |
經常使用操做 |
做用 |
---|---|
f |
放大當前選定區域(放大選定的一塊) |
m |
標記當前選定區域(能夠顯示時間長度) |
v |
高亮VSync(所在的一幀) |
g |
切換是否顯示60hz的網格線(同上) |
0 |
恢復trace到初始態,這裏是數字0而非字母o(縮小到初始) |
通常操做 |
做用 |
---|---|
h |
切換是否顯示詳情 |
/ |
搜索關鍵字 |
enter |
顯示搜索結果,可經過← →定位搜索結果 |
` |
顯示/隱藏腳本控制檯 |
? |
顯示幫助功能 |
Select mode: 雙擊已選定區能將全部相同的塊高亮選中;(對應數字1)
Pan mode: 拖動平移視圖(對應數字2)
Zoom mode:經過上/下拖動鼠標來實現放大/縮小功能;(對應數字3)
Timing mode:拖動來建立或移除時間窗口線。(對應數字4)
可經過按數字1~4,用於切換鼠標模式; 另外,按住alt鍵,再滾動鼠標滾輪能實現放大/縮小功能。