CPU Virtualization(Context Switch)

Recap2

CPU는 메모리와 다르게 물리적으로 쪼갤 수 없는 구조이기 때문에 전체 time을 작은 time slice로 잘라서 그 각각의 조각을 프로세스에게 준다.
CPU virtualization에서 고려해야할 것은 performancecontrol이다.

Direct Execution이란 program이 CPU에서 directly하게 실행되는 것이다. 성능측면에서는 direct하게 실행하는 것이 제일 좋다. 하지만 direct하게 실행했을 경우 control을 lose할 수 있다는 단점이 있다.
directly execution의 경우 user program이 무한 loop등을 실행하면 정상적인 방법으로는 영원히 OS가 control을 regain할 수 없다는 것과 user program이 시스템 자원을 원할 경우 이를 OS가 관리할 수 없다는 단점이 있어서 사용되지 않는다.

이를 해결하기 위해 user modekernel mode를 나눠서 시스템 자원을 요구하는 등의 stricted operation을 수행하는 경우 kernel mode로 privilige level을 upgrade해서 OS의 도움을 받는 방식으로 동작한다. 즉, user program에게 전체 권한을 주지 않는다.

OS를 통한 서비스가 끝나면 user program으로 return해야하기 때문에 user program의 suspended state를 kernel stack에 저장해둔다.
mode switch가 진행되려면 CPU를 멈춰야하기 때문에 하드웨어의 도움이 필요하다.


user program이 CPU의 control을 가지고 동작하고 있을 때 OS는 어떻게 하면 CPU control을 regain할 수 있을까?

Cooperative Approach

user program이 스스로 system call을 할 때까지 기다리는 방법이다. user application의 cooperation을 기다린다.
OS의 system call은 process가 직접 system call을 호출하기 전까지 실행될 수 없다. 그래서 OS는 이를 기다려야 한다.

application programmer가 software에 특정 interval이 지날 때마다 프로그램이 system call을 호출하도록 프로그래밍 해야한다. 그래야만 OS가 CPU control을 프로그램 실행 도중에 regain할 수 있다.

Non-Cooperative Approach

OS가 user의 cooperation을 필요로 하지 않는다.
OS가 periodically generate되는 interrupt를 setup한다. interrupt가 generate될 때마다 CPU가 멈추고 mode switch를 해서 OS의 handler code를 실행한다. 그 handler가 current process를 switch할지 아닐지를 결정한다(다른 프로세스를 실행할지 실행하던 프로세스를 계속 실행할지 결정).

Timer Interrupt

OS designer로부터 pre-defined된 period마다 raise되는 interrupt이다. 보통은 10ms를 사용한다.
timer interrupt가 발생하면 CPU를 멈추고 mode switch를 한다. 따라서 OS는 어떠한 프로세스가 실행되고 있었는지와 관계 없이 반드시 10ms마다 control을 regain하게 된다.

timer interrupt의 time interval의 길이는 trade-off 관계이다. time interval을 줄이면 mode switch를 수행할 때 필요한 시간의 비율이 증가하기 때문에 효율이 떨어질 수 있다. 하지만 multiple process들이 더 작은 time slice를 나눠갖게 되면서 response time이 좋아져 더 좋은 illusion을 제공할 수 있다.

Scheduler

timer interrupt가 발생했을 때 current process를 계속해서 실행할지, 다른 process를 실행할지 결정해주는 것이 scheduler이다.
만약 scheduler가 다른 process를 실행하기로 결정했다면 OS가 context switch를 실행한다.

즉, pick candidate process후 switch()를 실행하는 부분이다(kernel mode에서 동작).
모든 process는 switch()에서 멈춰있다. scheduler에 의해서 항상 동일한 구간에서 snapshot이 찍이기 때문이다.

Context Switch

current process에서 다른 process로 넘어가는 것을 의미한다.
current process의 register값들(general purpose registers, PC, kernel stack pointer)을 kernel stack에 저장하고 앞으로 실행할 process의 kernel stack에 들어있던 register값들을 CPU에 restore한다.
그리고 current process의 kernel stack에서 앞으로 실행할 process의 kernel stack으로 switch한다.

context switch등과 같은 critical part에서는 interrupt가 disable된다.

Limited Direct Execution Protocol (Timer Interrupt)

  1. [OS] OS가 boot될 때 trap table을 initialize한다.
  2. [Hardware] system call handler와 timer handler의 위치를 기억한다.
  3. [OS] interrupt timer를 시작한다.
  4. [Hardware] timer를 시작하고 CPU를 X ms마다 interrupt를 발생시킨다.
  5. [Program] process A가 실행된다.
  6. [Hardware] timer interrupt가 발생한다. timer interrupt가 발생하면 current process A의 register를 A의 kernel stack에 저장하고 kernel mode로 mode switch를 한다. 그리고 trap handler로 jump한다.
  7. [OS] trap(timer interrupt)을 handle한다. schedulerA를 실행할지 다른 process를 실행할지 결정한다. 만약 다른 process B를 실행하기로 결정했다면, switch() routine을 call한다.
    switch()가 call되면, A의 레지스터를 A의 proc struct에 저장하고 B의 레지스터를 B의 proc struct로부터 restore한 뒤 B의 kernel stack으로 switch한다. 그리고 return-from-trap을 통해 B로 return한다.
  8. [Hardware] B의 kernel stack으로부터 B의 register를 CPU에 restore하고 kernel mode에서 user mode로 mode switch한다. 그리고 BPC가 가리키는 값으로 jump한다.
  9. [Program] process B가 실행된다.

The xv6 Context Switch Code

.globl swtch
swtch:
	# Save old registers
	movl 4(%esp), %eax
    popl 0(%eax)
    movl %esp, 4(%eax)
    movl %ebx, 8(%eax)
    movl %ecx, 12(%eax)
    movl %edx, 16(%eax)
    movl %esi, 20(%eax)
    movl %edi, 24(%eax)
    movl %ebp, 28(%eax)
    
    # Load new registers
    movl 4(%esp), %eax
    movl 28(%eax), %ebp
    movl 24(%eax), %edi
    movl 20(%eax), %esi
    movl 16(%eax), %edx
    movl 12(%eax), %ecx
    movl 8(%eax), %ebx
    movl 4(%eax), %esp
    pushl 0(%eax)
    ret

좋은 웹페이지 즐겨찾기