모든 이야기

문맥 교환은 CPU가 하던 일을 어떻게 기억할까

CPU 하나에서 음악 재생과 문서 편집이 함께 진행되는 것처럼 보이는 이유 중 하나는 문맥 교환이다. 문맥 교환은 현재 실행 중인 작업을 멈추고 다른 작업을 실행할 수 있도록 실행 상태를 저장하고 복원하는 과정이다. 여기서 문맥은 단순히 프로그램 이름이 아니라, 다음 명령부터 실행을 이어 갈 수 있게 만드는 상태를 말한다.

CPU가 작업 A의 레지스터와 진행 위치를 저장하고 작업 B의 실행 상태를 복원하는 흐름

문맥 교환은 실행 상태를 바꿔 작업을 이어 가며, 캐시 상태에 따른 간접 비용도 생긴다.

저장할 것은 진행 위치와 작업 환경

프로그램 카운터는 다음 명령의 위치를, 스택 포인터는 현재 호출 스택의 위치를 가리킨다. 범용 레지스터에도 계산 중간값이 담긴다. 운영체제는 필요한 레지스터를 보관하고 다음 작업의 값을 복원한다. 주소 공간이 바뀌는 경우 주소 변환에 쓰는 설정도 바뀐다. 저장 대상은 CPU 구조, 호출 규약, 커널 구현에 따라 달라진다. OSTEP의 실행 제어 장에서 이 메커니즘을 확인할 수 있다.

문맥 교환의 계기는 시간 할당량의 소진, 입출력 대기, 잠금 대기, 더 높은 우선순위 작업의 등장 등이다. 먼저 인터럽트나 시스템 호출로 커널에 들어간 뒤 스케줄러가 다른 작업을 선택할 수 있다. 하지만 커널에 들어갔다고 반드시 다른 작업으로 바뀌는 것은 아니다. 사용자 모드와 커널 모드 사이의 전환, 실제 실행 작업의 변경은 구분할 필요가 있다.

두 작업을 바꾸는 작은 실험

A가 레지스터에 합계 120을 담고 다음 덧셈 직전에 멈췄다고 해 보자. 커널은 A의 진행 위치와 합계를 저장한 뒤 B가 이전에 멈춘 상태를 복원한다. B가 실행을 마치고 다시 A를 고르면 합계 120과 복귀 위치를 되살린다. 메모리를 통째로 복사하지 않아도 A는 자신의 계산을 이어 갈 수 있다.

같은 프로세스의 스레드 사이에서도 문맥 교환이 일어날 수 있다. 이때 주소 공간은 같지만 스택과 레지스터 문맥이 다르다. 서로 다른 프로세스로 전환할 때보다 주소 공간 관련 작업이 적을 수 있으나, 비용이 언제나 일정한 비율로 작다는 보장은 없다. 무엇을 저장하는지와 전환 뒤 어떤 데이터를 사용하는지가 실제 비용을 결정한다.

보이지 않는 재가열 비용

직접 비용은 저장·복원 코드와 스케줄러 실행에 든 시간이다. 간접 비용도 있다. 새 작업의 코드와 데이터가 캐시에 없다면 다시 읽어야 하며 주소 변환 캐시의 상태도 영향을 준다. 서로 다른 코어로 이동하면 이전 코어의 캐시 이점을 잃을 수 있다. 따라서 짧은 전환 명령의 실행 시간만 측정하면 전체 손실을 과소평가할 수 있다.

시간 할당량을 짧게 하면 여러 작업이 빨리 차례를 얻어 응답성이 좋아질 수 있다. 반대로 지나치게 짧으면 실제 일보다 전환에 더 많은 시간을 쓸 수 있다. 예를 들어 유효 작업 90마이크로초마다 전환 관련 비용 10마이크로초가 든다는 단순 모델에서는 시간의 10%가 전환에 쓰인다. 이 숫자는 설명용 가정이며 실제 컴퓨터의 고정 비용을 뜻하지 않는다.

진단할 때는 문맥 교환 횟수와 함께 CPU 사용률, 대기 원인, 처리량, 지연 시간을 본다. 입출력을 효율적으로 기다리기 위해 전환이 많은 서버도 있고, 불필요한 잠금 경쟁 때문에 많은 프로그램도 있다. 횟수를 무조건 줄이는 것보다 작은 작업을 적절히 묶고, 공유 자원 경쟁을 줄이며, 전환이 필요한 이유를 파악하는 편이 정확하다.

참고 자료

문맥 교환은 CPU가 하던 일을 어떻게 기억할까 · ariser