開發應用的時候,應該檢查它是否有流暢的使用者體驗,即60fps的幀率。如果由於某種原因丟幀,我們首先要做的就是知道系統在做什麼(造成丟幀的原因)。
Systrace允許你監視和跟蹤Android系統的行為(trace)。它會告訴你係統都在哪些工作上花費時間、CPU週期都用在哪裡,甚至你可以看到每個執行緒、程序在指定時間內都在幹嘛。它同時還會突出觀測到的問題,從垃圾回收到渲染內容都可能是問題物件,甚至提供給你建議的解決方案。本文章將介紹如何匯出trace以及使用它來優化UI的辦法。
總覽
Systrace可以幫助你分析應用在不同Android系統上的執行情況。它將系統和應用的執行緒執行情況放置在同一條時間線上分析。你首先需要收集系統和應用的trace(後面會告訴你怎麼做),之後Systrace會幫你生成一份細緻、直觀的報告,它展示了裝置在你監測的這段時間內所發生的事情。
圖1. 連續滑動應用5秒的Trace,它並沒有表現得很完美。
圖1展示了應用在滑動不流暢的時候生成的trace。預設縮放成全域性顯示,你可以放大到自己所關注的地方。橫軸代表著時間線,事件記錄按照程序分組,同一個程序內按執行緒進行縱向拆分,每個執行緒記錄自己的工作。
在本例中,一共有三個組:Kernel, SurfaceFlinger, App,他們分別以包名為標識。每個應用程序都會包含其中所有執行緒的記錄訊號,你可以看到從InputEvent到RenderThread都有。
生成Trace
在獲取trace之前需要做一些啟動工作。首先,裝置要求API>=16(Android 4.1),之後通過正常的Debug流程(開啟除錯、連線工作環境、安裝App)連線裝置。由於需要記錄磁碟活動和核心工作,你可能需要root許可權。不過大部分時候你只要能夠正常Debug即可。
Systrace 可以通過命令列或者圖形介面啟動,本篇文章重點介紹通過命令列使用Systrace。
在Android 4.3及以上的系統中獲取trace
在4.3以上的系統獲取Trace步驟:
- 保證裝置USB連線正常,並可以debug;
- 在命令列中設定選項,開啟trace,比如:
1
2
3
|
$ cd android-sdk/platform-tools/systrace
$ python systrace.py --time=10 -o mynewtrace.html sched gfx view wm
|
- 在裝置上做任何你想讓trace記錄的操作。
你可以通過Systrace選項來了解更多命令列選項。
在Android 4.2及以下的系統中獲取trace
在4.2及以下的系統中高效地使用Systrace的話,你需要在配置的時候顯式指定要trace的程序種類。一共有這兩類種類:
- 普通系統程序,比如圖形、聲音、輸入等。(通過tags設定,具體在Systrace命令列中有介紹)
- 底層系統程序,比如CPU、核心、檔案系統活動。(通過options設定,具體在Systrace命令列中有介紹)
你可以通過以下命令列操作來設定tags:
- 使用
--set-tags
選項:
1
2
3
|
$ cd android-sdk/platform-tools/systrace
$ python systrace.py --set-tags=gfx,view,wm
|
- 重啟adb shell來trace這些程序:
1
2
3
|
$ adb shell stop
$ adb shell start
|
你也可以通過手機上的圖形介面設定tags:
- 在裝置上進入設定> 開發者選項 > 監控 > 啟用跟蹤(部分手機上沒有這個選項);
- 選擇追蹤程序型別,點選確認。
注意: 在圖形介面中設定tag時adb shell不用重新啟動。
在配置完tags後,你可以開始收集操作資訊了。
如何在當前設定下啟動trace:
- 保證裝置的usb連線正常,並且可以正常debug;
- 使用低系統等級的命令列選項開啟trace,比如:
$ python systrace.py --cpu-freq --cpu-load --time=10 -o mytracefile.html
- 在裝置上做任何你想讓trace記錄的操作。
你可以通過Systrace選項來了解更多命令列選項。
分析trace報告
在你獲取trace之後你可以在網頁瀏覽器中開啟它。這部分內容告訴你怎麼通過trace去分析和解決UI效能。
監視幀數
每個應用都有一行專門顯示frame,每一幀就顯示為一個綠色的圓圈。不過也有例外,當顯示為黃色或者紅色的時候,它的渲染時間超過了16.6ms(即達不到60fps的水準)。’w’鍵可以放大,看看這一幀的渲染過程中系統到底做了什麼。
提示:你可以按右上角的’?’按鈕來檢視介面使用幫助。
圖2. Systrace顯示長渲染時間的幀
單擊該幀可以高亮它,這時候跟該幀有關的內容會被突出顯示。在5.0及以上的系統中,顯示工作被拆分成UI執行緒和Render執行緒兩部分;在5.0以下的系統中,所有的顯示工作在UI執行緒中執行。
點選單個Frame下面的元件可以看他們所花費的時間。每個事件(比如performTraversals
)都會在你選中的時候顯示出它們呼叫了哪些方法及所用的時間。
調查警告事件
Systrace會自動分析事件,它會將任何它認為效能有問題的東西都高亮警告,並提示你要怎麼去優化。
圖3. 選擇一個被高亮幀,它會顯示出檢測到的問題(回收ListView消耗時間太長)。
在你選擇類似圖三中的問題幀之後,它就會提示你檢測出的問題。在這個例子中,它被警告的主要原因是ListView的回收和重新繫結花費太多時間。在Systrace中也會提供一些對應連結,它們會提供更多解釋。
如果你想知道UI執行緒怎麼會花費這麼多時間的話,你可以使用TraceView,它會告訴你都是哪些函式在消耗時間。
你可以通過右側的’Alert’選項卡來檢視整個trace過程中發生的所有問題,並進行快速定位。
圖4. 點選Alert選項卡。
你可以將Alert面板中的問題視為需要處理的bug,很有可能每一次微小的優化能夠去除整個應用中的警告!
應用級別除錯
Systrace並不會追蹤應用的所有工作,所以你可以在有需求的情況下自己新增要追蹤的程式碼部分。在Android 4.3及以上的程式碼中,你可以通過Trace
類來實現這個功能。它能夠讓你在任何時候跟蹤應用的一舉一動。在你獲取trace的過程中,Trace.beginSection()
與Trace.endSection()
之間程式碼工作會一直被追蹤。
下面這部分程式碼展示了使用Trace
的例子,在整個方法中含有兩個Trace塊。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
public void ProcessPeople() {
Trace.beginSection("ProcessPeople");
try {
Trace.beginSection("Processing Jane");
try {
// 待追蹤的程式碼
} finally {
Trace.endSection(); // 結束 "Processing Jane"
}
Trace.beginSection("Processing John");
try {
// 待追蹤的程式碼
} finally {
Trace.endSection(); // 結束 "Processing John"
}
} finally {
Trace.endSection(); // 結束 "ProcessPeople"
}
}
|
注意:在Trace是被巢狀在另一個Trace中的時候,
endSection()
方法只會結束理它最近的一個beginSection(String)
。即在一個Trace的過程中是無法中斷其他Trace的。所以你要保證endSection()
與beginSection(String)
呼叫次數匹配。注意:Trace的begin與end必須在同一執行緒之中執行!
當你使用應用級別追蹤的時候,你必須通過-a
或者-app=
來顯式地指定應用包名。可以通過Systrace指南檢視更多關於它的資訊。
你在評估應用的時候應該開啟應用級別跟蹤,即使當你沒有手動新增Trace
訊號。因為很多庫函式裡面是有新增Trace訊號的(比如RecyclerView
),它們往往能夠提供很多資訊。