더 빠른 CPU의 비밀
4장의 장난감 CPU는 명령 하나에 세 박자가 걸렸다. 요즘 CPU는 한 박자에 명령을 여러 개 끝낸다. 어떻게 가능할까? 답은 “더 빨리 일하기”가 아니라 “동시에 여러 일을 겹쳐 하기”와 “미리 짐작해서 하기”에 있다. 세탁소와 요리사의 지혜를 빌려 CPU 속도의 비밀을 하나씩 풀어 보자.
- CPU 성능이 클럭, 박자당 명령 수, 코어 수의 곱으로 결정됨을 이해한다.
- 파이프라인이 명령을 겹쳐 실행해 처리량을 높이는 원리와 그 한계(의존성, 지연)를 안다.
- 분기 예측이 왜 필요한지, 예측이 틀리면 어떤 손해가 생기는지 체험한다.
- 클럭 경쟁이 2005년 무렵 멈추고 멀티코어 시대가 온 이유(전력·발열)를 설명한다.
- 암달의 법칙으로 코어를 늘려도 속도가 무한히 늘지 않는 이유를 이해한다.
CPU 속도는 세 가지의 곱
CPU가 1초에 처리하는 명령의 수는 대략 다음과 같이 쪼갤 수 있다.
박자를 빠르게 하든(클럭), 한 박자에 많이 하든(IPC), 일꾼을 늘리든(코어) 셋 중 하나를 키우면 빨라진다. 지난 50년의 CPU 역사는 이 세 가지를 차례로 키워 온 역사다.
그런데 클럭을 무한정 올릴 수는 없다. 한 박자 안에 신호가 회로의 가장 긴 길을 끝까지 지나가야 하기 때문이다. 3장의 덧셈기에서 올림수가 번져 가는 데 시간이 걸렸던 것을 떠올리자. 그 길이 짧아야 박자도 빨라진다. 그 길을 짧게 자르는 방법이 바로 파이프라인이다.
파이프라인: 세탁소의 지혜
빨래에는 세탁(30분) → 건조(30분) → 개기(30분)가 필요하다. 빨래 네 바구니를 한 바구니씩 끝까지 처리하면 4 × 90분 = 6시간이 걸린다. 하지만 첫 바구니가 건조기에 들어가는 순간 둘째 바구니를 세탁기에 넣으면? 세 기계가 동시에 돌아가서 2시간 30분이면 끝난다. 한 바구니가 걸리는 시간(90분)은 그대로지만, 끝나는 빈도가 30분마다 하나로 빨라진 것이다.
CPU도 명령 실행을 여러 단계로 나누고 각 단계를 맡는 회로를 따로 둔다. 전형적인 5단계는 가져오기(IF) → 해석(ID) → 실행(EX) → 메모리 접근(MEM) → 결과 쓰기(WB)이다. 한 명령이 해석 단계로 넘어가면 가져오기 회로는 바로 다음 명령을 가져온다. 이것이 파이프라인(pipeline)이다.
5단계 파이프라인
실제 CPU는 파이프라인을 15~20단계로 더 잘게 나누고, 한 박자에 여러 명령을 동시에 가져오는 슈퍼스칼라(superscalar) 구조를 쓴다. 세탁기를 여러 대 두는 셈이다. 게다가 앞 명령을 기다리는 동안 상관없는 뒤쪽 명령을 먼저 실행하는 비순차 실행(out-of-order execution)으로 빈칸을 메운다. 그 덕분에 요즘 CPU의 IPC는 4~8에 이른다.
분기 예측: 갈림길에서 미리 짐작하기
파이프라인에는 고민거리가 하나 있다. 4장의 JZ 같은 조건 점프(분기)를 만나면, 그 조건이 참인지는 실행 단계에 가서야 안다. 그런데 파이프라인은 이미 다음 명령 몇 개를 가져오고 있어야 한다. 어느 쪽 길의 명령을 가져와야 할까?
CPU는 기다리지 않고 짐작한다. 이를 분기 예측(branch prediction)이라 한다. 맞으면 아무 손해 없이 계속 달리고, 틀리면 잘못 가져온 명령들을 모두 버리고(파이프라인 비우기) 다시 시작한다. 한 번 틀릴 때마다 15~20박자를 잃는다.
매일 아침 8시에 오는 손님이 늘 아메리카노를 시킨다면, 바리스타는 손님이 문을 여는 순간 미리 커피를 내리기 시작한다. 맞으면 손님은 기다리지 않고, 가끔 라떼를 시키면 만든 커피를 버리고 다시 만든다. 손님의 습관이 규칙적일수록 이득이 크다.
분기 예측기 대결
숫자 배열을 돌며 “128보다 크면 더하기”를 하는 코드는 배열을 먼저 정렬하면 몇 배나 빨라진다. 계산량은 같지만, 정렬된 배열에서는 분기가 “안 감, 안 감, …, 감, 감, 감”처럼 규칙적이라 예측이 거의 다 맞기 때문이다. 위 시뮬레이터의 “정렬된 데이터”와 “무작위”를 비교해 보자. 이 사례는 프로그래머 커뮤니티에서 유명한 질문으로, 하드웨어를 이해해야 소프트웨어 성능을 이해할 수 있다는 좋은 예다.
클럭 경쟁의 끝: 전력과 열의 벽
1990년대부터 2000년대 초반까지 CPU 클럭은 해마다 쑥쑥 올라 100 MHz에서 3 GHz를 넘었다. 그런데 2005년 무렵부터 클럭은 3~5 GHz 근처에서 거의 멈췄다. 왜일까?
트랜지스터가 켜지고 꺼질 때마다 전기를 쓰고 열이 난다. 클럭을 올리려면 전압도 올려야 하는데, 소비 전력은 대략 전압의 제곱 × 클럭에 비례한다. 클럭을 1.5배로 올리려고 전압도 높이면 전력은 2~3배로 뛴다. 손톱만 한 칩에서 100 W 넘는 열이 나면 전기 난로의 열판보다 단위 면적당 열이 많아지고, 더 올리면 냉각이 따라가지 못한다. 이를 전력 장벽(power wall)이라 한다.
데스크톱 CPU의 클럭과 코어 수 추이 (대략)
그래서 업계는 방향을 틀었다. 박자를 더 빠르게 하는 대신, 같은 칩 안에 CPU 두뇌(코어)를 여러 개 넣기로 한 것이다. 이것이 멀티코어(multi-core)다. 요리사 한 명을 미친 듯이 빠르게 만드는 대신 요리사를 여러 명 고용하는 셈이다. 스마트폰은 한 걸음 더 나아가, 힘센 코어와 전기를 아끼는 작은 코어를 섞어 두고 일의 종류에 따라 골라 쓴다.
요리사를 늘리면 무조건 빨라질까: 암달의 법칙
요리사가 8명이면 요리가 8배 빨리 나올까? 감자 깎기, 채소 썰기는 나눠서 할 수 있다. 하지만 “국물을 3시간 끓이기”는 요리사가 몇 명이든 3시간이 걸린다. 프로그램도 마찬가지로, 나눠서 동시에 할 수 있는 부분(병렬 부분)과 반드시 순서대로 해야 하는 부분(순차 부분)이 섞여 있다.
암달의 법칙(Amdahl's law)은 이렇게 말한다. 순차 부분이 전체의 10%라면, 코어를 아무리 늘려도 10배 이상 빨라질 수 없다. 그 10%는 늘 그대로 남기 때문이다.
코어를 늘리면 얼마나 빨라질까
그래서 게임이나 사무용 프로그램처럼 순차 부분이 큰 일은 코어 수보다 코어 하나의 성능(클럭 × IPC)이 중요하고, 영상 편집이나 과학 계산처럼 잘게 나눌 수 있는 일은 코어 수가 중요하다. 극단적으로 잘 나뉘는 일, 예를 들어 화면의 수백만 픽셀을 각각 계산하는 일을 위해 코어를 수천 개 넣은 것이 GPU다(12장).
핵심 정리
- CPU 성능 ≈ 클럭 × IPC(박자당 명령 수) × 코어 수.
- 파이프라인은 명령 실행을 단계로 나눠 겹쳐 처리한다. 한 명령의 시간은 그대로지만 처리량이 늘어난다.
- 앞 명령의 결과가 필요한 의존성이 있으면 파이프라인에 빈칸(stall)이 생긴다. 비순차 실행이 이를 줄인다.
- 조건 점프의 방향을 미리 짐작하는 분기 예측이 틀리면 파이프라인을 비워야 해서 많은 박자를 잃는다. 규칙적인 패턴일수록 잘 맞는다.
- 전력과 발열 때문에 2005년 무렵 클럭 상승이 멈추고 멀티코어 시대가 왔다.
- 암달의 법칙: 순차 부분이 남아 있는 한 코어를 아무리 늘려도 속도 향상에는 한계가 있다.
확인 퀴즈
파이프라인을 쓰면 무엇이 좋아지는가?
분기 예측이 틀렸을 때 CPU가 하는 일은?
2005년 무렵부터 CPU 클럭이 크게 오르지 않은 주된 이유는?
프로그램의 80%만 병렬로 나눌 수 있다. 코어를 무한히 늘리면 최대 몇 배까지 빨라질까?