我的GitHub | 我的博客 | 我的微信 | 我的郵箱 |
---|---|---|---|
baiqiantao | baiqiantao | bqt20094 | baiqiantao@sina.com |
目錄
System tracing
官方文檔概覽
System tracing 就是記錄短時間內的設備活動。System tracing 會生成跟蹤文件,該文件可用於生成系統報告。此報告可幫助您了解如何最有效地提升應用或游戲的性能。
Android 平台提供了多種不同的跟蹤信息獲取途徑:
- Android Studio CPU profiler:在您與應用交互時,可實時檢查應用的 CPU 使用率和線程活動信息,可詳細了解應用正在執行哪些方法及其占用了多少 CPU 資源。
- System Tracing app:用於將設備活動保存到跟蹤文件的 Android 工具。在搭載
Android 10(API 29)
或更高版本的設備上,跟蹤文件會以Perfetto
格式保存。在搭載較低版本 Android 系統的設備上,跟蹤文件會以Systrace
格式保存。 - Systrace command-line tool:Systrace 是平台提供的舊版命令行工具,可記錄
短時間
內的設備活動,並保存在壓縮的文本文件
中。該工具會生成一份報告,其中匯總了 Android 內核中的數據,例如 CPU 調度程序、磁盤活動和應用線程。 - Perfetto command-line tool:Perfetto 是 Android 10 中引入的全新平台級跟蹤工具。這是適用於 Android、Linux 和 Chrome 的更加通用和復雜的開源跟蹤項目。與 Systrace 不同,它提供數據源超集,可讓您以
protobuf
編碼的二進制流形式記錄任意長度
的跟蹤記錄。您可以在 Perfetto 界面中打開這些跟蹤記錄。
Systrace 簡介
Systrace 是 Android 4.1 中新增的性能數據采樣和分析
工具。它可幫助開發者收集 Android 關鍵子系統
(如 SurfaceFlinger/SystemServer/Kernel/Input/Display 等 Framework 部分關鍵模塊、服務,View 系統等)的運行信息,從而幫助開發者更直觀的分析系統瓶頸,改進性能。
Systrace 允許你監視和跟蹤 Android 系統的行為,它會告訴你系統都在哪些工作上花費時間、CPU周期都用在哪里,甚至你可以看到每個線程、進程
在指定時間內都在干嘛。它同時還會突出觀測到的問題,從垃圾回收
到渲染內容
都可能是問題對象,甚至提供給你建議的解決方案。
Systrace 和 Perfetto 不會收集有關應用進程中
代碼
執行情況的詳細信息。如需詳細了解您的應用正在執行哪些方法
及其占用了多少 CPU 資源,請使用 Android Studio CPU profiler。
Systrace 的功能包括跟蹤系統的 I/O 操作、內核工作隊列、CPU 負載以及 Android 各個子系統的運行狀況等。在 Android 平台中,它主要由3部分組成:
- 內核部分:從本質上說,Systrace 是對 Linux Kernel 中
ftrace
的封裝。所以,如果要使用 Systrace 的話,必須開啟 kernel 中和 ftrace 相關的模塊。 - 數據采集部分:Android 定義了一個
Trace
類。應用程序可利用該類把統計信息輸出給 ftrace。同時,Android 還有一個atrace
程序(可通過adb shell atrace
調用),它可以從 ftrace 中讀取統計信息然后交給數據分析工具
來處理。 - 數據分析工具:Android 提供一個
systrace.py
( python 腳本文件,位於 Android SDK目錄/platform-tools/systrace
中,其內部將調用atrace
程序)用來配置數據采集的方式(如采集數據的標簽、輸出文件名等)和收集 ftrace 統計數據並生成一個結果網頁文件
供用戶查看。
systrace.py 工具
Systrace 工具在 Android-SDK 目錄下的 /platform-tools/systrace
里面。
Usage: systrace.py [options] [category1 [category2 ...]]
Example: systrace.py -b 32768 -t 15 gfx input view sched freq
注意,使用 systrace.py 時,用戶名(
C:\Users\...\
)一定不要有中文,否則因為python2
對中文支持的非常差,會報各種各樣奇葩的錯誤!
環境配置
使用 systrace.py
必須先配置好 python 環境,且 systrace.py
只支持使用 python2.x
執行,如果本地已安裝了 python3.x
,可以百度一下怎么在電腦上 同時配置 兩個 python 版本的環境。
可以在 Bash 中配置好對應的路徑和 Alias,例如:
alias est='cd D:/_data/_androidsdk/platform-tools/systrace; explorer .'
alias pst='python2 systrace.py -a com.bqt.test'
使用步驟
- 在代碼中合適的位置添加
Trace.beginSection("tag")
和Trace.endSection()
- 手機連接好電腦,開啟 adb 調試,准備好你要進行抓取的界面
- 執行
python2 systrace.py
腳本開始抓取 - 在手機上開始操作,不需要太長時間,一般 5 秒左右即可
- 設定好的時間到了之后,會自動生成
trace.html
文件 - 打開 Chrome,打開 chrome://tracing 頁面
- 點擊 Load 將生成的 trace.html 文件加載后即可進行分析
常用參數
可以通過 python2 systrace.py -h
查看支持哪些參數。
可能需要先安裝模塊:
pip2 install pypiwin32
也可以通過執行adb shell atrace --help
查看支持哪些參數,但是兩者結果不完全一致
- -h 顯示幫助信息:
-h
或–-help
, Show the help message. - -o 指定輸出文件名:
-o FILE
,不指定時默認為trace.html
- Write the HTML trace report to the specified file
- -t 限制抓取的時間:
-t N
或–time=N
,不指定時按 Enter 即可結束- Trace for N seconds. The default value is 5 seconds.
- -a 指定包名:
-a A
或—-app=A
,調試自定義的Trace
標記時必須指定包名- enable app-level tracing, specified as a comma-separated(逗號分隔) list of package names
- The apps must contain tracing instrumentation calls from the Trace class
*
is a wildcard matching any process
- -l 列出可用的類別:
-l
或--list-categories
,查看支持的類別- List the available tracing category tags
- 可能需要先安裝模塊:
pip2 install six
- 也可以通過執行
adb shell atrace --list_categories
查看支持的類別
自定義事件 -a
System tracing 僅在 system level 顯示進程的相關信息,因此有時很難知道應用或游戲的哪些方法
是在給定時間針對 system events 執行的。
Android 平台提供了一個 tracing API,可用於為特定的代碼段
添加標簽。如果您捕獲應用的 debug 版本的 system trace 跟蹤並添加 -a
選項,這些自定義事件便會顯示在 Systrace 報告中。
可用的類別 -l
如果您未指定任何類別,systrace
會生成包含所有可用類別的報告,可用類別取決於您所使用的已連接設備。
常用的類別有:gfx、input、view、webview、wm、am、pm、dalvik、power、res、webview、freq、disk、sync、memory、aidl、adb...
Trace 文件大小會影響其在 Chrome 中打開后的操作性能,在使用的時候可以根據自己的需求來進行選擇和配置。
如果要在跟蹤輸出中查看任務名稱,必須在命令參數中添加 sched 類別。
λ adb shell atrace --list_categories
gfx - Graphics
input - Input
view - View System
webview - WebView
wm - Window Manager
am - Activity Manager
sm - Sync Manager
audio - Audio
video - Video
camera - Camera
hal - Hardware Modules
res - Resource Loading
dalvik - Dalvik VM
rs - RenderScript
bionic - Bionic C Library
power - Power Management
pm - Package Manager
ss - System Server
database - Database
network - Network
adb - ADB
vibrator - Vibrator
aidl - AIDL calls
nnapi - NNAPI
rro - Runtime Resource Overlay
pdx - PDX services
sched - CPU Scheduling
freq - CPU Frequency
idle - CPU Idle
disk - Disk I/O
sync - Synchronization
memreclaim - Kernel Memory Reclaim
binder_driver - Binder Kernel driver
binder_lock - Binder global lock trace
memory - Memory
常用快捷鍵
- W/S 放大/縮小:,放大可以更好地看清局部細節,縮小以查看整體
- A/D 左移/右移:左移/右移內容,可以看當前時間前后的信息
- M 高亮:高亮選中當前鼠標點擊的段,可以快速標識出這個方法的左右邊界和執行時間
鼠標模式快捷切換: 主要是針對鼠標的工作模式進行切換
- 數字鍵1:切換到
Selection
模式(默認),這個模式下鼠標可以點擊某一個段查看其詳細信息,配合 M 和 ASDW 可以做基本的操作 - 數字鍵2:切換到
Pan
模式,這個模式下拖動鼠標可以左右拖動(建議) - 數字鍵3:切換到
Zoom
模式,這個模式下拖動鼠標可以放大和縮小 - 數字鍵4:切換到
Timing
模式,這個模式下主要是用來衡量時間的,比如通過拖動選擇一個起點和一個終點后, 可以查看起點和終點這中間的操作所花費的時間
Trace 類
Trace 類能夠在生成的 trace 文件中,在跟蹤的代碼段執行對應時間軸區間,打上一個 tag 標記,從而跟蹤應用的某些代碼的行為。
如果多次調用 beginSection(),調用 endSection() 只會結束最后調用的 beginSection() 方法。因此,對於嵌套調用,請務必將每次對 beginSection() 的調用與一次對 endSection() 的調用正確匹配。此外,您不能在一個線程上調用 beginSection(),而在另一個線程上結束它,您必須在同一個線程上調用這兩個方法。
Writes a trace message to indicate that a given section of code has begun. This call must be followed by a corresponding call to endSection()
on the same thread
.
//sectionName:The name of the code section to appear in the trace
public static void beginSection(@NonNull String sectionName) {
if (isTagEnabled(TRACE_TAG_APP)) {
if (sectionName.length() > MAX_SECTION_NAME_LEN) {
throw new IllegalArgumentException("sectionName is too long, max is ");
}
nativeTraceBegin(TRACE_TAG_APP, sectionName);
}
}
Writes a trace message to indicate that a given section of code has ended. This call must be preceeded by a corresponding call to beginSection(String)
. Calling this method will mark the end of the most recently begun section of code, so care must be taken to ensure that beginSection / endSection pairs are properly nested
and called from the same thread
.
public static void endSection() {
if (isTagEnabled(TRACE_TAG_APP)) {
nativeTraceEnd(TRACE_TAG_APP);
}
}
使用技巧
- 縱向信息記錄的是
調用關系
(流程圖) - 橫向信息記錄的是
調用順序
(時序圖)
線程狀態
Systrace 會用不同的顏色
來標識不同的線程狀態,在每個方法上面都會有對應的線程狀態來標識目前線程所處的狀態。通過查看線程狀態我們可以知道目前的瓶頸是什么,是 CPU 執行慢還是因為 Binder 調用,又或是進行 IO 操作,又或是拿不到 CPU 時間片。
線程狀態主要有下面幾個:
- 綠色:正在運行,線程正在完成與某個進程相關的工作或正在響應中斷
- 藍色:可運行,線程可以運行但目前未進行調度
- 白色:休眠,線程沒有可執行的任務,可能是因為線程在遇到斥鎖定時被阻止
- 橙色:不可中斷的休眠,線程在遇到 I/O 操作時被阻止或正在等待磁盤操作完成
- 紫色:可中斷的休眠,線程在遇到另一項內核操作(通常是內存管理)時被阻止
注意:在 Systrace 報告中,您可以點擊該線條以確定該線程在給定時間由哪個 CPU 控制。
綠色:運行中 Running
只有在該狀態的進程才可能在CPU上運行。而同一時刻可能有多個進程處於可執行狀態,這些進程的 task_struct 結構(進程控制塊)被放入對應CPU的可執行隊列中(一個進程最多只能出現在一個 CPU 的可執行隊列中)。進程調度器的任務就是從各個 CPU 的可執行隊列中分別選擇一個進程在該 CPU 上運行。
作用:我們經常會查看 Running 狀態的線程,查看其運行的時間,與競品做對比,分析快或者慢的原因:
- 是否頻率不夠?
- 是否跑在了小核上?
- 是否頻繁在 Running 和 Runnable 之間切換?為什么?
- 是否頻繁在 Running 和 Sleep 之間切換?為什么?
- 是否跑在了不該跑的核上面?比如不重要的線程占用了超大核
藍色:可運行 Runnable
線程可以運行但當前沒有安排,在等待 cpu 調度
作用:Runnable 狀態的線程狀態持續時間越長,則表示 cpu 的調度越忙,沒有及時處理到這個任務:
- 是否后台有太多的任務在跑?
- 沒有及時處理是因為頻率太低?
- 沒有及時處理是因為被限制到某個 cpuset 里面,但是 cpu 很滿?
- 此時 Running 的任務是什么?為什么?
白色:休眠中 Sleeping
線程沒有工作要做,可能是因為線程在互斥鎖上被阻塞。
作用:一般是在等事件驅動
橙色:不可中斷的睡眠態
線程在 I/O 上被阻塞或等待磁盤操作完成,一般底線都會標識出此時的 callsite :wait_on_page_locked_killable
作用:這個一般是標示 IO 操作慢,如果有大量的橘色不可中斷的睡眠態出現,那么一般是由於進入了低內存狀態,申請內存的時候觸發 pageFault,linux 系統的 page cache 鏈表中有時會出現一些還沒准備好的 page(即還沒把磁盤中的內容完全地讀出來) ,而正好此時用戶在訪問這個 page 時就會出現 wait_on_page_locked_killable 阻塞了。只有系統當 io 操作很繁忙時,每筆的 io 操作都需要等待排隊時,極其容易出現且阻塞的時間往往會比較長。
紫色:可中斷的睡眠態
線程在另一個內核操作(通常是內存管理)上被阻塞。
作用:一般是陷入了內核態,有些情況下是正常的,有些情況下是不正常的,需要按照具體的情況去分析
Linux 常見的進程狀態
- I 空閑 Idle
- D 不可中斷的休眠狀態(ususally IO),Uninterruptible sleep
- R 正在運行或在運行隊列中等待 Runnable
- S 處於休眠狀態 Sleeping
- T 停止或被追蹤 Terminate
- W 無駐留頁,沒有足夠的記憶體分頁可分配
- X 死掉的進程
- Z 僵死進程,進程已終止, 但進程描述符存在 Zombie
- < 優先級高的進程
- N 優先級較低的進程
- L 內存鎖頁,有記憶體分頁分配並縮在記憶體內 Lock
- s 進程的領導者,在它之下有子進程
- l 多進程的
可通過 adb shell ps
列出當前進程信息,其中S
列(State)代表進程狀態
進程喚醒信息分析
Systrace 會標識出一個非常有用的信息,可以幫助我們進行跨進程調用相關的分析。
一個進程被喚醒的信息往往比較重要,知道他被誰喚醒,那么我們也就知道了他們之間的調用等待關系,如果出現一段比較長的 sleep 情況,然后被喚醒,那么我們就可以去看是誰喚醒了這個線程,對應的就可以查看喚醒者的信息,看看為什么喚醒者這么晚才喚醒。
一個常見的情況是:應用進程使用 Binder 與 SystemServer 的 AMS 線程進行通信,但是恰好 AMS 的這個函數正在等待鎖釋放(或者這個函數本身執行時間很長),那么應用進程就需要等待比較長的時間,如果恰好是應用進程的主線程在進行等待,那么就會出現性能問題,比如響應慢或者卡頓,這就是為什么后台有大量的進程在運行,或者跑完 Monkey 之后,整機性能會下降的一個主要原因。
Systrace 可以標示出這個的一個原因是,一個任務在進入 Running 狀態之前,會先進入 Runnable 狀態進行等待,而 Systrace 會把這個狀態也標示在 Systrace 上
拉到最上面查看對應的 cpu 上的 taks 信息,會標識這個 task 在被喚醒之前的狀態:
信息區數據解析
線程時間片 Thread Timeslice
函數片 Slice
Counter Sample 采樣
Async Slice
CPU Slice
User Expectation
位於整個 Systrace 最上面的部分,標識了 Rendering Response 和 Input Response
2020-12-14