Google is committed to advancing racial equity for Black communities. See how.
本頁面由 Cloud Translation API 翻譯而成。
Switch to English

了解Systrace

systrace是用於分析Android設備性能的主要工具。但是,它實際上是其他工具的包裝。它是圍繞atrace的主機端包裝程序,它是控制用戶空間跟踪並設置ftrace的設備端可執行文件,也是Linux內核中的主要跟踪機制。 systrace使用atrace啟用跟踪,然後讀取ftrace緩衝區並將其包裝在獨立的HTML查看器中。 (雖然較新的內核支持Linux增強型Berkeley數據包過濾器(eBPF),但以下文檔與3.18內核(無eFPF)有關,因為Pixel / Pixel XL上使用了該文檔。)

systrace由Google Android和Google Chrome團隊擁有,是Catapult項目的一部分,是開源的。除了systrace,Catapult還包括其他有用的實用程序。例如,ftrace具有比systrace或atrace直接啟用的功能更多的功能,並且包含一些對於調試性能問題至關重要的高級功能。 (這些功能需要root用戶訪問權限,並且通常需要一個新內核。)

運行systrace

在Pixel / Pixel XL上調試抖動時,請從以下命令開始:

./systrace.py sched freq idle am wm gfx view sync binder_driver irq workq input -b 96000

當與GPU和顯示管道活動所需的其他跟踪點結合使用時,這使您能夠從用戶輸入跟踪到屏幕上顯示的幀。將緩衝區的大小設置為較大,以避免丟失事件(由於沒有較大的緩衝區,某些CPU在跟踪中的某個點之後不包含任何事件)。

通過systrace時,請記住,每個事件都是由CPU上的某些事件觸發的

由於systrace是基於ftrace構建的,並且ftrace在CPU上運行,因此CPU上的某些內容必須寫入ftrace緩衝區以記錄硬件更改。這意味著,如果您對顯示圍欄為何更改狀態感到好奇,則可以在其轉換的確切時間查看CPU上正在運行的內容(CPU上正在運行的內容觸發了日誌中的更改)。該概念是使用systrace分析性能的基礎。

示例:工作框架

本示例描述了常規UI管道的systrace。要繼續執行該示例,請下載跟踪的zip文件(還包括本節中提到的其他跟踪),解壓縮該文件,然後在瀏覽器中打開systrace_tutorial.html文件。警告該systrace是一個大文件;除非您在日常工作中使用systrace,否則這可能是一條包含更多信息的跟踪,比以前在單個跟踪中看到的要多得多。

為了保持一致的周期性工作負載(如TouchLatency),UI管道包含以下內容:

  1. SurfaceFlinger中的EventThread會喚醒應用程序UI線程,表明是時候渲染一個新框架了。
  2. 該應用程序使用CPU和GPU資源在UI線程,RenderThread和hwuiTasks中渲染框架。這是用於UI的大部分容量。
  3. 該應用程序使用活頁夾將渲染的幀發送到SurfaceFlinger,然後SurfaceFlinger進入睡眠狀態。
  4. SurfaceFlinger中的第二個EventThread喚醒SurfaceFlinger以觸發合成並顯示輸出。如果SurfaceFlinger確定沒有要做的工作,它將回到睡眠狀態。
  5. SurfaceFlinger使用Hardware Composer(HWC)/ Hardware Composer 2(HWC2)或GL處理合成。 HWC / HWC2的組成更快,功耗更低,但取決於片上系統(SoC)的局限性。這通常需要約4-6毫秒,但由於Android應用程序始終是三重緩衝的,因此可能與步驟2重疊。 (雖然應用程序始終是三重緩衝,但SurfaceFlinger中可能只有一個待處理的幀等待,這使其看起來與雙緩衝相同。)
  6. SurfaceFlinger分派最終輸出以與供應商驅動程序一起顯示,然後返回睡眠狀態,等待EventThread喚醒。

讓我們遍歷從15409 ms開始的幀:

運行EventThread的普通UI管道
圖1.普通UI管道,EventThread正在運行

圖1是一個被普通框架包圍的普通框架,因此這是理解UI管道如何工作的一個很好的起點。 TouchLatency的UI線程行在不同的時間包含不同的顏色。條形圖表示線程的不同狀態:

  • 灰色的。睡眠。
  • 藍色。可運行(可以運行,但是調度程序尚未選擇運行它)。
  • 綠色。正在運行(調度程序認為它正在運行)。
  • 紅。不間斷的睡眠(通常在內核鎖中睡眠)。可以指示I / O負載。對於調試性能問題非常有用。
  • 橙子。由於I / O負載而不會中斷睡眠。

要查看不間斷睡眠的原因(可從sched_blocked_reason跟踪點獲得),請選擇紅色的不間斷睡眠片。

當EventThread運行時,TouchLatency的UI線程變為可運行。要查看它的喚醒原因,請單擊藍色部分。

UI線程的TouchLatency
圖2. TouchLatency的UI線程

圖2顯示了TouchTatency UI線程被tid 6843喚醒,它對應於EventThread。 UI線程喚醒,渲染框架並將其排隊,以供SurfaceFlinger使用。

UI線程喚醒,渲染框架並將其排隊,以供SurfaceFlinger使用
圖3. UI線程喚醒,渲染框架並將其排隊,以供SurfaceFlinger使用

如果在跟踪中啟用了binder_driver標記,則可以選擇一個活頁夾事務以查看有關該事務涉及的所有進程的信息。

圖4.活頁夾交易

圖4顯示,由於tID 9579(TouchLatency的RenderThread),在15423.65毫秒處SurfaceFlinger中的Binder:6832_1變為可運行。您還可以在活頁夾事務的兩側看到queueBuffer。

在SurfaceFlinger一側的queueBuffer期間,來自TouchLatency的暫掛幀數從1變為2。

待處理的幀從1變為2
圖5.掛起的幀從1變為2

圖5顯示了三重緩衝,其中有兩個完整的幀,該應用程序即將開始渲染第三個。這是因為我們已經刪除了一些幀,所以該應用程序保留兩個待處理的幀,而不是一個,以嘗試避免進一步丟失幀。

不久之後,SurfaceFlinger的主線程被另一個EventThread喚醒,因此它可以將較舊的待處理幀輸出到顯示器:

SurfaceFlinger的主線程被另一個EventThread喚醒
圖6. SurfaceFlinger的主線程被另一個EventThread喚醒

SurfaceFlinger首​​先鎖存較舊的暫掛緩衝區,這將導致暫掛緩衝區計數從2減少到1。

SurfaceFlinger首​​先鎖在較舊的暫掛緩衝區上
圖7. SurfaceFlinger首​​先鎖在舊的暫掛緩衝區上

鎖住緩衝區後,SurfaceFlinger設置合成並將最後一幀提交給顯示。 (其中的某些部分已作為mdss跟踪點的一部分啟用,因此它們可能不包含在SoC中。)

SurfaceFlinger設置合成並提交最終幀
圖8. SurfaceFlinger設置合成並提交最後一幀

接下來, mdss_fb0在CPU 0上喚醒mdss_fb0是顯示管道的內核線程,用於將渲染的幀輸出到顯示器。我們可以在跟踪mdss_fb0視為其自己的行(向下滾動以查看)。

mdss_fb0在CPU 0上喚醒
圖9. mdss_fb0在CPU 0上喚醒

mdss_fb0喚醒,短暫運行,進入不間斷睡眠,然後再次喚醒。

示例:非工作框架

本示例介紹了用於調試Pixel / Pixel XL抖動的systrace。要跟隨該示例,請下載跟踪的zip文件(包括本節中提到的其他跟踪),解壓縮該文件,然後在瀏覽器中打開systrace_tutorial.html文件。

當您打開systrace時,您將看到以下內容:

在Pixel XL上運行的TouchLatency啟用了大多數選項
圖10.在Pixel XL上運行的TouchLatency(啟用了大多數選項,包括mdss和kgsl跟踪點)

當查找垃圾時,請檢查SurfaceFlinger下的FrameMissed行。 FrameMissed是HWC2提供的生活質量改進。查看其他設備的systrace時,如果該設備不使用HWC2,則可能不存在FrameMissed行。在這兩種情況下,FrameMissed都與SurfaceFlinger相關聯,而SurfaceFlinger缺少其極為常規的運行時之一,並且在com.prefabulated.touchlatency時應用程序的未決緩衝區計數( com.prefabulated.touchlatency )不變。

與SurfaceFlinger的FrameMissed相關
圖11.與SurfaceFlinger的FrameMissed相關性

圖11顯示了15598.29毫秒的丟失幀。 SurfaceFlinger在vsync間隔短暫醒來,不做任何工作就回到睡眠狀態,這意味著SurfaceFlinger認為不值得嘗試再次向顯示器發送幀。為什麼?

要了解此框架的管道如何中斷,請首先查看上面的工作框架示例,以查看普通的UI管道如何在systrace中出現。準備就緒後,返回錯過的幀並向後工作。請注意,SurfaceFlinger會喚醒並立即進入睡眠狀態。從TouchLatency查看待處理的幀數時,有兩個幀(有助於弄清楚發生了什麼的一個很好的線索)。

SurfaceFlinger喚醒並立即進入睡眠狀態
圖12. SurfaceFlinger喚醒並立即進入睡眠狀態

因為SurfaceFlinger中有框架,所以這不是應用程序問題。另外,SurfaceFlinger在正確的時間醒來,因此這不是SurfaceFlinger的問題。如果SurfaceFlinger和應用程序都看上去正常,則可能是驅動程序問題。

因為啟用了mdsssync跟踪點,所以我們可以獲得有關控制何時將幀提交到顯示器的圍柵(在顯示驅動程序和SurfaceFlinger之間共享)的信息。這些圍欄列在mdss_fb0_retire下,它表示何時顯示框架。這些圍欄是作為sync跟踪類別的一部分提供的。與SurfaceFlinger中的特定事件對應的圍欄取決於您的SOC和驅動程序堆棧,因此請與SOC供應商合作以了解跟踪中圍欄類別的含義。

mdss_fb0_退休圍欄
圖13. mdss_fb0_retire圍欄

圖13顯示的幀顯示了33 ms,而不是預期的16.7 ms。在該切片的一半處,該框架應該已被新的框架替代,但是沒有。查看上一幀並查找任何內容。

上一幀已破幀
圖14.破壞幀之前的幀

圖14顯示了14.482 ms的幀。破裂的兩幀片段為33.6 ms,大約是我們期望的兩幀(我們以60 Hz渲染,每幀16.7 ms,接近)。但是14.482毫秒根本不接近16.7毫秒,這表明顯示管道出了點問題。

確切調查圍欄的終止位置,以確定對其進行控制的方式。

調查圍欄末端
圖15.研究柵欄端

工作隊列包含__vsync_retire_work_handler ,當籬笆更改時該隊列正在運行。查看內核源代碼,您可以看到它是顯示驅動程序的一部分。它似乎在顯示管道的關鍵路徑上,因此必須盡快運行。它可以運行70個左右(不是很長的調度延遲),但這是一個工作隊列,可能無法準確調度。

檢查前一幀以確定是否有貢獻;有時抖動會隨著時間的流逝而加起來,並最終導致錯過最後期限。

前一幀
圖16.前一幀

kworker上的可運行線不可見,因為查看器在被選中時將其變為白色,但統計數據表明了這一點:部分顯示管線關鍵路徑的2.3 ms調度程序延遲很糟糕。在繼續之前,通過將顯示管道關鍵路徑的這一部分從工作隊列(作為SCHED_OTHER CFS線程運行)移動到專用SCHED_FIFO kthread,來解決延遲問題。此功能需要定時保證,以確保工作隊列無法提供(也不打算提供)。

這是這個原因嗎?很難下結論。除了易於診斷的情況(例如內核鎖爭用導致顯示關鍵線程進入睡眠狀態)外,跟踪通常不會指定問題。這種抖動是否可能是丟幀的原因?絕對。防護時間應為16.7毫秒,但與導致丟幀的幀中的防護時間根本不相近。考慮到顯示管線的緊密耦合,圍欄時序周圍的抖動可能會導致丟幀。

在此示例中,解決方案涉及將__vsync_retire_work_handler從工作隊列轉換為專用kthread。這樣可以顯著改善抖動,並減少彈跳球測試中的刺痛。隨後的跡線顯示了圍欄計時,其懸停時間非常接近16.7 ms。