编程进阶网编程进阶网
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 基础组成体系
  • 程序编程原理
  • 异常和IO系统
  • 六大设计原则
  • 设计模式导读
  • 创建型设计模式
  • 结构型设计模式
  • 行为型设计模式
  • 设计模式案例
  • 面向对象思想
  • 基础入门
  • 高级进阶
  • JVM虚拟机
  • 数据集合
  • Java面试题
  • C语言入门
  • C综合案例
  • C标准库
  • C语言专栏
  • C++入门
  • C++综合案例
  • C++专栏
  • HTML
  • CSS
  • JavaScript
  • 前端专栏
  • Swift
  • iOS入门
  • 基础入门
  • 开源库解读
  • 性能优化
  • Framework
  • 方案设计
  • 媒体音视频
  • 硬件开发
  • Groovy
  • 常用工具
  • 大厂面试题
  • 综合案例
  • 网络底层
  • Https
  • 网络请求
  • 故障排查
  • 专栏
  • 数组
  • 链表
  • 栈
  • 队列
  • 树
  • 递归
  • 哈希
  • 排序
  • 查找
  • 字符串
  • 其他
  • Bash脚本
  • Linux入门
  • 嵌入式开发
  • 代码规范
  • Markdown
  • 开发理论
  • 开发工具
  • Git管理
  • 百宝箱
  • 开源协议
  • 技术招聘
  • 测试经验
  • 职场提升
  • 技术模版
  • 关于我
  • 目标清单
  • 学习框架
  • 育儿经验
  • 我的专栏
  • 底层能力
  • 读书心得
  • 随笔笔记
  • 职场思考
  • 中华历史
  • 经济学故事
  • 01.崩溃捕获设计实践
  • 02.崩溃治理优化总结
  • 03.Native崩溃治理实践
  • 04.ANR监控设计实践
  • 05.CPU消耗优化实践
  • 06.卡顿监控设计实践
  • 07.卡顿治理优化实践
  • 08.网络分析与优化实践
  • 09.线程优化实践操作
  • 10.高性能图片优化方案
  • 11.OOM异常优化实践
  • 12.内存监控优化方案
  • 13.内存治理优化实践
  • 14.FPS监测设计实践
  • 15.进程优化设计实践
  • 16.App启动优化实践
  • 17.App页面UI优化实践
  • 18.App稳定性专项实践
  • 19.App瘦身优化实践
  • 20.常见代码优化实践
  • 21.移动端防抓包实践
  • 22.App磁盘沙盒实践
  • 23.Ping工具开发实践
  • 24.Gradle构建优化实践
  • 25.CodeReview实践总结

05.CPU消耗优化实践

目录介绍

  • 01.CPU概念介绍
    • 1.1 思考一下问题
    • 1.2 CPU内存架构
    • 1.3 CPU读写数据
    • 1.4 CPU换成&共享
    • 1.5 CPU使用率
  • 02.CPU如何收集
    • 2.1 CPU占用率获取
    • 2.2
  • 03.CPU排查分析
    • 3.1 CPU损耗原因
  • 04.CPU优化实践
    • 4.1 使用线程池
    • 4.2 减少CPU等待
    • 4.3 利用CPU闲置时刻
  • 05.CPU监控实践
    • 5.1 CPU监控思路

1.2 CPU内存架构

  • CPU的内存架构
    • image
      image
    • 现在的计算机,基本都是多个CPU,并且有些CPU还是多核的,因此你的Java程序中,每个CUP执行一个线程。
    • 并且俩个或者俩个以上的CPU在同时执行任务,这种情况就是我么所说的:并发。

1.3 CPU使用率

  • 在Linux系统下CPU分为:
    • CPU利用率分为用户态、系统态、空闲态,分别表示CPU处于用户态执行的时间,系统内核执行的时间,和空闲系统进程执行的时间。
    • 平时所说的CPU利用率是指:CPU执行非系统空闲进程的时间 / CPU总的执行时间。
  • 先介绍几个和Linux时间有关的名词:HZ、tick与jiffies。
    • HZ:Linux 核心每隔固定周期会发出timer interrupt (IRQ 0),HZ是用来定义每一秒有几次timer interrupts。例如HZ为1000,就代表每秒有1000次timer interrupts。
    • Tick :Tick是HZ的倒数,Tick = 1/HZ 。即timer interrupt每发生一次中断的时间。如HZ为250时,tick为4毫秒(millisecond)。
    • Jiffies :在Linux的内核中,有一个全局变量:Jiffies。 Jiffies代表时间。它的单位随硬件平台的不同而不同。jiffies的单位就是 1/HZ。Intel平台jiffies的单位是1/100秒,这就是系统所能分辨的最小时间间隔了。每个CPU时间片,Jiffies都要加1。 CPU的利用率就是用执行用户态+系统态的Jiffies除以总的Jifffies来表示。
  • CPU利用率计算公式也就是:
    • CPU使用率=(用户态Jiffies+系统态Jiffies)/总Jiffies

02.CPU如何收集

2.1 CPU占用率获取

  • CPU是系统非常重要的资源,在Android中/proc/stat
    • 包含了所有CPU的相关详情信息,查看CPU使用情况,CPU不是一个瞬时态,而是一个过程态的体现,一般可以使用top命令和dump cpuinfo命令进行CPU占用率获取。
  • top命令获取方法
    • top是比较经典的CPU计算方法,总的cpu时间 = user + nice + system + idle + iowait + irq + softirq
    • 例如:User 147 + Nice 11 + Sys 79 + Idle 408 + IOW 1 + IRQ 0 + SIRQ 6 = 652
    • 而proc->delta_time是两次读取/proc/pid/stat相减得到,可见,top是一段时间内,计算process的cpu jiffies与总的cpu jiffies差值得到。
    • 通过adb获取top:adb shell top -m 100 -n 1 -s cpu | grep 包名
  • dump cpuinfo命令获取方法
    • Android特有的命令,dump cpuinfo命令的实现在androidm/frameworks/base/core/java/com/android/internal/os/ProcessCpuTracker.java类里面,方法是printCurrentState
    • 进程的总Cpu时间processCpuTime = utime + stime + cutime + cstime,该值包括其所有线程的cpu时间。
    • 通过adb获取dump:adb shell dumpsys cpuinfo |grep 包名
    • https://www.jianshu.com/p/31b1a4aef550

2.2 总的CPU时间

  • 在Android低版本设备中,可以通过读取 /proc/stat 文件实现
    • /proc/stat 内容首行有8个数值,分别提供了所有CPU在 用户态(user)、用户态-低优先级(nice)、内核态(sys)、空闲态(idle)、io等待(iowait)、硬中断(irq)、软中断(softirq) 状态 下的时间总和,将这些值累加作为系统总的CPU时间(cpuTime)。
    • 计算 iowait/cpuTime 为系统的CPU空闲率,1-cpu空闲率 及为cpu利用率 。注意这里的时间单位为 jiffies,通常一个jiffies 等于10ms。
    • 总的cpu时间totalCpuTime = user + nice + system + idle + iowait + irq + softirq + stealstolen +guest
  • 在Android 8.0以上版本
    • 为了防止旁路攻击,普通应用程序已经无法访问/proc/stat 文件,所以无法通过/proc/stat 的方式计算系统cpu利用率。
    • 部分线下性能监控相关的开源库 如Dokit 会在Android8.0以上的设备 通过执行shell 命令 top -n 1 来直接获取某个进程CPU使用率信息,不过这种方式在高版本设备上也是无法使用的,得到的CPU使用率总是为0。
  • 计算cpu使用率
    • 1、采样两个足够短的时间间隔的Cpu快照,分别记作t1,t2,其中t1、t2的结构均为: (user、nice、system、idle、iowait、irq、softirq、stealstolen、guest)的9元组;
    • 2、计算总的Cpu时间片totalCpuTime。a) 把第一次的所有cpu使用情况求和,得到s1;b) 把第二次的所有cpu使用情况求和,得到s2;c) s2 - s1得到这个时间间隔内的所有时间片,即totalCpuTime = s2 - s1 ;
    • 3、计算空闲时间idle。idle对应第四列的数据,用第二次的idle - 第一次的idle即可 idle = idle2 - idle1
    • 4、计算cpu使用率。CPU总使用率(%) = 100*((totalCputime2- totalCputime1)-(idle2-idle1))/(totalCputime2-totalCputime1)

2.3 App应用CPU时间

  • 单个应用CPU监控
    • 将选中应用的PID传入,读取/proc/PID/stat文件信息及可获取该PID对应程序的CPU信息。
  • 计算方法
    • 1、首先获取应用的进程id: adb shell ps | grep com.package | awk '{print $2}' > tmp
    • 2、根据进程id,通过proc获取CPU信息 while read line; do adb shell cat /proc/line/stat | awk '{print 14,15,16,$17}' >> appcpu0; done < tmp
  • 以下只解释对我们计算Cpu使用率有用相关参数(14-17列) 参数解释
    • utime 该任务在用户态运行的时间,单位为jiffies
    • stime 该任务在核心态运行的时间,单位为jiffies
    • cutime 所有已死线程在用户态运行的时间,单位为jiffies
    • cstime 所有已死在核心态运行的时间,单位为jiffies
  • 进程的总Cpu时间
    • processCpuTime = utime + stime + cutime + cstime,该值包括其所有线程的cpu时间。
  • App的CPU占用率
    • 之后可以每1s获取一次CPU信息,分析获得app的CPU占用率等信息。
    • 单个程序的CPU使用率(%) = 100*(processCpuTime2-processCpuTime1)/(totalCpuTime2-totalCpuTime1)

03.CPU排查分析

3.1 CPU损耗原因

  • 对于线上系统突然产生的运行缓慢问题
    • 如果该问题导致线上系统不可用,那么首先需要做的就是,导出 jstack 和内存信息,然后重启系统,尽快保证系统的可用性。
  • 这种情况可能的原因主要有两种:
    • 代码中某个位置读取数据量较大,导致系统内存耗尽,从而导致 Full GC 次数过多,系统缓慢。
    • 代码中有比较耗 CPU 的操作,导致 CPU 过高,系统运行缓慢。
  • 另外有几种情况也会导致某个功能运行缓慢,但是不至于导致系统不可用:
    • 代码某个位置有阻塞性的操作,导致该功能调用整体比较耗时,但出现是比较随机的。
    • 某个线程由于某种原因而进入 WAITING 状态,此时该功能整体不可用,但是无法复现。
    • 由于锁使用不当,导致多个线程进入死锁状态,从而导致系统整体比较缓慢。
    • https://mp.weixin.qq.com/s/kM_azX-4tND0qydYelB3yg
    • https://mp.weixin.qq.com/s/ixm14buRWvsNlV5WpVZCmQ

04.CPU优化实践

4.1 使用线程池

4.2 减少CPU等待

4.3 利用CPU闲置时刻

更多

  • https://juejin.cn/post/7253062314307223611
    • https://juejin.cn/post/7253062314307223611
  • 速度优化:CPU 优化(上)
    • https://juejin.cn/post/7253062314307223611#heading-5
    • https://juejin.cn/post/7256406423817601085
  • Android发热监控实践
    • https://blog.itpub.net/70027824/viewspace-2990628/
  • 速度优化:充分利用 CPU 闲置时刻
    • https://juejin.cn/post/7374616167761444890
  • 【车载性能优化】将线程&进程运行在期望的CPU核心上
    • https://juejin.cn/post/7258251967956598839
  • Android平台下的cpu利用率优化实现
    • https://juejin.cn/post/7243240618788388922
贡献者: yangchong211
上一篇
04.ANR监控设计实践
下一篇
06.卡顿监控设计实践