[GPGPU Series 6] Thread Block to Warps

지난번 글에 Thread Block (TB) Scheduler가 TB를 Streaming Multiprocessor (SM)에 Scheduling하는 방법에 대해 설명했다. 간단히 다시 설명하면 TB는 Round-Robin방식으로 SM에 Scheduling 되고 총 Scheduling 가능한 TB의 개수는 크게 3가지 이유로 제한 된다.

이번글에서는 SM에 Scheduling된 TB를 Warp단위로 나누는 과정에 대해서 설명한다. Warp라는 개념은 GPU를 이해하는데 가장 중요한 부분이라고 생각한다. 앞 글에서 설명한 것과 같이 TB는 보통 1개 이상의 Thread로 구성되어 있으며 최대 1,024개 까지 구성할 수 있다 (Architecture 마다 차이가 있어서 최대 Thread 개수는 변경될 수도 있다). Warp는 하나의 TB의 Thread를 32개 단위로 나뉘어서 Instruction 한개를 실행하기 위한 최소 단위이다. Nvidia의 경우 Warp라는 용어를 사용하고 32개 단위로 Thread를 구성한다. AMD의 경우 Wavefront라는 용어를 사용하고 각 Wavefront는 총 64개의 Thread로 구성되어 있다. Mobile ARM의 경우 4개 또는 8개의 Thread를 하나의 단위로 구성하며 NVIDIA와 동일하게 Warp라는 단어를 사용한다 (출처 1).

그림 1: 1 Thread Block (256개 Thread)를 8개 Warp로 변경하는 방법

Warp를 생성하는 방법은 아주 단순하다. TB의 Thread를 순서대로 32개씩 나누면 Warp가 생성된다. 예를 들어 총 256개 Thread로 구성된 TB의 경우 0번 Thread부터 31번 Thread까지 0번 Warp가 되고, 32번 Thread부터 63번 Thread까지 1번 Warp가 된다. 256개의 Thread로 구성된 TB의 경우 총 8개의 Warp를 생성하게 된다. 그림 1은 256개의 Thread로 구성된 TB를 8개의 Warp로 변경하는 과정을 보여준다.

만약 TB가 32개 단위로 정확히 나뉘어지지 않는 경우가 발생한다고 가정하자. 예를 들어 유저가 각 TB를 250 Thread를 사용하여 생성하였다거나, Kernel의 마지막 TB의 경우 256개 보다 적은 수의 Thread를 가지는 경우가 발생한다. 이러한 경우 TB에서 생성되는 마지막 Warp의 경우 32개 보다 적은 Thread를 가질 수 있다. 예를 들어 TB가 250개의 Thread를 가지고 있다고 가정하면, Warp 0번 부터 Warp 6번 (총 7개)까지는 32개의 Thread를 가진다. 반면 제일 마지막 Warp의 경우 26개의 Thread만을 가지게 된다. 사실 예제를 위해서 250개라는 단위로 설명을 하였는데 가능하다면 처음 코딩을 하는 과정에서 32개 단위로 TB를 생성하는 것이 효율적이다. AMD를 사용하는 경우 TB을 생성하는 과정에서 64개 Thread 단위를 고려하는 것이 좋다.

마지막으로 정리하는 차원에서 각 SM에 총 8개의 TB가 Schduling 되었으며, 각 TB는 250개의 Thread로 구성되어 있다고 가정을 해보자. 그럼 각 SM은 총 64개의 Warp를 생성하게 되며, 8개의 Warp (Warp 7, Warp 15, Warp 23, Warp 31, Warp 39, Warp 47, Warp 55, Warp 63)는 총 26개의 Thread만 가지게 된다. 그외 나머지 Warp는 모두 32개의 Thread로 구성되어 있다.

지난 한달간 몸이 너무 안좋아서 글 작성이 너무 늦어졌다. 다음 장에서는 Warp가 실행되는 순서에 대해서 설명을 정리할 예정이다.

출처

  1. https://developer.arm.com/graphics/developer-guides/the-bifrost-shader-core

Leave a Comment