운영체제 용어 사전
프로세스context switch · TLB 플러시 · 선점

컨텍스트 스위치

CPU가 실행 대상을 바꾸며 상태를 저장·복원하는 것. 직접 비용보다 캐시가 식는 간접 비용이 크다.

CPU가 실행 중인 대상을 바꾸며 상태를 저장하고 복원하는 것.

무엇을 저장하나

  • ① 현재 실행 중인 것의 상태를 PCB(또는 TCB)에 저장한다
    • 레지스터 · 프로그램 카운터 · 스택 포인터
  • ② 스케줄러가 다음 대상을 고른다
  • ③ 그 대상의 상태를 복원한다
  • ④ (프로세스가 바뀌면) 페이지 테이블도 교체한다

진짜 비용은 간접 비용이다

  • 직접 비용 — 레지스터 저장·복원 — 수백 나노초

  • 간접 비용 — 캐시가 식는다 (새 작업의 데이터를 다시 읽어야 한다)

    • TLB 가 플러시된다 (프로세스 전환 시)
    • 분기 예측기가 초기화된다
    • 전환 직후 한동안 느리게 돈다
  • 간접 비용이 직접 비용의 몇 배가 되는 것이 보통이다

"전환 자체는 마이크로초인데 체감은 그보다 크다" 는 이 때문이다.

언제 일어나나

  • 타임 슬라이스를 다 썼다 (선점)
  • I/O 를 기다리게 됐다 (자발적 양보)
  • 더 높은 우선순위가 준비됐다
  • 인터럽트가 들어왔다
  • 시스템 콜에서 블로킹됐다

측정하기

vmstat 1
#  r  b   swpd   free  ...  in     cs   us sy id wa
#  2  0      0  1.2G       12000  45000  30 10 60  0
#                          ^^^^^  ^^^^^ 초당 인터럽트 · 컨텍스트 스위치

pidstat -w -p <pid> 1      # 프로세스별 전환 횟수
# cswch/s   자발적 (I/O 대기 등)
# nvcswch/s 비자발적 (선점당함) ← 이게 크면 CPU 경합이 심하다

nvcswch/s가 크다는 건 실행할 준비가 된 작업이 CPU보다 많다는 뜻이다 — 스레드 수를 줄이거나 코어를 늘려야 한다.

TLB 플러시를 피하는 기법

ASID / PCID

  • TLB 항목에 '어느 주소 공간의 것인지' 태그를 붙인다
  • 프로세스가 바뀌어도 전부 버리지 않아도 된다
  • 현대 CPU 는 대부분 지원한다

스레드가 많으면 왜 느려지나

스레드 10개 · 코어 4개 → 계속 돌아가며 전환한다

  • 각 스레드가 조금씩 일하고 캐시가 계속 식는다
  • 처리량이 오히려 떨어진다

그래서 CPU 바운드 작업의 스레드 수는 코어 수 근처가 최적이다

면접 함정

  • "컨텍스트 스위치는 무조건 나쁘다" → 없으면 멀티태스킹이 불가능하다. 과도한 것이 문제다.
  • "스레드 전환은 공짜" → 페이지 테이블 교체가 없을 뿐 캐시는 여전히 식는다.

줄이는 방법

  • ① 스레드 수를 코어 수 근처로 (CPU 바운드)
  • ② CPU 친화도(affinity)로 스레드를 특정 코어에 고정한다
    • 캐시가 유지된다
  • ③ 락 경합을 줄인다 — 락 대기가 곧 전환이다
  • ④ 배치로 처리한다 — 작업 단위가 작으면 전환 비율이 높아진다
taskset -c 0,1 ./app             # 코어 0,1 에만 돌린다
numactl --cpunodebind=0 --membind=0 ./app   # NUMA 노드까지 고정

NUMA에서 더 아프다

멀티 소켓 서버는 CPU 마다 '가까운 메모리' 가 다르다

스레드가 다른 소켓으로 옮겨 가면

  • 원래 쓰던 메모리가 이제 '먼 메모리' 가 된다
  • 접근 지연이 2배 가까이 늘 수 있다

"서버를 큰 걸로 바꿨는데 성능이 안 올랐다" 의 흔한 원인

numactl --hardware               # 노드 구성과 노드 간 거리
numastat -p <pid>                # 이 프로세스가 어느 노드 메모리를 쓰나

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 프로세스 — 주소공간·fork/exec·컨텍스트 스위치