GPU 병렬 연산 원리, SM과 워프가 일하는 방식
가이드 한 명이 깃발을 들고 서른두 명의 단체 관광객을 이끈다고 해 봅시다. 가이드가 다음 행선지를 알리면 모두가 같은 방향으로 움직이고, 한 팀이 식당 앞에서 줄을 서는 동안에는 옆 팀이 먼저 관람을 진행합니다.
GPU(Graphics Processing Unit)도 이런 단체 이동과 비슷하게 일합니다. 이 글에서 다룰 GPU 병렬 연산은 같은 명령을 수십 개의 스레드가 묶음으로 함께 실행하고, 기다리는 묶음은 건너뛰어 바쁜 묶음이 계속 일하게 하는 구조입니다.
관광과 다른 점이 있습니다. 한 묶음의 크기는 하드웨어가 정해 둔 값이고, 한 명이 다른 길로 가려 하면 나머지는 그 사이 기다려야 합니다. 이 글의 용어는 NVIDIA가 문서에서 쓰는 표현(SM, 워프 등)을 기준으로 하며, 다른 회사의 GPU에서는 같은 개념이 다른 이름으로 불립니다.
지연을 줄일까 처리량을 늘릴까, CPU와 다른 설계 철학
CPU 코어는 한 작업을 최대한 빨리 끝내는 데 초점을 맞춥니다. 큰 캐시와 분기 예측, 명령의 순서를 바꿔 실행하는 복잡한 제어 회로가 모두 한 스레드의 지연을 줄이기 위한 장치입니다.
GPU는 반대로 수많은 작업의 전체 처리량을 늘리는 쪽을 택했습니다. 화면의 픽셀이나 행렬의 원소처럼 같은 계산을 서로 다른 데이터에 반복하는 일에서는 한 작업의 속도보다 한꺼번에 몇 개를 끝내느냐가 중요하기 때문입니다. 그래서 GPU 병렬 연산은 데이터가 많고 서로 의존하지 않는 일에서 힘을 냅니다.
이를 위해 GPU는 제어 회로와 캐시에 쓸 면적을 줄이고 단순한 연산 유닛을 대량으로 깔았습니다. 대신 개별 스레드는 느리고 분기에 약하다는 대가를 치릅니다. 이 설계가 지연은 감수하고 처리량을 얻는 선택입니다.
SIMT와 워프, 스레드 묶음이 함께 움직이는 방식
프로그래머는 GPU 프로그램을 스레드 하나의 코드로 씁니다. 같은 코드를 수천수만 개의 스레드가 각자 다른 데이터로 실행하는 모델을 SIMT(Single Instruction, Multiple Threads)라고 부릅니다.
스레드는 스레드 블록(Thread Block) 단위로 묶여 처리 단위 하나에 배정되고, 하드웨어는 블록 안의 스레드를 다시 32개씩 쪼갭니다. 이 32개 묶음이 워프(Warp)이며, 워프 안의 스레드는 같은 명령을 같은 순간에 각자의 데이터에 실행합니다.
이 구조 덕분에 명령 하나를 해석하는 비용을 32개 스레드가 나눠 부담하고, 제어 회로를 줄이면서도 연산 유닛을 꽉 채울 수 있습니다. 프로그래머에게는 스레드마다 독립된 흐름처럼 보이지만 하드웨어는 워프 단위로 명령을 내보냅니다. 벡터 폭을 코드에 직접 드러내야 하는 SIMD와 달리, SIMT는 스레드 단위로 코드를 쓰게 해 주는 점이 다릅니다.
SM 안의 구성, 코어와 레지스터 파일과 공유 메모리
GPU는 SM(Streaming Multiprocessor)이라는 처리 단위를 수십 개에서 수백 개 규모로 복제해 놓은 칩이며, SM의 수와 세부 구성은 세대와 제품마다 달라집니다. SM 하나가 사실상 작은 프로세서이고, 스레드 블록은 한 SM 안에서 끝까지 실행됩니다.
SM 안에는 크게 네 가지가 들어 있습니다. 계산을 수행하는 정수와 부동소수점 유닛, 다음에 실행할 워프를 고르는 워프 스케줄러(Warp Scheduler), 모든 스레드의 변수를 담는 큰 레지스터 파일, 블록 안 스레드가 데이터를 주고받는 공유 메모리(Shared Memory)입니다. 세대에 따라 행렬 곱 전용 유닛이 함께 들어가기도 합니다.
레지스터 파일이 유난히 큰 이유가 중요합니다. 수십 개의 워프가 동시에 SM에 머물려면 각 스레드의 값이 모두 레지스터에 올라가 있어야 하기 때문입니다. 그러면 워프를 바꿔 실행할 때 값을 저장하고 불러오는 비용이 거의 들지 않습니다.
공유 메모리는 SM 안에 있는 빠른 SRAM으로, 어떤 데이터를 올릴지 프로그래머가 직접 정합니다. 같은 블록의 스레드가 한 번 읽어 온 데이터를 함께 재사용하게 해서 느린 외부 메모리 접근을 줄입니다.
워프 하나가 명령을 실행하는 길
- 워프 스케줄러가 실행 준비가 된 워프를 하나 고릅니다.
- 그 워프의 다음 명령이 발행됩니다.
- 워프 속 32개 스레드가 각자의 레지스터에서 피연산자를 읽습니다.
- 연산 유닛이 32개 스레드의 계산을 수행합니다. 유닛 수에 따라 몇 사이클에 나눠 처리하기도 합니다.
- 메모리 명령이면 공유 메모리나 캐시를 먼저 확인하고, 없으면 L2와 외부 메모리까지 요청합니다.
GPU 병렬 연산이 지연을 숨기는 방법
외부 메모리 접근은 수백 사이클이 걸릴 만큼 느립니다. CPU는 큰 캐시와 순서를 바꾼 실행으로 이 시간을 줄이거나 메우지만, GPU는 다른 워프를 실행해서 기다리는 시간을 가립니다.
한 워프가 메모리 응답을 기다리는 동안 스케줄러는 준비된 다른 워프로 즉시 바꿉니다. 레지스터에 모든 값이 올라가 있어 전환 비용이 거의 없으므로, 기다림이 쌓이는 대신 연산 유닛이 계속 일합니다. 이를 지연 숨기기(Latency Hiding)라고 합니다.
가상 계산 예시, 필요한 워프 수실제 제품 값이 아니라 설명을 위한 가정입니다. 메모리 지연을 400사이클로 두고, 워프가 메모리 요청 한 번 사이에 20사이클 분량의 연산 명령을 실행하며, 스케줄러는 사이클마다 명령 하나를 발행한다고 둡니다.
한 워프는 20사이클 일하고 400사이클을 기다리므로 한 주기가 420사이클입니다. 스케줄러가 쉬지 않으려면 420 ÷ 20 = 21개의 워프가 번갈아 실행되어야 합니다.
문제는 한 SM이 동시에 올려 둘 수 있는 워프 수가 레지스터 파일과 공유 메모리의 용량에 묶여 있다는 점입니다. 스레드당 레지스터를 많이 쓰면 올릴 수 있는 워프가 줄어 지연을 숨기기 어려워지고, 올라와 있는 워프의 비율을 점유율(Occupancy)이라고 부릅니다.
분기 발산과 메모리 병합, 워프 효율이 깎이는 곳
GPU 병렬 연산의 효율은 워프 안의 32개 스레드가 얼마나 같은 일을 하느냐에 달려 있습니다. 이 가정이 깨지는 대표적인 경우가 분기이고, 두 번째가 메모리 접근 패턴입니다.
워프 안에서 if와 else로 갈라지는 스레드가 있는 상황을 분기 발산(Branch Divergence)이라고 합니다. 하드웨어는 한 경로를 실행하는 동안 다른 경로의 스레드를 마스크로 꺼 두고, 끝나면 반대로 실행하는 식으로 두 경로를 차례로 처리합니다.
가상 예시, 분기 발산의 비용32개 스레드 중 16개는 경로 A, 16개는 경로 B를 타고, 각 경로가 명령 10개라고 둡니다.
두 경로를 차례로 실행하므로 10 + 10 = 20사이클이 걸려, 분기가 없을 때의 10사이클보다 두 배가 됩니다. 각 경로를 실행하는 동안 32개 중 16개만 일하니 연산 유닛 활용률은 절반입니다.
메모리 쪽에서는 메모리 병합(Memory Coalescing)이 중요합니다. 워프의 32개 스레드가 연속된 주소를 읽으면 하드웨어가 이 요청을 소수의 큰 접근으로 합쳐 줍니다. 4바이트 값을 스레드마다 하나씩 읽는다면 32 × 4 = 128바이트의 연속 구간이 한꺼번에 처리되는 셈입니다.
반대로 스레드들이 흩어진 주소를 읽으면 여러 번의 접근으로 쪼개져 대역폭이 낭비됩니다. 공유 메모리에서도 여러 스레드가 같은 뱅크에 동시에 접근하면 차례를 기다리는 충돌이 생깁니다.
흔한 오해는 GPU는 코어 수가 훨씬 많으니 어떤 연산에서나 CPU보다 빠르다는 생각입니다. 분기가 많거나 앞 결과에 계속 의존하는 일, 데이터가 작아 병렬로 나눌 거리가 없는 일에서는 GPU의 이점이 거의 나타나지 않습니다.
SM 구성 요소별 역할 비교 표
| 구분 | 워프 스케줄러 | 연산 유닛 | 레지스터 파일 | 공유 메모리와 L1 |
|---|---|---|---|---|
| 하는 일 | 실행 가능한 워프를 골라 명령 발행 | 정수와 부동소수점 계산 수행 | 스레드의 변수 저장 | 블록 안의 데이터 공유와 재사용 |
| 부족할 때 생기는 문제 | 준비된 워프가 없으면 연산 유닛이 놂 | 계산 자체가 병목이 됨 | 올릴 수 있는 워프가 줄어 지연을 못 숨김 | 외부 메모리 접근이 늘어남 |
| 설계 포인트 | 많은 워프 중 빠르게 선택 | 단순하고 작게 만들어 수를 늘림 | 큰 용량으로 전환 비용을 없앰 | 빠른 SRAM, 프로그래머가 직접 관리 |
| 놓치기 쉬운 점 | 코어 수만 보고 성능을 단정하는 오해, 병목이 레지스터인지 메모리인지 분기인지에 따라 결과가 달라집니다. | |||
핵심 정리
GPU는 지연을 줄이는 대신 처리량을 늘리는 설계이고, 32개 스레드의 워프가 같은 명령을 함께 실행하는 SIMT 구조 위에서 SM이 많은 워프를 상주시킵니다. 한 워프가 메모리를 기다리는 동안 다른 워프를 실행하는 방식으로 지연을 가리며, 가상 예시에서는 21개의 워프가 필요했습니다. GPU 병렬 연산의 성능은 코어 수보다 분기와 메모리 접근 패턴, 그리고 워프를 얼마나 꽉 채울 수 있는지에 좌우됩니다.
단체 관광에서 가이드의 깃발 하나로 많은 인원을 움직일 수 있는 것은 모두가 같은 일정을 따를 때입니다. 일정이 갈리거나 식당 대기가 길어져도 다른 팀이 이어서 움직이도록 짜 두는 것이, 이 칩이 큰 처리량을 내는 방식입니다.
면접 대비 질문
면접 대비 질문GPU가 메모리 접근 지연을 숨기는 방식을 워프와 SM의 구조로 설명하고, 이 방식의 한계를 말해 보세요.
[답변 포인트] CPU는 캐시와 비순차 실행으로 지연을 줄이지만 GPU는 많은 워프를 SM에 상주시켜 한 워프가 기다리는 동안 다른 워프를 실행한다는 점에서 시작합니다. 레지스터 파일이 커서 워프 전환 비용이 거의 없다는 점과, 필요한 워프 수가 지연 대비 연산량의 비율로 정해진다는 점을 가상 수치로 연결합니다. 한계로는 레지스터와 공유 메모리 용량이 점유율을 제한한다는 점, 분기 발산과 비병합 메모리 접근이 워프 효율을 떨어뜨린다는 점, 병렬로 나눌 거리가 적은 작업에는 이득이 작다는 점까지 덧붙이면 좋습니다.









