性能優化 Systrace 系統跟蹤 [MD]


博文地址

我的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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM