Context switch

Intro

A context switch (also sometimes referred to as a process switch or a task switch) is the switching of the CPU (central processing unit) from one process or thread to another.

Context switch过高会导致CPU像个搬运工,频繁在寄存器和运行队列之间奔波,更多的时间花在了线程切换,而不是真正工作的线程上。直接的消耗包括CPU寄存器需要保存和加载,系统调度器的代码需要执行。间接消耗在于多核cache之间的共享数据。

A process (also sometimes referred to as a task) is an executing (i.e., running) instance of a program. In Linux, threads are lightweight processes that can run in parallel and share an address space (i.e., a range of memory locations) and other resources with their parent processes (i.e., the processes that created them).

A context is the contents of a CPU’s registers and program counter at any point in time. A register is a small amount of very fast memory inside of a CPU (as opposed to the slower RAM main memory outside of the CPU) that is used to speed the execution of computer programs by providing quick access to commonly used values, generally those in the midst of a calculation. A program counter is a specialized register that indicates the position of the CPU in its instruction sequence and which holds either the address of the instruction being executed or the address of the next instruction to be executed, depending on the specific system.

context 是指任何时间点cpu寄存器和程序计数器中的内容。

Context switching can be described in slightly more detail as the kernel (i.e., the core of the operating system) performing the following activities with regard to processes (including threads) on the CPU: (1) suspending the progression of one process and storing the CPU’s state (i.e., the context) for that process somewhere in memory, (2) retrieving the context of the next process from memory and restoring it in the CPU’s registers and (3) returning to the location indicated by the program counter (i.e., returning to the line of code at which the process was interrupted) in order to resume the process.

内核为每个进程维持一个上下文(context)。上下文就是内核重新启动一个被抢占的进程的所需的状态。它由一些对象的值组成,这些对象包括通用目的的寄存器、浮点寄存器、程序计数器、用户栈、状态寄存器、内核栈和各种内核数据结构,比如描绘地址空间的页表、包含有关当前进程信息的进程表,以及包含进程已打开文件的信息的文件表。

在进程执行的某些时刻,内核可以决定抢占当前进程,并重新开始一个先前被抢占的进程。这种决定就叫做调度(schedule),是由内核中称为调度起 (schduler)的代码处理的。当内核选择的一个新的进程运行时,我们就说内核调度了这个进程。在内核调度了一个新的进程运行后,它就抢占当前进程,并使用一种称为上下文切换的机制来将控制转移到新的进程,上下文切换1)保存当前进程的上下文,2)恢复某个先前被抢占的进程被保存的上下文,3)将控制传递给这个新恢复的进程。

上下文交换(context switch),又称环境切换,电脑术语,是一个储存和重建CPU状态&action=edit&redlink=1) (内文&action=edit&redlink=1)),因此令多个行程(process)可以分享单一CPU资源的计算过程。要交换CPU上的行程时,必需先行储存目前行程的状态,再将欲执行的行程之状态读回CPU中。

什么时候发生context switch

CS只能发生在内核态(kernel mode)

多工

最常见的,在一些排程(scheduling)算法内,其中行程有时候需要暂时离开CPU,让另一个行程进来CPU运作。在先占式多工系统中,每一个行程都将轮流执行不定长度的时间,这些时间段落称为time slice。如果行程并非自愿让出CPU(例如执行I/O操作时,行程就需放弃CPU使用权),当时限到时,系统将产生一个定时中断,操作系统将排定由其它的行程来执行。此机制用以确保CPU不致被较依赖处理器运算的行程垄断。若无定时中断,除非行程自愿让出CPU,否则该行程将持续执行。对于拥有较多I/O指令的行程,往往执行不了多久,便需要让出CPU;而较依赖处理器的行程相对而言I/O操作较少,反而能一直持续使用CPU,便形成了垄断现象。此即Convoy效应。

中断处理

在接受到中断的时候,CPU必须要进行上下文交换。

用户状态或者kernel状态的交换

用户态kernel mode交换发生的时候,并不需要进行上下文交换;并且用户态和kernel mode的交换本身并不是一个上下文交换。不过,根据操作系统的不同,有时候会在此时进行一次上下文交换的步骤。

上下文切换:具体步骤

在一次交换中,第一个行程的状态要被纪录在某个地方,这样当排程器(scheduler)要回到这个行程时,才可以重建这个行程并且继续运算。

这里所谓“行程的状态”,包含了这个行程使用的所有暂存器(register),特别是程式计数器;加上所有操作系统可能需要的特定资料。这些资料一般以名为行程控制表(process control block,PCB)的数据结构储存起来。

Q

时间片

时间片(timeslice)又称为“量子(quantum)”或“处理器片(processor slice)”是分时操作系统分配给每个正在运行的进程微观上的一段CPU时间(在抢占内核中是:从进程开始运行直到被抢占的时间)。现代操作系统(如:WindowsLinuxMac OS X等)允许同时运行多个进程 —— 例如,你可以在打开音乐播放器听音乐的同时用浏览器浏览网页并下载文件。事实上,由于一台计算机通常只有一个CPU,所以永远不可能真正地同时运行多个任务。这些进程“看起来像”同时运行的,实则是轮番穿插地运行,由于时间片通常很短(在Linux上为5ms-800ms),用户不会感觉到。

时间片由操作系统内核的调度程序分配给每个进程。首先,内核会给每个进程分配相等的初始时间片,然后每个进程轮番地执行相应的时间,当所有进程都处于时间片耗尽的状态时,内核会重新为每个进程计算并分配时间片,如此往复。

时间片实际上就是分配给每个可运行进程的处理器时间段。

时间片是一个数值,它表明进程在被抢占前所能持续运行的事件。调度策略必须规定一个默认的时间片,但这并不是件简单的事。时间片过长会导致系统对交互的响应表现欠佳;让人觉得系统无法并发执行应用程序。时间片太短会明显增大进城切换带来的处理器耗时,因为肯定会有相当一部分系统时间用在进程切换上,而这些进程能够用来运行的时间片却很短。此外,i/o消耗型和处理器消耗型的进程之间的矛盾在这里也再次显露出来:i/o消耗型不需要长的时间片,而处理器消耗型的进程则希望越长越好。

引发上下文切换的原因

对于抢占式操作系统而言:

  • 当前任务的时间片用完之后,系统CPU正常调度下一个任务;
  • 当前任务碰到IO阻塞,调度线程将挂起此任务,继续下一个任务;
  • 多个任务抢占锁资源,当前任务没有抢到,被调度器挂起,继续下一个任务;
  • 用户代码挂起当前任务,让出CPU时间;
  • 硬件中断;

上下文切换的查看方法

sar -w,这个只能看出主机上总的上下文切换的情况。

1
2
3
4
5
6
7
#sar -w 1
11:27:52 AM proc/s cswch/s
11:27:53 AM 0.00 968.00
11:27:54 AM 1.00 1133.00
11:27:55 AM 1.00 1001.00
11:27:56 AM 0.00 764.00
11:27:57 AM 0.00 855.00

vmstat也可以查看总的上下文切换情况。

1
2
3
4
5
6
7
#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 257464 36056 13466164 0 0 1622 80 1 1 25 0 75 0 0
0 0 0 257148 36160 13466148 0 0 0 359 626 944 0 0 99 0 0
0 0 0 260744 36284 13462208 0 0 81 1059 804 1023 1 0 99 0 0
0 0 0 274496 36332 13448692 0 0 3555 6991 1584 1048 7 0 92 1 0

查看每个进程或进程的上下文使用情况,可以通过pidstat命令或者通过查看proc。

1
2
3
4
5
6
7
# pidstat -w   每个进程的context switching情况
# pidstat -wt 细分到每个threads
查看proc下的文件方法如下:
# pid=307
# grep ctxt /proc/$pid/status
voluntary_ctxt_switches: 41 #自愿的上下文切换
nonvoluntary_ctxt_switches: 16 #非自愿的上下文切换

cswch/s: 每秒任务主动(自愿的)切换上下文的次数,当某一任务处于阻塞等待时,将主动让出自己的CPU资源。nvcswch/s: 每秒任务被动(不自愿的)切换上下文的次数,CPU分配给某一任务的时间片已经用完,因此将强迫该进程让出CPU的执行权。

参考文档

Computer Systems A Programmer’s Perspective

http://www.linfo.org/context_switch.html

http://en.wikipedia.org/wiki/Program_counter

http://zh.wikipedia.org/wiki/%E4%B8%8A%E4%B8%8B%E6%96%87%E4%BA%A4%E6%8F%9B

http://zh.wikipedia.org/wiki/%E6%97%B6%E9%97%B4%E7%89%87

http://www.361way.com/linux-context-switch/5131.html

http://cs.stackexchange.com/questions/18496/what-happens-when-time-slices-are-too-short-or-too-long

http://www.cnblogs.com/zhiranok/archive/2012/08/13/context_switch_1.html

More than your eyes can see