【工利其器】工具使用之(四)systrace篇(1)官網翻譯

宋者為王發表於2019-04-05

前言

       Android 開發者官網中對該工具有專門的介紹,本篇文章作為systrace系列的開頭,筆者先不做任何介紹,僅僅翻譯一下官網的介紹。在後續的文章中再整理一份學習教程,以及筆者的實踐經歷。官網中對System Trace的介紹文件路徑為【https://developer.android.google.cn/studio/command-line/systrace?hl=en#java】。或者在進入到官網的首頁後,按照Android Developers > Android Studio > USER GUIDE > Command line tools > systrace的路徑訪問該文件。

       該文件主要包含如下內容:

 

一、systrace簡述

       systrace命令允許你收集和檢查在你的裝置上執行的所有系統級別程式的定時資訊。它聯合Android核心(比如CPU排程程式)、磁碟活動和app執行緒,生成一份HTML報告,如圖1所示:

  圖1:一個systrace的HTML報告案例,它顯示了與app 5秒鐘的互動。這份報告高亮顯示了那些systrace認為可能沒有被適當地渲染的幀。

       這份報告提供了一份在給定時間段內Android裝置系統程式的全域性圖。它也檢查了被捕獲的追蹤資訊,用於高亮顯示它觀察到的問題,比如顯示動作或動畫時的UI jank(筆者注:介面來不及重新整理導致的卡塞空白現象),以及提供修復這些問題的建議。但是,systrace不會收集在app程式內與程式碼執行相關的資訊。 關於你的app正在執行哪些方法以及它佔用了多少CPU資源的詳情,請檢視 【Android Studio CPU profiler】。你也可以使用CPU Profiler來生成追蹤日誌,匯出並檢查它們。

       這份文件解釋了怎樣從命令列生成systrace報告,操作由工具生成的trace檔案,並且使用它們分析及改善應用的UI效能。

★注意:在執行於Android 9(API level 28)或者更高的裝置上,你可以使用一個叫做System Tracing的系統app在裝置上記錄system trace。

      為了執行systrace,請完成下面的步驟:

      systrace工具在Android SDK Tools 包中提供,其路徑為 android-sdk/platform-tools/systrace/

 

二、語法

       為了給app生成HTML報告,你需要在命令列中使用如下的語法執行systrace:

$python systrace.py [option][categories]

       例如,如下的命令列呼叫了systrace用於記錄裝置活動,並且生成一份名為 mynewtrace.html 的HTML報告。該categories列表對大多數裝置而言是一個合理的預設列表。

$ python systrace.py -o mynewtrace.html sched freq idle am wm gfx view \ binder_driver hal dalvik camera input res
★ 提示:如果你想看輸出的trace中任務的名字,你的命令引數中必須包含“sched” category。

 想檢視你連線的裝置所支援的category列表,請執行下面的命令:

$ python systrace.py --list-categories

 如果你沒有指定任何的category或者option,systrace會生成一個包含所有可用category的報告並且使用預設的設定。這些可用的category依賴於你所連線的正在使用的裝置。

  1、全域性option

 

全域性option描述
-h | --help 顯示幫助資訊
-l | --list-categories 列出你連線的裝置所支援的可用category

  2、命令和命令選項

Commands and options Description
-o file 把HTML trace報告寫入到指定file。如果你不指定這個選項,systrace將會把你的報告儲存到和systrace.py相同的根目錄下,並且命名為trace.html。
-t N | --time=N 追蹤裝置活動N秒鐘。如果你不指定該選項,systrace將會提示你在命令列中按Enter鍵結束追蹤。
-b N | --buf-size=N 使用一個大小為N KB的trace快取。這個選項可以讓你限制追蹤過程中收集的資料的大小。
-k functions
| --ktrace=functions
追蹤指定核心函式的活動,在一個以逗號隔開的列表中列出。
-a app-name
| --app=app-name

 啟用追蹤app,這些app在以逗號分隔的程式名列表中被指定列出。這些app必須包含來自於Trace 類的追蹤檢測呼叫。

無論何時你profile你的應用,你都應該指明這個選項,很多庫(比如RecyclerView)都包含了追蹤檢測呼叫,

當你啟用應用級別的追蹤時,這些呼叫提供了有用的資訊。想了解更多資訊,請閱讀關於怎樣“檢測你的app程式碼”這部分內容。

--from-file=file-path 從檔案當中建立一個互動式的HTML報告,比如包含原始trace資料的TXT檔案,而不是執行實時追蹤。
-e device-serial
| --serial=device-serial
在指定連線的裝置上進行追蹤,該裝置由裝置序列號來識別。
categories 包含你所指定的系統程式的追蹤資訊,比如gfx表示用於影象渲染的系統程式。你可以通過加上 -l 命令執行systrace來檢視你所連線的裝置上可用的服務列表。

 

三、調查使用者介面效能問題

       systrace 在檢查你的app的使用者介面效能方面尤其有用,因為它能夠分析你的程式碼和幀率來驗證問題區域和建議可能的解決方案。首先,按照如下步驟進行:

      1)在你連線的裝置上執行你的app。

      2)用下面的命令執行systrace,

$ python systrace.py -t 10 [other-options] [categories]

       這個例子會追蹤你的app 10秒鐘。

      3)當systrace正在執行的時候,和你的app進行互動(筆者注:即操作你的app)。

      4)在你定義的限定時間過去後,比如該例中的10秒,systrace會生成一個HTML 報告。

      5)使用一個web瀏覽器開啟這份HTML報告。

       通過和這份報告互動,你可以檢查裝置在這段記錄時間內的CPU使用情況。為了幫助操作HTML報告,請檢視“鍵盤快捷鍵”這一部分,或者點選報告右上角的"?"按鈕。

       下面這一部分解釋了怎樣檢查報告中的資訊,從而找到並修復UI效能問題。

  1、檢查幀和警告

       如圖2所示,報告列出了每一個渲染UI幀的程式並且沿著時間線指出了所有的渲染幀。這些幀在16.6毫秒內渲染一幀, 需要維持一個穩定的每秒60幀的幀率,在報告中他們用綠色的圓圈表示。那些渲染超過16.6毫秒的幀則用黃色或者紅色圓圈表示。

圖2:長時間執行的幀放大後的systrace顯示

★ 注意:在執行版本為Android5.0(API level 21)或更高的裝置上,UI執行緒和渲染執行緒之間用於渲染幀的工作是分離的。在之前的版本中,建立幀的所有工作都是在UI執行緒中完成的。

       點選一個圓圈會讓它變成高亮並且提供額外的資訊,這些資訊是關於系統渲染這一幀做所的工作,包括警告。同時也會向你顯示渲染這一幀過程中系統正在執行的方法,所以你可以調查引起那些UI jank的方法。

圖3:選擇有問題的幀,一個警告會出現在trace報告下面來標識問題。

       當你選擇一個渲染較慢的幀,你會在報告皮膚底部看到一個警告。圖3中顯示的警告喚起了該幀主要的問題,而該幀在ListView內回收和重新繫結時花費了太多時間。有一些連結指向trace中有關事件,他們解釋了更多關於這段時間內系統做了些什麼。

       為了檢視該工具在你的trace中發現的每一個警告,以及該裝置觸發每一個警告的次數,請點選視窗最右邊的“Alerts”標籤,如圖4所示。這個“Alerts”皮膚會幫你檢視在這份trace中發生了什麼問題,以及引起UI jank的頻率。把這個皮膚當成一個bug列表去修復。通常,一個在某區域微小的改變或者改善可能消除你app中整個警告型別。

圖4:點選右側的“Alert”按鈕將顯示“alter”標籤

       如果你看到在UI執行緒中做了太多的工作,你需要找出是哪個方法消費了太多的CPU時間。有一種方法就是新增trace標記(檢視“檢測你的app程式碼”這一節)到那些你認為有可能導致這些瓶頸的方法中,用來檢視那些在systrace中出現的功能呼叫。如果你不確定在UI執行緒中哪些方法可能導致瓶頸,使用Android Studio CPU profier 。你可以生成trace日誌並且使用CPU Profiler來匯入和檢測它們。  

  2、HTML報告鍵盤快捷鍵

     下面的表格列出了當瀏覽systrace HTML報告時可用的鍵盤快捷鍵。

按鍵描述
W 放大trace時間軸。
S 縮小trace時間軸。
A 在時間軸上向左平移。
D 在時間軸上向右平移。
E 將trace時間軸置於當前滑鼠的中心。
G 在當前選擇的任務的開始處顯示網格。
Shift + G 在當前選擇的任務的結尾處顯示網路.
Right Arrow 在當前選擇的時間軸上選擇下一個事件(筆者注:當聚焦在frame 圓圈上時容易看到效果)。
Left Arrow 愛當前選擇的時間軸上選擇前一個事件。

 

四、檢測你的app程式碼

       因為systrace僅僅只在系統級別給你顯示程式資訊,所以在HTML報告中很難知道在給定的時間內你的app執行了哪些方法。在Android4.3(API level 18)已經更高的版本中,你可以在你的程式碼中使用Trace類來標記HTML報告中執行的事件。你沒有必要用systrace去檢測你的程式碼來記錄trace,但是這樣做可以幫助你看到你的app程式碼中哪部分可能引起執行緒掛起或者UI jank。這種途徑有別於使用Debug類,Trace類簡單地新增標籤到systrace報告,但是Debug類通過.trace檔案能幫助你檢測詳細的app CPU使用情況。

       為了生成包含你檢測trace事件的systrace HTML報告,你需要執行結合-a或者--app命令列執行systrace,並指明你的app的包名。

       下面的程式碼例項向你展示了怎樣使用Trace類來標記方法的執行,包括在那個方法內的兩段巢狀的程式碼塊:

 1 public class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {
 2     ...
 3     @Override
 4     public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 5         Trace.beginSection("MyAdapter.onCreateViewHolder");
 6         MyViewHolder myViewHolder;
 7         try {
 8             myViewHolder = MyViewHolder.newInstance(parent);
 9         } finally {
10             // In 'try...catch' statements, always call endSection()
11             // in a 'finally' block to ensure it is invoked even when an exception
12             // is thrown.
13             Trace.endSection();
14         }
15         return myViewHolder;
16     }
17 
18    @Override
19     public void onBindViewHolder(MyViewHolder holder, int position) {
20         Trace.beginSection("MyAdapter.onBindViewHolder");
21         try {
22             try {
23                 Trace.beginSection("MyAdapter.queryDatabase");
24                 RowItem rowItem = queryDatabase(position);
25                 dataset.add(rowItem);
26             } finally {
27                 Trace.endSection();
28             }
29             holder.bind(dataset.get(position));
30         } finally {
31             Trace.endSection();
32         }
33     }
34 ...
35 }

 

★ 注意:當你呼叫beginSection(String)多次,呼叫endSection()只結束最近一次呼叫的beginSection(String)。所以,對於巢狀的程式碼,比如上面例子中的,你需要確定你適當地匹配了一次beginSection()呼叫和一次endSection()。另外,你不能在一個執行緒中呼叫beginSection(),卻在另外一個執行緒中結束它,你必須在相同的執行緒中呼叫endSection()。

 

結語

       到這裡,該篇文章就翻譯結束了,後面的文章中,筆者將根據自己的理解和實際操作,繼續對System Trace進行闡述。限於筆者的水平,如有翻譯不準確或不妥當的地方,望不吝賜教。

相關文章