Android Studio 如何分析 CPU 活動
前面的小節我們學習了應用開發,構建,發布,接下來幾個小結我們學習如何剖析應用性能。本小節我們將學習如何分析 CPU 活動。
1. 什么是 CPU Profiler
1.1 CPU Profiler 概覽
優化應用的 CPU 使用率能帶來諸多好處,如提供更快、更順暢的用戶體驗,以及延長設備電池續航時間。我們可以使用 CPU Profiler 在與應用交互時實時檢查應用的 CPU 使用率和線程活動,也可以檢查記錄的方法跟蹤數據、函數跟蹤數據和系統跟蹤數據的詳細信息。
CPU Profiler 記錄和顯示的特定信息類型由我們選擇的記錄配置確定:
系統跟蹤數據
捕獲精細的詳細信息,以便我們檢查應用與系統資源的交互情況。
方法和函數跟蹤數據
對于應用進程中的每個線程,我們可以了解一段時間內執行了哪些方法 (Java) 或函數 (C/C++),以及每個方法或函數在其執行期間消耗的 CPU 資源。我們還可以使用方法和函數跟蹤數據來識別調用方和被調用方。調用方是指調用其他方法或函數的方法或函數,而被調用方是指被其他方法或函數調用的方法或函數。我們可以使用此信息來確定哪些方法或函數負責調用常常會消耗大量資源的特定任務,并優化應用的代碼以避免不必要的工作。
1.2 打開 CPU Profiler
要打開 CPU Profiler,請按以下步驟操作:
依次選擇 View > Tool Windows > Profiler 或點擊工具欄中的 Profile 圖標 。如果 Select Deployment Target 對話框顯示提示,請選擇要將我們的應用部署到哪個設備上以進行性能剖析。
點擊 CPU 時間軸上的任意位置以打開 CPU Profiler。當打開 CPU Profiler 時,它會立即開始顯示應用的 CPU 使用率和線程活動。系統會顯示類似于下圖的界面。
-
事件時間軸:顯示應用中的 Activity 在其生命周期內不斷轉換而經歷各種不同狀態的過程,并指示用戶與設備的交互,包括屏幕旋轉事件;
-
CPU 時間軸:顯示應用的實時 CPU 使用率(以占總可用 CPU 時間的百分比表示)以及應用當前使用的線程總數。 此時間軸還會顯示其他進程(如系統進程或其他應用)的 CPU 使用率,以便我們可以將其與我們應用的 CPU 使用率進行對比。我們可以通過沿時間軸的橫軸方向移動鼠標來檢查歷史 CPU 使用率數據;
-
線程活動時間軸:列出屬于應用進程的每個線程,并使用下面列出的顏色在時間軸上指示它們的活動。記錄跟蹤數據后,我們可以從此時間軸上選擇一個線程,以在跟蹤數據窗格中檢查其數據。
-
綠色:表示線程處于活動狀態或準備使用 CPU。也就是說,線程處于正在運行或可運行狀態。
-
黃色:表示線程處于活動狀態,但它正在等待一項 I/O 操作(如磁盤或網絡 I/O),然后才能完成它的工作。
-
灰色:表示線程處于休眠狀態并且沒有占用任何 CPU 時間。 當線程需要訪問尚不可用的資源時,就會出現這種情況。在這種情況下,要么線程主動進入休眠狀態,要么內核將線程置于休眠狀態,直到所需的資源可用。
-
2. 記錄 CPU 活動
2.1 記錄跟蹤數據
要開始記錄跟蹤 CPU 活動數據,請從 CPU Profiler 頂部的下拉菜單中選擇記錄配置,然后點擊 Record,如下圖,CPU Profiler 顯示了正在進行的記錄的狀態、持續時間和類型。
與我們的應用交互,然后在完成時點擊 Stop。分析器將自動選擇記錄的時間范圍,并在跟蹤數據窗格中顯示其跟蹤信息,如下圖所示。如果要檢查其他線程的跟蹤數據,請從線程活動時間軸上選擇相應線程。
-
選定范圍:確定要在跟蹤數據窗格中檢查所記錄時間的哪一部分。當我們首次記錄跟蹤數據時,CPU Profiler 會自動在 CPU 時間軸上選擇記錄的完整長度。要僅檢查已記錄的時間范圍中的一部分的跟蹤數據,請拖動突出顯示區域的邊緣;
-
時間戳:指示所記錄跟蹤數據的開始和結束時間(相對于分析器開始收集 CPU 使用率信息的時間)。要選擇完整的記錄,請點擊時間戳;
-
跟蹤數據窗格:顯示我們選擇的時間范圍和線程的跟蹤數據。此窗格要在我們至少記錄一條跟蹤數據后才會顯示。 在此窗格中,我們可以選擇如何查看每個堆棧軌跡(使用跟蹤數據標簽頁),以及如何測量執行時間(使用時間參考下拉菜單);
-
跟蹤數據窗格標簽頁:選擇如何顯示跟蹤數據詳細信息;
-
時間參考菜單:選擇以下選項之一,以確定如何測量每次調用的時間信息:
- Wall clock time:該時間信息表示實際經過的時間。
- Thread time:該時間信息表示實際經過的時間減去線程沒有占用 CPU 資源的那部分時間。對于任何給定的調用,其線程時間始終小于或等于其掛鐘時間。使用線程時間可以讓我們更好地了解線程的實際 CPU 使用率中有多少是給定方法或函數占用的。
2.2 選擇記錄配置
在開始記錄跟蹤信息之前,請為要捕獲的分析信息選擇適當的記錄配置:
-
對 Java 方法采樣:在應用的 Java 代碼執行期間,頻繁捕獲應用的調用堆棧。分析器會比較捕獲的數據集,以推導與應用的 Java 代碼執行有關的時間和資源使用信息;
-
跟蹤 Java 方法:在運行時檢測應用,以在每個方法調用開始和結束時記錄一個時間戳。系統會收集并比較這些時間戳,以生成方法跟蹤數據,包括時間信息和 CPU 使用率;
-
對 C/C++ 函數采樣:捕獲應用的原生線程的采樣跟蹤數據。要使用此配置,我們必須將應用部署到搭載 Android 8.0(API 級別 26)或更高版本的設備上;
-
跟蹤系統調用:捕獲非常翔實的細節,以便我們檢查應用與系統資源的交互情況。我們可以檢查線程狀態的確切時間和持續時間、直觀地查看所有內核的 CPU 瓶頸在何處,并添加要分析的自定義跟蹤事件。 當我們排查性能問題時,此類信息至關重要。要使用此配置,我們必須將應用部署到搭載 Android 7.0(API 級別 24)或更高版本的設備上。
2.3 Debug API 記錄 CPU 活動
除了手動點擊 Record 和 Stop 來記錄跟蹤數據外,我們還可以在代碼中使用 Debug API 讓應用能夠在 CPU Profiler 中開始和停止記錄 CPU 活動。
當我們的應用調用 startMethodTracing(String tracePath) 時,CPU Profiler 將開始記錄;當我們的應用調用 stopMethodTracing() 時,CPU Profiler 將停止記錄。在記錄使用此 API 觸發的 CPU 活動時,CPU Profiler 會將 Debug API 顯示為作用中的 CPU 記錄配置。
Tips:要使用 Debug API 控制 CPU 活動的記錄,請將檢測的應用部署到搭載 Android 8.0(API 級別 26)或更高版本的設備上。
2.4 記錄應用啟動的 CPU 活動
要在應用啟動過程中自動開始記錄 CPU 活動,請執行以下操作:
- 依次選擇 Run > Edit Configurations;
2. 在 Profiling 標簽中,勾選 Start recording a method trace on startup 旁邊的復選框;
-
從菜單中選擇 CPU 記錄配置;
-
點擊 Apply;
-
依次選擇 Run > Profile,將我們的應用部署到搭載 Android 8.0(API 級別 26)或更高版本的設備上。
3. 導入導出 CPU 活動
3.1 導出跟蹤數據
使用 CPU Profiler 記錄 CPU 活動后,我們可以將相應數據導出為 .trace 文件,以便與他人共享或日后進行檢查。
要從 CPU 時間軸導出跟蹤文件,請執行以下操作:
-
在 CPU 時間軸上,右鍵點擊要導出的記錄的方法跟蹤數據或系統跟蹤數據;
-
從菜單中選擇 Export trace;
-
瀏覽到要保存文件的目標位置,指定文件名,然后點擊 OK。
要從 Sessions 窗格導出跟蹤文件,請執行以下操作:
-
在 Sessions 窗格中,右鍵點擊要導出的記錄的跟蹤數據;
-
點擊會話條目右側的 Export method trace 或 Export system trace 按鈕;
-
瀏覽到要保存文件的目標位置,指定文件名,然后點擊 OK。
3.2 導入跟蹤數據
我們可以導入使用 Debug API 或 CPU Profiler 創建的 .trace 文件。
要導入跟蹤文件,請在分析器的 Sessions 窗格中點擊 Start new profiler session 圖標 ,然后選擇 Load from file。
我們可以檢查導入到 CPU Profiler 中的跟蹤數據,就像檢查直接在 CPU Profiler 中捕獲的跟蹤數據一樣,但有下面幾點不同:
-
CPU 活動未顯示在 CPU 時間軸上。
-
線程活動時間軸僅指明了可在哪里獲取各線程的跟蹤數據,而未指明實際線程狀態(如運行中、等待中或休眠中)。
4. 檢查 CPU 活動
CPU Profiler 中的跟蹤數據窗格提供多個標簽頁,供我們選擇如何查看所記錄的跟蹤數據中的信息。
要查看方法跟蹤數據和函數跟蹤數據,我們可以從 Call Chart、Flame Chart、Top Down 和 Bottom Up 標簽頁中進行選擇。要查看系統跟蹤數據,我們可以從 Trace Events、Flame Chart、Top Down 和 Bottom Up 標簽頁中進行選擇。
4.1 Call Chart 標簽頁
Call Chart 標簽頁會以圖形來呈現方法跟蹤數據或函數跟蹤數據,其中調用的時間段和時間在橫軸上表示,而其被調用方則在縱軸上顯示。對系統 API 的調用顯示為橙色,對應用自有方法的調用顯示為綠色,對第三方 API(包括 Java 語言 API)的調用顯示為藍色。
上圖顯示了一個調用圖表示例,說明了給定方法或函數的 Self 時間、Children 時間和 Total 時間的概念。
4.2 Flame Chart 標簽頁
Flame Chart 標簽頁提供一個倒置的調用圖表,用來匯總完全相同的調用堆棧。也就是說,將具有相同調用方順序的完全相同的方法或函數收集起來,并在火焰圖中將它們表示為一個較長的橫條(而不是將它們顯示為多個較短的橫條,如調用圖表中所示)。這樣更方便我們查看哪些方法或函數消耗的時間最多。不過,這也意味著,橫軸不代表時間軸,而是表示執行每個方法或函數所需的相對時間。
為幫助說明此概念,不妨考慮下圖中的調用圖表。請注意,方法 D 多次調用 B(B1、B2 和 B3),其中一些對 B 的調用也調用了 C(C1 和 C3)。
由于 B1、B2 和 B3 具有相同的調用方順序 (A → D → B),因此系統將它們匯總在一起,如下圖所示。同樣,也將 C1 和 C3 匯總在一起,因為它們也具有相同的調用方順序 (A → D → B → C)。請注意,C2 不包括在內,因為它具有不同的調用方順序 (A → D → C)。
匯總的調用用于創建火焰圖,如下圖所示。 請注意,對于火焰圖中的任何給定調用,占用最多 CPU 時間的被調用方最先顯示。
4.3 Top Down 和 Bottom Up 標簽頁
Top Down 標簽顯示一個調用列表,在該列表中展開方法或函數節點會顯示它的被調用方。
如下圖所示,在 Top Down 標簽頁中展開方法 A 的節點會顯示它的被調用方,即方法 B 和 D。在此之后,展開方法 D 的節點會顯示它的被調用方,即方法 B 和 C,依此類推。與 Flame chart 標簽頁類似, Top Down 樹也匯總了具有相同調用堆棧的完全相同的方法的跟蹤信息。也就是說,Flame chart 標簽頁提供了 Top down 標簽頁的圖形表示方式。
Top Down 標簽提供以下信息來幫助說明在每個調用上所花的 CPU 時間(時間也可表示為在選定范圍內占線程總時間的百分比):
-
Self:方法或函數調用在執行自己的代碼(而非被調用方的代碼)上所花的時間;
-
Children:方法或函數調用在執行它的被調用方(而非自己的代碼)上所花的時間;
-
Total:方法的 Self 時間和 Children 時間的總和。這表示應用在執行調用時所用的總時間。
Bottom Up 標簽頁顯示一個調用列表,在該列表中展開函數或方法的節點會顯示它的調用方。如下圖,提供了方法 C 的 Bottom Up 樹。在該 Bottom Up 樹中打開方法 C 的節點會顯示它獨有的各個調用方,即方法 B 和 D。請注意,盡管 B 調用 C 兩次,但在“Bottom Up”樹中展開方法 C 的節點時,B 僅顯示一次。在此之后,展開 B 的節點會顯示它的調用方,即方法 A 和 D。
Bottom Up 標簽頁用于按照占用的 CPU 時間由多到少(或由少到多)的順序對方法或函數排序。我們可以檢查每個節點以確定哪些調用方在調用這些方法或函數上所花的 CPU 時間最多。 與 Top Down 樹相比, Bottom Up 樹中每個方法或函數的時間信息參照的是每個樹頂部的方法(頂部節點)。 CPU 時間也可表示為在該記錄期間占線程總時間的百分比。
4.4 Trace Events 標簽頁
檢查系統跟蹤數據時,我們可以使用 Trace Events 標簽查看每個線程上發生的事件的詳細信息。
要查看某個線程的詳細信息,請在 Threads 窗格中選擇該線程。這樣將在 Kernel 窗格中突出顯示該線程在每個 CPU 內核上的活動,并在 Trace Events 標簽頁中顯示該線程的事件。在 Trace Events 標簽頁中將鼠標指針懸停在某個事件上可查看該事件的名稱以及在每種狀態下所用的時間。
例如,下圖中,在 Threads 窗格中選擇了 RenderThread,在 Kernel 窗格中突出顯示了該線程在 CPU 0 和 CPU 1 上的活動,并在 Trace Events 標簽頁中顯示了在特定事件上所花的時間。
5. 小結
本節課程我們主要學習了如何記錄和分析 CPU 活動。本節課程的重點如下:
- 掌握如何記錄跟蹤 CPU 數據;
- 掌握如何檢查分析 CPU 數據。