LabHub

컴퓨터 구조 · GPU 와 병렬처리 · 이론

GPU — 지연을 줄이는 대신 처리량을 넓힌 설계

LabHub 에서 이어서 보기

한 줄 요약

CPU 는 한 스레드를 최대한 빨리 끝내도록 만들어졌고, GPU 는 수만 스레드를 동시에 굴려 메모리 대기 시간을 서로 가려 주도록 만들어졌다.

왜 이게 필요했나

CPU 는 한 흐름의 지연을 줄이는 데 트랜지스터를 쓴다. 분기 예측기, 비순차 실행 엔진, 커다란 캐시가 전부 "지금 이 스레드가 멈추지 않게" 하는 장치다. 문제는 이 방식의 수익이 체감한다는 것이다. 예측기를 두 배로 키워도 성능은 몇 퍼센트 오른다.

같은 트랜지스터를 다르게 쓰는 방법이 있다. 제어 회로를 극단적으로 단순화하고 산술 유닛을 잔뜩 채운 뒤, 스레드를 아주 많이 올려 둔다. 한 스레드가 메모리를 기다리는 동안 다른 스레드를 실행하면 대기 시간이 가려진다. 이것이 GPU 의 설계 철학이며, 그래서 GPU 는 지연을 줄이는 장치가 아니라 지연을 감추는 장치다.

어떻게 동작하나

GPU 는 여러 개의 스트리밍 멀티프로세서(SM) 로 이루어진다. 각 SM 안에서 스레드는 32개씩 묶여 워프(warp) 단위로 스케줄링되며, 한 워프 안의 스레드들은 같은 명령어를 각자의 데이터에 대해 실행한다(SIMT).

여기서 두 가지 성능 함정이 나온다.

분기 발산(divergence). 워프 안에서 절반은 if 로, 절반은 else 로 가면 하드웨어는 양쪽 경로를 순차로 실행하면서 해당하지 않는 스레드를 잠시 꺼 둔다. 결과는 맞지만 시간은 두 경로의 합이 된다. 조건이 데이터에 따라 제각각인 커널이 느린 이유다.

병합 접근(coalescing). 한 워프의 32개 스레드가 연속된 주소를 읽으면 메모리 트랜잭션 몇 개로 끝난다. 흩어진 주소를 읽으면 최악의 경우 32개의 트랜잭션이 필요하다. 같은 계산인데 인덱싱만 바꿔도 배수로 갈리는 이유가 여기 있다.

메모리 계층도 CPU 와 다르다. SM 안에는 프로그래머가 명시적으로 관리하는 공유 메모리가 있다. 캐시가 알아서 해 주기를 기다리는 대신, 재사용할 데이터를 직접 올려 두고 여러 스레드가 나눠 쓴다. 행렬 곱셈 커널의 성능 대부분이 이 공유 메모리 타일링에서 나온다.

점유율(occupancy) 은 SM 이 동시에 유지할 수 있는 워프 수 대비 실제로 올라간 워프 수다. 점유율이 낮으면 가릴 스레드가 부족해 메모리 대기가 그대로 드러난다. 다만 점유율이 높다고 늘 빠른 것은 아니다. 레지스터를 많이 쓰는 커널은 점유율을 낮추더라도 스레드당 작업량을 늘리는 편이 나을 때가 있다.

현장에서 만나는 모습

AI 추론에서 GPU 사용률이 30퍼센트를 못 넘는다는 이야기가 흔하다. 원인은 대개 연산 부족이 아니라 메모리 대역폭이다. LLM 디코딩은 거대한 가중치를 읽어와 작은 입력과 곱하고 버리므로 산술 강도가 낮고, 그래서 roofline 의 왼쪽 비탈에 놓인다. 이 구간에서는 연산 성능이 더 높은 칩을 사도 성능이 오르지 않는다. 답은 읽을 바이트를 줄이거나(양자화) 배치를 키워 같은 가중치 읽기를 여러 요청이 나눠 쓰게 만드는 것이다.

TPU 같은 가속기가 다른 답을 낸 지점도 여기다. 시스톨릭 어레이는 데이터를 격자 사이로 흘리며 재사용해서 메모리 접근당 연산 수를 극대화한다. 범용성을 포기하고 산술 강도를 사 온 설계다.

이어지는 퀴즈에서 확인할 것

"GPU 가 CPU 보다 빠르다"는 말이 왜 절반만 맞는지, 그리고 GPU 를 사고도 성능이 안 나오는 전형적인 이유를 설명할 수 있는지 확인한다.