簡介
trace [tres] vt.跟蹤,追蹤; 追溯,探索; 探索; 查找; n.痕跡; 痕跡,蹤跡; 微量,極少量;
1
1
1
trace [tres] vt.跟蹤,追蹤; 追溯,探索; 探索; 查找; n.痕跡; 痕跡,蹤跡; 微量,極少量;
Systrace允許你
監視和跟蹤Android系統的行為,它會告訴你
系統都在哪些工作上花費時間、CPU周期都用在哪里,甚至你
可以看到每個線程、進程在指定時間內都在干嘛。它同時還會
突出觀測到的問題,從垃圾回收到渲染內容都可能是問題對象,甚至
提供給你建議的解決方案。
Systrace的功能包括
跟蹤系統的I/O操作、內核工作隊列、CPU負載以及Android各個子系統的運行狀況等。在Android平台中,它主要由3部分組成:
- 內核部分:Systrace利用了Linux Kernel中的ftrace功能,所以,如果要使用Systrace的話,必須開啟kernel中和ftrace相關的模塊。
- 數據采集部分:Android定義了一個Trace類,應用程序可利用該類把統計信息輸出給ftrace。同時,Android還有一個atrace程序,它可以從ftrace中讀取統計信息然后交給數據分析工具來處理。
- 數據分析工具:Android提供一個systrace.py(python腳本文件,位於Android SDK目錄/tools/systrace中,其內部將調用atrace程序)用來配置數據采集的方式(如采集數據的標簽、輸出文件名等)和收集ftrace統計數據並生成一個結果網頁文件供用戶查看。從本質上說,Systrace是對Linux Kernel中ftrace的封裝。應用進程需要利用Android提供的Trace類來使用Systrace。
啟動Systrace
Systrace是Android4.1中新增的,所以
要求要生成Trace的手機在Android 4.1以上。
Systrace工具可以在sdk/platform-tools/ 中找,源碼位於external/chromium-trace下面。
Systrace可以通過命令行,Eclipse,Android Studio等方式啟動。
【Using Android Studio】
- 1.In Android Studio, open an Android application project. 1.Open the Device Monitor by selecting Tools > Android > Monitor.
- 2.In the Devices tab, select the device on which to run a trace. If no devices are listed, make sure your device is connected via USB cable and that debugging is enabled on the device.
- 3.Click the Systrace icon at the top of the Devices panel to configure tracing.
- 4.Set the tracing options and click OK to start the trace.

【Using Eclipse】
- 1.In Eclipse, open an Android application project. 1.Switch to the DDMS perspective, by selecting Window > Perspectives > DDMS.
- 2.In the Devices tab, select the device on which to run a trace. If no devices are listed, make sure your device is connected via USB cable and that debugging is enabled on the device.
- 3.Click the Systrace icon at the top of the Devices panel to configure tracing.
- 4.Set the tracing options and click OK to start the trace.

【Using Device Monitor】
- 1.Navigate to your SDK tools/ directory. 1.Run the monitor program.
- 2.In the Devices tab, select the device on which to run a trace. If no devices are listed, make sure your device is connected via USB cable and that debugging is enabled on the device.
- 3.Click the Systrace icon at the top of the Devices panel to configure tracing.
- 4.Set the tracing options and click OK to start the trace.
生成Trace分析文檔
生成Trace分析文檔的步驟如下:
- 打開手機調試模式,連接手機,運行APP
- 啟動Systrace
- 手機准備好你要進行抓取的界面
- 配置文件路徑、抓取時間等
- 點擊確定后開始操作手機,在時間到了后會自動生成報表(這個文件至少也有好幾兆)
- 使用Chrome(其他瀏覽器很可能打不開)將這個文件打開進行分析
Systrace的一些配置

- duration:抓取時間,通常設置5秒,並在5秒內重現問題,時間太短會導致問題重現時沒有被抓到,時間太長會導致JavaHeap不夠而無法保存。因此在能抓到問題點的情況下,時間越小越好。
- Buffer Size:存儲Systrace的size,同樣太小會導致信息丟失,太長會導致Java Heap不夠而無法保存,建議【20480】。如果檢測結果有異常,請調整Buffer Size的大小試試。
- Application:檢測的應用,默認選擇none
- Commonly Used Tag:常用標簽,這部分TAG全部使能上。只關注顯示情況的話 ,只選取Graphics和View System就可以。
- Advanced Options:高級選項。如果設備root了,可以看到更多的TAG,如eMMC commands/ Synchonization/Kernel Workqueues。
測試時發現,5.1的華為手機點擊確定后報以下誤:
Unexpected error while collecting system trace.
Unable to find trace start marker 'TRACE:':error opening /sys/kernel/debug/tracing/options/overwrite: No such file or directory
2
2
1
Unexpected error while collecting system trace.
2
Unable to find trace start marker 'TRACE:':error opening /sys/kernel/debug/tracing/options/overwrite: No such file or directory
而7.0的三星手機正常
打開Trace文檔
可以用
Chrome瀏覽器打開生成的trace文件。
瀏覽時可以使用w/s/a/d快捷鍵來放大、縮小、移動等操作。
可以點擊右上角的?號來查看等多的操作。
Key | Description |
w | Zoom into the trace timeline. |
s | Zoom out of the trace timeline. |
a | Pan left on the trace timeline. |
d | Pan right on the trace timeline. |
e | Center the trace timeline on the current mouse location. |
g | Show grid at the start of the currently selected task. |
Shift+g | Show grid at the end of the currently selected task. |
Right Arrow | Select the next event on the currently selected timeline. |
Left Arrow | Select the previous event on the currently selected timeline. |
雙擊 |
Zoom into the trace timeline. |
Shift+雙擊 | Zoom out of the trace timeline. |
分析Trace文檔--簡介
縱軸代表着時間線,事件記錄按照進程分組,同一個進程內按線程進行縱向拆分,每個線程記錄自己的工作,可收縮/展開。
在本例中,一共有三個組:Kernel, SurfaceFlinger, App,他們分別以
包名為標識。
每個應用進程都會包含其中
所有線程的記錄信號,你可以看到從InputEvent到RenderThread都有。
除了進程和線程運行信息,還有兩個重要信息:
【Frame】
在每個app進程,都有一個Frames行,正常情況以綠色的圓點表示。當圓點顏色為黃色或者紅色時,意味着這一幀超過16.6ms(即發現丟幀),這時需要通過放大那一幀進一步分析問題。對於Android 5.0(API level 21)或者更高的設備,該問題主要聚焦在UI Thread和Render Thread這兩個線程當中。對於更早的版本,則所有工作在UI Thread。
【Alerts】
Systrace能自動分析trace中的事件,並能自動高亮性能問題作為一個Alerts,建議調試人員下一步該怎么做。
比如對於丟幀時,點擊黃色或紅色的Frames圓點便會有相關的提示信息;另外,在systrace的最右側,有一個Alerts tab可以展開,這里記錄着所有的的警告提示信息。
當我們點擊了Alerts或者點擊右邊的Alerts列表中的任何一點,我們可以看到,在界面的最底部,會有相對應的優化提示,以及可能會出現優化的視頻教程鏈接。
比如上面的提示說你View的draw繪制花的時間太長了,然后我們可以根據Description來很明白的看到提示的內容是什么。

然后我們可以點擊一塊Frames中的F來查看,同樣的它會生成一份跟Alerts類似的報告結果並放在界面的最低端。
我們可以通過按下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.
//ListView項目回收涉及inflating視圖。 確保您的Adapter#getView() 循環使用傳入的View,而不是構建新的View。
1
Description :ListView item recycling involved inflating views. Ensure your Adapter#getView() recycles the incoming View, instead of constructing a new one.
2
//ListView項目回收涉及inflating視圖。 確保您的Adapter#getView() 循環使用傳入的View,而不是構建新的View。
根據系統提示,我們就能順着這條路去找界面的代碼哪里出現了不足從而優化完善。
當然Systrace
無法幫你定位到代碼里面的具體到某一行代碼,但是我們可以通過Alerts和Frames來能基本上優化了不足的地方,然后我們可以根據
TraceView來分析具體函數花了多長時間來進一步優化代碼提高性能。
分析Trace文檔--案例
上面介紹了Systrace中不同區域的功能,當然最有趣的還是
Alerts和Frames
兩欄,讓我們來選擇最上方的Alerts瞧瞧:

這個警告指出了,有一個View#draw()方法執行了比較長的時間。我們可以在下面看到問題的描述、鏈接,甚至是相關的視頻。
下面我們看Frames這一行,可以看到這里展示了被繪制出來的每一幀,並且用綠、黃、紅三顏色來區分它們在繪制時的性能。我們選一個紅色幀來瞅瞅:

在最下方,我們看到了與這一幀所相關的一些警告。
在這三個警告中,有一個是我們上面所提到的(View#draw())。接下來我們在這一幀處放大並在下方展開“Inflation during ListView recycling”這條警告:

我們可以看到警告部分的總耗時32毫秒,遠高於了我們對保障60fps所需的16.6毫秒繪制時間。
同時還有更多的ListView每個條目的繪制時間,大約是6毫秒每個條目,總共五個。而Description描述項中的內容會幫助我們理解問題,甚至提供問題的解決方案。回到我們上一張圖片,我們可以在“inflate”這一個塊區處放大,並且觀察到底是哪些View在被填充過程中耗時比較嚴重。
下面是另外一個渲染過慢的實例:

在選擇了某一幀之后,我們可以按“m”鍵來高亮這一幀,並且在上方看到了這一部分的耗時,如圖,我們看到了這一陣的繪制總共耗時大約19毫秒。而當我們展開這一幀唯一的一個警告時,我們發現了“Scheduling delay”這條錯誤。
Scheduling delay(調度延遲)的意思就是一個線程在處理一塊運算的時候,在很長一段時間都沒有被分配到CPU上面做運算,從而導致這個線程在很長一段時間都沒有完成工作。我們選擇這一幀中最長的一塊,從而得到更加詳細的信息:

在紅框區域內,我們看到了“Wall duration”,他代表着這一區塊的開始到結束的耗時。之所以叫作“Wall duration”,是因為他就像是牆上的一個時鍾,從線程的一開始就為你計時。
而CPU Duration一項中顯示了實際CPU在處理這一區塊所消耗的時間。
很顯然,兩個時間的差距還是非常大的。整個區塊耗時18毫秒,而在這之中CPU只消耗了4毫秒的時間去運算。這就有點奇怪了,所以我們應該看一下在這整個過程之中,CPU去干嗎了。

可以看到,所有四個線程都非常的繁忙。
選擇其中的一個線程會告訴我們是哪個程序在占用他,在這里是一個包名為com.udinic.keepbusyapp的程序。在這里,由於另外一個程序占用CPU,導致了我們的程序未能獲得足夠的CPU資源。
但是這種情況其實是暫時的,因為被其他后台應用占用CPU的情況並不多見,但仍有其他應用的線程或是主線程占用CPU。而Systrace也只能為我們提供一個概覽,他的深度是有限的。所以要找到我們app中到底是什么讓我們的CPU繁忙,我們還要借助另一個工具——Traceview。
通過Trace類跟蹤應用案例
Trace類能夠讓你在任何時候跟蹤應用的一舉一動。在你獲取trace的過程中,Trace.beginSection()與Trace.endSection()之間代碼工作會一直被追蹤。
比如,我們在recyclerview的bindview中使用sleep模擬耗時操作,滾動時會出現明顯卡頓
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
@Override
public void onBindViewHolder(StaggredAdapter.MyHolder holder, int position) {
holder.mivItem.setImageResource(mlstPics.get(position));
Trace.beginSection("aaa");//生成的trace文件中,會在跟蹤的代碼段執行對應時間軸區間打上一個tag標記
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Trace.endSection();//Trace的begin與end必須在同一線程之中執行
}
x
1
api = Build.VERSION_CODES.JELLY_BEAN_MR2) (
2
3
public void onBindViewHolder(StaggredAdapter.MyHolder holder, int position) {
4
holder.mivItem.setImageResource(mlstPics.get(position));
5
6
Trace.beginSection("aaa");//生成的trace文件中,會在跟蹤的代碼段執行對應時間軸區間打上一個tag標記
7
try {
8
Thread.sleep(1000);
9
} catch (InterruptedException e) {
10
e.printStackTrace();
11
}
12
Trace.endSection();//Trace的begin與end必須在同一線程之中執行
13
}
使用systrace跟蹤,生成如下分析圖

找到分析進程對應的ui線程,線程的縱向信息記錄的是調用關系,橫向信息記錄的是調用順序,代碼中的標記“aaa”標記了sleep的時間段,可以按m鍵高亮顯示這個標記對應的時間段,可以看出以下信息:
- 丟幀,在aaa標記時段的前面,有一幀標紅的frame,它跟下一個frame之間間隔事件很長(代碼sleep中)
- 調用關系,RV滾動 ---> bindview ---> aaa(sleep)
2017-10-20