Skip to content

CPU 분석 (스케줄링 · 사용률 · Cooldown) ​

B4-2 02번 이슈(CPU 분석)에 필수 개념을 정리하고, 실제 테스트에서 CpuWorker가 어떻게 동작했는지 요약합니다. 뒤쪽에서는 운영체제가 CPU를 나눠 주는 CPU 스케줄링을 기술 면접 수준으로 자세히 다룹니다.

CPU 분석 필수 개념 ​

1. CPU 스케줄링 (CPU Scheduling) ​

정의: 여러 프로세스가 CPU를 공유할 때, 어떤 프로세스가 언제 CPU를 사용할지 결정하는 것

현실적 예시:

1초 동안 4개의 프로세스가 있다면:
- Process A: 0.0 ~ 0.25초 CPU 사용
- Process B: 0.25 ~ 0.5초 CPU 사용
- Process C: 0.5 ~ 0.75초 CPU 사용
- Process D: 0.75 ~ 1.0초 CPU 사용

→ OS가 프로세스들을 번갈아가며 실행

우리 테스트에서:

CpuWorker가 5% ~ 30% CPU 사용
= OS가 CpuWorker에게 CPU 시간을 일부 할당
= 나머지 CPU는 다른 프로세스에 할당

2. CPU 사용률 (CPU Utilization) ​

정의: CPU가 실제로 작업하는 시간의 비율

계산:

CPU 사용률 = (실제 작업 시간 / 총 시간) × 100%

예:
- 1초 동안 0.3초 작업 → 30% CPU 사용률
- 1초 동안 0.05초 작업 → 5% CPU 사용률

로그에서 보이는 것:

2026-05-27 05:58:52,265 [INFO] [CpuWorker] Current Load: 5.00%
→ 지난 1초 동안 CPU를 5% 사용했다는 뜻

3. CPU 한계 (CPU Limit / Threshold) ​

정의: 특정 프로세스가 사용할 수 있는 최대 CPU 비율

우리 테스트:

CPU_MAX_OCCUPY=30%
= CpuWorker는 최대 30%까지만 CPU 사용 가능
= 30%를 초과하면 제한됨

현실적 예시:

컴퓨터 CPU가 100% 능력이라고 하면:
- 이 프로세스: 최대 30까지만 사용
- 다른 프로세스들: 나머지 70을 나눠 씀

4. Throttling (스로틀링 / 조절) ​

정의: CPU 사용을 의도적으로 줄이는 행위

우리 로그에서:

2026-05-27 05:59:12,998 [INFO] [CpuWorker] Peak reached (30.00%). Starting cooldown...

→ CPU가 30%에 도달하자 CPU 사용을 줄임 (throttle)

실생활 예시:

- 노트북 배터리 부족 → CPU 속도 낮춤
- 폰 발열 높음 → CPU 성능 제한
- 서버 부하 높음 → 특정 서비스 속도 제한

5. Cooldown (쿨다운 / 회복 시간) ​

정의: 과부하 상태에서 벗어나기 위해 대기하는 기간

우리 테스트에서:

Phase 1: CPU 상승 (5% → 30%)
         ↓
Phase 2: Cooldown 시작 (Peak reached)
         CPU를 30% → 5%로 낮춤
         약 16초 소요
         ↓
Phase 3: Cooldown 완료 (5%)
         다시 상승 시작

시간대:

05:59:12 - Cooldown 시작
05:59:28 - Cooldown 완료 (약 16초)

6. 워크로드 (Workload) ​

정의: 프로세스가 해야 할 일의 양 또는 강도

우리 테스트:

CpuWorker의 워크로드:
- 초기: 낮음 (5% CPU만 사용)
- 중간: 증가 (점점 더 많은 계산)
- 최고: 30% (최대 허용치)
- 쿨다운: 낮춤 (의도적으로 일을 줄임)

CPU 스케줄링 자세히 보기 ​

스케줄링이 하려는 일 ​

CPU는 하나인데 실행하고 싶은 프로세스는 여럿입니다. 스케줄링은 CPU를 최대한 놀리지 않으면서 프로세스들에게 잘 나눠 주는 규칙입니다. 비유하면 은행 창구 직원 한 명이 손님 여러 명을 어떤 순서로 받을지 정하는 일과 같습니다.

좋은 스케줄링의 조건은 세 가지로 요약됩니다.

  • 오버헤드(순서를 정하고 바꾸는 데 드는 비용)는 적게
  • CPU 사용률은 높게
  • 기아 현상(어떤 프로세스가 끝없이 순서를 못 받는 것)은 적게

시스템 종류에 따라 무엇을 더 중요하게 보는지도 다릅니다.

시스템목표예
일괄 처리 (Batch)정해진 시간에 최대한 많은 일 처리 (처리량, throughput)밤새 도는 정산 작업
대화형 (Interactive)빠른 응답, 짧은 대기우리가 쓰는 PC, 스마트폰
실시간 (Real-time)정해진 기한(deadline) 반드시 지키기자동차 브레이크 제어, 항공 시스템

선점 vs 비선점 ​

  • 선점(preemptive): 운영체제가 실행 중인 프로세스에게서 CPU를 강제로 빼앗아 다른 프로세스에 줄 수 있습니다. 급한 일을 바로 처리할 수 있어 응답성이 좋지만, 전환이 잦아 오버헤드가 생기고 각 작업이 언제 끝날지 예측하기 어렵습니다.
  • 비선점(nonpreemptive): 한 번 CPU를 받으면 스스로 끝나거나 입출력 등을 기다리느라 내려놓을 때까지 계속 씁니다. 처리 시간 예측은 쉽지만, 긴 작업 하나가 CPU를 오래 붙잡으면 뒤의 짧은 작업들이 오래 기다립니다.

프로세스 상태와 스케줄링 ​

프로세스는 생성(New), 준비(Ready), 실행(Running), 대기(Waiting), 종료(Terminated) 상태를 오갑니다.

text
          승인              디스패치
 [생성] ─────────▶ [준비] ─────────▶ [실행] ─────────▶ [종료]
                   ▲   ▲ ◀───────────  │       종료
                   │   │   인터럽트    │
                   │   │  (시간 다 씀)  │ 입출력/이벤트 대기
                   │   └──── [대기] ◀──┘
                   │ 입출력/이벤트 완료
상태 바뀜의미
승인 (Admitted)새 프로세스를 만들어도 된다고 허락받아 준비 상태로
디스패치 (Dispatch)준비 상태 프로세스 중 하나를 골라 CPU에 올림
인터럽트 (Interrupt)시간이 다 됐거나 더 급한 일이 생겨, 실행 중이던 프로세스를 준비 상태로 돌려보냄
입출력/이벤트 대기파일 읽기처럼 기다려야 하는 일이 생겨 대기 상태로
입출력/이벤트 완료기다리던 일이 끝나 다시 준비 상태로
종료 (Exit)실행을 마침

스케줄러가 끼어드는 시점으로 보면 차이가 분명해집니다. 비선점 방식은 실행 중인 프로세스가 대기로 가거나 종료될 때만 다음 프로세스를 고릅니다. 선점 방식은 여기에 더해 인터럽트(시간 초과)로 준비 상태로 내려갈 때, 대기하던 프로세스가 입출력을 마치고 준비 상태로 돌아올 때도 다시 고를 수 있습니다. 상태와 PCB는 PCB와 컨텍스트 스위칭에서 더 자세히 다룹니다.

스케줄링 알고리즘 ​

비선점 방식

  1. FCFS (First Come First Served): 도착한 순서대로 처리합니다. 가장 단순하지만, 오래 걸리는 작업이 앞에 오면 뒤의 짧은 작업들이 줄줄이 기다리는 호위 효과(convoy effect)가 생깁니다.
  2. SJF (Shortest Job First): 실행 시간이 가장 짧을 것으로 예상되는 작업부터 처리합니다. 평균 대기 시간을 가장 짧게 만드는 방식으로 알려져 있지만, 긴 작업은 계속 밀려 기아 현상이 생길 수 있고, 실행 시간을 미리 정확히 알기 어렵습니다.
  3. HRN (Highest Response-ratio Next): SJF가 긴 작업을 너무 불리하게 대하는 문제를 보완합니다. 아래 값이 큰 작업부터 처리하므로, 오래 기다린 작업일수록 우선순위가 올라갑니다.
    • 우선순위 = (대기 시간 + 실행 시간) / 실행 시간

선점 방식

  1. SRTF (Shortest Remaining Time First): SJF의 선점 버전입니다. 실행 중이라도 남은 시간이 더 짧은 작업이 도착하면 CPU를 넘겨줍니다.
  2. 우선순위 스케줄링 (Priority): 정해 둔 우선순위가 높은 작업부터 처리합니다. 우선순위가 낮은 작업이 끝없이 밀리는 기아(Starvation)가 생길 수 있는데, 기다린 시간만큼 우선순위를 조금씩 올려 주는 에이징(Aging)으로 해결합니다. (우선순위 스케줄링은 비선점으로도 만들 수 있습니다.)
  3. 라운드 로빈 (Round Robin): 도착 순서대로 줄을 세우되, 모두에게 똑같은 시간 할당량(Time Quantum, Time Slice)만큼만 CPU를 주고 다 못 끝내면 줄 맨 뒤로 보냅니다. 할당량이 너무 크면 FCFS와 같아지고, 너무 작으면 컨텍스트 스위칭이 잦아져 오버헤드가 커집니다. 대화형 시스템에서 많이 씁니다.
  4. 다단계 큐 (Multilevel Queue): 작업을 성격에 따라 여러 그룹(예: 시스템 작업, 대화형 작업, 일괄 작업)으로 나눠 그룹마다 큐를 따로 둡니다. 큐마다 다른 알고리즘을 쓸 수 있고(대화형은 라운드 로빈, 일괄 처리는 FCFS 등), 큐 사이에도 우선순위가 있습니다. 한 번 들어간 큐에서 다른 큐로 옮겨 가지 않습니다. 높은 큐만 계속 실행돼 낮은 큐가 굶는 것을 막으려고, 큐마다 CPU 시간을 비율로 나눠 주기도 합니다.
  5. 다단계 피드백 큐 (Multilevel Feedback Queue): 다단계 큐에서 큐 사이 이동을 허용한 방식입니다. 위쪽 큐일수록 우선순위가 높고 시간 할당량이 작습니다.
    • 할당량을 다 쓰고도 못 끝낸 작업은 CPU를 오래 쓰는 작업(CPU burst)으로 보고 한 단계 아래 큐로 내립니다.
    • 할당량 안에 입출력 등으로 CPU를 스스로 내려놓은 작업은 원래 큐에 그대로 둡니다.
    • 그래서 짧은 작업과 입출력 위주의 작업(인터럽트가 잦은 작업)이 우선권을 갖고, 평균 반환 시간이 줄어듭니다. 아래 큐에서 너무 오래 기다린 작업은 위로 올려 기아를 막기도 합니다.
text
다단계 피드백 큐
 큐 0 (할당량 8ms)  ──▶ 다 못 끝내면 아래로
 큐 1 (할당량 16ms) ──▶ 다 못 끝내면 아래로
 큐 2 (FCFS)
 위 큐가 비어 있을 때만 아래 큐를 실행

스케줄링을 평가하는 기준 ​

기준뜻
CPU 사용률CPU가 쉬지 않고 일한 비율 (높을수록 좋음)
처리량 (Throughput)단위 시간당 끝낸 작업 수 (많을수록 좋음)
반환 시간 (Turnaround Time)작업이 도착해서 완전히 끝날 때까지 걸린 시간 = 대기 시간 + 실행 시간
대기 시간 (Waiting Time)준비 큐에서 CPU를 기다린 시간의 합
응답 시간 (Response Time)도착해서 처음으로 CPU를 받기까지 걸린 시간

직접 계산해 보기 ​

작업 4개가 아래처럼 도착했을 때 FCFS, SJF(비선점), 라운드 로빈(할당량 2)을 비교해 봅니다.

작업도착 시각실행 시간
P108
P214
P322
P431
python
from collections import deque

# (이름, 도착 시각, 실행 시간)
jobs = [("P1", 0, 8), ("P2", 1, 4), ("P3", 2, 2), ("P4", 3, 1)]

def report(name, finish):
    print(f"[{name}]")
    total_wait = 0
    for p, arrive, burst in jobs:
        turnaround = finish[p] - arrive      # 도착부터 끝날 때까지
        wait = turnaround - burst            # 그중 기다린 시간
        total_wait += wait
        print(f"  {p}: 끝난 시각 {finish[p]:2}, 반환 시간 {turnaround:2}, 대기 시간 {wait:2}")
    print(f"  평균 대기 시간 = {total_wait / len(jobs)}")

def fcfs():
    t, finish = 0, {}
    for p, arrive, burst in sorted(jobs, key=lambda j: j[1]):
        t = max(t, arrive) + burst
        finish[p] = t
    return finish

def sjf():  # 비선점: CPU가 빌 때마다 도착한 작업 중 가장 짧은 것
    t, finish, left = 0, {}, list(jobs)
    while left:
        ready = [j for j in left if j[1] <= t] or [min(left, key=lambda j: j[1])]
        p, arrive, burst = min(ready, key=lambda j: j[2])
        t = max(t, arrive) + burst
        finish[p] = t
        left.remove((p, arrive, burst))
    return finish

def round_robin(quantum):
    t, finish = 0, {}
    remain = {p: b for p, _, b in jobs}
    pending = sorted(jobs, key=lambda j: j[1])
    queue = deque()
    while len(finish) < len(jobs):
        while pending and pending[0][1] <= t:
            queue.append(pending.pop(0)[0])
        if not queue:
            t = pending[0][1]
            continue
        p = queue.popleft()
        run = min(quantum, remain[p])
        t += run
        remain[p] -= run
        while pending and pending[0][1] <= t:   # 실행 중에 도착한 작업이 먼저 줄을 섬
            queue.append(pending.pop(0)[0])
        if remain[p] == 0:
            finish[p] = t
        else:
            queue.append(p)
    return finish

report("FCFS", fcfs())
report("SJF", sjf())
report("Round Robin (q=2)", round_robin(2))
text
[FCFS]
  P1: 끝난 시각  8, 반환 시간  8, 대기 시간  0
  P2: 끝난 시각 12, 반환 시간 11, 대기 시간  7
  P3: 끝난 시각 14, 반환 시간 12, 대기 시간 10
  P4: 끝난 시각 15, 반환 시간 12, 대기 시간 11
  평균 대기 시간 = 7.0
[SJF]
  P1: 끝난 시각  8, 반환 시간  8, 대기 시간  0
  P2: 끝난 시각 15, 반환 시간 14, 대기 시간 10
  P3: 끝난 시각 11, 반환 시간  9, 대기 시간  7
  P4: 끝난 시각  9, 반환 시간  6, 대기 시간  5
  평균 대기 시간 = 5.5
[Round Robin (q=2)]
  P1: 끝난 시각 15, 반환 시간 15, 대기 시간  7
  P2: 끝난 시각 11, 반환 시간 10, 대기 시간  6
  P3: 끝난 시각  6, 반환 시간  4, 대기 시간  2
  P4: 끝난 시각  9, 반환 시간  6, 대기 시간  5
  평균 대기 시간 = 5.0
  • FCFS는 시간 0에 혼자 도착한 긴 작업 P1(8)이 먼저 CPU를 잡아서, 짧은 P3, P4가 오래 기다립니다(호위 효과).
  • SJF는 P1이 끝난 뒤 짧은 순서(P4 → P3 → P2)로 처리해서 평균 대기 시간이 줄었습니다. 대신 가장 긴 P2가 맨 뒤로 밀렸습니다.
  • 라운드 로빈은 P1이 CPU를 2만큼만 쓰고 줄 뒤로 가기 때문에, 짧은 P3가 시각 6에 바로 끝납니다. 평균 대기 시간도 가장 짧지만, 가장 긴 P1은 맨 마지막에 끝나고 작업을 자주 바꾸는 만큼 컨텍스트 스위칭 비용이 듭니다.

B4-2 테스트와 연결해 보기 ​

CpuWorker가 30%를 넘지 못하게 막은 CPU_MAX_OCCUPY와 Cooldown은 애플리케이션이 스스로 사용량을 줄인 것입니다. 운영체제 스케줄러는 그와 별개로 모든 프로세스에게 CPU 시간을 나눠 주고, 남은 70%는 이 스케줄링 규칙에 따라 다른 프로세스들이 나눠 썼습니다.

요약: CPU (02번) ​

CpuWorker가 부하를 계속 증가시킴
→ 30%에 도달하면 "Peak reached"
→ Cooldown 시작 (부하 자동 감소)
→ 5%까지 내려가면 "Cooldown complete"
→ 다시 부하 증가
→ 반복 (무한 사이클)

결론: CPU 정상 작동, 자동 조절 메커니즘 우수

정리 ​

CPU 관련 개념 ​

  1. CPU 스케줄링: 여러 프로세스가 CPU를 공유하는 방식
  2. CPU 사용률: (실제 작업시간 / 총시간) × 100%
  3. Throttling: CPU 사용을 의도적으로 제한
  4. Cooldown: 과부하에서 벗어나기 위한 회복 기간
  5. Workload: 프로세스가 해야 할 일의 양

CPU 스케줄링 개념 ​

개념비전공자 버전 요약
선점 / 비선점하던 일을 운영체제가 빼앗을 수 있느냐 없느냐
FCFS온 순서대로. 긴 손님이 앞에 있으면 다 같이 기다림
SJF / SRTF빨리 끝나는 일부터. 평균 대기는 짧지만 긴 일이 계속 밀림
HRN오래 기다릴수록 순서가 앞당겨지는 SJF
우선순위 + 에이징중요한 일 먼저, 너무 오래 기다리면 순위를 올려 줌
라운드 로빈모두에게 같은 시간만큼 돌아가며 CPU를 줌
다단계 (피드백) 큐줄을 여러 개 두고, 피드백 큐는 CPU를 오래 쓰는 일을 아래 줄로 내림
반환 시간 / 대기 시간 / 응답 시간끝날 때까지 / 줄 서서 기다린 시간 / 처음 CPU를 받기까지

학습 팁: CPU 이해하기 ​

  1. CPU 사용률이란 뭔가? (= 일하는 시간의 비율)
  2. 한계를 정하면? (= CPU_MAX_OCCUPY)
  3. 한계에 도달하면? (= Cooldown으로 자동 조절)
  4. 프로세스는? (= 계속 살아있음)

출처: Codyssey-B1/B4-2

참고: 스케줄링 목표, 다단계 큐, 다단계 피드백 큐