Android 性能监控- cpu 监控

android 中CPU 也是性能监控的重要指标之一,主要关注两个指标点:

  1. cpu 总使用率
  2. 应用程序 cpu 使用率

如何检测/监控 cpu 数据?

一种是在开发过程中使用工具去检测,如 DDMS 或者 android studio 的 cpu profile,也可以使用 adb shell top 去获取cpu 的具体使用情况,后面会一一介绍。

基本概念

在 android 中,cpu 的信息获取基本和 linux 一致,所以概念也是一致的,比如 cpu 时间片的划分,如果系统切换线程,需要系统调用,会消耗额外的资源。

linux 系统下,CPU 可能处于这几种状态,用户态,系统态,空闲态;

平时所说的CPU利用率是指:CPU执行非系统空闲进程的时间 / CPU总的执行时间。

linux 下 cpu 的时间片是以 Jiffies 为单位的,不同平台可能大小不一样。

开发环境获取 cpu 使用率

一般,我们使用 top 命令 和 dumpcpu info 命令去获取 cpu 占用率。

top 命令获取 cpu 使用率

top 命令如下:

adb shell top -m 100 -n 1 -s cpu | grep com.yy.hiyo

输出结果如下:

xiewenzhongdeMacBook-Pro% adb shell top -m 100 -n 1 -s cpu | grep com.yy.hiyo
22578 u0_a467  10 -10   1% S   159 2274080K 393856K  ta com.yy.hiyo

或者进入 adb shell,间隔打印 cpu 调用情况,如下

xiewenzhongdeMacBook-Pro% adb shell
jason:/ $ top -d 5 | grep com.yy.hiyo

结果如下:

22578 u0_a467  10 -10   7% S   152 2267368K 401284K  ta com.yy.hiyo
22762 u0_a467  20   0   0% S    44 1921224K 202512K  fg com.yy.hiyo:pushservice

22578 u0_a467  10 -10   7% S   152 2267368K 401672K  ta com.yy.hiyo
22762 u0_a467  20   0   0% S    44 1921224K 202512K  fg com.yy.hiyo:pushservice
22578 u0_a467  10 -10   7% S   152 2267368K 401292K  ta com.yy.hiyo
22762 u0_a467  20   0   0% S    44 1921224K 202512K  fg com.yy.hiyo:pushservice
22578 u0_a467  10 -10   7% S   152 2267368K 398808K  ta com.yy.hiyo
22762 u0_a467  20   0   0% S    44 1921224K 202512K  fg com.yy.hiyo:pushservice
22578 u0_a467  10 -10   6% S   152 2267368K 401240K  ta com.yy.hiyo
22762 u0_a467  20   0   0% S    44 1921224K 202512K  fg com.yy.hiyo:pushservice
22578 u0_a467  10 -10   8% S   152 2267408K 404704K  ta com.yy.hiyo
22762 u0_a467  20   0   0% S    44 1921224K 202512K  fg com.yy.hiyo:pushservice
22578

一般排查 cpu 性能问题是否修复,肯定要用到这个命令的。

dump 命令获取 cpu 使用率

具体命令如下:

xiewenzhongdeMacBook-Pro% adb shell dumpsys cpuinfo |grep com.yy.hiyo
  73% 22578/com.yy.hiyo: 55% user + 17% kernel / faults: 9777 minor

top 和 dump 的区别

top 是通过计算 cpu 时间片的,而 dump cpuinfo 是实际时间,所以,一般 top 的数值会比 dump 出来的数值要小一点。

使用 android studio cpu profile 获取 cpu 使用率

前面介绍的都是通过命令行去获取 cpu 信息,但是在我们的 ide 中,也包含了类似的功能,而且附带函数的分析结果,现在来看一下 android studio 的 cpu profile 怎么获得这个cpu 数据,并且我们怎么去分析这个数据。

这个就比较简单了,只要手机有个 debug 包,就能开始玩了~

这里简单说一下,怎么通过这个 cpu profile 去发现问题。

特定场景优化 cpu 指标
  1. 查看 flame chart,选择 thread time 查看耗时函数
  2. 查看不同线程的 cpu 使用情况,查找频繁切换 cpu 时间片的线程,看是否能够优化

使用 cpu profile 检查 cpu 活动

自动测试如何获取 cpu 数据

读取 /proc 伪文件

/proc文件系统是一个伪文件系统,它只存在内存当中,而不会占用外存空间,它以文件系统的方式为内核与进程提供通信的接口。用户和应用程序可以通过 /proc 得到系统的信息,并且可以改变内核的某些餐你输。由于系统的信息,如进程是动态改变的,所有用户或者应用程序读取 /proc 目录中的文件时,/proc 文件系统会动态的从系统内核读取所需要的信息并且提交返回。

cpu 的使用率在 /proc/stat ,应用程序占CPU 使用率 /proc/<pid>/stat

先来看一些概念:

CPU 指标 含义
user 用户态时间
nice 用户态时间(低优先级 nice>0)
system 内核态时间
idle 空闲时间
iowait io等待时间
irq 硬中断
sofirq 软中断

先来查看 /proc/stat/,进入 adb shell,之后执行命令 cat /proc/stat,window 控制台输出如下

C:\Users\wumen>adb shell
HWELE:/ $ cat /proc/stat
//这两行的我自己加的
//   user   nice system  idle   iowait irq  softirq stealstolen guest  guest_nice
cpu  316074 61343 253065 1444324 6172 40364 19834   0   0    0
cpu0 44059 9452 46981 451869 2436 23154 10826 0 0 0
cpu1 49085 7764 43845 135308 317 4271 2779 0 0 0
cpu2 57030 12457 46039 129292 311 4997 2692 0 0 0
cpu3 53797 11908 45292 130017 270 4829 2634 0 0 0
cpu4 38564 4322 23863 144488 1805 1200 372 0 0 0
cpu5 35105 4924 18579 147982 713 972 295 0 0 0
cpu6 21082 5762 16562 151543 178 505 132 0 0 0
cpu7 17349 4751 11901 153822 138 433 101 0 0 0
intr 36009451 0 0 0 0 8990394 0 543378 4630 530 530909 536270 0 0 0 19683 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 0 0 0 0 399258 1948 1052126 0 0 0 0 0 0 0 0 0 0 71 0 1441531 24562 546 309283 63745 0 45943 0 0 0 0 19 0 54275 332468 0 0 0 0 1225 1036 1174 1132 941 905 887 710 162 0 0 0 189196 0 0 0 0 0 0 0 14297 0 0 0 0 0 0 0 53 0 360583 0 1303 0 0 0 0 0 0 6147 0 0 0 0 0 0 284 0 0 0 118 19 8893 853680 0 0 0 0 0 111 0 1 1 1 0 0 54 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 389 4044 0 10 0 25 0 0 3 0 232988 547 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 389 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 0 0 0 0 0 0 12 0 0 237 0 232 0 0 0 0 0 0 0 0 0 0 0 0 0 0 17759 122 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
ctxt 52644985
btime 1581121871
processes 39820
procs_running 5
procs_blocked 0
softirq 21861214 46801 5509747 115704 476006 237918 0 2571152 6232069 0 6671817
HWELE:/ $
  1. 这些时间单位都是 jiffies,jiffies 是linux 内核中的全局变量,用来记录系统启动以来产生的节拍数,可能是1-10ms 之间的数值,具体视内核版本。
  2. 具体的数值,我在上面标注了,可以参考表格或者阅读 linux 手册理解

那么怎么计算某个时刻cpu 的总体使用率呢?

首先要得到 cpu 的总体使用时间,也就是,第一行的全部数据:

totalCPUTime = user + nice + system + idle + iowait + irq + softirq + stealstolen + guest + guest_nice

那么 cpu 使用率的计算,则需要取两次数据,计算公式如下:

totalCPUrate = ((totalCPUTime2-idle2)-(totalCPUTime1-idle1))/(totalCPUTime2-totalCPUTime1)x100%

获取 app cpu 使用率也是类似的计算方式,读取的是 /proc/pid/stat 伪文件

具体的代码实现如下(kotlin):

 private val procPath = "/proc/stat"
    private var pid = 0
    private val appProcPath = "/proc/$pid/stat"
    private var mLastCpuIdle = 0L
    private var mLastCpuTotalUse = 0L
    private var mCpuUsageRate = 0L
    private var mAPPLastCpuUsage = 0L
    private var mAppCpuUsageRate = 0L

    fun doSmaple() {
        try {
            //读取cpu
            val ips = InputStreamReader(FileInputStream(procPath))
            val bufferReader = BufferedReader(ips, BUFF_SIZE)
            val cpuCodaRate = bufferReader.readLine()
            if (pid == 0) {
                pid = android.os.Process.myPid()
            }
            val appIps = InputStreamReader(FileInputStream(appProcPath))
            val appBufferedReader = BufferedReader(appIps, BUFF_SIZE)
            val appCpuCodeRate = appBufferedReader.readLine()
            if (cpuCodaRate.isEmpty()) {
                //do something
            } else {
                val cpuInfoArray = cpuCodaRate.split(" ")
                if (cpuInfoArray.size >= 9) {
                    val user = cpuInfoArray[2].toLong()
                    val nice = cpuInfoArray[3].toLong()
                    val system = cpuInfoArray[4].toLong()
                    val idle = cpuInfoArray[5].toLong()
                    val ioWait = cpuInfoArray[6].toLong()
                    val total = user + nice + system + idle + ioWait +
                            cpuInfoArray[7].toLong() +
                            cpuInfoArray[8].toLong()
                    mCpuUsageRate = if (mLastCpuIdle <= 0L) {
                        0
                    } else {
                        val currentTotal = total - mLastCpuTotalUse
                        val currentIdle = idle - mLastCpuIdle

                        //计算app cpu 使用率
                        val appCpuInfo = appCpuCodeRate.split(" ")
                        if (appCpuInfo.size >= 17) {
                            val appTotalTime = appCpuInfo[13].toLong() +
                                    appCpuInfo[14].toLong() +
                                    appCpuInfo[15].toLong() +
                                    appCpuInfo[16].toLong()
                            if (mAPPLastCpuUsage <= 0L) {
                                mAppCpuUsageRate = 0L
                            } else {
                                mAPPLastCpuUsage = appTotalTime
                                mAppCpuUsageRate =
                                    (appTotalTime - mAPPLastCpuUsage) * 100 / currentTotal
                            }
                        }
                        (currentTotal - currentIdle) * 100 / (currentTotal)

                    }
                    mLastCpuIdle = idle
                    mLastCpuTotalUse = total
                }

            }
        } catch (exception: Exception) {
            exception.printStackTrace()
        }
    }

然后根据这个代码进行简单的测试。

自动使用命令获取 cpu 使用率

除此之外,还可以使用这个类 Runtime 类执行下面接口去获取 cpu 信息:

//Runtime类
public Process exec(String command) throws IOException {
    return exec(command, null, null);
}

如何评价 cpu 使用异常

我们主要关注的是 cpu 的使用率,但是 cpu 的 使用情况,还要根据线程的使用情况去评估,就是找出值得优化的点,主要关注:

  1. Cpu 使用的峰值
  2. 关注线程的 stime 和 utime,可以忽略 io wait time 等
  3. 关注频繁切换cpu 时间片的线程

参考文档:android 性能测试之cpu占有率统计方法总结

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容