App性能测试——CPU使用率
CPU
使用率是性能测试是一项重要指标,CPU
占用过高会使得设备运行程序出现卡顿与发热,甚至出现应用程序Crash
,影响用户体验。在排除硬件环境的限制下,应用程序应该尽可能少的占用CPU
。
Android CPU占用
CPU使用率原理
Android
系统内核是基于Liunx
,在Linux
系统下CPU
利用率分为用户态、系统态、空闲态,分别表示CPU
处于用户态执行的时间,系统内核执行的时间,和空闲系统进程执行的时间。
平时所说的CPU利用率是指:CPU执行非系统空闲进程的时间 / CPU总的执行时间。那么这里所说的时间含义是什么呢?
HZ
:Linux
核心每隔固定周期会发出timer interrupt
(时钟中断),HZ
是用来定义每一秒有几次时钟中断。例如HZ
为1000
,就代表每秒有1000
次时钟中断。Jiffies
:在Linux
的内核中,有一个全局变量:Jiffies
。Jiffies
代表时间。它的单位随硬件平台的不同而不同。jiffies
的单位就是1/HZ
。Intel
平台jiffies
的单位是1/100
秒,这就是系统所能分辨的最小时间间隔了。每个CPU
时间片,Jiffies
都要加1
。那么CPU利用率计算公式如下:
1 | CPU使用率=(用户态Jiffies+系统态Jiffies)/总Jiffies |
CPU测试方法
adb 命令
由于Android
是基于Linux
内核改造而成的操作系统,自然而然也能使用Linux
的一些常用命令。比如我们可以使用top
命令查看哪些进程是 CPU
的主要消耗者。
Top
命令使用方法如下:
1 | >adb shell top -h |
注意:由于Android 8.0
以后Google
的权限限制,再也拿不到进程CPU的实时占用率,只能拿到自己本身进程的Jiffies
,而由于拿不到系统整体Jiffies
的情况下,就没办法衡量CPU当前的消耗状况了,也没办法根据当前CPU状态实时做一些策略调整。
输入adb shell top
命令可以看到如下所示数据
1 | User 22%, System 20%, IOW 0%, IRQ 7% |
- 第一组数据的含义
User
: 处于用户态的运行时间,不包含优先值为负进程Nice
: 优先值为负的进程所占用的CPU
时间Sys
: 处于核心态的运行时间Idle
: 除IO
等待时间以外的其它等待时间IOW
:IO
等待时间IRQ
: 硬中断时间SIRQ
: 软中断时间
- 第二组数据含义
PID
: 进程id
USER
: 进程所有者NI
:nice
值。负值表示高优先级,正值表示低优先级PR
: 优先级CPU%
: 当前瞬时CPU
占用率S
: 进程状态:D=不可中断的睡眠状态, R=运行, S=睡眠, T=跟踪/停止, Z=僵尸进程#THR
: 程序当前所用的线程数VSS
:Virtual Set Size
虚拟耗用内存(包含共享库占用的内存)RSS
:Resident Set Size
实际使用物理内存(包含共享库占用的内存)PCY
: 调度策略优先级。UID
: 进程所有者的用户id
Name
: 进程的名称
- 我们可以还使用
findstr
命令获取某个应用的CPU
占用率。
1 | λ adb shell top -m 100 -n 1 -d 1 -s cpu | findstr com.youku.phone |
iOS CPU使用率
iOS系统架构
iOS系统架构主要由以下四层组成:
UI
层: 主要有SpringBoard、Spotlight
等UI交互界面- 应用框架层:主要有
Cocoa Touch
- 核心框架层:主要有
OpenGL
等图形、多媒体组件 Darwin
:操作系统核心。
Darwin
iOS
是基于 Apple Darwin
内核,Darwin
的内核是XNU
(类Unix)。XNU
是两种技术的混合体:Mach
和BSD
。BSD
层确保了Darwin
的UNIX
特性,真正的内核是Mach
,但是对外部隐藏。
BSD
以上属于用户态,所有的内容都可以被应用程序访问,而应用程序不能访问内核态。当需要从用户态切换到内核态的时候,需要通过mach trap
实现切换。
Mach
内核是轻量级的平台,只能完成操作系统最基本的职责,如:进程和线程、虚拟内存管理、任务调度、进程通信和消息传递机制。其他的工作,如文件操作和设备访问,都是由 BSD
层实现。
事实上,Mach
并不能识别 UNIX
中的所有进程,而是采用一种稍微不同的方式,使用了比进程更轻量级的概念:任务(Task
)。
iOS App线程
经典的 UNIX
采用了自上而下的方式:最基本的对象是进程,然后进一步划分为一个或多个线程;Mach
则采用了自底向上的方式:最基本的单元是线程,一个或多个线程包含在一个任务中。
因此iOS App
作为进程运行时会有多个线程,每个线程对 CPU
的使用率不同。各个线程对 CPU
使用率的总和,就是当前 App
对 CPU
的占用率。
iOS测试利器-Instruments
Instruments简介
Instruments 是 Xcode 的一个工具集,为我们提供了强大的程序性能分析及测试能力。
使用 Instruments 你可以做下面这些事:
- 检查一个或多个应用或进程的行为。
- 检查设备相关的功能,比如:Wi-Fi、蓝牙等。
- 在真机或模拟器上进行性能测试。
- 创建自定义的
DTrace
来分析系统以及应用的各种行为。 - 跟踪源码中的问题。
- 对 App 进行性能分析。
- 查找 App 中的内存问题,比如:内存泄露(
Leaked memory
)、废弃内存(Abandoned memory
)、僵尸(zombies
)等。 - 进行系统级别的问题定位。
- 通过脚本记录一个用户行为序列,从而可以通过运行脚本对你的 iOS 应用进行自动化测试。
- 保存测试配置模板以供复用。
Instruments工具集
在Xcode中点击菜单Open Developer tool-> Instruments
即可打开,如下图所示:
- 从上图中我们可以看到
Instruments
有许多菜单,不同菜单支持的功能如下所示:
CPU占用率测试
- 使用
Time Profiler
可以来监测CPU使用统计信息,如下图所示选择选择点击红色按钮运行后,就能得到 CPU 性能的结果了。
- 注意:测试的app 需要使用
debug
包否则会出现如下报错。
- 如下图所示:可以查看运行过程中CPU使用率情况,底部可以详细看到应用每个线程占用的CPU。
- 我们还能在时间轴面板里面去选择一段时间来查看该时间段里更为细节的 CPU 性能:
- 数据导航栏菜单含义如下:
Weight
:调用它自身和它的子类花费的时间以及占总时间的百分比。Self-Weight
:自身花费的时间。Symbol Name
: 被调用的名字。
- 关于Call Tree有如下选项:
Separate by State
(不建议选择):通过状态分类查看CPU占用。Separate by Thread
(默认选择):通过线程分类来查看那些线程占用CPU最多。Invert Call Tree
(不建议选择):调用树倒返过来,如选上就会返过来从最底层调用向上一级一级的显示。如果想要查看那个方法调用为最深时使用会更方便些。Hide System Libraries
(建议选择):选上它只会展示与应用有关的信息,一般情况下我们只关心自己写的代码所需的耗时,而不关心系统库的CPU耗时。Flatten Recursion
(一般不选):选上它会将调用栈里递归函数作为一个入口。Top Functions
(一般不选):选上它会将最耗时的函数降序排列,而这种耗时是累加的,比如A
调用了B
,那么A
的耗时数是会包含B
的耗时数。
参考资料
- https://www.jianshu.com/p/31b1a4aef550
- http://chuquan.me/2019/06/10/ios-performance-monitor-cpu-mem-fps/
- http://www.samirchen.com/use-instruments/
- https://jsonchao.github.io/2020/01/26/%E6%B7%B1%E5%85%A5%E6%8E%A2%E7%B4%A2Android%E5%8D%A1%E9%A1%BF%E4%BC%98%E5%8C%96%EF%BC%88%E4%B8%8A%EF%BC%89/
- https://blog.csdn.net/u010144805/article/details/79152837
- https://www.jianshu.com/p/141b84f14505
- https://www.jianshu.com/p/7ab1de7bd525
- https://www.jianshu.com/p/029cc1b039d6