優(yōu)化應用程序的CPU使用率對系統(tǒng)有很大幫助,例如提供更流暢的用戶體驗以及節(jié)省設備電池壽命。在與應用程序交互時,可以使用CPU Profiler實時檢查應用程序的CPU使用率和線程活動,也可以檢查方法跟蹤、功能跟蹤和系統(tǒng)跟蹤中的詳細信息。CPU Profiler記錄和顯示的信息類型取決于您的配置:
可以通過下面的步驟打開CPU Profiler:
如果彈出Select Deployment Target對話框,請選擇要進行分析的設備。如果已通過USB連接設備,但未看到列出的設備,請確保已開啟USB調試。
打開CPU Profiler時,它會立即開始顯示應用程序的CPU使用率和線程活動。您應該看到類似下圖的內容。
如上圖所示,CPU Profiler默認視圖包括以下時間線:
Thread activity時間線:列出屬于應用程序進程的每個線程,并使用下面列出的顏色沿時間線指示其活動。記錄跟蹤后,可以從此時間線中選擇一個線程,以在跟蹤窗中檢查其數(shù)據(jù)。
CPU Profiler還報告Android Studio和Android平臺添加到應用程序進程中的線程(如JDWP、Profile Saver、Studio:VMStats、Studio:Perfa和Studio:Heartbeat)的CPU使用情況(不過在線程活動時間線中顯示的確切名稱可能有所不同)。Android Studio報告這些數(shù)據(jù)方便您確定線程活動和CPU使用情況實際上是由應用程序的代碼引起的。
要開始記錄跟蹤,請從CPU Profiler頂部的下拉菜單中選擇一個記錄配置,然后單擊Record。如下圖,CPU Profiler會顯示正在進行的記錄的狀態(tài)、持續(xù)時間和類型。
與應用程序交互,完成后單擊Stop 。Profiler自動選擇記錄的時間范圍,并在跟蹤窗格中顯示其跟蹤信息,如下圖所示。如果要檢查其他線程的跟蹤,請從線程活動時間線中選擇它。
時間參考菜單:選擇以下選項確定如何測量每個調用的計時信息,
篩選:按函數(shù)、方法、類或包名稱篩選跟蹤數(shù)據(jù)。例如,如果要快速識別與特定調用相關的跟蹤數(shù)據(jù),請單擊 Filter 或按Ctrl+F,然后在搜索字段中輸入名稱。在Call chart 和Flame chart選項卡中,將強調包含與搜索查詢匹配的調用、包或類的調用堆棧。在Top down和Bottom up選項卡中,這些調用堆棧的優(yōu)先級高于其他跟蹤結果。還可以通過選中搜索字段旁邊的選擇框來啟用以下選項:
在開始記錄跟蹤信息之前,請為要捕獲的分析信息選擇適當?shù)挠涗浥渲茫?/p>
您可以在CPU Recording Configurations對話框中創(chuàng)建、編輯和查看記錄配置,該對話框通過從CPU Profiler頂部的記錄配置的下拉菜單中選擇Edit configurations”打開。
若要查看現(xiàn)有記錄配置的設置,請在CPU Recording Configurations對話框的左窗格中選擇它。要創(chuàng)建新的錄制配置,請執(zhí)行以下操作:
注意:如果您使用的連接設備搭載的是 Android 8.0(API 級別 26)或更高版本,那么對跟蹤數(shù)據(jù)的文件大小沒有限制,系統(tǒng)會忽略此值。不過,您仍需留意每次記錄后設備收集了多少數(shù)據(jù),Android Studio 可能難以解析大型跟蹤文件。例如,如果您記錄的是采樣時間間隔很短的采樣跟蹤數(shù)據(jù),或是在應用短時間內調用許多方法的情況下記錄檢測跟蹤數(shù)據(jù),那么很快就會生成大型跟蹤文件。
您可以使用Debug API讓應用程序能夠啟動和停止CPU Profiler中的活動記錄。當你在應用程序中調用startMethodTracing(String tracePath)時,CPU Profiler開始記錄,當你的應用調用stopMethodTracing()時,CPU Profiler停止記錄。當使用Debug API做為觸發(fā)CPU的活動記錄時,CPU Profiler會將Debug API顯示為活動CPU的記錄配置。
要使用Debug API控制CPU活動的記錄,請將插入指令的應用程序安裝到運行Android 8.0(API級別26)或更高版本的設備上。關于Debug API使用的詳細信息,會在后面描述。
要在應用程序啟動期間自動開始記錄CPU活動,請執(zhí)行以下操作:
重要提示: Debug API 應該與用于開始和停止 CPU 活動記錄的其他方法(如 CPU Profiler 圖形界面中的按鈕,以及應用啟動時自動記錄的記錄配置中的設置)分開使用。
使用CPU Profiler記錄CPU活動后,可以將數(shù)據(jù)導出為.trace文件以與其他人共享或稍后檢查。要從CPU時間軸導出跟蹤文件,請執(zhí)行以下操作:
要從Sessions窗格導出跟蹤文件,請執(zhí)行以下操作:
可以導入Debug API或CPU Profiler創(chuàng)建的.trace文件用來分析。通過在Profiler的Sessions 窗格中單擊Start new profiler session,然后選擇Load from file,導入跟蹤文件。與直接在CPU Profiler中捕獲的跟蹤一樣,您可以分析在CPU Profiler中導入的跟蹤,但要注意下列的不同:
CPU Profiler中的跟蹤窗格提供了幾個選項卡,允許您選擇如何從記錄的跟蹤中查看信息。對于方法跟蹤和函數(shù)跟蹤,可以從Call Chart、Flame Chart、Top Down和Bottom Up中進行選擇。對于系統(tǒng)跟蹤,可以從Trace Events、Flame Chart、Top Down和Bottom Up中進行選擇。
Call Chart選項提供了方法跟蹤或函數(shù)跟蹤的圖形表示,其中調用的周期和時間在水平軸上表示,并且其被調用方沿垂直軸示出。對系統(tǒng)APIs的調用顯示為橙色,對應用程序自身方法的調用顯示為綠色,對第三方APIs(包括Java APIs)的調用顯示為藍色。下圖顯示了一個示例調用圖,并說明了給定方法或函數(shù)的self time、children time和total time的概念。在“使用Top Down和Bottom Up檢查跟蹤”一節(jié)會進一步解釋這些概念。
提示:要跳轉到某個方法或函數(shù)的源代碼,請右鍵點擊該方法或函數(shù),然后選擇 Jump to Source。從任何跟蹤數(shù)據(jù)窗格標簽中均可執(zhí)行此操作。
Flame Chart選項提供一個反向調用圖,用于聚合相同的調用堆棧。也就是說,將收集共享相同調用方序列的相同方法或函數(shù),并將其表示為flame圖表中的一個長條形圖(而不是顯示為調用圖中的多個短條形圖)。這樣可以更容易地看到哪些方法或函數(shù)消耗的時間最多。但是,這也意味著水平軸并不代表時間線,而是指示每個方法或函數(shù)執(zhí)行的相對時間量。
為了幫助說明這個概念,請考慮下圖中的調用圖。注意,方法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)。
聚合調用用于創(chuàng)建flame圖表,如下圖所示。注意,對于flame圖表中的任何給定調用,消耗最多CPU時間的被調用方都會首先出現(xiàn)。
Top Down選項顯示調用列表,其中展開方法或函數(shù)節(jié)點將顯示其被調用方。圖“Top Down”顯示了圖“Call Chart”中調用圖的Top Down。圖中的每個箭頭都重調用者指向被調用者。
如圖“Top Down”所示,在Top Down選項中展開方法A的節(jié)點將顯示其被調用方B和D。之后,展開方法D的節(jié)點將顯示其被調用方B和C等。與Flame chart選項類似,自頂向下的樹為共享相同調用堆棧的相同方法的聚合信息。也就是說,Flame chart選項提供了Top down選項的圖形表示。
Top Down選項提供以下信息,幫助描述每次調用所用的CPU時間(時間也表示為所選范圍內線程總時間的百分比):
Bottom Up選項顯示調用列表,其中展開函數(shù)或方法的節(jié)點將顯示其調用方。根據(jù)圖“Top Down”所示的示例跟蹤,圖“Bottom Up”為方法C提供了一個自底向上的樹。在自底向上樹中打開方法C的節(jié)點將顯示其每個唯一的調用方B和D。請注意,盡管B調用了C兩次,但在自底向上樹中展開方法C的節(jié)點時,B只出現(xiàn)一次。之后,展開B的節(jié)點將顯示其調用方A和D。
Bottom Up的選項對于按占用最多(或最少)CPU時間的方法或函數(shù)排序非常有用。您可以檢查每個節(jié)點,以確定哪些調用方在調用這些方法或函數(shù)時花費的CPU時間最多。與自頂向下的樹相比,自下而上的樹中的每個方法或函數(shù)的計時信息都參考每個樹頂部(頂部節(jié)點)的方法。CPU時間也表示為該記錄期間線程總時間的百分比。下表有助于解釋如何解釋頂級節(jié)點及其調用方(子節(jié)點)的計時信息。
Self | Children | Total | |
---|---|---|---|
位于自下而上樹的頂部的方法或函數(shù)(頂節(jié)點) | 表示方法或函數(shù)執(zhí)行其自己的代碼而不是其被調用者所花費的總時間。與自上而下的樹相比,此計時信息表示在記錄期間對該方法或函數(shù)的所有調用的總和。 | 表示方法或函數(shù)花費在執(zhí)行其被調用方而不是其自身代碼上的總時間。與自上而下的樹相比,此計時信息表示在記錄時間內對該方法或函數(shù)的所有調用的總和。 | self time和children time的總和。 |
調用者 (子節(jié)點) | 表示被調用者得到調用時花費的總時間。以圖“Bottom Up”中的自底向上的樹為例,方法B的自身時間等于每次執(zhí)行B調用C時的自身時間之和。 | 表示被調用方的子級時間的總計。以圖“Bottom Up”中的自底向上的樹為例,方法B的子級時間等于每次執(zhí)行B調用C時的子級時間之和 。 | self time和children time的總和。 |
注意:對于給定的記錄,當分析器達到文件大小限制時,Android Studio 會停止收集新數(shù)據(jù)(不過,不會停止記錄)。在執(zhí)行檢測跟蹤時,這種情況通常發(fā)生得更快,因為與采樣跟蹤相比,此類跟蹤會在更短的時間內收集更多的數(shù)據(jù)。如果您將檢查時間范圍延長至達到限制后的記錄期間,則跟蹤數(shù)據(jù)窗格中的時間數(shù)據(jù)不會發(fā)生變化(因為沒有新數(shù)據(jù)可用)。此外,當您僅選擇沒有數(shù)據(jù)可用的記錄部分時,對于時間信息,跟蹤數(shù)據(jù)窗格將顯示 NaN。
檢查系統(tǒng)跟蹤時,可以使用Trace Events選項查看每個線程上發(fā)生的事件的詳細信息。要查看線程的詳細信息,請在Threads窗格中選擇該線程。這將在Kernel窗格中突出顯示線程在每個CPU核心上的活動,并在Trace Events選項中顯示線程的事件。將鼠標指針懸停在Trace Events選項中的事件上,可以查看事件的名稱和在每個狀態(tài)下花費的時間。
例如,下顯示了在Threads窗格中選擇的RenderThread,其活動在Kernel窗格中的CPU 0和CPU 1上突出顯示,以及在Trace Events選項中的特定事件上花費的時間。
您可以檢查應用程序渲染主線程上的每個幀所需的時間,并使用RenderThread來調查導致UI抖動和低幀速率的瓶頸。要查看幀渲染數(shù)據(jù),請使用Trace System Calls配置記錄跟蹤。記錄跟蹤后,在名為FRAMESS的部分下查找有關每個幀的信息,如下圖所示。
要在應用程序執(zhí)行時進行方法跟蹤,可以使用Debug類在應用程序中加入代碼。通過這種方式,您可以更好地控制設備何時啟動和停止記錄跟蹤信息。設備還可以使用指定的名稱保存跟蹤日志,以便以后可以輕松標識每個日志。然后可以使用Android Studio CPU Profiler查看每個跟蹤日志。 在開始生成跟蹤日志之前,請確保您的應用具有寫入外部存儲(WRITE_EXTERNAL_STORAGE)的權限,以便它可以將跟蹤日志保存到設備。
要創(chuàng)建跟蹤日志,請在希望系統(tǒng)開始記錄跟蹤數(shù)據(jù)的位置調用startMethodTracing()。在調用中,可以指定.trace文件的名稱,系統(tǒng)將其保存到目標設備上應用數(shù)據(jù)的特定目錄中,也就是getExternalFilesDir()返回的目錄,該目錄位于大多數(shù)設備上的~/sdcard/中。trace文件包含二進制方法跟蹤數(shù)據(jù)和帶有線程和方法名稱的映射表。要停止跟蹤,請調用stopMethodTracing()。下面示例了開始并停止記錄名為sample.trace的跟蹤日志:
// Starts recording a trace log with the name you provide. For example, the// following code tells the system to start recording a .trace file to the// device with the name "sample.trace".Debug.startMethodTracing("sample");...// The system begins buffering the generated trace data, until your// application calls <code><a href="/reference/android/os/Debug.html#stopMethodTracing()">stopMethodTracing()</a></code>, at which time it writes// the buffered data to the output file.Debug.stopMethodTracing();
注意,如果您的應用程序在不更改跟蹤日志名稱的情況下再次調用StestMeMeTraceTrn(),它會覆蓋保存到設備的現(xiàn)有日志。下節(jié)會介紹如何動態(tài)更改每個跟蹤日志的名稱。
如果系統(tǒng)在調用StestMeTraceTracle()之前達到最大緩沖區(qū)大小,系統(tǒng)將停止跟蹤并向控制臺發(fā)送通知。啟動和停止跟蹤的方法可以在整個應用程序過程中工作。也就是說,可以在Activity的onCreate(Bundle)方法中調用startMethodTracing(),在Activity的onDestroy()方法中調用stopMethodTracing()。請注意,啟用配置文件時,應用程序的運行速度會更慢。也就是說,不應該使用分析數(shù)據(jù)來確定絕對時間(例如,“method foo()需要2.5秒才能運行”)。跟蹤日志中的計時信息僅在與以前的跟蹤日志進行比較時才有用,因此您可以查看最近的更改是否使應用程序更快或更慢。
當安裝到運行Android5.0(API級別21)及更高版本的設備時,您可以使用sample-based profiling來跟蹤,從而減小運行時對性能的影響。要啟用sample profiling,請使用特定采樣間隔的startMethodTracingSampling()(而不是調用startMethodTracing())。系統(tǒng)會定期收集樣本,直到應用程序調用stopMethodTracing()。
如果應用程序在不指定跟蹤日志新名稱的情況下多次啟動和停止方法跟蹤,則設備將用新的跟蹤日志覆蓋舊的跟蹤日志,即只保留最新的跟蹤日志。要將多個跟蹤日志保存到設備,請在應用程序每次調用startMethodTracing()時動態(tài)重命名跟蹤日志。下面的示例使用SimpleDateFormat類在每個跟蹤日志名字中加入當前日期和時間:
// Uses the <code><a href="/reference/java/text/SimpleDateFormat.html">SimpleDateFormat</a></code> class to create a String with// the current date and time.SimpleDateFormat dateFormat = new SimpleDateFormat("dd_MM_yyyy_hh_mm_ss", Locale.getDefault());String logDate = dateFormat.format(new Date());// Applies the date and time to the name of the trace log.Debug.startMethodTracing( "sample-" + logDate);
系統(tǒng)在設備上創(chuàng)建跟蹤日志后,可以通過以下方式之一訪問該文件:
使用adb pull命令將文件復制到本地計算機。下面的命令將名為sample.trace的跟蹤日志從設備復制到本地計算機的~/Documents/trace logs/目錄。
adb pull path-on-device/sample.trace ~/Documents/trace-logs/
Android Developers: cpu profiler