Android基准配置文件Baseline Profile方案提升启动速度
作者:linversion 发布时间:2022-08-12 18:54:42
引言
偶然在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.0ExampleStartupBenchmark_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.4ExampleStartupBenchmark_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


猜你喜欢
- 引言在学习Java过程中,排序sort是我们常用的功能;在Java里,数组有Arrays.sort()可以排序,集合则是Collection
- 一、RESTful风格API的好处API(Application Programming Interface),顾名思义:是一组编程接口规范
- 应用:直接使用bootcdn提供的静态资源,不需要本地存储bootcdn 官网:https://www.bootcdn.cn/staticf
- 配置多个别名 typeAliasesPackage<property name="typeAliasesPackage&qu
- ListView允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕.1. ListView的简单用
- JFinal 是基于 Java 语言的极速 WEB + ORM 框架,其核心设计目标是开发迅速、代码量少、学习简单、功能强大、轻量级、易扩展
- 上周,公司的项目改版要求加上一个右滑返回上一个界面,于是就在网上找了一些开源库打算实现.但是在使用的时候遇见了许多的问题.试了两天用过 ht
- 下面展示一下FTP软件上传功能的过程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下1、上传前上传前选择好要将文件或文件夹上传到远程FTP
- 今天闲来无事写了一个清内存的小东西,类似360,在桌面上悬浮,点击后清除后台无用程序,清除后台程序是通过调用ActivityManger.k
- 执行引擎也只有几个概念, JVM方法调用和执行的基础数据结构是 栈帧, 是内存区域中 虚拟机栈中的栈元素, 每一个方法的执行就对应着一个栈帧
- 目录前言一 安全性问题1.1 调用接口的先决条件-token1.2 使用POST作为接口请求方式1.3 客户端IP白名单1.4 单个接口针对
- springcloud多个消费端重复定义feign clientspring cloud消费端调用服务提供者,有两种方式rest+ribbo
- 累加数累加数 是一个字符串,组成它的数字可以形成累加序列。一个有效的 累加序列 必须 至少 包含 3 个数。除了最开始的两个数以外,序列中的
- 本文实例讲述了Android使用WebView.loadUri()打开网页的方法。分享给大家供大家参考,具体如下:程序如下所示:import
- 在C#2.0中,微软给我们带来了一些新的特性,例如泛型,匿名委托等。然而,这些新的特性多多少少会给人一种从别的语言中“抄”来的感觉(例如泛型
- 一、饿汉式单例类public class Singleton { privat
- 本文实例为大家分享了Android实现表情功能的具体代码,供大家参考,具体内容如下Dialog实现表情评论功能核心问题:1、如何得到键盘弹起
- 本文实例为大家分享了Android实现闪屏页效果的具体代码,供大家参考,具体内容如下1.效果图2.闪屏页逻辑及布局2.1 activity_
- 前言C#基于NAudio工具对Wav音频文件进行剪切,将一个音频文件剪切成多个音频文件注:调用方法前需要导入NAudio.dll或者在NuG
- 本文实例为大家分享了AnAndroid图片无限轮播的具体代码,供大家参考,具体内容如下public class MainActivity e