CPU
平均负载
Load Average,简单理解它是指单位时间内,系统处于__可运行状态__和__不可中断状态__的平均进程数,即__平均活跃进程数__。因此理论上最理想情况是逻辑 CPU 核心数量
- 可运行状态进程:正在使用 CPU 或者正在等待 CPU 的进程,即 R 状态
- 不可中断状态进程:正处于内核态关键流程中的进程,这些流程是不可打断的,如等待磁盘 IO,即 D 状态
简单举例如下:
CPU 密集型进程,CPU 使用率 与 平均负载 都会升高
I/O 密集型进程,等待 I/O 导致平均负载升高,CPU 使用率不一定很高
大量等待 CPU 调度的进程,平均负载 与 CPU 使用率 都会升高
使用率
- usr CPU 使用率:CPU 在用户态运行的时间百分比,usr CPU 使用率高说明有应用程序比较繁忙
- sys CPU 使用率:CPU 在内核态运行的时间百分比(不包括中断)
- wait IO CPU 使用率:CPU 在等待 IO 的时间百分比,iowait高通常说明系统与硬件设备的 IO 交互时间较长
- 硬中断、软中断 CPU 使用率:内核调用硬中断、软中断处理程序的时间百分比
- 虚拟化环境中会用到的窃取 CPU 使用率(steal)和客户 CPU 使用率(guest),分别表示被其他虚拟机占用的 CPU 时间百分比,和运行客户虚拟机的 CPU 时间百分比
CPU 上下文切换
每个任务运行前,CPU 都需要知道任务从哪里加载和运行,即需要系统帮它设置好 CPU 寄存器和程序计数器(PC),它们都是 CPU 在运行任何任务前必须依赖的环境,因此也被叫做 CPU 上下文
CPU 上下文切换即先把前一个任务的 CPU 上下文保存起来(在内核中),然后加载新任务的上下文,最后跳转到程序计数器所指的新位置,运行新任务。切换操作同样要运行在 CPU 上(sys CPU)
-
特权模式切换:进程通过调用系统调用完成从用户态切换到内核态的运行,首先保存用户态 CPU 上下文,然后加载内核态 CPU 上下文,最后跳转到内核态运行内核任务;系统调用结束后,首先恢复原来保存的上下文,然后跳转到用户态,继续运行
-
进程上下文切换:进程是由内核管理和调度的,进程的切换只能发生在内核态)。进程的上下文不仅包括内核堆栈、寄存器等内核空间的状态,还包括虚拟内存、栈、全局变量等用户空间的资源
- 性能问题:
- 切换带来的一系列操作占用 CPU
- 虚拟内存更新后,TLB(虚拟内存到物理内存的映射缓存)被刷新,内存访问变慢 - 切换时机:
- 公平调度
- 系统资源不足,挂起需要资源的进程
- 进程主动挂起自身,如调用sleep
- 发生硬件中断时,CPU 上的进程会被中断挂起,转而执行内核中的中断服务程序(不涉及进程用户态资源的保存与恢复)
- 性能问题:
-
线程上下文切换:线程是调度的基本单位,而进程则是资源拥有的基本单位。内核中的任务调度的对象是线程。同一进程内线程的上下文切换包括了线程的私有数据、栈、寄存器等,虚拟内存和全局变量等资源是不需要保存与恢复的
-
中断上下文切换:对同一个 CPU 来说,中断处理比进程拥有更高的优先级。如上所述会引起进程上下文切换
进程状态
- R,Running or Runnable
- D,Dist Sleep,Uninterruptible Sleep
- Z,Zombie
- S,Interruptible Sleep
- I,Idle
- T/t,Stopped or Traced,暂时或追踪
- s,一个会话的领导进程
- 会话:指共享同一个控制终端的一个中多个进程组,如打开一个控制终端(TTY)就对应一个会话
- +,表示前台进程组
- 进程组:一组相关联的进程,如每个子进程都是父进程所在组的成员
软中断
Linux 将中断处理过程分两部分,第一部分快速处理中断,它在中断禁止模式下运行(打断 CPU 正在执行的任务,立即执行中断处理程序),主要处理跟硬件紧密相关的或时间敏感的工作,即硬中断;第二部分用来延迟处理上半部未完成的工作,即软中断,通常以内核线程的方式运行(由内核触发),每个 CPU 都对应一个软中断内核线程,名字是 ksoftirqd/CPU编号。发软中断事件频率过高时,内核线程也会因为 CPU 使用率过高而导致软中断处理不及时,进而引发网络收发延迟、调度缓慢等性能问题
例如在第一部分把网卡数据读到内存中,然后更新硬件寄存器状态表示数据读取完成,最后发送一个软中断信号;在第二部分接收到软中断信号并被唤醒后,需要从内存中找到网络数据,再按照网络协议栈,对数据进行逐层解析和处理,直到把它送给应用程序
性能分析相关命令
-
top/uptime:可以观察当前平均负载情况
- %iowait,等待 IO 的 CPU 时间百分比
- top -H -p PID 可查看PID下的线程
-
htop:top增强版
-
atop:CPU、内存、磁盘和网络等各种资源的全面监控
-
mpstat:实时查看每个 CPU 的性能指标以及所有 CPU 的平均指标
-
pidstat:实时查看进程的 CPU、内存、IO 以及上下文切换等性能指标
- pidstat -u CPU指标
- pidstat -d 展示统计数据
- pidstat -wt -u -p PID 1:查看某个进程的线程上下文切换情况
- cswch, voluntary context switches,每秒自愿上下文切换次数,指进程无法获取所需资源导致的上下文切换
- nvcswch, non voluntary context switches,每秒非自愿上下文切换次数,指进程由于时间片已到等原因,被系统强制调度而发生的上下文切换
- %wait,进程等待 CPU 的时间百分比
-
dstat:可以同时查看 CPU 和 I/O 两种资源的使用情况
-
pstree
-
vmstat:主要用来分析系统的内存使用情况,也常用来分析 CPU 总体上下文切换的中断的次数
- cs, context switch,每秒上下文切换次数,总体上下文切换情况
- in, interrrupt,每秒中断次数
- r, Running or Runnable,就绪队列长度
- b, Blocked,不可中断睡眠状态进程数
-
perf
- perf top -g -p PID:查找热点函数,实时显示占用 CPU 时钟最多的函数或指令
- perf record -e cpu-clock -g -p {PID}:采样
- perf report -i perf.data:解析perf.data,但不是很直观
- git clone https://github.com/brendangregg/FlameGraph.git
- perf script -i perf.data &> data.unfold:解析perf.data
- ./FlameGraph/stackcollapse-perf.pl data.unfold &> data.fold
- ./FlameGraph/flamegraph.pl data.fold > data.svg:查看火焰图
-
/proc/softirqs 软中断运行情况(系统运行以来的累积次数)
- watch -d cat ...
-
/proc/interrupts 硬中断运行情况
-
sar:系统活动报告工具,实时查看系统当前活动,也可以配置保存和报告历史统计数据
- sar -n DEV 1,显示网络收发报告
- rxpck/s、txpck/s 表示每秒接收、发送网络帧数,即 PPS
- rxkB/s、txKB/s 表示每秒接收、发送kB数,即 BPS
- sar -n DEV 1,显示网络收发报告
-
参考
性能测试相关工具
待补充
内存
生产环境性能问题分析
tbb concurrent queue 的无限循环导致 CPU 使用瞬间打满
重构后的 本地缓存 使用 CPU 过高
CPU 的上下文切换,调整合适的线程数量
usleep 3 并不准确
程序性能测试工具
程序处理请求过程中,根据监控发现latency会产生周期性的峰值。因此尝试了多种性能测试工具,记录如下。
vmstat
- 参考 vmstat命令
vmstat -at 1 | tee vmstat.log
查看缺页中断
- 参考
watch -n 1 -d 'ps -o majflt,minflt -p pid
- 其中 majflt 与 minflt 的不同是, majflt 表示需要读写磁盘,可能是内存对应页面在磁盘中需要 load 到物理内存中,也可能是此时物理内存不足,需要淘汰部分物理页面至磁盘中
查看进程运行在哪些CPU内核上
- 参考
ps -o pid,psr,comm -p pid
- psr列
taskset -a -p -c 0-30 pid
- 设置pid进程运行在0~30核上
top -H -d 1 -p pid
- 查看pid进程的线程
- 按f,选择需要显示的列
- top命令后按1可显示CPU列表,shift+p排序
查看内存泄露
-
valgrind
- 参考 valgrind详解与使用实例
valgrind —leak-check-full --show-leak-kinds=all --log-file=“valgrind.log"
-
sanitize
- 参考https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer
- 比valgrind对程序性能影响更小,但需要GCC 4.8以上或使用clang编译
strace
- 参考 强大的strace命令用法详解
strace -cp pid -f
- 统计pid进程所有系统调用的耗时占比
pstack pid
-
查看线程栈
-
分析死锁原因
- 使用pstack可以打印出各线程栈信息,基本上可以确定哪些线程在block状态
- gdb attach pid
- info thread
- 打印所有线程信息
- thread pid
- 切换到block住的thread
- p pthread_mutex_
- 查看互斥锁的__owner是哪个线程
- info thread
-
参考
gprof
- 安装graphviz
sudo yum install graphviz
- 下载gprof2dot.py
gprof -b ./docFeatureServer gmon.out > report.txt
python ./gprof2dot.py -n0 -e0 -s -w report.txt > report.do
dot ./report.dot -T svg -o report.svg
- 参考