Android使用基准配置文件(Baseline Profile)方案提升启动速度记录

您所在的位置:网站首页 挖掘机启动操作方法视频 Android使用基准配置文件(Baseline Profile)方案提升启动速度记录

Android使用基准配置文件(Baseline Profile)方案提升启动速度记录

2023-05-13 13:15| 来源: 网络整理| 查看: 265

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第1天,点击查看活动详情

偶然在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就可以了。

截屏2023-02-01 13.57.16.png

会在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 4 ExampleStartupBenchmark_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模块一致就可以了 模块都加上flavorDimensions "env"

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才行

VariantDependenciesBuilder NullPointerException 模块都加上flavorDimensions "env"

The server may not support the client's requested TLS protocol versions: (TLSv1.2, TLSv1.3). You may need to configure the client to allow other protocols to be used 在gragle.properties加入systemProp.https.protocols=TLSv1.1,TLSv1.2,TLSv1.3,同时确保设置里的proxy没被设成127.0.0.1,一般使用了clashX会有这个问题。[参考](You have JVM property “https.proxyHost“ set to “127.0.0.1“ - 简书 (jianshu.com))

官方文档

生成基准配置文件

在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.4 ExampleStartupBenchmark_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、列表滑动,生成新的文件即可。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3