/proc文件系统是一个伪文件系统,它只存在内存当中,而不占用外存空间。它以文件系统的方式为内核与进程提供通信的接口。用户和应用程序可以通过/proc得到系统的信息,并可以改变内核的某些参数。由于系统的信息,如进程,是动态改变的,所以用户或应用程序读取/proc目录中的文件时,proc文件系统是动态从系统内核读出所需信息并提交的。 从proc文件中可以获取系统、进程、线程的cpu时间片使用情况,所以两次采集时间片的数据就可以获取进程CPU占用率, CPU占用率 = (processJiffiesT2 - processJiffiesT1)/(totalJiffiesT2 - totalJiffiesT1) 。
计算全局CPU的占用率
获取全局CPU时间片使用情况:读取/proc/stat。该文件包含了所有CPU活动的信息,该文件中的所有值都是从系统启动开始累计到当前时刻,文件的内容如下:
cpu 690147 127021 569289 1089017 13320 60126 47538 0 0 0
cpu0 142791 23193 133874 1060113 13029 18745 20841 0 0 0
cpu1 154519 25120 135622 3340 66 17931 16760 0 0 0
cpu2 133688 23304 100911 3770 39 8834 3632 0 0 0
cpu3 120756 19955 88630 3791 23 7938 2835 0 0 0
cpu4 42735 10146 33064 4355 49 2234 976 0 0 0
cpu5 36984 9418 27224 4438 58 1169 841 0 0 0
cpu6 31962 8891 28760 4571 37 2454 1074 0 0 0
cpu7 26712 6994 21204 4639 19 821 579 0 0 0
intr 44130436 0 0 0 9889722 0 2250953 4 6 6 0 0 23 0 198 42 0 0 0 0 0 0 0 15468 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 11 0 0 11 0 0 0 0 0 0 360076 0 0 2162785 4497 19006 2924 0 0 6 0 0 147 34518 682055 0 0 537 1279684 6 233823 162318 22135 0 0 0 0 0 114063 49440 846651 0 0 0 0 13012 0 0 69 0 322279 29757 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 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 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 44880 0 0 0 0 2682 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 3 4422 426807 21795 0 0 0 0 0 8 10 3 0 10895 9073 21 63194 8840 5 4 162258 522033 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 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 44624 0 2 1 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 1 1 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 1 1 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 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 8097 0 0 0 0 118 0 0 2 0 0 0 0 0 108 59722 2 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 2 2 3 0 3 3 233 7 0 0 0 0 0 0 0 0 28 2 0 11470 0 11 54
ctxt 78449988
btime 1582142779
processes 65559
procs_running 3
procs_blocked 0
softirq 13449609 1992988 2521207 14577 396245 3188145 7007 1181961 2267553 0 1879926
第一行的数值表示的是CPU总的使用情况,所以我们只要用第一行的数字计算就可以了。第一行各个字段的含义:
user (690147) 从系统启动开始累计到当前时刻,处于用户态的运行时间,不包含 nice值为负进程。
nice (127021) 从系统启动开始累计到当前时刻,nice值为负的进程所占用的CPU时间
system (569289) 从系统启动开始累计到当前时刻,处于核心态的运行时间
idle (1089017) 从系统启动开始累计到当前时刻,除IO等待时间以外的其它等待时间
iowait (13320) 从系统启动开始累计到当前时刻,IO等待时间(since 2.5.41)
irq (60126) 从系统启动开始累计到当前时刻,硬中断时间(since 2.6.0-test4)
softirq (47538) 从系统启动开始累计到当前时刻,软中断时间(since 2.6.0-test4)
全局cpu时间片为:totalJiffies = user + nice + system + idle + iowait + irq + softirq
T1时刻全局cpu时间片为:totalJiffiesT1 = userT1 + niceT1 + systemT1 + idleT1 + iowaitT1 + irqT1 + softirqT1
T2时刻全局cpu时片为:totalJiffiesT2 = userT2 + niceT2 + systemT2 + idleT2 + iowaitT2 + irqT2 + softirqT2
T1到T2时间段运行的全局cpu时间片为:gapTotalJiffies = totalJiffiesT2 - totalJiffiesT1
T1到T2时间段的idle cpu时间片为:gapIdle = idleT2 - idleT1
T1到T2时间段全局cpu的占用率为:100 * (gapTotalJiffies - gapIdle) / (float) gapTotalJiffies
计算进程的CPU占用率
获取进程CPU时间片使用情况:读取/proc/pid/stat,该文件包含了某一进程所有的活动的信息,该文件中的所有值都是从系统启动开始累计到当前时刻,内容如下
6873 (a.out) R 6723 6873 6723 34819 6873 8388608 77 0 0 0 41958 31 0 0 25 0 3 0 5882654 1409024 56 4294967295 134512640 134513720 3215579040 0 2097798 0 0 0 0 0 0 0 17 0 0 0
各个字段的含义:
pid=6873 进程(包括轻量级进程,即线程)号
comm=a.out 应用程序或命令的名字
task_state=R 任务的状态,R:runnign, S:sleeping (TASK_INTERRUPTIBLE), D:disk sleep (TASK_UNINTERRUPTIBLE), T: stopped, T:tracing stop,Z:zombie, X:dead
ppid=6723 父进程ID
pgid=6873 线程组号
sid=6723 c该任务所在的会话组ID
tty_nr=34819(pts/3) 该任务的tty终端的设备号,INT(34817/256)=主设备号,(34817-主设备号)=次设备号
tty_pgrp=6873 终端的进程组号,当前运行在该任务所在终端的前台任务(包括shell 应用程序)的PID。
task->flags=8388608 进程标志位,查看该任务的特性
min_flt=77 该任务不需要从硬盘拷数据而发生的缺页(次缺页)的次数
cmin_flt=0 累计的该任务的所有的waited-for进程曾经发生的次缺页的次数目
maj_flt=0 该任务需要从硬盘拷数据而发生的缺页(主缺页)的次数
cmaj_flt=0 累计的该任务的所有的waited-for进程曾经发生的主缺页的次数目
utime=1587 该任务在用户态运行的时间,单位为jiffies
stime=1 该任务在核心态运行的时间,单位为jiffies
cutime=0 所有已死线程在用户态运行的时间,单位为jiffies
cstime=0 所有已死在核心态运行的时间,单位为jiffies
priority=25 任务的动态优先级
nice=0 任务的静态优先级
num_threads=3 该任务所在的线程组里线程的个数
it_real_value=0 由于计时间隔导致的下一个 SIGALRM 发送进程的时延,以 jiffy 为单位.
start_time=5882654 该任务启动的时间,单位为jiffies
vsize=1409024(page) 该任务的虚拟地址空间大小
rss=56(page) 该任务当前驻留物理地址空间的大小
rlim=4294967295(bytes) 该任务能驻留物理地址空间的最大值
start_code=134512640 该任务在虚拟地址空间的代码段的起始地址
end_code=134513720 该任务在虚拟地址空间的代码段的结束地址
start_stack=3215579040 该任务在虚拟地址空间的栈的结束地址
kstkesp=0 esp(32 位堆栈指针) 的当前值, 与在进程的内核堆栈页得到的一致.
kstkeip=2097798 指向将要执行的指令的指针, EIP(32 位指令指针)的当前值.
pendingsig=0 待处理信号的位图,记录发送给进程的普通信号
block_sig=0 阻塞信号的位图
sigign=0 忽略的信号的位图
sigcatch=082985 被俘获的信号的位图
wchan=0 如果该进程是睡眠状态,该值给出调度的调用点
nswap 被swapped的页数,当前没用
cnswap 所有子进程被swapped的页数的和,当前没用
exit_signal=17 该进程结束时,向父进程所发送的信号
task_cpu(task)=0 运行在哪个CPU上
task_rt_priority=0 实时进程的相对优先级别
task_policy=0 进程的调度策略,0=非实时进程,1=FIFO实时进程;2=RR实时进程
进程的Cpu时间片为:processJiffies = utime + stime + cutime + cstime,该值包括其所有线程的cpu时间
T1时刻进程的cpu时间片为:processJiffiesT1 = utimeT1 + stimeT1 + cutimeT1 + cstimeT1
T2时刻进程的cpu时片为:processJiffiesT2 = utimeT2 + stimeT2 + cutimeT2 + cstimeT2
T1到T2时间段运行的进程的cpu时间片为:gapProcessJiffies = processJiffiesT2 - processJiffiesT1
T1到T2时间段进程的cpu的占用率为:100 * gapProcessJiffies / (float) gapTotalJiffies
计算线程的CPU占用率
获取线程CPU时间片使用情况:读取/proc/pid/task/tid/stat,这个文件的内容与/proc/pid/stat相同。该文件包含了某一进程所有线程的信息,该文件中的所有值都是从系统启动开始累计到当前时刻。
线程的Cpu时间片为:threadJiffies = utime + stime
T1时刻线程的cpu时间片为:threadJiffiesT1 = utimeT1 + stimeT1
T2时刻线程的cpu时片为:threadJiffiesT2 = utimeT2 + stimeT2
T1到T2时间段运行的线程的cpu时间片为:gapThreadJiffies = threadJiffiesT2 - threadJiffiesT1
T1到T2时间段线程的cpu的占用率为:100 * gapThreadJiffies / (float) gapTotalJiffies
有关进程的CPU使用率的常用命令
ps 命令
通过ps命令可以查看系统中相关进程的CPU使用率的信息。ps命令算出来的cpu使用率是相对于进程启动时的平均值,随着进程运行时间的增大,该值会趋向于平缓。
top命令
通过top命令可以查看系统中相关进程的实时信息(cpu使用率等)。某一个线程在其运行期间其所使用的cpu可能会发生变化。在多核的情况下top命令输出的cpu使用率实质是按cpu个数*100%计算的。
/proc/stat与top的cpu信息的联系与区别
/proc/stat文件显示的是从启动到当前时间,各种cup时间的累计值;而top则是显示实时的cpu使用情况。top通过读取/proc/stat去计算cpu占用情况。
不同Android版本计算CPU占用率
API Level <= 23
1、通过java读取/proc/stat、/proc/pid/stat、/proc/pid/task/tid/stat的内容并计算CPU占用率
2、用JNI读取/proc/stat、/proc/pid/stat、/proc/pid/task/tid/stat的内容并计算CPU占用率
API Level == 24
用java读取/proc/stat、proc/pid/stat、proc/pid/task/tid/stat的内容并计算CPU占用率
API Level > 25
通过java执行adb shell cat命令读取/proc/stat、proc/pid/stat、proc/pid/task/tid/stat的内容并计算CPU占用率
参考工具
工具名称 | 支持API Level | 是否需要集成SDK | 实现原理 | 源码地址 |
---|---|---|---|---|
SoloPi | 19 <= API Level <= 28 | 否 | 根据不同API版本分别使用JNI、java的InputStreamReader、 adb shell cat读取/proc/stat、/proc/pid/stat | https://github.com/alipay/SoloPi |
Matrix | 18 <= API Level <= 24 | 是 | 用java的RandomAccessFile读取/proc/stat、/proc/pid/stat。进程的CPU占用率为processJiffies/totalJiffies,不是采集两次时间片的数据计算,所以CPU占用率不准确 | https://github.com/Tencent/matrix |
GT | 21 <= API Level <= 24 | 是 | 通过java的Scanner读取/proc/stat、/proc/pid/stat | https://github.com/Tencent/GT |
参考文档
http://man7.org/linux/man-pages/man5/proc.5.html
Linux中通过/proc/stat等文件计算Cpu使用率
linux系统/proc/stat信息与top的cup信息的联系及区别