1 背景
由于Android 8.0以后Google新加了权限限制,应用无法通过读取/proc/stat节点的方式计算CPU的实时占用率, 根据google官方解释需要system app才可以拿到权限。
这样导致,第三方应用想在在Android 8.0拿到的进程占比数据基本全是0;
2 常规cpu占比计算方法
分别读取cpu整体运行状态的节点/proc/stat以及关注的进程pid的节点proc/$pid/stat信息中如下4个字段:
utime 该任务在用户态运行的时间,单位为jiffies
stime 该任务在核心态运行的时间,单位为jiffies
cutime 累计的该任务的所有的waited-for进程曾经在用户态运行的时间,单位为jiffies
cstime 累计的该任务的所有的waited-for进程曾经在核心态运行的时间,单位为jiffies
以上均参数是自从系统最后一次启动后的系统统计的。如下分别在一段时间内分别在起始和结束时刻读取各个参数,对各参数先累加,然后对应结束起始点求差,差结果相除得到cpu占比。
3 不同方案及数据
如下是,使用demo开始直播后采集的一段cpu数据,
大致过程是:开启视频-开启数据发送-打开美颜贴纸-关闭美颜贴纸-再打开美颜贴纸-关闭推流-停播;
以下方案数据均取自同样时间段;
(1) top命令
top命令使用如第二小节的计算方法获取进程cpu占用率,也是比较客观和常用的标准方法;
以上数据是通过adb运行top命令当时获得;
该方法能够比较灵敏准确展示cpu使用情况,在开启编码、打开美颜贴纸时刻,cpu数据会涨上来,反之则会降下去;
但如果通过内置top命令到sdk进行驱动获取cpu占比本身方案比较消耗资源,不建议采用,仅仅适合adb等场景。
该数据作为其他方案对标的参考;
(全文数据图表中,蓝色数据代表原始采集值班数据,红色曲线是取滑动平均之后的趋势曲线);
(2) 读取app 1s内jiffies差值节点(proc/$pid/stat)
该方法计算一段时间内(1s)对应pid进程的(utime + stime + cutime +sutime)数据,即1s内该进程使用了多少cpu的时间片程度,一定程度也可以反映cpu的使用情况;
缺陷是仅仅保留了top计算方法的分子,无整机cpu的jiffies数据,无法衡量全局cpu使用情况;
该数据虽无法了解占用全局的cpu使用情况,得到并不是百分比,
但也较好反应了该app进程使用cpu的变化情况;红色趋势曲线同top拿到的cpu数据红色趋势曲线变化是匹配度很高。
(3) 线程调度延时
这里简单的通过,定时(1s)创建一个runable任务,计算从开始抛到在另外一个looper线程开始执行所需要的耗时,来体现当前cpu的繁忙程度,耗时越长,体现cpu越繁忙。
上面数据也能一定程度上反应出cpu的繁忙程度,红色趋势曲线接近top的红色趋势曲线,但准确度不如方案(2);
前半截数据同top的红色趋势曲线比较吻合,但后半截也有提升的趋势,但提升幅度较小。有可能跟整体cpu相关程度较低导致。
(4) 进程使用所在亲和cpu的主频占比
首先通过读取CPU Affinity属性获取当前进程被安排到cpu那几个核上;
然后读取当前进程运行时分配的cpu核的当前主频档位和最大主频;
进而根据权重计算出当前进程平均的使用主频占比,占比越大说明系统越繁忙。
根据以上的数据,并不适合使用平均趋势来衡量,而倾向于使用top前几的峰值的分布密度情况来确认cpu繁忙程度;
比如高峰值在某段时间内出现的次数越多衡量cpu越繁忙;
(5) asm汇编单指令耗时
通过计算一条汇编指令的执行时间来评估cpu耗时。
从上面数据看,特征不明显,适用性较差。
4 结论
综上:比较倾向采用方案结合(2)(3)(4)替代原cpu进程占比的计算方式;后续在此基础上进一步调优落地;
参考文献:
https://cloud.tencent.com/developer/article/1427843
http://www.brendangregg.com/blog/2017-05-09/cpu-utilization-is-wrong.html