실제 GPU가 어떻게 동작하는지 이해하기 위해서는 Streaming MultiProcessor (SM)과 Warp에 대한 개념 이해가 필요로 합니다. 각 개념에 대해서 공부한 내용을 정리해보았습니다.
Streaming Multiprocessor (SM)
✔ 정의
Streaming Multiprocessor(SM)은 CUDA thread block이 배치되어 실행되는 GPU 내부의 기본 실행 단위의 하드웨어입니다. 이때 GPU는 여러 개의 SM으로 구성되어 있으며, 각 SM은 독립적으로 block을 실행합니다.

✔ SM의 내부 구성
SM 내부에는 아래와 같은 자원들이 존재
합니다.
- CUDA core (연산 유닛)
- Register
- Shared Memory
- L1 Cache
- Warp scheduler
✔ 동작 흐름
- Grid가 실행됩니다.
- 여러 개의 Block이 생성됩니다.
- Block 단위로 SM에 배치됩니다.
- SM이 해당 Block을 실행합니다.
이때 중요한 점은 Thread가 SM에 직접적으로 배치되는게 아닌 Block 단위로 SM에 배치가 된다는 점입니다.
Warp
✔ 정의
Warp은 32개의 thread로 구성된 GPU의 실제 실행 단위를 의미합니다.
CUDA 코드는 thread 단위로 작성되지만, 실제 GPU는 warp 단위 (32개의 thread를 묶어서)로 실행합니다.
✔ 구조 예시
Block (256 threads)
├─ Warp 0 (thread 0~31)
├─ Warp 1 (32~63)
├─ Warp 2
├─ ...
block size가 256인 경우 32개의 thread를 1개의 warp으로 묶어서 실행하므로, 256 / 32 = 8, 즉 8개의 warp이 생성됩니다.
Warp Scheduler
SM 내부에는 여러 warp 중 실행할 warp을 선택하는 Warp Scheduler라는 하드웨어 유닛이 존재합니다.
GPU는 global memory 접근 시 수백 cycle의 latency가 발생하게 됩니다.
따라서 대규모 병렬 작업 시 병목 현상이 발생하게 되는데 이를 극복하기 위해 Latency Hiding 기법이 사용됩니다.
Latency Hiding은 특정 warp이 memory 접근을 위해 대기 상태에 있다면 다른 warp을 실행하여 latency를 줄이는 방식을 의미합니다.
이때 warp 수가 중요한데,
warp 수가 많을 수록 대기중인 warp 대신 실행할 warp이 많아지기 때문에 SM이 계속 연산을 하게 되고 이를 통해 throughput이 증가하는 효과를 가지게 됩니다.
반대로 warp 수가 적을 수록 memory latency 동안에 SM이 대기상태에 있기 때문에 throughput이 감소하여 연산 속도가 줄어드는 영향을 끼치게 됩니다.
질문 및 정리
✔thread은 왜 32의 배수로 설정하는가?
GPU는 thread를 warp 단위로 스케쥴링합니다.
32의 배수가 아니면 마지막 warp은 partially active 상태가 되기 때문입니다. 예시로 만약 40 thread를 사용한다면 warp0은 32개의 thread를 사용하지만 warp1은 8개의 thread만 active가 되고 24개는 inactive 상태가 되기 때문에 자원 낭비가 발생 할 수 있습니다.
✔SM 자원이 부족하게 되면 어떻게 되는가?
SM의 자원이 부족하다는 의미는 3가지 종류가 있을 수 있습니다.
- register 부족
- shared memory 부족
- 최대 thread 수 초과
만약 SM당 register가 64K일때 Block 하나가 40K register를 사용한다면 SM에는 block이 1개만 배치될 수 있습니다.
이렇게 된다면 warp수가 감소하고 latency hiding이 약화되어 GPU가 대기하는 시간이 많아지게 됩니다. 따라서 throughput이 감소하게 되는 영향을 끼치게 됩니다.
즉, CUDA 성능은 단순하게 thread 수를 많이 쓴다는게 아닌 SM의 자원을 얼마나 효율적으로 사용하는가에 따라 달려있습니다.
✔예시 계산 해보기
만약 나의 GPU 사양이 아래와 같다고 가정하였을때
- SM 8개
- SM당 최대 2048 thread
- SM당 최대 64 warp
kernel<<<32, 256>>>으로 커널을 실행할때
32 block, 각 block 당 256개의 thread, block 당 8개의 warp이 실행됩니다.
이때 SM 하나에는 2048 / 256 = 8 block이 올라갈 수 있습니다.
SM 당 8개 block이 올라가므로 8개의 SM에는 64개의 block을 올릴 수 있지만 32개의 block을 실행하였으므로 SM의 절반만 사용하게 된다는 의미입니다.
