2024年测试应用启动性能(2),2024年最新字节跳动+阿里+华为+小米等10家大厂面试真题

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上软件测试知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化的资料的朋友,可以戳这里获取

想把启动性能测试 “测” 好并非易事


我最近需要测试一款应用的启动性能 (同时摆弄了一下 Startup 库来了解它是如何影响启动性能的,未来的文章中会有更多相关内容)。我发现,就像我 以往做这类事情时一样,启动性能并不容易明确地被测试出来。

如果您正在测试一段运行时代码,那么有许多解决方案供您选择。从 “编写紧密的循环并使用 System.currentTimeMillis() 计算时间增量” 这种琐碎的方法,到更复杂和有用的解决方案,如使用 AndroidX benchmark 库所提供的功能。

但是按照定义,应用启动时的许多操作运行在系统调用您的代码之前。那么您要如何确定整个启动过程所需要的时间呢?

我浏览了一些日志信息、检查了一些底层 API,并询问了一些平台团队的工程师,终于获得了一些有用的信息。更棒的是,我现在可以使用 adb shell 工具完全自动化我的测试并输出信息,从而可以轻松地将结果导入到电子表格中进行分析。

我会在下面的文字中解释上述命令所使用的一些代码片段,并向您展示一到两个启动测试的简单步骤。

ActivityTaskManager 启动日志


正如我在早些时间的一篇 博客 (不幸的是该博客已经过时而且并不正确) 中所写的那样,在 KitKat 发布后,有一个十分方便的日志一直在记录系统信息。无论何时,当一个 Activity 启动时,您都能看到日志中工具输出了以下信息:

ActivityTaskManager: Displayed com.android.samples.mytest/.MainActivity: +1s380ms

复制代码

这个持续时间 (本例中为 1,380ms) 表示了从启动应用到系统认为其 “已启动” 所花费的时间,其中包括绘制第一帧 (所以是 “已显示” 的状态)。

到达 “已显示” (Displayed) 状态的过程并不需要包含您应用就绪之前所做的事情的花费时间。只要您的应用确定已完成加载和初始化,就可以通过调用 Activity.reportFullyDrawn() 向系统提供这些额外的信息。当您调用了该可选方法时,系统会记录另一个带有时间戳和持续时间的日志:

2020-11-18 15:44:02.171 1279-1336/system_process

I/ActivityTaskManager: Fully drawn

com.android.samples.mytest/.MainActivity: +2s384ms

复制代码

我只想要到 “已显示” 时所持续的时间,所以内建的日志对我来讲已经足够好了。

自动化启动


性能测试总是应当多次去运行测试用例,以排除结果中的可变因素。进行的运行次数越多,平均结果就越可靠。我至少会尝试运行测试十次,但是做的次数更多效果会更好。根据结果的变化程度以及时间的长短 (因为变量的存在会对持续时间更短的测试产生更大的影响),可能需要运行更多次才行。

疯狂就是重复做相同的事情,却期待不同的结果。

——阿尔伯特 爱因斯坦

性能测试推论:

“疯了” 就是同一件事只做一次,却希望得到最佳结果。

——不是爱因斯坦说的

通过点击图标来连续多次启动应用是一件非常繁琐的事情。而且这种操作不具备一致性,且有许多难以预测的因素,因为很容易就会引入变量——如您偶然间错误地启动了另一个应用,或者使系统做了额外的工作而无法获得计时结果。

因此,我真正想要的是某种从命令行启动应用的方式。有了它,我就可以反复运行该命令来执行相同的操作,从而避免手动启动应用带来的可变性 (和乏味)。

adb (Android 调试桥,阅读至此的读者应该都对它很熟悉了吧) 提供了我所需要的东西。更具体地说,adb shell 提供了用于启动应用的命令行界面: adb shell am start-activity。该命令还能够在应用启动完成之前保持阻塞状态,因此我们还要使用 -W 参数 (这对下一步来说是必需的。我们下一步将使用后续命令杀死启动后的应用)。这是完整的启动命令:

$ adb shell am start-activity -W -n

com.android.samples.mytest/.MainActivity

复制代码

最后一个参数是应用的包名与组件信息。您可以看到它们与上一部分中 ActivityTaskManager 输出的日志相同。

运行此命令将启动应用 (除非该应用已经在前台,但这种情况并不是理想的状态,我们将在下一步对这种情况进行处理),并输出以下信息:

Starting: Intent { cmp=com.android.samples.mytest/.MainActivity }

Status: ok

LaunchState: COLD

Activity: com.android.samples.mytest/.MainActivity

TotalTime: 1380

WaitTime: 1381

Complete

复制代码

检查一下 TotalTime 结果: 结果与我们在日志中看到的信息完全相同:

ActivityTaskManager: Displayed

com.android.samples.mytest/.MainActivity: +1s380ms

复制代码

这意味着我们无需翻看 logcat,而是可以直接从运行命令的控制台中便可获取这些信息。更棒的是,我们可以剥离多余的文本并仅保留启动结果,从而更轻松地提取此数据以供其他地方使用。

为了将上面的输出转换为启动持续时间,我使用 grep 和 cut shell 命令来输出内容 (有多种方法可以执行此操作,我只是随机选择了其中一个):

adb shell am start-activity -W -n

com.android.samples.mytest/.MainActivity | grep “TotalTime” | cut -d ’ ’ -f 2

复制代码

现在,当我运行这条命令时,就能如我预期般的只获得一个简单的数字:

$ [start-activity command as above…]

1380

复制代码

冷启动是性能测试的最佳起点


在您检查启动性能前,最好先了解 “冷启动” 和 “热启动” 之间的区别。

冷启动” 是指您的应用在安装后的第一次启动、重启,或者不在后台时的启动。

另一方面,“热启动” 是指您的应用已经启动且正在后台运行 (但被暂停了) 时的启动。

这两种情况都值得去测试和理解。但总的来说,冷启动才是您进行启动性能测试的最佳起点,这其中有两个原因:

  • 一致性 : 冷启动可以确保您的应用每次启动时都经历相同的操作。应用被热启动时,我们没法明确知道哪些步骤被跳过,而哪些步骤被执行,因而也无从得知您到底在对什么进行计时 (也无法保证重复测试时所测试的内容是否一致);

  • 最坏情况 : 按照定义,冷启动是最坏的情况——这是您的用户经历启动过程时间最长的场景。您需要专注于最坏情况的统计数据,而不是状况最好的热启动。如果您忽略最坏情况,许多重大问题将无法被解决。

为了在每次运行时强制进行冷启动,您需要在两次运行期间终止应用。再一次强调,在屏幕上执行这一操作 (例如,将应用从启动器的 “概览” 列表中滑出) 是乏味且容易出错的,而 adb shell 可以解决这一问题。

有几个不同的 shell 命令可用于终止应用。最显而易见的是 adb shell am kill…… 但事实上这条命令并不能解决问题。当您启动应用后,应用会处在前台,而 kill 不会终止处在前台的应用。作为替代,您需要使用 force-quit 命令:

adb shell am force-stop com.android.samples.mytest

复制代码

您可以使用应用的包名告诉它需要终止哪个应用。

我喜欢循环,让我们来循环它


现在,您已经有了可以启动应用、输出启动持续时间数据,以及退出应用并使其可以再次启动的一系列命令。您可以一遍又一遍地在控制台中输入这些内容,但是在 shell 中,我们可以将这些命令放在循环里,然后只用一个命令就可以重复运行它。

在执行此操作时,为了避免应用被终止而产生副作用 (例如,当应用程序被终止时,系统会将启动器拉到前台),您可能会想要在终止应用后延缓下一次的启动。为此,我增加了一秒钟的 sleep 以在两次操作之间插入一个小的缓冲时间。

下面是我所使用的命令的最终版本,其中包括了终止应用、等待一秒钟,然后重启应用。我将这一过程循环执行了 100 次,从而可以提供一个合理的样本量:

$ for i in seq 1 100

do

adb shell am force-stop com.android.samples.mytest

sleep 1

adb shell am start-activity -W -n com.android.samples.mytest/.MainActivity | grep “TotalTime” | cut -d ’ ’ -f 2

done

复制代码

在运行此命令时,每当启动完成,我都可以获得输出到控制台的启动持续时间,而这正是我要跟踪和分析的数据。

注意 : 以上操作其实有更简单的方式,您可以使用 -S (用于首先停止 Activity) 和 -R COUNT (用于执行 start-activity 命令 COUNT 次) 来循环启动 Activity,所以我也可以用下面的命令完成以上操作:

$ adb shell am start-activity -S -W -R 100-n

com.android.samples.mytest/.MainActivity | grep “TotalTime” | cut -d ’ ’ -f 2

复制代码

但是,为了在应用的终止和启动之间加入缓冲时间,以确保其处于非活动的状态,我希望能使用 sleep 1 命令,因此我采用了更为冗长的方式进行循环。此外,shell 脚本的代码非常优雅,不是吗?

尽可能地锁住主频


img
img

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

[外链图片转存中…(img-meFJM1Qv-1715165745215)]
[外链图片转存中…(img-j4NpYDae-1715165745215)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 38
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值