本系列记录操作系统常见性能指标,写这个主要是记录也是回顾,笔记很长,拆分了几个部分,本篇记录CPU 的性能指标
CPU是计算机中最常见的概念,但是如何衡量CPU是否存在性能瓶颈,需要看哪些指标,可能多少都能说出来,CPU负载高、CPU使用率高、CPU缓存命中率低等等。具体怎样算高,哪些因素影响,如何排查呢?这里简单记录一下一些概念,希望帮助理解。
一、CPU负载
平均负载
平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,包括了正在使用 CPU 的进程,还包括等待 CPU 和等待 I/O 的进程
平均负载 = (正在运行的进程数 + 等待运行的进程数) / CPU内核数
1)可运行状态的进程
是指正在使用 CPU 或者正在等待 CPU 的进程
ps 命令看到的,处于 R 状态(Running 或 Runnable)的进程
2)不可中断状态的进程
正处于内核态关键流程中的进程,并且这些流程是不可打断的
ps 命令中看到的 D 状态(Uninterruptible Sleep,也称为 Disk Sleep)的进程
3)top 中看到的负载均衡
top 看到的load average: 0.02, 0.10, 0.05 分别是表示1分钟,5分钟,15分钟的平均负载
如果一个单核CPU平均负载为1,则表示该CPU正在运行一个进程60秒,或者多个进程正在分时运行,使得CPU使用率保持在100%。
但是对于多核CPU,平均负载超过1就表示在满负荷运行了。
看看下文理解平均负载
Understanding Linux CPU Load - when should you be worried? | Scout APM Blog
平均负载高场景
CPU 密集型进程,使用大量 CPU 会导致平均负载升高;
I/O 密集型进程,等待 I/O 也会导致平均负载升高,但 CPU 使用率不一定很高;
大量等待 CPU 的进程调度也会导致平均负载升高,此时的 CPU 使用率也会比较高。
分析步骤
分析思路
- 平均负载高有可能是 CPU 密集型进程导致的;
- 平均负载高并不一定代表 CPU 使用率高,还有可能是 I/O 更繁忙了;
- 当发现负载高的时候,你可以使用 mpstat、pidstat 等工具,辅助分析负载的来源
分析步骤
- top 命令查看平均负载是否有异常,看看平均负载是否在减小(1分钟 5分钟 15分钟)
- pidstat 5 5可以直观看到进程的用户态和系统态CPU使用情况
- mpstat 5 5查看是否是IO等待或者中断导致的负载高
注意:
sysstat 11.5.5 以上版本才有%wait字段
sysstat 软件包含了mpstat/iostat/pidstat等软件,而且会通过记录系统的CPU性能数据
默认在/var/log/sa 目录下,可以通过sar -f sa文件查看记录的数据
二、上下文切换
上下文:CPU的任何任务的执行,必须依赖CPU寄存器(CPU 内置的容量小、但速度极快的内存)以及程序计数器(用来存储 CPU 正在执行的指令位置、或者即将执行的下一条指令位置)
上下文切换类型
上下文切换有三类,进程、线程的上下文切换,以及中断上下文切换
1)进程上下文切换
进程从用户态进入内核态时,需要系统调用来完成
系统调用的CPU上下文切换过程(不切换进程):
- CPU 寄存器里原来用户态的指令位置,需要先保存起来
- 接着,为了执行内核态代码,CPU 寄存器需要更新为内核态指令的新位置
- 最后才是跳转到内核态运行内核任务
- 系统调用结束后,CPU 寄存器需要恢复原来保存的用户态,再切换到用户空间,继续运行进程
进程上下文切换描述:
- 进程是由内核来管理和调度的,进程的切换只能发生在内核态
- 进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态
- 所以,进程上下文切换包含用户态和内核态的资源
常见进程切换场景:
- CPU时间片用完,进程挂起,切换等待CPU的进程
- 进程在系统资源不足时,等待资源满足后才运行,进程挂起,系统调度其他进程
- 进程通过sleep函数自主挂起,系统重新调度进程
- 有优先级更高的进程需要运行时,当前进程挂起,运行高优先级进程
- 发生硬件中断时,CPU上进程挂起,转而执行内核中的中断服务程序
简单来说就是用完了CPU时间片,或者被抢占了的时候会进程上下文切换
2)线程上下文切换
常见线程上下文切换场景:
- 前后两个线程属于不同进程,资源不共享,此时与进程上下文切换一样
- 前后两个线程属于相同进程,虚拟内存和全局变量是共享的,所以只需要切换线程私有的数据、寄存器等不共享的数据
3)中断上下文切换
产生原因
为了快速响应硬件的事件,中断处理会打断进程的正常调度和执行,转而调用中断处理程序,响应设备事件
消耗资源
- 由于中断上下文不涉及进程的用户态,所以中断过程打断了用户态的进程,也不需要保存和恢复这个进程的虚拟内存、全局变量等用户态资源
- 中断上下文,其实只包括内核态中断服务程序执行所必需的状态,包括 CPU 寄存器、内核堆栈、硬件中断参数等
中断记录
/proc/interrupts 这个只读文件中读取中断使用情况
中断处理两个阶段
- 上半部直接处理硬件请求,也就是我们常说的硬中断,特点是快速执行;
- 而下半部则是由内核触发,也就是我们常说的软中断,特点是延迟执行。
例如:
网卡接收到数据包后,通过硬件中断的方式,通知内核有新的数据到了,内核调用中断处理程序响应;
上半部就是将网卡数据读入内存,更新寄存器状态,再发送软中断信号,通知下半部处理;
下半部收到软中断信号唤醒后,从内存中找到网络数据,根据网络协议栈,对数据进行逐层解析处理,直到发送给应用。
上下文切换分析方法
分析思路
- 自愿上下文切换变多了,说明进程都在等待资源,有可能发生了 I/O 等其他问题
- 非自愿上下文切换变多了,说明进程都在被强制调度,也就是都在争抢 CPU,说明 CPU 的确成了瓶颈
- 中断次数变多了,CPU 被中断处理程序占用,需要查看 /proc/interrupts 文件来分析具体的中断类型
分析步骤
pidstat -w 查看系统的上下文切换情况,依据切换类型分析大致原因
cswch(voluntary context switches)自愿上下文切换:
描述:指进程无法获取所需资源,导致的上下文切换
场景:I/O、内存等系统资源不足时,就会发生自愿上下文切换
nvcswch(non voluntary context switches)非自愿上下文切换:
描述:进程由于时间片已到等原因,被系统强制调度,进而发生的上下文切换
场景:大量进程都在争抢 CPU 时,就容易发生非自愿上下文切换
注意:pidstat 默认显示进程的指标数据,加上 -t 参数后,才会输出线程的指标
三、CPU使用率
单位时间内 CPU 繁忙情况的统计,跟平均负载并不一定完全对应
我们有时候能在 top 命令的结果里面能看到超过100%的情况,这是因为这个进程占用了多个CPU
top 通过读取 /proc/stat 文件计算CPU利用率,/proc/stat 文件包含各种系统统计信息,包括 CPU 利用率数据。
常用分析思路
mpstat 5 5
- 用户 CPU 和 Nice CPU 高,说明用户态进程占用了较多的 CPU,所以应该着重排查进程的性能问题
- 系统 CPU 高,说明内核态占用了较多的 CPU,所以应该着重排查内核线程或者系统调用的性能问题
- I/O 等待 CPU 高,说明等待 I/O 的时间比较长,所以应该着重排查系统存储 I/O 问题
- 软中断和硬中断高,说明软中断或硬中断的处理程序占用较多的 CPU,着重排查内核中的中断服务程序
- 碰到常规问题无法解释的 CPU 使用率情况时,首先要想到有可能是短时应用导致的问题
- 应用里直接调用了其他二进制程序,这些程序通常运行时间比较短,通过 top 等工具也不容易发现
- 应用本身在不停地崩溃重启,而启动过程的资源初始化,很可能会占用相当多的 CPU
常用分析软件
top
默认使用 3 秒时间间隔 \ 默认显示所有CPU的使用率平均值 \ 按1切换到每个CPU的使用率
状态
- R 是 Running 或 Runnable 的缩写,表示进程在 CPU 的就绪队列中,正在运行或者正在等待运行
- D 是 Disk Sleep 的缩写,也就是不可中断状态睡眠,一般表示进程正在跟硬件交互,并且交互过程不允许被其他进程或中断打断
- Z 是 Zombie 的缩写,进程实际上已经结束了,但父进程还没有回收它的资源(比如进程的描述符、PID 等)
- S 是 Interruptible Sleep 的缩写,也就是可中断状态睡眠,表示进程因为等待某个事件而被系统挂起。当进程等待的事件发生时,它会被唤醒并进入 R 状态
- I 是 Idle 的缩写,也就是空闲状态,用在不可中断睡眠的内核线程上。
- 对某些内核线程来说,它们有可能实际上并没有任何负载,用 Idle 正是为了区分这种情况
- D 状态的进程会导致平均负载升高, I 状态的进程却不会
- T 或者 t,也就是 Stopped 或 Traced 的缩写,表示进程处于暂停或者跟踪状态
- X 是 Dead 的缩写,表示进程已经消亡,所以你不会在 top 或者 ps 命令中看到它
处理
- 正常情况下,不可中断状态在很短时间内就会结束,如果长时间的不可中断进程出现,考虑IO或硬件问题
- 僵尸进程是父进程未正常回收子进程资源,导致的,如果大量且长时间存在,需要及时处理
- 查看子进程结束的处理是否正确,比如有没有调用 wait() 或 waitpid(),抑或是,有没有注册 SIGCHLD 信号的处理函数
- pstree -aps 僵尸进程pid 找到父进程
- a Show command line arguments.
- p Show PIDs.
- s Show parent processes of the specified process.
僵尸进程持续的时间都比较短,在父进程回收它的资源后就会消亡,或者在父进程退出后,由 init 进程回收后也会消亡;
crond 的定时任务在执行时会大量标准输出时,可能会引起sendmail 的僵尸进程,不会释放,需要重定向标准输出;
使用率
top 命令专门有一行CPU%,如下是man 对该部分的介绍:
us, user : 未被优先级调整过的用户进程所占用的 CPU 时间
time running un-niced user processes
sy, system : 代表内核进程运行所占用的 CPU 时间
time running kernel processes
ni, nice : 指经过优先级调整(即降低了优先级)的用户进程所消耗的 CPU 时间
time running niced user processes
id, idle : 指 CPU 在内核空闲处理程序中花费的时间,也就是 CPU 处于空闲状态的时间
time spent in the kernel idle handler
wa, IO-wait : 表示 CPU 等待 I/O 操作完成所花费的时间
time waiting for I/O completion
hi : 用于服务硬件中断所消耗的 CPU 时间
time spent servicing hardware interrupts
si : 服务软件中断所占用的 CPU 时间
time spent servicing software interrupts
st : 指虚拟机被管理程序(hypervisor)占用的时间,即虚拟机被 hypervisor 抢走的 CPU 周期比例
time stolen from this vm by the hypervisor
如果发现 st 值较高, steal time 超过了 10%并且持续了 20 分钟,那么虚拟机就可能出现性能下降 (一般就是CPU超分了):
- 如果所有虚拟机的 st 值都上涨了,说明虚拟机需要增加更多的 CPU 资源配额;
- 如果只是一部分虚拟机的 st 值陡峭增长,那么意味着物理机器被超分了,可以考虑将自己的虚拟机迁移到其他物理机器上;
ps
使用的是进程的整个生命周期(/proc/stat)
ps -ef standard syntax 优点看到父进程
ps aux BSD syntax 优点看状态和使用情况
perf
perf 是Linux 性能分析工具,可以查看实时的性能数据以及导出和导入性能数据,目前不太熟悉
实例
perf top
实时显示占用 CPU 时钟最多的函数或者指令,因此可以用来查找热点函数(需要累积一定量的事件)
- Overhead ,是该符号的性能事件在所有采样中的比例,用百分比来表示
- Shared ,是该函数或指令所在的动态共享对象(Dynamic Shared Object)
- Object ,是动态共享对象的类型
- [.] 表示用户空间的可执行程序、或者动态链接库
- [k] 则表示内核空间
- Symbol 是符号名,也就是函数名,函数名未知时,用十六进制的地址来表示
perf top -e cycles:k # 查看内核空间CPU消耗最多的函数
perf top -e cycles:u # 查看用户空间CPU消耗最多的函数
perf top -g -p pid
-g开启调用关系分析,-p指定进程号
perf record -g -p <pid>
记录相关信息到perf.data
perf report perf.data
加载文件记录的信息,通常用于解决容器内与宿主机依赖不一致的情况、
dstat
dstat 它吸收了 vmstat、iostat、ifstat 等几种工具的优点,可以同时观察系统的 CPU、磁盘 I/O、网络以及内存使用情况,这个软件来自 pcp-system-tools工具包
dstat --list # 查看所有可用的插件
dstat # 默认 -cdngy 参数,可以查看cpu 磁盘IO 网络IO 上下文切换
dstat -at # 在默认基础上加时间打印
mpstat
mpstat 5 5
压测软件
ab
Apache HTTP服务器基准测试工具,用来测试网站性能,如下是一次请求10个,共计100个请求
ab -c 10 -n 100 http://localhost:8080/
注意这个得带上末尾的路径,光写端口不行,不要用来测试正常运行的网站!!!
四、CPU缓存命中率
CPU缓存命中率是指CPU在执行操作时,所需数据已经在缓存中的比例。缓存命中率的高低直接影响到CPU的性能表现。
这节内容来自AI生成
理解缓存命中率
- 缓存命中:当CPU需要读取或写入数据时,如果这些数据已经存储在CPU缓存中,则称为缓存命中,此时CPU可以直接从缓存中快速读取或写入数据。
- 缓存不命中:如果CPU需要的数据不在缓存中,则需要从主内存(RAM)中读取,这个过程比从缓存中读取要慢得多,这种情况称为缓存不命中。
缓存命中率的影响
- 性能提升:缓存命中可以显著减少CPU访问主内存的次数,从而提高数据访问速度,提升系统性能。
- 性能下降:缓存不命中会导致CPU等待从主内存读取数据,增加访问延迟,降低系统性能。
分析和排查方法
1)使用Perf工具:可以使用Perf工具来监测CPU缓存的命中率
- 这将显示LLC(最后一级缓存)的读取、不命中、写入和写入不命中的统计信息。
perf stat -e LLC-loads,LLC-load-misses,LLC-stores,LLC-store-misses
实测:虚拟机会返回不支持,物理机才有效;按Ctrl+c 停止采集;
2)优化代码和数据结构:
- 紧凑化数据结构:减少数据结构的内存占用,以便更多的数据可以被缓存。
- 软件预取数据:提前将可能需要的数据加载到缓存中,以增加缓存命中率。
- 去除伪共享缓存:避免不同线程或进程的数据块共享缓存行,减少缓存不命中。
3)查看CPU缓存配置:了解CPU缓存的层次结构和大小,可以帮助分析缓存不命中的原因。
- 可以使用
lscpu
命令来查看CPU的详细信息,包括缓存的大小和层次结构 - 使用
cat /proc/cpuinfo
命令也可以获取到CPU的相关信息 lscpu | grep -E 'cache|CPU' - 工具如
dmidecode
可以提供更详细的硬件信息,包括CPU缓存配置(没看懂)
4)代码分析:通过性能分析工具(如gprof、Valgrind等)来分析代码,找出频繁导致缓存不命中的代码段。
5)系统监控:使用系统监控工具(如htop、vmstat等)来监控CPU和内存的使用情况,辅助分析缓存命中率。