Linux性能调优:CPU处理进程的原理及性能分析

1、CPU上下文切换
那什么时候会发生上下文切换呢?

结合上下文切换的类型和进程的生命周期,也可以总结以下几个情况:

CPU正常情况下应该被充分利用,所以CPU被执行的时间是被平均分的时间段所划分,每个进程都可以分配到,当某个进程的时间被执行完了之后就会被挂起,再执行下一个时间段的进程。这个过程就会发生上下文切换,这也是没有事件干预下最常见的。
我们知道在编写程序时,可以加个sleep函数,这也是进程主动结束运行被挂起而触发的上下文切换。
在进程信息中有个优先级,系统给它分配的优先级高时,它就会被优先执行,抢占其他进程的CPU,从而发生上下文切换。
当资源不足时,进程执行不了而被挂起,也是一种上下文切换。
发生了硬件事件,也就是中断和异常处理程序执行了,也会发生上下文切换。
了解这几种常见的情况,能够帮忙我们更好的理解影响CPU性能的因素。

2、观察CPU上下文切换
我们在上面文章中已经说了上下文切换对CPU性能影响非常大,那如何观察上下文切换的信息,可以通过vmstat这个工具。
#每3秒执行一次
root@node:~# vmstat 3
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 477767936 883712 9970296 0 0 0 2 0 0 0 0 99 0 0
0 0 0 477766688 883716 9970120 0 0 0 12 380 754 0 0 100 0 0
0 0 0 477770016 883716 9970292 0 0 0 0 1956 4706 1 1 98 0 0
输出结果信息中可以观察到以下几个重要信息

** r: ** 运行和就绪队列中进程的数量。
** b: ** 处于不可中断的进程数。
** in: ** 系统中断次数。
** cs: ** 上下文切换次数。

vmstat给出的是系统整体的上下文切换情况,可以使用pidstat工具查看具体进程的。

#每3秒输出一次
root@node:~# pidstat -w 3
Linux 4.15.0-58-generic (zw2ahyper02n06) 11/26/2025 _x86_64_ (64 CPU)

09:20:52 PM UID PID cswch/s nvcswch/s Command
09:20:55 PM 0 8 0.33 0.00 ksoftirqd/0
09:20:55 PM 0 9 12.83 0.00 rcu_sched
09:20:55 PM 0 12 0.33 0.00 watchdog/0

这里有两个参数很重要cswch和nvcswch。

cswch 表示进程每秒自愿上下文切换次数,也就是进程主动放弃而进行的上下文切换,一般是在等待I/O完成、等待资源分配或者sleep调用等情形下发生。换种说法就是系统资源存在不足时会更多发生自愿上下文切换。
nvcswch 表示每秒非自愿上下文切换次数,非自愿顾名思义就是强制切换,一般是在有更高优先级进程要执行、强制调度等情形下发生。说明了当前系统负载压力较大,CPU需求量较高。

3、引起CPU性能问题的分析
有了上面给出的CPU指标,还有了我们可以观察到的CPU上下文切换信息,我们怎么来分析他们呢?

还是从最直接的uptime和top命令开始,一般情况下,当出现CPU性能问题时,直接的反映往往是load
average(平均负载)、%CPU(cpu使用率)的异常增加,当出现这些信息时,我们会进一步的来分析。

vmstat命令输出中 r 的值是运行或者就绪队列中的进程数,当它与cpu核数做比较,大于核数就说明有争抢CPU资源的情况存在,造成CPU压力大。这时往往会造成后面参数 cs 上下文切换的增加,导致us用户态和sy内核态的使用率大幅增加。

上面说过vmstat只是整体情况,我们需要知道到底是哪个进程导致的异常,pidstat命令输出中会给出cswch和nvcswch值异常的进程。如果无法看出进程数值的差异,有时还需要观察这两个参数线程的值,因为CPU处理的单位是线程。使用命令 pidstat -wt 3 (加参数t)。
root@cs1ahyper01n07:~# pidstat -wt 3
Linux 4.15.0-58-generic (cs1ahyper01n07) 11/27/2025 _x86_64_ (64 CPU)

05:17:45 PM UID TGID TID cswch/s nvcswch/s Command
05:17:48 PM 0 8 - 10.79 0.00 ksoftirqd/0
05:17:48 PM 0 - 8 10.79 0.00 |__ksoftirqd/0
05:17:48 PM 0 9 - 107.62 0.00 rcu_sched
05:17:48 PM 0 - 9 107.62 0.00 |__rcu_sched
05:17:48 PM 109 4695 - 1.27 0.00 ntpd
05:17:48 PM 109 - 4695 1.27 0.00 |__ntpd
05:17:48 PM 0 - 4832 3.81 0.00 |__basereport
05:17:48 PM 0 - 58955 1.90 0.00 |__basereport
05:17:48 PM 0 - 9412 1.59 0.00 |__basereport
05:17:48 PM 0 - 4863 48.25 0.00 |__bkunifylogbeat

TID为线程ID,TGID为主线程ID,主线程ID跟进程ID一样。

除了这几个上下文参数和使用率参数之外,还要注意下中断参数 in,下面我们看下中断异常如何排查。
4、常见的中断异常排查
在vmstat输出中in参数是CPU中断数值,一般伴随着CPU性能问题发生时,这个值也会变化。这个值的查看在虚拟文件系统/proc/interrupts中。

一般用命令 watch -d /proc/interrupts ,每2s观察一次变化。
60: 0 0 0 256 0 0 0 0 PCI-MSI 131075-edge virtio4-request
61: 0 0 0 0 0 0 0 0 PCI-MSI 196608-edge virtio7-config
62: 0 0 227 0 0 0 0 0 PCI-MSI 196609-edge virtio7-req.0
NMI: 0 0 0 0 0 0 0 0 Non-maskable interrupts
LOC: 19978406 21499538 19037427 19051650 24423046 16673118 16385116 16393098 Local timer interrupts
SPU: 0 0 0 0 0 0 0 0 Spurious interrupts
PMI: 0 0 0 0 0 0 0 0 Performance monitoring interrupts
IWI: 0 0 0 0 0 0 0 0 IRQ work interrupts
RTR: 0 0 0 0 0 0 0 0 APIC ICR read retries
RES: 6886121 6006679 7293859 5923199 5446282 7366956 7156611 6750252 Rescheduling interrupts
CAL: 492454 478584 493309 495546 405377 394787 400837 410006 Function call interrupts
TLB: 585098 564485 581136 594965 564140 550393 550720 550566 TLB shootdowns
TRM: 0 0 0 0 0 0 0 0 Thermal event interrupts
THR: 0 0 0 0 0 0 0 0 Threshold APIC interrupts
DFR: 0 0 0 0 0 0 0 0 Deferred Error APIC interrupts
MCE: 0 0 0 0 0 0 0 0 Machine check exceptions
MCP: 5006 5006 5006 5006 5006 5006 5006 5006 Machine check polls
ERR: 0
MIS: 0
PIN: 0 0 0 0 0 0 0 0 Posted-interrupt notification event
NPI: 0 0 0 0 0 0 0 0 Nested posted-interrupt event
PIW: 0 0 0 0 0 0 0 0 Posted-interrupt wakeup event

针对输出的内容,我们检查分析一下可能存在的问题。

NMI: 这个值是不可屏蔽中断,数值为0时正常的,非0是表示出现了硬件故障,可以使用dmesg命令看一下是否有硬件故障日志。
LOC: 这个值是CPU核心调度,是负载均匀分布在所有核心上,如果不同核心差异较大,说明CPU存在故障或者定时器有问题,可以使用top/htop命令观察一下。
RES: 这个是重新调度中断,当负载过高时,会进行CPU核心平衡调度,如果出现进程异常,一般这个值会剧烈增加,进程频繁调度(pidstat观察),上下文切换也会增加。
TLB: 这个是进程页表刷新,防止不同CPU核心中缓存不一致。如果数值异常增加,可以用ps aux --sort=-%mem看是否有进程频繁申请/释放内存;
其他几个指标大多跟硬件有关,非零值时可以去dmesg日志中查看一下是否有硬件故障。

阅读剩余
THE END