운영체제(Operating System) 4강
반효경 교수님 - CPU Scheduling
- Lecture
- CPU burst & I/O burst
- CPU Scheduling
Lecture
- 운영체제 - 반효경 교수님
- CPU Scheduling 1
- CPU Scheduling 2
CPU burst & I/O burst
프로세스의 작업은 크게 두가지로 나뉘는데, 결과를 화면에 출력하거나, 다른 파일에 접근하여 데이터를 읽어오거나, 다른 컴퓨터와 통신하는 등의 I/O 작업과, 어떤 결과를 도출해내기 위한 CPU 연산 작업으로 이뤄져있다.
CPU burst
CPU 버스트는 사용자 프로세스가 CPU를 할당받아 명령어들을 빠르게 수행하는 단계이다.
이 때, 사용자 프로세스는 CPU 내에서 일어나는 명령(연산)이나 메모리에 접근하는 일반 명령(읽기, 쓰기)을 수행 할 수 있다.
I/O burst
I/O 버스트는 사용자 프로세스가 시스템 콜을 통해 운영체제에 작업을 위탁한 후 운영체제에 의해 I/O 작업을 진행하는 단계이다.
이 단계에서 모든 I/O 작업은 커널 모드로 수행되기 때문에 오로지 운영체제를 통해서만 수행된다.
이처럼 사용자 프로그램이 수행되는 과정은 CPU 버스트와 I/O 버스트의 반복으로 구성된다.
CPU bound process & I/O bound process
각 사용자 프로세스는 CPU 버스트와 I/O 버스트의 비율이 다르다.
사용자 입출력이 많은 프로세스는 I/O 버스트가 CPU 버스트에 비해 많은 비율을 차지하겠지만, 사용자 입출력이 거의 없이 오로지 연산만 하는 경우는 CPU 버스트의 비율이 더 높게 나타난다.
이러한 기준에서 프로세스는 CPU bound process
와 I/O bound process
로 나눌 수 있다.
프로세스 수행 구조를 보면 I/O bound process는 짧은 CPU 버스트를 많이 가지고 있는 반면, CPU bound process는 소수의 긴 CPU 버스트로 구성되고 있는 것을 볼 수 있다.
CPU Scheduling
컴퓨터 시스템 내에서 수행되는 프로세스들의 CPU 버스트를 분석해보면 대부분의 프로세스가 짧은 CPU 버스트를 가지며, 극히 일부분의 프로세스만 긴 CPU 버스트를 갖는다.
이는 다시 말해서 CPU를 한 번에 오래 사용하기보다는 잠깐 사용하고 I/O 작업을 수행하는 프로세스가 많다는 것이다.
즉, 사용자와의 대화형 작업(인터랙션)을 많이 수행한다고 볼 수 있는데, 사용자에 대한 빠른 응답을 위해서는 해당 프로세스에게 우선적으로 CPU를 할당하는 것이 바람직하다. 왜냐하면, 만약 CPU 바운드 프로세스에게 먼저 CPU를 할당한다면 그 프로세스가 CPU를 다 사용할 때까지 수많은 I/O 바운드 프로세스는 기다려야할 것이다. 이는 사용자 경험측면에서 봤을 때 컴퓨터의 응답이 느려진다는 치명적인 결과로 이어진다.
이러한 이유로 어떤 프로세스에게 CPU를 더 먼저 할당해줄지를 결정하는 CPU 스케쥴링이 필요해졌다.
CPU Scheduler
CPU 스케쥴러는 준비 상태에 있는 프로세스들 중 어떠한 프로세스에게 CPU를 할당할 지 결정하는 운영체제의 코드이다.
즉, 단순히 운영체제 코드에 정의된 어떤 함수일 뿐이며, 이를 범용적으로 CPU 스케쥴러라고 부르는 것이다.
이 코드는 당장 깃허브에 리눅스 프로젝트를 검색해 들어가면 볼 수 있다.
CPU 스케쥴러가 필요한 경우
CPU 스케쥴링이 필요한 경우는 프로세스에게 다음과 같은 상태 변화가 있는 경우이다.
- Running -> Blocked (예: I/O 요청하는 시스템 콜)
- Running -> Ready (예: 할당 시간 만료로 타이머 인터럽트 발생)
- Blocked -> Ready (예: I/O 완료 후 인터럽트)
- Terminated (예: 프로세스 종료)
1, 4번째의 스케쥴링은 강제로 빼앗지 않고 자진 반납하는 non-preemptive(비선점, 자발적인)
방식이고, 그 외의 스케쥴링은 CPU를 강제로 빼앗는 preemptive(선점, 강제적인)
방식이다.
Dispatcher
CPU를 누구한테 누구한테 줄 지 결정했으면 해당 프로세스에게 넘겨야 하는데, 디스패처가 이 역할을 수행한다. 이 과정이 Context Switch
에 해당한다.
참고로, 디스패처는 관제탑에서 여러 비행기들에게 지시하는 사람을 의미한다.
Scheduling Criteria
시스템 측면
시스템 측면에서의 성능 척도라는 것은 CPU 하나를 가지고 최대한 일을 많이 시키면 좋은 것이다.
따라서 다음 두개의 지표를 본다.
- CPU utilization (CPU 이용률)
- 전체 시간 중에서 CPU가 놀지 않고 일을 한 시간의 비율
- keep the CPU as busy as possible (가능한 바쁘게 일을 시켜야 한다)
- Throughput (처리량, 산출량)
- 주어진 시간동안 몇개의 작업을 완료했는가
- CPU를 원하는 프로세스 중 몇 개가 원하는 만큼의 CPU를 사용하고 있고, 이번 CPU 버스트를 끝내어 레디큐를 떠났는지 측정한 것
- 더 많은 프로세스들이 CPU 작업을 완료하기 위해서는 CPU 버스트가 짧은 프로세스에게 우선적으로 CPU를 할당하는 것이 유리할 것
프로세스 측면
프로세스 측면에서의 성능 척도라는 것은 자신이 CPU를 빨리 얻어서 해야 할 작업을 빨리 끝내면 좋은 것이다.
따라서 다음 세가지의 지표를 본다.
- Turnaround time (소요 시간, 반환 시간)
- 프로세스가 CPU를 사용하기 위해 레디큐에 들어와서, CPU를 다 사용하고 나갈 때까지 걸린 시간을 의미
- 즉, Turnaround time = Waiting time + 실제로 CPU를 사용한 시간
- Waiting time (대기 시간)
- CPU 버스트 중 프로세스가 레디큐에서 CPU를 얻기 위해 기다린 시간의 총 합을 의미
- 시분할 시스템의 경우 CPU를 강제적으로 계속 빼앗길 수 있기 때문에, 한 번의 CPU 버스트 중에도 레디큐에서 기다리는 시간이 여러 번 발생할 수 있다
- Response time (응답 시간)
- 프로세스가 준비 큐에 들어온 후 첫 번째 CPU를 획득하기까지 기다린 시간을 뜻한다
- 응답 시간은 대화형 시스템에 적합한 성능 척도로서, 사용자 입장에서 가장 중요한 성능 척도라고 할 수 있다
중국집으로 비유한 스케쥴링 성능 척도
중국집에 주방장 한명과 여러 손님이 있다.
중국집 입장에서는 주방장한테 일을 많이 시키는게 좋다.
- CPU utilization: 전체 시간 중 주방장이 일을 한 시간의 비율. 당연히 높으면 좋을 것
- Throughput: 정해진 시간 동안 주방장이 몇명의 손님에게 요리를 만들어 주었는가. 당연히 높으면 좋을 것
손님 입장에서는 중국집에 밥을 먹으러 들어가서 밥을 먹고 나오는 시간이 짧으면 짧을수록 좋다.
- Turnaround time: 손님이 중국집에 들어와 음식을 주문하고, 주문한 음식을 다 먹고 나가기까지 소요된 총 시간
- Waiting time: 음식을 먹은 시간을 제외한 순수하게 기다린 시간 (코스요리 처럼 음식이 여러 번 나누어져 나오는 경우 중간중간 기다린 시간을 모두 다 합쳐야 한다)
- Response time: 최초의 음식이 나오기까지 손님이 기다린 시간
CPU Scheduling Algorithms
FCFS (First-Come First-Served)
- 먼저 온 순서대로 처리하는 방식 (
non-preemptive
) - 버스트 타임이 긴 프로세스와 짧은 프로세스들이 있는 상황에, 버스트 타임이 가장 긴 프로세스가 가장 먼저 도착하면 버스트 타임이 짧은 프로세스들은 앞의 프로세스가 끝날때까지 대기해야만 한다
- 마트 계산대로 비유하자면, 나는 아이스크림 하나만 결제하고 나가면 되는데, 앞에 카트를 통째로 채워온 손님이 먼저 도착하여 계산을 하고 있는 경우와 같다
- 위 사진처럼 어떤 프로세스가 먼저 CPU를 할당받느냐에 따라 전체 대기 시간에 상당한 영향을 미침
- 1번
- 대기 시간: P1 = 0, P2 = 24, P3 = 27
- 평균 대기 시간: (0 + 24 + 27) / 3 = 17
- 2번
- 대기 시간: P1 = 6, P2 = 0, P3 = 3
- 평균 대기 시간: (6 + 0 + 3) / 3 = 3
- 1번
- 긴 프로세스 하나 때문에 짧은 프로세스 여러 개가 기다리는 현상을
Convoy effect
라 부른다
SJF (Shortest-Job-First)
- 버스트 타임이 가장 짧은 프로세스에게 가장 먼저 CPU를 할당하는 방식
- 평균 대기 시간을 가장 짧게 가져가는 알고리즘 (minimum average wating time)
- 문제점
- Starvation (기아): 버스트 타임이 짧은 프로세스가 계속해서 들어오면 버스트 타임이 상대적으로 긴 프로세스가 영원히 CPU를 할당받지 못할 수도 있다
- 정확한 버스트 타임을 미리 알 수 없고, 과거 버스트 타임을 통해 추정만 할 수 있다
Priority Scheduling
우선 순위
가 제일 높은 프로세스에게 CPU를 할당- 일반적으로
우선 순위 값(priority number)
이 작을 수록 높은 우선 순위를 갖는다. (정수형) - non-preemptive (비선점형)
- 일단 CPU를 할당 받으면, 더 높은 우선 순위를 가진 프로세스가 들어와도 CPU 버스트가 완료될 떄까지 CPU를 빼앗기지 않는다
- preemptive (선점형)
- CPU를 할당받아 작업중이더라도 더 높은 우선 순위를 가진 프로세스가 들어오면 CPU를 빼앗긴다
- SJF는 버스트 타임을 우선순위로 사용하는 우선 순위 스케쥴링의 일종이라고 볼 수 있다
- 문제점
- Starvation (기아): 우선 순위가 낮은 프로세스가 지나치게 오래 기다리거나, 혹은 영원히 CPU를 할당 받지 못할 수도 있다
- 해결 방안
- Aging (노화): 우선 순위가 낮은 프로세스에 대해 기다린 시간만큼 비례하여 우선 순위를 높여주는 기법
RR (Round Robin)
- 각 프로세스는 동일한 크기의
할당 시간(time quantum)
을 가진다 - 할당 시간이 지나면 프로세스는 CPU를 빼앗기고 레디큐 맨 뒤에 가서 줄을 선다
- 사용자에게 짧은 응답 시간을 보장함
- CPU를 줬다 뺏었다를 반복하기 때문에 CPU를 최초로 얻기까지 걸리는 시간이 짧다
- n개의 프로세스가 레디큐에 있고, 할당 시간이 q인 경우 어떤 프로세스도
(n - 1) * q
이상 기다리지 않는다 - CPU를 할당받기 위해 기다리는 시간이 CPU 버스트에 비례한다
- 성능
- q가 커질 수록
FCFS
에 가까워진다 - q가 작을 수록
Context Switch
로 인한 오버헤드가 증가한다
- q가 커질 수록
- 일반적으로 SJF보다 평균 Turnaround time이 길지만, 응답 시간은 짧다
- 시간이 오래 걸리는 프로세스와 짧게 걸리는 프로세스가 섞여 있을 때는 효율적이지만, 시간이 동일한 프로세스만 있을 때는 비 효율적이다.
위와 같이 RR은 정해진 할당 시간(20) 만큼만 공평하게 CPU를 사용한다.
Multi-Level Queue
- 우선 순위에 따라 여러개의 레디큐를 둔다
- 사용자에게 빠른 응답을 줘야하는 대화형 작업은 우선순위가 높은 전위큐에 넣는다
- 전위큐에서는 주로 RR 스케쥴링 기법을 사용한다
- 계산 위주의 작업은 우선순위가 낮은 후위큐에 넣는다
- 후위큐에서는 주로 FCFS 스케쥴링 기법을 사용한다
- 사용자에게 빠른 응답을 줘야하는 대화형 작업은 우선순위가 높은 전위큐에 넣는다
- 멀티 레벨 큐 자체에 대한 스케쥴링이 필요하다
- 고정 우선순위 방식 (Fixed Priority Scheduling)
- 전위큐에 있는 프로세스에게 우선적으로 CPU가 할당되고, 전위큐가 비어 있는 경우에만 후위큐에 있는 프로세스에게 CPU가 할당된다
- Starvation (기아) 가능성이 존재한다
- 타임 슬라이스 방식 (Time Slice)
- 각 큐에 CPU 사용 시간을 적절한 비율로 할당한다.
- 예: 80%는 전위큐, 20%는 후위큐
- 고정 우선순위 방식 (Fixed Priority Scheduling)
Multi-Level Feedback Queue
- 현대에 와서, 대다수의 컴퓨터들이 채택하고 있는 CPU 스케쥴링 기법이다
- 프로세스가 여러 개로 분할된 레디큐 내에서 다른 큐로 이동이 가능하다
- 멀티 레벨 피드백 큐를 이용하여 Aging (노화) 기법을 구현할 수 있다
- Aging 기법은 프로세스가 우선 순위가 낮은 큐에서 오래 기다리면, 우선 순위가 높은 큐로 승격하는 방식이다
- 멀티 레벨 피드백 큐를 정의하는 요소
- 큐의 수
- 각 큐의 스케쥴링 알고리즘
- 프로세스를 상위큐로 승격하는 기준
- 프로세스를 하위큐로 강등하는 기준
- 프로세스가 도착했을 때 들어갈 큐를 결정하는 기준
- 일반적으로 처음 들어온 프로세스는 CPU 할당 시간을 짧게 하여 우선 순위가 가장 높은 전위큐에 배치한다
- 만약 주어진 할당 시간 안에 작업을 완료하지 못하면 CPU 할당 시간을 조금 더 주되, 우선 순위가 한 단계 낮은 큐로 강등한다
- 이 과정을 반복하다가 최하위큐에 배치가 된다
Multi-Processor Scheduling
은행으로 비유하자면, 행원 한명과 은행 창구 하나만 있던 상황에서, 행원과 은행 창구가 여러명으로 늘어난 것과 같은 상황이다.
이렇게 되어도 근본적인 CPU 스케쥴링에는 큰 차이가 없으나 몇가지 특이한 상황이 발생할 수 있다.
Real-time Scheduling
정해진 시간 안에 반드시 실행이 되어야 하는, 즉 프로세스에 데드라인
이 있는 경우 사용하는 기법이다.
Hard real-time systems
- 정해진 시간 안에 반드시 작업이 끝나도록 스케쥴링해야 한다
- 미사일 발사 버튼같은 것들을 생각해볼 수 있다
Soft real-time systems
- 데드라인이 존재하기는 하지만 지키지 못했다고 해서 위험한 상황이 생기지는 않는다
- 일반 프로세스에 비해 높은 우선 순위를 갖도록 한다
Thread Scheduling
Local Scheduling
- 운영체제가 스레드의 존재를 모르는 것을 유저 레벨 스레드라고 한다
- OS가 아닌 사용자 프로세스가 직접 어느 스레드한테 CPU를 줄 것인지 결정한다
- 대표적으로 구버전 JVM의 스레드 스케쥴링이 있다
Global Scheduling
- 커널 레벨 스레드의 경우 일반 프로세스처럼 운영체제의 단기 스케쥴러가 어떤 스레드를 스케쥴할 지 결정한다
Scheduling Algorithmic Evaluation
Queuing Model
- 주로 이론가들이 수행하는 방식
- 확률 분포로 주어지는 도착율(Arrival Rate)과 처리율(Service Rate)등을 통해 각종 성능 지표를 계산한다
Implementation & Measurement
- 주로 구현가들이 수행하는 방식으로, 실측을 의미한다
- 실제 시스템에 알고리즘을 구현하여 실제 작업에 대해서 성능을 측정하여 비교한다
- 예를 들어 새로운 CPU 스케쥴링 알고리즘을 개발했다고 가정하면, 리눅스의 스케쥴링 함수를 직접 개발한 알고리즘으로 수정한 후 컴파일 하여 컴파일된 리눅스를 직접 돌려 성능 지표를 뽑아낸 후 기존 리눅스와 비교하는 방식이라고 생각하면 되겠다
Simulation
- 알고리즘을 모의 프로그램으로 작성한 후 trace(실제 시스템에서 추출한 입력값)를 입력으로 하여 결과를 비교한다