前言

通过查看系统cpu信息可以监控系统的程序运行状况以及系统状况,对后续的性能优化、故障诊断、资源管理、安全性等等都非常重要。
众所周知安卓基于Linux,查看cpu相关信息的方法基本相同,但是部分参数与linux略有区别,这里只针对安卓上的部分参数作基本解读


一、Android查看cpu相关信息的方法

1.1 Top命令

adb shell top 或adb shell Enter(回车) top

在这里插入图片描述

1.1.1 任务总览

任务(进程) 系统现在共有592个进程,其中处于运行中的有2个,590个在休眠(sleep),stoped状态的有0个,zombie状态(僵尸)的有0个

1.1.2 内存使用

内存状态: 物理内存总量 (3.5G) 使用中的内存总量(3.4G) 空闲内存总量(59Mb) 缓存的内存量(15Mb)
1TB=1024GB ,1GB=1024MB ,1MB=1024KB ,1KB=1024字节。

1.1.3 交换区状况

swap交换分区: 交换区总量(2.0G) 使用的交换区总量(98Mb) 空闲交换区总量(1.9G) 缓冲的交换区总量(1.4G)

1.1.4 cpu占用率

800%cpu 7%user 0%nice 21%sys 766%idle 0%iow 4%irq 1%sirq 0%host
cpu状态
800%cpu – CPU总量   1个核是100%
7%user – 用户空间占用CPU的百分比。
0%nice – 改变过优先级的进程占用CPU的百分比
21%sys – 内核空间占用CPU的百分比
766%idle – 空闲CPU百分比
0%iow – IO等待占用CPU的百分比
4%irq – 硬中断(Hardware IRQ)占用CPU的百分比
1%sirq – 软中断(Software Interrupts)占用CPU的百分比
0%host –

我们可以通过计算得知:7+21+766+4+1=799 约等于800%
cpu的占用率(使用率)可以通过 (800%-766%idle)/800%计算得到

1.1.5 进程详细信息

PID — 进程id
USER — 进程所有者 ,启动进程的用户。
PR — 进程优先级
NI — nice值。负值表示高优先级,正值表示低优先级
VIRT — 虚拟内存使用量。
RES — 物理内存使用量。
SHR — 共享内存使用量。
S — 进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程 I=空闲状态
%CPU — 上次更新到现在的CPU时间占用百分比
%MEM — 进程使用的物理内存百分比
TIME+ — 进程占用的CPU时间总计
ARGS— 命令行参数。

1.2 proc/xxx 目录

Linux proc/目录详解

这里只介绍cpuinfo和stat文件信息

1.2.1 cat /proc/cpuinfo

adb shell cat /proc/cpuinfo

主要是cpu的一些硬件信息

processor   : 0
Processor   : AArch64 Processor rev 4 (aarch64)
model name  : AArch64 Processor rev 4 (aarch64)
BogoMIPS    : 26.00
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part    : 0xd03
CPU revision    : 4

processor   : 1
Processor   : AArch64 Processor rev 4 (aarch64)
model name  : AArch64 Processor rev 4 (aarch64)
BogoMIPS    : 26.00
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part    : 0xd03
CPU revision    : 4

processor   : 2
Processor   : AArch64 Processor rev 4 (aarch64)
model name  : AArch64 Processor rev 4 (aarch64)
BogoMIPS    : 26.00
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part    : 0xd03
CPU revision    : 4

processor   : 3
Processor   : AArch64 Processor rev 4 (aarch64)
model name  : AArch64 Processor rev 4 (aarch64)
BogoMIPS    : 26.00
Features    : fp asimd evtstrm aes pmull sha1 sha2 crc32
CPU implementer : 0x41
CPU architecture: 8
CPU variant : 0x0
CPU part    : 0xd03
CPU revision    : 4

processor :表示 4 核 CPU,id号0-3
Processor :处理器的架构和版本信息。,处理器架构为 AArch64,版本为 rev 4。
model name :同样是描述处理器的架构和版本信息,与上一项类似
BogoMIPS :在系统内核启动时粗略测算的CPU速度(Million Instructions Per Second)
          通过一个简单的循环测试计算出来的值。因此,它并不准确地反映了 CPU 的实际性能。
Features :列出了该处理器支持的一些特性和指令集。处理器支持的特性包括浮点运算(fp)、SIMD 指令集(asimd)、事件流(evtstrm)、AES 加密指令(aes)、多倍乘(pmull)、SHA-1 加密指令(sha1)、SHA-2 加密指令(sha2)、CRC32 校验指令(crc32)等
CPU implementer:表示 CPU 的实现者标识符,0x41 对应的是 ARM 公司。
CPU architecture:表示 CPU 的架构版本,8 对应的是 ARMv8 架构。
CPU variant:表示 CPU 的变体标识符。
CPU part :表示 CPU 的部件标识符。
CPU revision:表示 CPU 的修订版本号。

1.2.2 cat /proc/stat

adb shell cat /proc/stat

cpu  10482627 403910 10374029 108104397 17890 2916045 559432 0 0 0
cpu0 1639634 106156 2203923 46409477 14139 527023 133383 0 0 0
cpu1 1593605 91112 2254611 8611648 1234 508073 130478 0 0 0
cpu2 1617916 87120 2244413 8607307 1138 515380 138253 0 0 0
cpu3 1627092 85860 2264758 8598776 1227 511266 142722 0 0 0
cpu4 968015 7045 294983 8974688 30 211232 4194 0 0 0
cpu5 992425 8100 341480 8972072 56 212606 3505 0 0 0
cpu6 1014721 9074 362541 8959730 22 214518 3418 0 0 0
cpu7 1029216 9439 407315 8970693 40 215944 3476 0 0 0
intr 835312893 0 0 3607787 0 0 308627600 0 23601166 0 0 0 0 0 0 0 0 194936 0 0 0 16972073 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 480 3 0 0 11 11 2204672 208308 0 2 1 1838 55 2 204478 0 0 0 0 0 0 2 0 0 0 0 434607 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2449420 0 155234 1898 97723 412499 0 0 69 0 0 0 0 0 2 3 0 0 2 0 11 0 9 429 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 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 0 177903 997637 792069 6 199483 2569606 166236 0 0 0 0 0 536208 70822 1878629 0 0 0 0 0 0 1 0 1 0 0 1 0 1 0 1 0 1 0 228 0 0 0 6140 19060772 0 1165 0 0 32423 0 0 0 0 0 0 6345 5077 1 2298 0 0 0 0 0 0 0 0 0 0 0 0 0 1099 0 0 2 0 0 0 0 0 12 36 21 948 43 0 41 1394 14 0 63 0 0 43 0 0 52244 6512 0 6039 0 0 44 0 0 0 0 0 345 1416756 0 0 1 33770 0 0
ctxt 1450309488
btime 1701832878
processes 5287756
procs_running 1
procs_blocked 0
softirq 115697955 40856 42519104 155619 819646 504315 0 5772282 35412329 0 30473804
1.2.2.1 cpu信息总览

cpu-cpu7 这一段每一列的具体含义如下:

user:CPU 处于进程为用户态的时间。一般/高优先级,仅统计nice<=0
nice:CPU 处于进程为nice用户态的时间。 低优先级,仅统计nice>0
system:CPU 处于内核态的时间。
idle:CPU 处于空闲态的时间。
iowait:CPU 等待 I/O 操作的时间。
IRQ:CPU 处理硬中断的时间。
softIRQ:CPU 处理软中断的时间。
steal:CPU 被其他虚拟 CPU 窃取的时间。
guest:运行虚拟 CPU 时花费真实 CPU 的时间。
guest_nice:运行一个带nice值的guest花费的时间。即不只是运行虚拟cpu,而且这个cpu的进程优先级较低。

它们的数值单位都为jiffies 看下jiffies的基本定义:

在 Linux 内核中,jiffies 是一个全局变量,用于表示系统启动以来的时钟中断次数。
比如时钟频率为 1000HZ,即每秒发生 1000 次时钟中断,因此 jiffies 值每秒增加 1000,那么1个jiffies=1/1000=0.001s=1ms

标红的两段针对nice值进行了区分,有必要先看下nice的定义:

在 Linux 系统中,nice 值是用来表示进程调度优先级的一个参数,其取值范围是 -20 到 19。nice 值越低,进程的优先级越高,越容易获得 CPU 时间。nice 值越高,进程的优先级越低,CPU 时间分配更少。
具体来说,nice 值的取值范围如下:

  • -20:最高优先级
  • -19 到 -1:较高优先级
  • 0:默认优先级
  • 1 到 19:较低优先级
  • 20:最低优先级(实际上,nice 值不能超过 19)
1.2.2.2中断信息
intr 835312893 0 0 3607787 0 0 30862........

这行给出中断的信息,第一个为自系统启动以来,发生的所有中断的次数,之后的每个数对应一个特定的中断自系统启动以来所发生的次数

1.2.2.3 上下文切换信息
ctxt 1450309488

自系统启动以来CPU发生的上下文交换的次数

1.2.2.4 运行时间
btime 1701832878

系统启动时间,以 Unix 时间戳的形式表示。
Unix 时间戳是指自 1970 年 1 月 1 日 00:00:00 UTC 起至当前时间的总秒数。因此,btime 中的时间戳单位是秒。

1.2.2.5 所有任务信息
processes 5287756

表示自系统启动以来所创建的任务的数量

1.2.2.6 运行任务信息:
procs_running 1

表示当前运行队列中正在运行着的任务数量

1.2.2.7 阻塞任务信息
procs_blocked 0

表示当前被阻塞的任务的数量

1.2.2.8 软中断信息
softirq 115697955 40856 42519104 155619 819646 504315 0 5772282 35412329 0 30473804

表示从系统启动以来的软中断计数,第一列表示所有软中断的总和,之后各列表示某个指定软中断的数量


二、cpu占用率的计算

通过读取、计算 proc/stat下的部分信息来计算当前的cpu占用率

核心思路:1-(idle的jiffies/总的jiffies) *100% 将空闲态占用时间去掉,剩下的不就全是cpu使用的时间了嘛

    /**
     * ^ 表示匹配行的开头。
     * cpu 匹配 "cpu" 这个单词。
     * \\s+ 匹配一个或多个空格字符。
     * (\\d+\\s+){9} 匹配由一个或多个数字加上一个或多个空格字符组成的序列,重复9次。
     * \\d+ 匹配一个或多个数字。
     * $ 匹配行的结尾。 因此,整个正则表达式可以匹配以 "cpu" 开头,后面跟着10个由空格分隔的数字的行。
     */
public static String getCPURate() {
        String path = "/proc/stat";// 系统CPU信息文件
        long Totaljiffies[] = new long[2];
        long totalIdle[] = new long[2];
        FileReader fileReader = null;
        BufferedReader bufferedReader = null;
        Pattern pattern = Pattern.compile("^cpu\\s+(\\d+\\s+){9}\\d+$", Pattern.MULTILINE);
                                                                 //正则表达式,只获取第一行
        for (int i = 0; i < 2; i++) {  //每一次调用分为两次获取 方便求差
            Totaljiffies[i] = 0;
            totalIdle[i] = 0;
            try {
                fileReader = new FileReader(path);
                bufferedReader = new BufferedReader(fileReader, 8192);
                String str;
                while ((str = bufferedReader.readLine()) != null) {  //读取stat信息
                    if (str.toLowerCase().startsWith("cpu")) {//以cpu开头的
                        Matcher matcher = pattern.matcher(str);//直接获取第一行cpu开头的数据
                                                            // 不需要cpu0-7的,那样的话还得多几步运算
                        while (matcher.find()) {
                            String[] values = extractValues(matcher.group());
                            Totaljiffies[i] = sumValues(values);
                            totalIdle[i] = Long.parseLong(values[3]);
                        }
                    }
                    if(i==0){//第一次获取后进行延时等待系统更新信息
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                if (bufferedReader != null) {
                    try {
                        bufferedReader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        double rate = 0;
        if (Totaljiffies[1] > Totaljiffies[0] ) {//正常情况下第二次总的jiffies一定比第一次获得的数据大
            rate = 1.0 * ((Totaljiffies[1] - totalIdle[1]) - (Totaljiffies[0] - totalIdle[0]))
                    / (Totaljiffies[1] - Totaljiffies[0]);
        }
        return String.valueOf(rate);
    }
   /**
     * 头行去掉cpu,合并成String[]数组 
     * @param input
     * @return
     */
    public static String[] extractValues(String input) {
        String[] parts = input.split("\\s+");
        String[] values = new String[parts.length - 1]; // 去掉 "cpu",所以长度减一

        System.arraycopy(parts, 1, values, 0, parts.length - 1);
        return values;
    }
   /**
     * 求数组和
     * @param input
     * @return
     */
    public static Long sumValues(String input[]) {
        Long sum = Long.valueOf(0);
        for (String value : input) {
            sum += Integer.parseInt(value);
        }
        return sum;
    }



Oncreate里使用匿名线程更新view,很不严谨···


   DecimalFormat df = new DecimalFormat("#0.00");
   
   new Thread() {
            @Override
            public void run() {
                super.run();
                while (true) {
                    cpu = Double.parseDouble(df.format(Double.parseDouble(getCPURate()) * 100));
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    Cpurate.setText("cpu占用率为"+String.valueOf(cpu)+"%");
                }
            }

        }.start();

对比top:
注:需要将Selinux权限设置为宽容模式,不然没有权限读取内部信息:adb shell setenforce 0
在这里插入图片描述

因为时间更新的缘故,top显示的比我app上的更新的快一点。

三、总结

本文归纳了查看Android上cpu大部分信息的方法以及java上层获取计算cpu使用率的方法,希望对你有所帮助。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐