【文章內容使用 Gemini 1.5 Pro 自動產生】
Flutter 應用程式的效能測試
Flutter 框架在預設情況下非常快速,但這是否意味著您不必考慮效能呢?不。絕對有可能撰寫出速度緩慢的 Flutter 應用程式。另一方面,也有可能充分利用框架,讓您的應用程式不僅速度快,而且高效,消耗更少的 CPU 時間和電池。
Flutter 效能優化的概略準則如下:
- 更新狀態時,目標盡可能少的 Widget。
- 僅在必須時更新狀態。
- 將計算密集型任務放在建構方法之外,理想情況下是在主隔離區之外。
事實上,對於許多有關效能优化的問題,答案是「視情況而定」。對 特定 Widget 進行的 特定 優化是否值得付出努力和維護成本?特定 情況下的 特定 方法是否有意義?
這些問題唯一有用的答案來自測試和測量。量化每個選擇對效能的影響,並根據這些資料做出決定。
好消息是,Flutter 提供了出色的效能分析工具,例如 Dart DevTools(目前處於預覽發行階段),其中包含 Flutter Inspector,或者您可以直接從 Android Studio(安裝 Flutter 外掛後)使用 Flutter Inspector。您有 Flutter Driver 用於測試您的應用程式,以及用於儲存效能資訊的 Profile 模式。
壞消息是現代智慧型手機非常「聰明」。
治理器的問題
iOS 和 Android 治理器使量化 Flutter 應用程式的效能變得特別困難。這些系統級別的守護程序會根據負載調整 CPU 和 GPU 單位的速度。當然,這大多是好事,因為它確保在消耗盡可能少的電池的情況下提供流暢的效能。
缺點是,您可以透過讓應用程式 更多 地工作來使其顯著 更快。
在下方,您可以看到如何將具有無意義 print
語句的迴圈加入到應用程式中,使治理器切換到更高檔,從而使應用程式更快,其效能也更可預測。
在此實驗中,較差的程式碼導致更快的建構時間(上方)、更快的柵格化時間和更高的畫面更新率。當客觀上較差的程式碼導致更好的效能指標時,您便無法依賴這些指標來提供指導。
這只是一個例子,說明行動應用程式的效能基準測試為何會不合常理且困難。
在下方,我分享了一些我在處理 Flutter 的 Google I/O 應用程式 Developer Quest 時收集的技巧。
基本建議
- 在 DEBUG 模式下不要測量效能。僅在 profile 模式下測量效能。
- 在真實設備上測量,而不是在 iOS 模擬器或 Android 模擬器中。軟體模擬器非常適合開發,但它們與真實設備的效能特性有很大差異。Flutter 不允許您在模擬設備上以 profile 模式執行,因為這沒有任何意義。您以這種方式收集的資料不適用於現實世界的效能。
- 理想情況下,使用相同的物理設備。將其作為您的專用效能測試設備,不要用於其他任何用途。
- 了解 Flutter 的 效能分析工具。
CPU/GPU 治理器
如上所述,現代作業系統會根據負載和其他一些啟發式算法更改其處置的每個 CPU 和 GPU 的頻率。(例如,觸碰螢幕通常會使 Android 手機切換到更高檔。)
在 Android 上,您可以關閉這些治理器。我們稱此過程為「比例鎖定」。
- 建立一個比例鎖定效能測試設備的腳本。您可以使用 Skia 的做法 作為靈感。您也可以查看 Unix CPU API。
- 除非您執行的基準測試作業規模龐大,例如 Skia,否則您可能想要更輕量級且不那麼通用的工具。查看 Developer Quest 的 shell 腳本 以獲取一些提示。例如,以下摘錄將 CPU 設為使用者空間治理器(唯一不會自行更改 CPU 頻率的治理器)。
1 |
|
- 您的目標在此不是模擬現實世界的效能(沒有使用者會比例鎖定其設備),而是讓不同執行之間的效能指標具有可比性。
- 最終,您需要進行實驗,並將 shell 腳本調整為您將使用的設備。這項工作很繁瑣,但直到您完成這項工作之前,您的效能資料都會欺騙您。
Flutter Driver
Flutter Driver 讓您可以自動測試您的應用程式。請閱讀 flutter.dev 的 效能分析 部分,以獲取有關如何在分析應用程式時使用它的具體做法。
- 在效能測試時,不要手動測試您的應用 Programm。始終使用 Flutter Driver 以確保您比較的是同樣的事物。
- 撰寫 Flutter Driver 程式碼,讓它測試您真正想要測量的內容。如果您追求的是一般的應用程式效能,請嘗試瀏覽應用程式的各個部分,並執行使用者會執行的操作。
- 如果您的應用程式包含機率因素(隨機、網路事件等),請將其模擬出來。這些瀏覽過程應盡可能彼此相似。
- 如果需要,請使用 Timeline 的
startSync()
和finishSync()
方法來新增自訂時間軸事件。例如,當您感興趣的是特定函數的效能時,此方法非常有用。將startSync()
放在其開頭,將finishSync()
放在其結束位置。 - 儲存摘要(
writeSummaryToFile
)和更重要的是原始時間軸(writeTimelineToFile
)。 - 對於應用程式的每個版本,請執行多次測試。對於 Developer Quest,我將其收斂到 100 次執行。(當您測量雜訊較大的事物時,例如第 99 個百分位數,您可能需要更多次執行。)對於基於 POSIX 的系統,這只意味著執行類似以下內容:
for i in {1..100}; do flutter drive --target=test_driver/perf.dart --profile; done
。
時間軸
時間軸是 profile 執行結果的原始輸出。Flutter 將此資訊轉儲到一個 JSON 檔案中,可以將其載入到 chrome://tracing
中。
- 了解如何在 Chrome 的追蹤時間軸中打開完整時間軸。您只需要在 Chrome 瀏覽器中打開
chrome://tracing
,點選「載入」,然後選擇 JSON 檔案。您可以在 這個簡短的教學課程 中了解更多資訊。(Flutter 也提供了 時間軸工具,目前處於技術預覽階段。我沒有使用它,因為 Developer Quest 專案在 Flutter 的時間軸工具準備就緒之前就已經開始了。) - 使用 WSAD 鍵在
chrome://tracing
中移動時間軸,並使用 1234 切換操作模式。 - 首次設定效能測試時,請考慮使用完整的 Android 系統追蹤來執行 Flutter Driver。這為您提供了更多關於設備中實際發生的事情的洞察力,包括 CPU 比例資訊。但是,請不要在完全開啟系統追蹤的情況下測量您的應用程式,因為它會使一切都變得更慢且更不可預測。
- 如何使用 Flutter Driver 執行完整的 Android 系統追蹤?首先,使用
/path/to/your/android/sdk/platform-tools/systrace/systrace.py --atrace-categories=gfx,input,view,webview,wm,am,sm,audio,video,camera,hal,app,res,dalvik,rs,bionic,power,pm,ss,database,network,adb,pdx,sched,irq,freq,idle,disk,load,workq,memreclaim,regulators,binder_driver,binder_lock
開始 Android 系統追蹤。然後,使用flutter run test_driver/perf.dart --profile --trace-systrace
啟動應用程式。最後,使用flutter drive --driver=test_driver/perf_test.dart --use-existing-app=http://127.0.0.1:NNNNN/
(其中 NNNNN 是flutter run
上面的埠號)啟動 Flutter Driver。
指標
查看盡可能多的指標總比少好,但我發現有些指標比其他指標更有用。
- 建構時間和柵格化時間(TimelineSummary 預設提供的指標)僅適用於實際上不包含太多 UI 建構以外的內容的非常嚴格的效能測試。
- 不要將 TimelineSummary.frameCount 作為計算畫面更新率 (FPS) 的方法。Flutter 的 profile 工具不會提供實際的畫面更新率資訊。TimelineSummary 提供
countFrames()
方法,但它只計算已完成的畫面建構次數。一個經過良好優化的應用程式會限制不必要的重新建構,其畫面更新率將低於頻繁重新建構的未優化應用程式。 - 我個人透過測量執行 Dart 程式碼所花費的總 CPU 時間來獲得最有用的資料。這計算了在建構方法中以及在建構方法之外執行的程式碼。假設您在比例鎖定的設備上執行 profile 測試,則總 CPU 時間是應用程式將消耗多少電池電量的良好近似值。
- 找出執行 Dart 程式碼所花費的總 CPU 時間最簡單的方法是測量時間軸中 MessageLoop:FlushTasks 事件的範圍。對於 Developer Quest,我撰寫了一個 Dart 工具 來提取這些事件。
- 若要偵測卡頓(即跳過的畫面),請尋找極端值。例如,對於 Developer Quest 的特定案例和我們用於測試的設備,查看第 95 個百分位數的建構時間很有幫助。(即使比較具有截然不同的效率水準的程式碼,第 90 個百分位數的建構時間也過於相似,而第 99 個百分位數的數字往往會出現雜訊。您的情況可能有所不同。)
- 如上所述,請對應用程式的每個版本執行多次測試(可能 100 次)。然後,使用具有誤差範圍的平均值或百分位數資料。更好的是,使用箱型圖。
結果
設定完畢後,您便能夠自信地比較提交和實驗。在下方,您可以看到針對常見困境的答案:「這個優化是否值得維護開銷?」
我認為在 特定 案例中,答案是肯定的。只需增加幾行程式碼,我們應用程式的每次自動瀏覽平均可以節省 12% 的 CPU 時間。
但是,這是本文的主要訊息 - 另一項優化的測量結果可能會顯示出截然不同的情況。試圖過度外推效能測量結果是引人入勝的,但錯誤的做法。
換句話說:「視情況而定」。我們應該接受這句話。
Flutter 應用程式的效能測試 最初發佈在 Flutter 上的 Medium,人們在那裡透過突出顯示和回應這個故事來繼續討論。