個案研究:Gmail Wear OS 團隊如何將應用程式啟動效能提升 50%

應用程式啟動是指應用程式對使用者的第一印象。使用者不喜歡等待,因此請務必確保應用程式可快速啟動。為向您介紹實際應用程式開發團隊如何發現應用程式啟動問題並診斷出問題,以下提供 Gmail Wear OS 團隊的做法。

Gmail Wear OS 團隊進行了最佳化工作,特別著重於應用程式啟動和執行階段轉譯效能,以滿足團隊的應用程式效能標準。不過,即使您沒有指定目標門檻,只要花一些時間調查,應用程式在大部分情況下一定會有改善空間。

擷取追蹤記錄並查看應用程式啟動情況

如要開始分析,請擷取包含應用程式啟動作業的追蹤記錄,以便在 Perfetto 或 Android Studio 中進一步檢查。本個案研究採用 Perfetto,原因是 Perfetto 可顯示裝置系統本身和應用程式以外的活動。在 Perfetto 中上傳追蹤記錄時,看起來會像這樣:

圖 1 Perfetto 中追蹤記錄的初始檢視畫面。

由於您要的重點是改善應用程式啟動程序,因此請找出含有「Android App Startups」自訂指標的資料列。將遊標懸停在資料列上方,然後按一下顯示的圖釘圖示 ,將資料列固定在檢視區塊頂端,會很有幫助。「Android App Startups」列的長條 (或區塊) 會顯示應用程式啟動涵蓋的時間範圍,直到第一個應用程式影格繪製到畫面上為止,因此您應找出其中是否有問題或瓶頸。

「Android App Startups」列,其中醒目顯示固定選項。
圖 2. 請將 Android App Startups 自訂指標固定在資訊主頁頂端,以便進行分析。

請注意,即使使用 reportFullyDrawn(),「Android App Startups」指標也代表初始顯示時間。如要找出完整顯示時間,請在 Perfetto 搜尋框中搜尋 reportFullyDrawn()

檢查主執行緒

首先,檢查主執行緒上有什麼活動。主要執行緒非常重要,因為它通常是發生所有 UI 轉譯的位置;一旦封鎖,系統就不會執行繪圖,且應用程式似乎凍結。因此希望確保主執行緒上沒有任何長時間執行的作業。

如要找到主要執行緒,請找出含有應用程式套件名稱的資料列,然後展開該列。名稱與套件相同的兩個資料列 (通常是該部分的前兩列) 代表主要執行緒。在兩個主要執行緒列中,第一個列代表 CPU 狀態,第二列則代表追蹤點。將兩個主要執行緒資料列固定在「Android App Startups」指標下方。

Android App Startups 和主要執行緒列已固定。
圖 3. 將主要執行緒列固定在 Android App Startups 自訂指標下方,以利分析。

可執行狀態和 CPU 爭用所花費的時間

如要取得應用程式啟動期間 CPU 活動的匯總檢視畫面,請將遊標拖曳到主執行緒上,擷取應用程式啟動時間範圍。顯示的「Thread States」(執行緒狀態) 面板會顯示所選時間範圍內每個 CPU 狀態花費的總時間。

查看處於 Runnable 狀態的時間。執行緒處於 Runnable 狀態時,執行緒可以執行,但不會排定任何工作。這表示裝置負載相當繁重,無法排定高優先順序的工作。而且使用者可見的應用程式在排程中的優先順序最高,因此閒置主執行緒通常表示應用程式內的密集程序 (例如動畫轉譯) 與主要執行緒在 CPU 作業時間之間競爭。

在「討論串狀態」面板中,以不同狀態醒目顯示總時間。
圖 4. 評估 RunnableRunning 狀態的相對時間,初步瞭解 CPU 爭用情況的數量。

Runnable 狀態與 Running 狀態時間的比率越高,發生 CPU 爭用情況的可能性就越高。以這種方式檢查效能問題時,請先專注處理執行時間最長的影格,然後處理較小的問題。

分析處於 Runnable 狀態的時間時,請考慮裝置硬體。由於描述的應用程式是在具有兩個 CPU 的穿戴式裝置上執行,因此預期在 Runnable 狀態花費的時間較長,並且與其他程序相比,所爭用的 CPU 爭用情形比採用 CPU 較多的裝置還多。雖然 Runnable 狀態花費的時間比一般手機應用程式預期的更長,但或許也能在穿戴式裝置的使用情境下理解。

OpenDexFilesFromOat*的使用時間

現在,請查看 OpenDexFilesFromOat* 花費的時間;在追蹤記錄中,這項作業的發生時間與 bindApplication 片段相同。這個片段代表讀取應用程式 DEX 檔案所需的時間。

已封鎖的繫結器交易

接著,查看繫結器交易。繫結器交易代表用戶端和伺服器之間的呼叫:在這種情況下,應用程式 (用戶端) 會使用 binder transaction 呼叫 Android 系統 (伺服器),而伺服器會透過 binder reply 回應。請確保應用程式不會在啟動期間進行不必要的繫結器交易,因為這會增加 CPU 爭用的風險。如果可以,請在應用程式啟動期過後,延後涉及繫結器呼叫的工作。如果您要進行繫結器交易,請確認這些交易時間不會超過裝置的 Vsync 刷新率

在這種情況下,第一筆繫結器交易通常與 ActivityThreadMain 配量相同時,似乎較長。如要進一步瞭解相關情況,請按照下列步驟操作:

  1. 如要查看相關的繫結器回覆,並進一步瞭解繫結器交易的優先順序,請按一下繫結器交易配量。
  2. 如要查看繫結器回覆,請前往「Current Selection」面板,然後按一下「追蹤執行緒」區段下方的「繫結至回覆」。如果您想手動前往該執行緒,「Thread」欄位也會通知執行緒回應是在發生,但屬於其他程序。畫面上會出現一行連結繫結器交易和回覆的內容。

    有一行文字會連接繫結器呼叫和回覆。
    圖 5. 找出應用程式啟動期間發生的繫結器交易,並評估是否可以延後交易。
  3. 如要查看系統伺服器如何處理這項繫結器交易,請將「Cpu 0」和「Cpu 1」執行緒固定在畫面頂端。

  4. 尋找包含繫結器回覆執行緒名稱的配量 (在本例中為「Binder:687_11 [2542]」),找出處理繫結器回覆的系統程序。按一下相關的系統程序,進一步瞭解繫結器交易。

請查看與在 CPU 0 上發生的繫結器交易相關的系統程序:

系統程序結束時,顯示「可執行」(已先佔)。
圖 6. 系統程序處於 Runnable (Preempted) 狀態,表示將延遲。

「End State」(結束狀態) 顯示 Runnable (Preempted),表示程序因 CPU 正在執行其他作業而開始延遲。如要找出會遭到先佔的項目,請展開「FtraceEvents」資料列。在可供使用的「Ftrace 事件」分頁中,捲動並查看與「Binder:687_11 [2542]」相關的繫結器執行緒相關的事件。在系統程序遭到先佔的當下,有兩個包含「decon」引數的系統伺服器事件發生,代表這些事件與螢幕控制器相關。這聽起來很合理,因為顯示控制器會將影格放在螢幕上,這是一項重要任務!活動日期維持原樣。

與興趣相似交易相關的 FTrace 事件醒目顯示。
圖 7. FTrace 事件表示繫結器交易遭到螢幕控制器事件延遲。

JIT 活動

如要調查即時編譯 (JIT) 活動,請展開屬於應用程式的程序,找出兩個「Jit 執行緒集區」列,然後將其固定至檢視區塊頂端。由於此應用程式可在應用程式啟動期間使用基準設定檔,因此在第一個影格繪製之前,只有少數 JIT 活動會發生,以第一個 Choreographer.doFrame 呼叫的結尾表示。不過請注意,啟動緩慢原因為 JIT compiling void,表示系統在標示為 Application creation 的追蹤點期間發生的系統活動,會造成許多背景 JIT 活動。如要解決這個問題,請將設定檔集合展開到應用程式可供使用的位置,將第一個影格繪製至基準設定檔後不久後發生的事件。在多數情況下,您可以在基準設定檔集合 Macrobenchmark 測試的結尾新增一行程式碼,等待特定 UI 小工具在螢幕上顯示,代表畫面已完整填入。

以「Jit Compiling void」切片醒目顯示 Jit 執行緒集區。
圖 8.如果您發現大量 JIT 活動,請將基準設定檔展開至應用程式可供使用的時間。

成果

透過此分析,Gmail Wear OS 團隊進行了以下改善:

  • 當使用者查看 CPU 活動時,會在應用程式啟動期間發現爭用情形,因此他們取代了用來表示應用程式正在載入的單一靜態圖片的旋轉圖示。同時,他們也延長啟動畫面的時間,延遲閃亮狀態,第二個螢幕狀態代表應用程式正在載入,釋放到可用的 CPU 資源。這會讓應用程式啟動延遲時間縮短 50%。
  • 從查看 OpenDexFilesFromOat*JIT 活動所花的時間,他們讓 R8 重寫基準設定檔。這使得應用程式啟動延遲時間提高了 20%。

以下是該團隊提供幾個訣竅,說明如何有效分析應用程式效能:

  • 設定可自動收集追蹤記錄和結果的持續性程序。建議您使用基準化為應用程式設定自動追蹤。
  • 針對您認為能夠改善成效的變更進行 A/B 測試,如果不會改進,則拒絕。您可以使用 Macrobenchmark 程式庫評估不同情境下的效能。

如要進一步瞭解相關內容,請參閱下列資源: