阿里云 云原生应用研发平台EMAS 李嘉华(千瞬)
简介: 性能测试在移动测试领域一直是一个大难题,它最直观的表现是用户在前台使用 App 时的主观体验,然而决定体验优劣的背后,涉及到了许许多多的技术变迁。阅读此文,带你揭秘App性能测试。
前言
性能测试在移动测试领域一直是一个大难题,它最直观的表现是用户在前台使用 App 时的主观体验,然而决定体验优劣的背后,涉及到了许许多多的技术变迁。
- 当我们习惯于诺基亚时,智能机出现了;当我们学会native开发时,hybrid来了;当各种 hybrid 框架下的巨型应用倾向成熟时,小程序出现在了我们眼前;紧接着直播、iot、ar、vr、人工智能,新的技术与应用场景正在以无法想象的速度向前发展。性能测试技术在快速变化的场景与开发技术面前,面临着巨大的挑战,当我们还在纠结如何测试 a 时,b 就已经出来了。
- 性能测试本身,有发展日渐成熟的解决方案,如线上性能监控APM、线下性能采集工具;有基于各个应用场景衍生的测试技术,如压力测试、稳定性测试、功耗测试等;也有基于各项性能指标(内存、cpu、电量、流量)而来的各种专项测试能力。
我们致力于打造线上线下一体的性能解决方案,希望能够帮助开发者发现、定位与解决一系列移动端性能问题。本文将着重介绍 EMAS 性能测试平台的能力与规划,还是那句话:功能决定现在,性能决定未来。
通常我们在采集 Android 设备性能数据时,都是通过 adb shell 获取各项系统数据,对采集效率、数据准确度等影响很大。阿里云移动测试做了大量技术优化创新,目前性能测试采集间隔为1s,并且同时做到了无侵入、低延迟、低功耗。
在介绍技术方案之前,这里将本文的方案(app_process)与 adb shell 的方案做一组简单的数据对比。
- 采集的所有性能数据为:cpu、memory、fps、network
- 开发环境: java + ddmlib
- 测试电脑:MacBook Pro (Retina, 15-inch, Mid 2015) 上进行测试
- 测试设备:OPPO R17/Android 8.0
尽管对比的样本数不多,且不同实现方式也会有些许差异,但基于 app_process 的性能采集方案依然有很明显的优势:
- 性能数据误差更小。相比之下性能与精度的提升是显而易见的,在部分手机上app_process的cpu开销甚至低于1%;
- 数据采集更及时、响应更快。由于 app_process 接口的高效性,我们在每一秒钟都会监控被测应用的 pid,实际上性能数据对 APP 重启等动作的响应是实时的;
- 兼容性更好。ps、top等命令在不同的设备上可能存在数据格式上的差异,这类不同机型的适配问题在本文方案中是不存在的。
1. APP_PROCESS
在Android系统中,zygote 通过 fork()调用一个app_process进程作为App的载体,我们同样也可以通过app_process运行一个普通的 java 程序,这个java程序可以像 App 一样通过 binder 跨进程与 system_server 通信,实现并调用一些 Android 系统服务的接口,同时,通过app_process启动的程序拥有shell等同的权限,这样可以完成一些 app 无权限但是 adb 能够完成的命令。
通过下图我们简单理解一下 Android Binder 与本文的基本原理,更多细节可以自行搜索学习。通常来说,如果我们的 App 能够获取到一个 Manager(如 ActivityManager),那么 System_Server 中必然存在对应的 Service(如 ActivityManagerService),那么我们就可以通过 ActivityManagerProxy 与它通信。
2. 性能指标
目前 移动测试 性能测试平台支持采集的性能指标如下:
2.1 内存
指标说明
- TotalPss: 应用实际占用物理内存
- NativePss: native进程申请分配的物理内存
- SwapPss: 动态内存交换区,zRAM 交换可通过压缩内存页面并将其放入动态分配的内存交换区来增加系统中的可用内存量。由于这是以牺牲 CPU 时间为代价来增加少量内存,所以 swapPss的异常变化可能对系统性能造成影响。(https://source.android.com/devices/tech/config/low-ram.html)
原理
通过adb shell dumpsys meminfo pid,我们可以获得如下内容
Applications Memory Usage (in Kilobytes):
Uptime: 543447125 Realtime: 543469686
** MEMINFO in pid 23178 [com.huawei.browser:sandboxed_process0:com.huawei.browser.sandbox.SandboxedProcessService0:6] **
Pss Private Private SwapPss Heap Heap Heap
Total Dirty Clean Dirty Size Alloc Free
------ ------ ------ ------ ------ ------ ------
Native Heap 99 96 0 2028 6656 4327 2328
Dalvik Heap 4 0 0 754 3078 1030 2048
Dalvik Other 4 4 0 366
Stack 8 8 0 26
Other dev 4 0 4 0
.so mmap 535 4 0 319
.jar mmap 114 0 0 0
.apk mmap 2 0 0 0
.dex mmap 622 0 4 2617
.oat mmap 409 0 0 0
.art mmap 259 16 0 2183
Other mmap 14 0 0 6
Unknown 28 28 0 455
TOTAL 10856 156 8 8754 9734 5357 4376
App Summary
Pss(KB)
------
Java Heap: 16
Native Heap: 96
Code: 8
Stack: 8
Graphics: 0
Private Other: 36
System: 10692
TOTAL: 10856 TOTAL SWAP PSS: 8754
在 Android 10 以下的设备中,我们可以通过activityManager.getProcessMemoryInfo(pids) 获取进程相关的内存信息,Android 10之后的系统对这个接口加了一些限制,数据更新时间为5分钟,需要直接调用meminfo service 来dump获取这部分内容。
2.2 CPU
指标说明
ProcessCpu:测试进程CPU使用率
SystemCpu:整机CPU使用率
原理
通过读取/proc/stat文件,我们可以看到下面的内容
cpu 2490696 175785 2873834 17973539 12823 680472 230184 0 0 0
cpu0 621631 33199 739364 12893642 10736 365458 86720 0 0 0
cpu1 623944 30576 688904 677748 609 145744 93230 0 0 0
cpu2 519768 33948 650022 685194 703 78117 23873 0 0 0
cpu3 499978 33082 547153 687802 650 81072 21360 0 0 0
cpu4 32586 4853 41910 774975 36 2097 1025 0 0 0
cpu5 30950 5003 40730 776693 19 2060 999 0 0 0
cpu6 99227 22708 109219 722048 23 3970 2140 0 0 0
cpu7 62610 12414 56531 755434 44 1952 836 0 0 0
intr 209333749 0 0 0 0 35952688 0 11796562 7 5 5 17537 80 2431 0 0 0 1069962 0 35 1334360 0 0 0 0 0 11 11 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 34984538 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 505 50695 1174791 345 0 0 0 11301652 24660 0 111 0 0 0 0 0 0 0 0 0 0 0 86153 54 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1099230 0 18 1814 0 0 23 514624 1300943 248469 0 0 0 0 0 97168 60709 1641967 609754 38618 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0