이성열

계산은 빠른데 떠올리는 건 느린 컴퓨터

지난 글에서 Fetch-Decode-Execute 사이클을 통해 CPU가 명령어를 처리하는 과정을 살펴보았다. 그런데 한 가지 문제가 있었다. 오늘날 CPU는 1초에 수십억 개의 명령어를 처리할 수 있지만, 메모리에서 데이터를 가져오는 속도는 이에 비해 수백 배 느리다. CPU가 아무리 빨라도 메모리를 기다리는 시간이 병목이 된다.

이 속도 차이를 어떻게 해결할 수 있을까?

책상, 서랍, 창고

일상에서 비슷한 문제를 이미 해결하고 있다. 지금 공부하고 있다고 생각해 보자. 자주 보는 교과서는 책상 위에 펼쳐 두고, 가끔 참고하는 자료집은 서랍에 넣어 두고, 이번 학기에 안 쓰는 책은 창고에 보관한다.

왜 이렇게 할까? 모든 책을 창고에 두면 꺼내러 갈 때마다 시간이 낭비된다. 반대로 모든 책을 책상 위에 올려놓을 수는 없다. 책상은 공간이 좁기 때문이다. 그래서 자주 쓰는 것일수록 가까이 두는 전략을 자연스럽게 사용한다.

컴퓨터에서도 같은 전략을 쓸 수 있지 않을까? 그런데 “자주 쓰는 데이터”가 정말 있긴 한 걸까?

지역성

프로그램이 데이터에 접근하는 패턴을 관찰하면 흥미로운 규칙을 발견할 수 있다.

시간적 지역성(temporal locality): 한번 접근한 데이터는 곧 다시 접근할 가능성이 높다. 반복문에서 카운터 변수 i를 매번 읽고 쓰는 것이 대표적이다.

공간적 지역성(spatial locality): 접근한 데이터 근처의 데이터도 곧 접근할 가능성이 높다. 배열을 처음부터 끝까지 순서대로 훑는 경우가 이에 해당한다.

프로그램은 전체 메모리를 골고루 쓰지 않는다. 특정 영역에 집중적으로 접근하는 경향이 있다. 그렇다면 자주 쓰는 데이터를 CPU 가까이에 두는 작고 빠른 저장소를 만들면 어떨까?

캐시

그 저장소가 바로 캐시(cache) 다. 캐시는 CPU와 RAM 사이에 위치한 소용량 고속 메모리다. CPU가 데이터를 요청하면 먼저 캐시를 확인한다.

  • 캐시 히트(cache hit): 캐시에 데이터가 있으면 바로 가져온다. 빠르다.
  • 캐시 미스(cache miss): 캐시에 없으면 RAM에서 가져온 뒤 캐시에 복사해 둔다. 느리다.
메모리
캐시
비어있음
비어있음
비어있음
비어있음
접근 0회 · 히트 0적중률 0%

다음 순서대로 조작해보자:

  1. 메모리 주소를 하나 클릭한다. 처음에는 캐시가 비어 있으니 미스가 발생한다.
  2. 같은 주소를 다시 클릭한다. 이번에는 캐시에 있으므로 히트가 발생한다.
  3. 서로 다른 주소를 5개 이상 클릭한다. 캐시가 4칸뿐이라 가장 오래전에 접근한 데이터가 밀려난다.

캐시가 가득 차면 가장 오래전에 사용된 데이터를 내보내고 새 데이터를 넣는다. 전체 접근 중 히트의 비율을 적중률(hit rate) 이라 한다. 적중률이 높을수록 CPU가 RAM을 기다리는 시간이 줄어든다.

그렇다면 지역성이 있는 패턴과 없는 패턴은 적중률이 얼마나 다를까?

지역성과 적중률

  1. “순차 접근” 버튼을 누른다. 0-3을 두 번 반복하고 4-7을 두 번 반복하는 패턴이다. 두 번째 반복부터 히트가 발생하며 적중률이 높다.
  2. “랜덤 접근” 버튼을 누른다. 같은 횟수지만 무작위 주소에 접근한다. 적중률이 크게 떨어진다.

캐시가 효과적인 이유는 지역성 덕분이다. 프로그램이 데이터에 접근하는 패턴에 지역성이 있기 때문에, 작은 캐시만으로도 높은 적중률을 달성할 수 있다. 랜덤 접근처럼 지역성이 없으면 캐시의 효과는 사라진다.

그런데 캐시를 하나만 둘 필요는 없다.

메모리 계층 구조

실제 컴퓨터에서는 레지스터부터 RAM까지 여러 단계의 저장소를 둔다. 이를 메모리 계층 구조(memory hierarchy) 라 한다.

계층용량속도
레지스터수십 개1 사이클
L1 캐시수십 KB~4 사이클
L2 캐시수백 KB~10 사이클
L3 캐시수십 MB~40 사이클
RAM수 GB ~ 수십 GB~200 사이클

위로 갈수록 빠르고 작으며, 아래로 갈수록 느리고 크다. 각 계층이 바로 아래 계층의 캐시 역할을 한다. L1이 미스면 L2를, L2도 미스면 L3를, L3도 미스면 RAM을 확인한다.

RAM 아래에는 SSD나 HDD 같은 보조기억장치가 있다. 여기까지 내려가면 접근 시간이 수만~수십만 사이클로 늘어난다.

마무리

이 시리즈의 첫 글에서 0과 1로 시작해, 논리 게이트를 배우고, 가산기로 계산을 하고, 래치로 기억을 하고, 튜링 머신폰 노이만 구조로 컴퓨터의 설계 원리를 세우고, CPU로 명령어를 실행하고, 캐시와 메모리 계층 구조로 속도 문제까지 해결했다. 0과 1에서 출발해 동작하는 컴퓨터 한 대를 조립한 셈이다.

컴퓨터의 구조를 알았으니, 이제 데이터를 효율적으로 다루는 방법이 필요하다. 같은 문제라도 데이터를 어떻게 정리하고 어떤 순서로 처리하느냐에 따라 성능이 달라진다. 다음 파트에서는 자료구조와 알고리즘을 다룬다.