原文連接:Performance testing of Flutter apps 做者:Filip Hracek (from Flutter team)android
Flutter 在默認狀態下就能運行得很是快,這點很是棒! 可是否這就意味着你徹底不須要考慮性能呢?git
答案是否認的,編寫一個速度很是慢的 Flutter 應用是徹底可能的。然而,另外一方面你也能夠充分利用這個框架,讓你的 app 不只快速,高效,並且使用更少的 CPU 時間和電量。github
這就是咱們想要的!在一個有意義的指標上來比較兩個版本的應用在統計上明顯的差別web
在 Flutter 中有一些性能優化的通用指導原則:chrome
你可能很難相信,對於大多數性能優化的問題來講,它們的答案通通指向了這句話——「它究竟取決於什麼?」。對於特定 Widget 是否值得進行特定優化,並付出維護成本?在特定狀況下的特殊處理是否合理?shell
對於這些問題惟一有用答案是測試和測量。量化每一個選擇對性能的影響,並根據該數據作出決定。瀏覽器
好消息是 Flutter 提供了出色的性能分析工具,例如包含 Flutter Inspector 的 Dart DevTools(目前還處於預覽版),或是 Android Studio 中的 Flutter Inspector(安裝了 Flutter 插件下)。你可使用 Flutter Driver 操做應用,並在 Profile 模式下保存性能信息。性能優化
然而壞消息是,如今的手機實在是太過智能了。😂bash
系統級守護進程須要根據當前負載調整 CPU 和 GPU 單元的速度,可是 iOS 和 Android 的管理器卻很難量化 Flutter 應用的性能。總的來講這仍是一件好事,由於它確保了平穩的性能,同時也消耗盡量少的電量。網絡
然而缺點是你徹底能夠經過提升其效率以顯著加快應用的運行速度。
下面的例子中,你能夠看到如何在應用中循環打印一些無心義的 print 語句,使得管理器切換到更高的檔位,從而讓應用運行更快速,性能更加可預測。
管理器的問題:在默認狀況下,你沒法相信這些數字。在上面這個盒子圖中,咱們在 x 軸上進行單獨運行(用它們開始的確切時間標記),並在 y 軸上表示構建時間。正如你所看到那樣,當咱們引入一些徹底沒必要要的打印語句時,它居然會縮短(而不是增長) build 時間。
在這個實驗中(上圖),更差的代碼反而致使了更快的構建時間,更快的光柵化時間和更高的幀率。若是客觀上更差的代碼會獲得更好的性能,那麼你就不能遵循這些指標。
上面僅僅是爲了解釋爲什麼移動應用性能基準不直觀,以及測試困難的一個例子。
接下來,我將分享一些 Google I/O app 上 Flutter 的例子,Developer Quest。
正如咱們剛纔所說的,現代操做系統根據負載和一些其餘的啓發式調整每一個 CPU 和 GPU 的頻率。(例如,觸摸屏幕一般會讓 Android 手機將其優先級置於更高的檔位。)
在 Android 上你可以直接關掉這些管理器,咱們稱之爲「scale locking」。
#!/usr/bin/env bash
GOV="userspace"
echo "Setting CPU governor to: ${GOV}"
adb shell "echo ${GOV} > /sys/devices/system/cpu/cpu${CPU_NO}/cpufreq/scaling_governor"
ACTUAL_GOV=`adb shell "cat /sys/devices/system/cpu/cpu${CPU_NO}/cpufreq/scaling_governor"`
echo "- result: ${ACTUAL_GOV}"
複製代碼
Flutter Driver 可以自動執行應用。你能夠閱讀 flutter.dev 上性能分析的文章,瞭解如何使用它來分析應用。
startSync()
方法 和 finishSync()
方法,來添加自定義時間軸事件。例如,當你想要測試特定方法的性能時,這頗有用。將 startSync()
放在它的開頭,並在方法結束時使用 finishSync()
。for i in {1..100}; do flutter drive --target=test_driver/perf.dart --profile; done
複製代碼
時間軸是你運行 profile 模式下輸出的原始資料。Flutter 將此信息轉儲到可被 chrome://tracing
加載的 JSON 文件中。
chrome://tracing
,而後點擊「Load」,選擇那個 JSON 文件。你能夠在這篇 簡短指導 中得到關於它的更多信息。(一樣有 Flutter Timeline tooling,但目前還處於 tech preview 階段。由於在 Flutter 的 timeline tooling 準備就緒以前,Developer Quest 項目就已經開始了,因此我還沒用過那個。)chrome://tracing
的 timeline 中移動,以及使用 1234 來更改操做模式。/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 systrace。 而後經過 flutter run test_driver/perf.dart --profile --trace-systrace
運行 app。最後,經過 flutter drive --driver=test_driver/perf_test.dart --use-existing-app=http://127.0.0.1:NNNNN/
啓動 Flutter Driver(其中 NNNNN 是 Flutter run
上運行的端口給你的)。最好能看盡量多的指標,但我發現一些相比其餘更有用的指標。
build 的時間 和 光柵化的時間 僅在真正嚴格的性能測試中才有用(默認狀況下提供的度量標準是 TimelineSummary
),這些測試除了 UI 以外不會包含太多其餘內容。
不要把 TimelineSummary.frameCount
看做計算每秒幀數(FPS)的方法。Flutter 的配置文件工具不能給你提供真實的幀速率信息。TimelineSummary
雖然提供了 countFrames()
方法,但它只會計算已完成的幀構建了多少次。一個優化良好的應用能夠限制沒必要要的重建,每秒的幀數比常常重建的未經優化的應用程序少不少。
我我的得到的最有用的數據是經過測量運行 Dart 代碼所花費的總 CPU 時間獲得的。這會算上 build 方法和外部執行的代碼。假設你在 scale-locked 的設備上運行配置文件測試,總 CPU 時間能夠很好地估算你的應用程序將消耗更多仍是更少的電。
MessageLoop:FlushTasks
事件的範圍。在製做 Developer Quest
的時候,我編寫了一個 Dart 工具來提取它們。當這些都設置好了以後,你就可以自信地比較提交和實驗。下面,你能夠看到一個很常見困境的答案:「這種優化值得維護開銷嗎?」
我認爲對於這個狀況來講,答案是確定的。只需幾行代碼,咱們應用的每一個自動測試平都可以減小 12% 的 CPU 時間。
然而,本文的主要內容是,不一樣的測量方式可能會反映處很是不一樣的東西。嘗試過於寬泛地推斷性能測量也許十分符合直覺,但倒是錯誤的。
換句話說:「它究竟取決於什麼」。咱們應該信奉這句話。
以上即是翻譯的所有內容,我認爲這篇文章對咱們構建高效的 Flutter 應用具備很大的指導意義,因此便翻譯出來分享給你們。
如如有譯誤還請指出。