序言
表弟:CPU平均负载zhuanlan.zhihu.com我们理解了平均负载( Load Average),并用三个案例展示了不同场景下平均负载升高的分析方法。这其中,多个进程(或线程)竞争 CPU 就是一个经常被我们忽视的问题。
进程在竞争 CPU 的时候并没有真正运行,为什么还会导致系统的负载升高呢?CPU 上下文切换就是罪魁祸首。我们都知道,Linux 是一个多任务操作系统,它支持远大于 CPU 数量的任务同时运行。当然,这些任务实际上并不是真的在同时运行,而是因为系统在很短的时间内,将 CPU 轮流分配给它们,造成多任务同时运行的错觉。
而在每个任务运行前,CPU 都需要知道任务从哪里加载、又从哪里开始运行,也就是说,需要系统事先帮它设置好 CPU 寄存器和程序计数器(Program Counter,PC)。
CPU上下文
什么是CPU上下文呢?说直白点就是CPU的寄存器信息,以ARM为例,CPU寄存器信息如下所示:
CPU 寄存器,是 CPU 内置的容量小、但速度极快的内存。而程序计数器,则是用来存储 CPU 正在执行的指令位置、或者即将执行的下一条指令位置。它们都是 CPU 在运行任何任务前,必须的依赖环境,因此也被叫做 CPU 上下文。
CPU 上下文切换,就是先把前一个任务的 CPU 上下文(也就是 CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。而这些保存下来的上下文,会存储在系统内核中,并在任务重新调度执行时再次加载进来。这样就能保证任务原来的状态不受影响,让任务看起来还是连续运行。
进程上下文切换
进程上下文切换是指从一个进程切换到另一个进程运行。而系统调用过程中一直是同一个进程在运行。所以,系统调用过程通常称为特权模式切换,而不是上下文切换。但实际上,系统调用过程中,CPU 的上下文切换还是无法避免的。
特权模式
内核把虚拟地址空间划分为两个部分,因此能够保护各个系统进程,使之彼此隔离。所有的现代CPU 都提供了几种特权级别,进程可以驻留在某一特权级别。每个特权级别都有各种限制,例如对执行 某些汇编语言指令或访问虚拟地址空间某一特定部分的限制。IA-32体系结构使用4种特权级别构成的系统, 各级别可以看作是环。内环能够访问更多的功能,外环则较少,如图所示:
尽管英特尔处理器区分4种特权级别,但Linux只使用两种不同的状态:核心态和用户状态。 两种状态的关键差别在于对高于TASK_SIZE的内存区域的访问。简而言之,在用户状态禁止访问内核空间。 用户进程不能操作或读取内核空间中的数据,也无法执行内核空间中的代码。这是内核的专用领域。 这种机制可防止进程无意间修改彼此的数据而造成相互干扰。从用户状态到核心态的切换通过系统调用的特定转换手段完成。
换个角度看,也就是说,进程既可以在用户空间运行,又可以在内