Linux性能优化读书笔记(1):平均负载上下文切换

一、平均负载的理解

每次发现系统变慢,可以执行top或者uptime命令,来了解系统负载情况。

pi@raspberrypi:~ $ uptime
 20:22:35 up  4:46,  2 users,  load average: 0.63, 0.83, 0.88

uptime命令列出的就是top命令的第一行。前几列为当前时间,系统运行时间和正在登陆用户数(包括SSH远程登陆的用户,可用who命令具体查看)。后面三个数字,依次是过去1分钟、5分钟、15分钟平均负载(Load Average)

平均负载指单位时间内,系统处于可运行状态和不可中断状态的平均进程数(ps命令的R和D),也就是平均活跃进程数,与CPU使用率无关。谈到进程,回顾ps命令

使用静态的ps命令,给进程拍了一张快照,一般只要背两个命令

  • ps -l仅查看自己的bash相关进程
  • ps aux 查看所有系统运行的进程。注意没有-号
pi@raspberrypi:~ $ ps -l
F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
0 S  1000  1078  1075  0  80   0 -  1531 wait   pts/0    00:00:02 bash
0 T  1000  3026  1078  0  80   0 -  1317 signal pts/0    00:00:00 nano
0 R  1000 10651  1078  0  80   0 -  1817 -      pts/0    00:00:00 ps

其中S代表进程的状态(STAT):

  • R(Running)进程正在运行,正在使用CPU或者正在等待CPU的进程。很多操作系统教科书将正在CPU上执行的进程定义为RUNNING状态、而将可执行但是尚未被调度执行的进程定义为READY状态(就绪态),这两种状态在linux下统一为 TASK_RUNNING状态。
  • S(Sleep)进程处于睡眠状态或者阻塞状态,可以被唤醒
  • D(Disk Sleep) 不可被唤醒的、不可被中断的睡眠(或者阻塞态)。它们处于内核态关键流程中,比如等待硬件设备的IO情况。

C代表CPU使用率,PRI/NI代表CPU执行的优先级,数值越小代表进程越快被CPU执行。

平均负载就是平均活跃进程数。如果平均负载为2,在只有2个CPU系统上,每个CPU都刚好运行着一个进程。那么CPU利用率为100%。所以平均负载=CPU个数最理想

所以我们要知道CPU个数,可以使用lscpu命令。我的树莓派有4个cpu。

pi@raspberrypi:~ $ lscpu
Architecture:          armv7l
Byte Order:            Little Endian
CPU(s):                4
On-line CPU(s) list:   0-3
Thread(s) per core:    1
Core(s) per socket:    4
Socket(s):             1
Model:                 4
Model name:            ARMv7 Processor rev 4 (v7l)
CPU max MHz:           1400.0000
CPU min MHz:           600.0000
BogoMIPS:              38.40

平均负载不等于单位时间的Cpu使用率。即0.63不等于CPU使用率63%。平均负载不仅包括了正在使用CPU的进程还包括等待CPU和等待IO的进程。而CPU使用率仅包括正在使用CPU

  • CPU密集型进程,使用大量CPU会导致平均负载升高,两者一致
  • IO密集型进程,等待IO(处于不可被唤醒的、不可被中断的睡眠态)也会导致平均负载升高,而CPU使用率不一定高

二、CPU上下文切换

Linux是一个多任务操作系统,而任务并不是同时在执行,而是在很短时间内,将CPU轮流分配,操作多任务通行运行的错觉

CPU上下文是指CPU寄存器和程序计数器PC。都是CPU运行任何任务前,必须依赖的环境。上下文切换,先把前一个任务的CPU上下文保存起来,然后记载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。而保存下来的上下文会存储在系统内核中,任务重新调度执行时再次加载进来。

过多的上下文切换,会把cpu时间消耗在寄存器、内核栈和虚拟内存等数据的保存和恢复上

根据任务不同,CPU上下文切换分为不同场景:进程上下文,线程上下文和中断上下文切换

进程上下文切换

Linux根据特权等级,把进程的运行空间分为内核空间(最高权限)和用户空间(必须通过系统调用陷入内核,才能访问特权资源)

进程在用户空间运行,称为进程的运行态,陷入内核空间,称为进程内核态。通过系统调用,从用户态到内核态转变。一次系统调用,发生,两次CPU上下文切换:(用户空间-内核空间-用户空间)。系统调用属于同一进程内的CPU上下文切换

  • 先保存CPU寄存器例原来用户态的指令位置
  • 接着,为了执行内核态代码,CPU寄存器需要更新为内核态执行的新位置,最后跳转到内核态运行内核任务

进程的切换只能发生在内核态(进程是由内核来管理),所以进程上下文不仅包括虚拟内存栈、全局变量等用户空间资源,还包含了内核堆栈、寄存器等内核空间状态。(进程上下文不仅包括用户空间资源,还包括内核空间资源)所以,进程上下文切换比系统调用多了一步。例如下图,保存和恢复上下文需要内核在CPU上运行才能完成

  • 在保存当前进程的内核状态和CPU寄存器之前,需要先把该进程虚拟内存、栈保存
  • 加载下一进程的内核态后,还需要刷新进程的虚拟内存和用户栈

Linux性能优化读书笔记(1):平均负载上下文切换_第1张图片

LINUX为每个CPU维护就绪队列,根据不同的规则(时间片、优先级等)选择进程调度到CPU上,发生进程上下文切换

 线程上下文切换

线程是调度的基本单位,而进程则是资源拥有的单位,也就是说线程持有一部分私有数据,还和同一个进程的其他线程共享整个进程资源。

在多线程环境下,每个线程拥有一个栈和一个程序计数器。栈和程序计数器用来保存线程的执行历史和线程的执行状态,是线程私有的资源。其他的资源(比如堆、地址空间、全局变量)是由同一个进程内的多个线程共享。

线程上下文切换可分为两种

  • 前后两个进程属于不同进程,那么资源不共享,所以切换过程和进程上下文一样。
  • 前后两个进程属于同一进程,虚拟内存共享,切换时只需要切换线程的私有数据、寄存器等不共享的数据

线程上下文切换和进程上下问切换一个最主要的区别是线程的切换虚拟内存空间依然是相同的,但是进程切换是不同的。所以同进程的线程切换,要比多进程间的切换消耗更少,这是多线程的优势

关于线程分为两种,决定了线程切换时需不需要内核的管理

  •  内核级线程:切换由内核控制,当线程进行切换的时候,由用户态转化为内核态。切换完毕要从内核态返回用户态;可以很好的利用smp,即利用多核cpu。windows线程就是这样的。
  •  用户级线程内核的切换由用户态程序自己控制内核切换,不需要内核干涉,少了进出内核态的消耗,但不能很好的利用多核Cpu,目前Linux pthread大体是这么做的。

中断上下文切换

中断处理打断进程的正常调度的执行,为了快速响应硬件事件,转而调用中断处理程序,应对设备事件。这时就要将进程当前状态保存,中断结束后,进程恢复,从原来的状态运行。

中断上下文切换不涉及进程的用户态。所以不需要保存恢复进程的虚拟内存、全局变量等用户态资源,只包括内核态中断服务程序执行所必须的状态,比如CPU寄存器、内核堆栈等

 

三、检测系统资源变化

使用vmstat分析CPU/内存/磁盘/IO状态,执行追踪,类似vmstat 5代表每5秒钟更新一次。

pi@raspberrypi:~ $ 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
 1  0      0 849492  10568  57156    0    0    46     1  546   52  1  1 98  0  0
 0  0      0 849492  10568  57156    0    0     0     0 2058   60  0  0 100  0  0
 0  0      0 849532  10568  57156    0    0     0     3 2063   75  0  0 100  0  0
 0  0      0 849532  10568  57156    0    0     0     0 2047   49  0  0 100  0  0
 

进程字段(procs):

  • r:就绪队列中的进程数量,包括正在运行和就绪态的进程
  • b:处于不可中断睡眠状态的进程数

内存交换区(swap)

  • so:由于内存不足而将没用到的进程写入到磁盘交换区。si/so太大,表示内存中数据经常需要在磁盘和内存之间传输

磁盘读写(io)

  • bi:由磁盘读入的区块数量

系统(system)

  • in(interrupt):每秒中断的次数
  • cs(context switch):每秒上下文切换次数。

 

你可能感兴趣的:(Linux性能优化读书笔记(1):平均负载上下文切换)