이전 글에서 OS가 CPU를 가상화하는 방법 중 메커니즘에 해당하는 Context Switch에 대해서 알아보았다.
Context Switch를 통해 한정된 CPU에서 많은 프로세스를 짧은 시간 간격으로 번갈아 가면서 실행시킴으로써 우리는 한번에 여러 프로세스가 실행되는 것처럼 느낄 수 있다.
이 글에서는 프로세스가 전환될 때 어떤 프로세스를 선택하는지를 결정하는 프로세스 스케줄링
에 대해서 알아보자.
어떤 스케줄링 기법이 좋은지 판단하기 위해서는 측정 방법(metric)이 필요하다.
여러 metric을 가지고 스케줄링 정책들을 비교할 수 있다.
평균 Turnaround time 증가!!
Convoy Effect
라고도 한다.preemption
개념을 추가하자!batch computing
에는 좋은 정책이다. (batch computing : 예전에는 매우 큰 job을 할당하고, 다음 날 결과를 확인헀다.)response time
response time
은 엄청나게 좋지만, turnaround time
은 좋지 못하다.컴퓨터를 사용할 때 다양한 타입의 Workload가 발생한다.
이에 따른 다양한 policy가 필요하다!
-> batch computing : turnaround time을 줄여야 한다.
-> interactive computing : response time을 줄여야 한다.
위 방법 중에 두 computing 환경에 모두 적합한 정책이 없다.
실제 상황에서는 작업이 batch, interactive한 job들이 섞여 있다!
또한 프로세스가 어떤 타입에 해당하는지도 알 수가 없다!
MLFQ의 목표
: batch -> turnaround time 최적화, interactive -> response time 최적화
interactive job
batch job
starvation
Priority Boost
라는 개념이 도입된다.Priority Boost
: 일정 시간이 흐르면, 모든 job을 가장 위의 queue로 올린다.MLFQ를 사용하기 위해서는 time slice, priority boost가 실행되는 시간 등 많은 변수들을 조작해야하는데 여기에 쉬운 정답은 존재하지 않는다고 한다.
turnaround time이나 response time에 최적화되는 스케줄링 기법이 아니라,
각 job들이 CPU의 제어권을 특정 퍼센티지 이상 가질 수 있도록 보장하는 기법이다.
이 기법들은 fairness
로 평가한다.
ticket
: CPU를 쓸 수 있는 티켓이라고 생각하자. process의 중요도에 따라서 ticket을 배분한다.stride
를 갖는다. stride
= ticket 비율의 역수
pass value
를 갖는다. 이는 0으로 초기화되며, 프로세스가 실행될 때마다 stride
만큼 증가한다.pass value
를 갖는 프로세스를 실행한다.CFS에서는 고정된 time slice 개념을 사용하지 않는다.
대신에 vruntime(virtual runtime)
이라는 개념을 사용한다.
프로세스가 실행되면, vruntime이 일정 크기만큼 증가하고, 스케줄러는 가장 낮은 vruntime을 갖는 프로세스를 스케줄한다.
고정된 time slice없이 어떻게?
sched_latency
, min_granuality
같은 매개변수를 사용해서 스케줄한다.
sched_latency
: 최소한 process가 한번은 실행될 수 있도록 하는 구간의 길이
CFS는 sched_latency
를 이용하여 time slice를 동적으로 결정한다.
time slice
= sched_latency
/ 실행중인 프로세스 수
ex) sched_latency가 48m이고, 4개의 프로세스가 실행되고 있다면, 각 프로세스는 12ms의 time slice를 갖게 된다.
min_granulairy
: time slice의 최솟값을 보장한다
CFS에서 min_granuality
보다 작은 time slice
를 배정할 수는 없다!
프로세스 수가 너무 많아져, time slice가 작아지면 context switch가 많이 발생해서 성능 저하가 오기 때문에 이를 방지하기 위해!
vruntime을 증가시킬 때, CFS에서는 nice_value
라는 개념을 사용한다
프로세스 별로 nice_value값이 정해진다. (-20~ 19)
CFS는 이 nice_value를 weight
에 매핑한다.
우선순위에 비례하여 weight값이 커지는 형태다
vruntime_i = vruntime_i + (1024 / weight_i) * runtime_i
(1024 = weight_0)
(runtime_i = 프로세스i가 실제 실행된 시간)
(vruntime_i = 프로세스i의 vruntime)
vruntime
을 key로 하는 red-black tree
를 사용하여 다음 실행될 프로세스를 O(logN)에 찾는다.starvation
을 막기 위해 vruntime을 red-black tree에 있는 vruntime의 최솟값으로 설정한다.