網站首頁 編程語言 正文
引言
偶然在Youtube上看到一名國外安卓開發者分享了一個提升應用性能的視頻,其中使用到了macro benchmark來進行性能測量,包括啟動速度和列表幀率,方法是生成一個baseline-prof.txt文件放于app/src/main/下。查閱google的官方文檔,其背后原理如下:
通過在應用或庫中分發基準配置文件,Android 運行時 (ART) 可以通過預先 (AOT) 編譯來優化包含的代碼路徑,從而針對每位新用戶以及每個應用更新提升性能。這種配置文件引導的優化 (PGO) 可讓應用優化啟動、減少互動卡頓,并提高整體的運行時性能,從而讓用戶從首次啟動開始便獲得更好的使用體驗。
基準配置文件介紹
baseline-prof.txt文件中定義了安裝時要預編譯的代碼路徑,打包時會跟隨aab一起上傳到Google Play,通過Google play安裝時將獲得預編譯的收益。
這個方案看起來很不錯,相比于其它的那些難以上手的啟動優化方案,這個似乎比較好落地,于是乎我開始了接入嘗試,最后艱難成功了。
測量工具
官方建議使用Jetpack Macrobenchmark來測試應用在已啟動基準配置文件時的性能,然后將這些結果與已停用基準配置文件時的基準進行比較。接入的方式也很簡單,如果你的AS版本滿足要求,File/New Module/Benchmark就可以了。
會在benchmark Module生成一個ExampleStartupBenchmark測試類,將其修改一下變成如下。
@RunWith(AndroidJUnit4ClassRunner::class) class ColdStartupBenchmark { @get:Rule val benchmarkRule = MacrobenchmarkRule() /** * 不使用基準配置文件 */ @Test fun startupNoCompilation() = startup(CompilationMode.None() ) /** * 使用基準配置文件模式 */ @Test fun startupBaselineProfile() = startup(CompilationMode.Partial()) @Test fun startupFullCompilation() = startup(CompilationMode.Full()) private fun startup(compilationMode: CompilationMode) = benchmarkRule.measureRepeated( packageName = "com.example.macrobenchmark.target", metrics = listOf(StartupTimingMetric()), compilationMode = compilationMode, iterations = 10, startupMode = StartupMode.COLD, setupBlock = { pressHome() } ) { // Waits for the first rendered frame, which represents time to initial display. startActivityAndWait() // Waits for content to be visible, which represents time to fully drawn. //此處可刪除,my-content根據自己項目首頁的布局決定 device.wait(Until.hasObject(By.res("my-content")), 5_000) } }
選擇帶有Benchmark后綴的build variant,測試結果如下所示:
ExampleStartupBenchmark_startUpCompilationModePartial
timeToInitialDisplayMs ? min 290.7, ? median 310.5, ? max 391.2
Traces: Iteration 0 1 2 3 4ExampleStartupBenchmark_startUpCompilationModeNone
timeToInitialDisplayMs ? min 359.4, ? median 381.9, ? max 420.6
Traces: Iteration 0 1 2 3 4
timeToInitialDisplayMs
?- 從系統收到啟動 intent 到渲染目標 activity 的第一幀的時間
timeToFullDisplayMs
?- 從系統收到啟動 intent 到應用通過?reportFullyDrawn?方法報告已完成繪制的時間。這個需要你手動調用activity.reportFullDrawn()才會有結果展示,表示此時已完全繪制。
Trace: Iteration
可以看到每次啟動的trace記錄,點擊數字會跳到Profiler分析界面
運行的時候可能會遇到的問題:
有配置多渠道(Flavor),然后提示Run configuration ExampleStartupBenchmark is not supported in the current project.Cannot obtain the package.解決辦法是benchmark里的flavor保持跟app模塊一致就可以了
aar依賴找不到
Could not determine the dependencies of null. Could not resolve all task dependencies for configuration':benchmark:flavorDemoBenchmarkTestedApks'. Could not find :your_aar_name_in_testModule_libs:. Required by: project :benchmark > project :app > project :testModule
解決方案:在benchmark模塊的build.gradle中添加
repositories { flatDir { dirs '../testModule/libs', '../app/libs' } }
Unable to read any metrics during benchmark因為benchmark模塊中的benchmark buildtype中debuggable要設為true才行
官方文檔
生成基準配置文件
在benchmark模塊處新建一個測試類:
@ExperimentalBaselineProfilesApi @RunWith(AndroidJUnit4::class) class BaselineProfileGenerator { @get:Rule val baselineProfileRule = BaselineProfileRule() @Test fun startup() = baselineProfileRule.collectBaselineProfile(packageName = "com.example.app") { pressHome() // This block defines the app's critical user journey. Here we are interested in // optimizing for app startup. But you can also navigate and scroll // through your most important UI. startActivityAndWait() } }
新建一個Android9以上版本模擬器(真機不行),注意系統選擇不包含Google Api的,執行adb root命令,修改ndk filter添加支持,之后就可以跑上面新建的測試了,執行完成之后基準配置文件會生成于benchmark/build/outputs/connected_android_test_additional_output/flavorDemoBenchmark/Pixel 2
處,名字類似于BaselineProfileGenerator_generateBaselineProfile-baseline-prof-2023-01-30-07-29-28.txt,將之拷貝到app/src/main/目錄下,重命名為baseline-prof.txt。
官方文檔
驗證優化效果
萬事俱備,只欠驚喜,驗證一下對啟動速度有多大提升。
在app模塊添加以下依賴:
dependencies { implementation("androidx.profileinstaller:profileinstaller:1.3.0-alpha03") }
連接真機再次跑ExampleStartupBenchmark測試,在不同機型分別得到的結果為:
Pixel 1: android 10
ExampleStartupBenchmark_compilationPartial ?
timeToInitialDisplayMs ? min 1,359.2, ? median 1,422.4, ? max 2,583.0 ?ExampleStartupBenchmark_compilationNone ?
timeToInitialDisplayMs ? min 1,454.1, ? median 1,556.7, ? max 2,610.3?
三星S20: android 13
ExampleStartupBenchmark_compilationPartial
timeToInitialDisplayMs ? min 597.2, ? median 683.9, ? max 763.4ExampleStartupBenchmark_compilationNone
timeToInitialDisplayMs ? min 699.5, ? median 726.1, ? max 753.5
三星S8+: android7
ExampleStartupBenchmark_compilationPartial ?
timeToInitialDisplayMs ? min 1,089.1, ? median 1,121.6, ? max 1,249.4?ExampleStartupBenchmark_compilationNone ?
timeToInitialDisplayMs ? min 1,147.5, ? median 1,166.2, ? max 1,338.2
觀察數據可以看出,總體來說有一定的提升,特別是在性能低一點的機器會比較明顯,但相比于google官方給的文檔中的示例結果(提升20%+)還有一點差距,猜測應該跟生成的baseline-prof.txt有關,因為我這里只生成了啟動過程到完成第一幀繪制時的熱點代碼列表,google的例子是生成了到首頁并且切換tab的熱點代碼。
此外,基準配置文件也可以用在提升首次打開操作流暢性上,原理也是一樣的,只需要在BaselineProfileGenerator處添加首次進入之后的一些操作,比如像官方的例子一樣的切換tab、列表滑動,生成新的文件即可。
原文鏈接:https://juejin.cn/post/7195535228230975547
相關推薦
- 2022-03-14 C語言撲克牌游戲示例(c語言紙牌游戲)
- 2022-03-23 C++實現AVL樹的基本操作指南_C 語言
- 2023-04-29 Linux?grep?-q用法示例詳解_linux shell
- 2023-07-16 oracle 創建定時任務
- 2022-12-31 Android入門之Service的使用詳解_Android
- 2022-10-05 虛擬機VMware?Tools安裝步驟_VMware
- 2022-06-26 Qt中QtWebEngine加載本地網頁跨域問題的總結_C 語言
- 2022-06-01 C語言?深入淺出講解指針的使用_C 語言
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支