CUDA 그리드 치수, 블록 치수 및 스레드 구성 이해 (간단한 설명) [닫기]


161

GPU는 스레드를 어떻게 실행하도록 구성되어 있습니까?


CUDA 프로그래밍 가이드는이를 시작하기에 좋은 장소 여야합니다. 또한 여기 에서 CUDA 소개를 확인하는 것이 좋습니다 .
Tom

답변:


287

하드웨어

GPU 장치에 예를 들어 4 개의 멀티 프로세싱 장치가 있고 각각 768 개의 스레드를 실행할 수있는 경우 주어진 순간에 4 * 768 개의 스레드 만 실제로 병렬로 실행됩니다 (더 많은 스레드를 계획하는 경우 대기 중) 그들의 차례).

소프트웨어

스레드는 블록으로 구성됩니다. 블록은 다중 처리 장치에 의해 실행됩니다. 1Dimension (x), 2Dimensions (x, y) 또는 3Dim 인덱스 (x, y, z)를 사용하여 블록의 스레드를 식별 (인덱싱) 할 수 있지만 어떤 경우에도 xy z <= 768 (다른 제한 사항이 적용됨) x, y, z에 대해서는 가이드 및 장치 기능을 참조하십시오).

분명히 4 * 768 이상의 스레드가 필요한 경우 4 개 이상의 블록이 필요합니다. 블록은 1D, 2D 또는 3D로 색인 될 수도 있습니다. GPU에 들어가기 위해 대기중인 블록이 있습니다 (이 예에서는 GPU에 4 개의 멀티 프로세서가 있고 동시에 4 개의 블록 만 실행되기 때문에).

이제 간단한 사례 : 512x512 이미지 처리

하나의 스레드가 하나의 픽셀 (i, j)을 처리하기를 원한다고 가정하십시오.

각각 64 개의 스레드 블록을 사용할 수 있습니다. 그런 다음 512 * 512 / 64 = 4096 블록이 필요합니다 (따라서 512 x 512 스레드 = 4096 * 64)

blockDim = 8 x 8 (블록 당 64 스레드)을 갖는 2D 블록의 스레드를 구성 (이미지 색인화를 쉽게하기 위해)하는 것이 일반적입니다. 나는 그것을 ThreadPerBlock이라고 부른다.

dim3 threadsPerBlock(8, 8);  // 64 threads

및 2D gridDim = 64 x 64 블록 (필요한 4096 블록). numBlocks라고 부르는 것을 선호합니다.

dim3 numBlocks(imageWidth/threadsPerBlock.x,  /* for instance 512/8 = 64*/
              imageHeight/threadsPerBlock.y); 

커널은 다음과 같이 시작됩니다 :

myKernel <<<numBlocks,threadsPerBlock>>>( /* params for the kernel function */ );       

마지막으로, "4096 블록 대기열"과 같은 블록이 있으며 64 개의 스레드가 실행되도록 GPU의 멀티 프로세서 중 하나에 블록이 할당되기를 기다리고 있습니다.

커널에서 스레드에 의해 처리 될 픽셀 (i, j)은 다음과 같이 계산됩니다.

uint i = (blockIdx.x * blockDim.x) + threadIdx.x;
uint j = (blockIdx.y * blockDim.y) + threadIdx.y;

11
각 블록이 768 개의 스레드를 실행할 수 있다면 왜 64 개만 사용합니까? 최대 한계 인 768을 사용하면 블록 수가 줄어들고 성능이 향상됩니다.
알리자

10
@Aliza : 블록은 논리적 이며 768 스레드의 제한은 각 물리적 처리 장치에 대한 것입니다. 작업을 스레드에 분배하기 위해 문제점의 스펙에 따라 블록을 사용합니다. 모든 문제에 대해 항상 768 개의 스레드 블록을 사용할 수있는 것은 아닙니다. 64x64 이미지 (4096 픽셀)를 처리해야한다고 상상해보십시오. 4096/768 = 5.333333 블록?
cibercitizen1

1
블록은 논리적이지만 각 블록은 코어에 할당됩니다. 코어보다 많은 블록이 있으면 코어가 사용 가능해질 때까지 블록이 대기합니다. 귀하의 예에서 6 블록을 사용하고 여분의 스레드가 아무것도하지 않도록 할 수 있습니다 (6 블록의 스레드의 2/3).
Aliza

3
@ cibercitizen1-Aliza의 요점은 좋은 것이라고 생각합니다. 가능하면 가능한 한 블록 당 많은 스레드를 사용하고 싶습니다. 적은 수의 스레드가 필요한 제약 조건이있는 경우 두 번째 예에서 왜 그런지 설명하는 것이 좋습니다 (그러나 먼저 더 단순하고 바람직한 경우를 먼저 설명).

6
@thouis 그렇습니다. 그러나 각 스레드에 필요한 메모리 양은 응용 프로그램에 따라 다릅니다. 예를 들어, 마지막 프로그램에서 각 스레드는 최소 제곱 최적화 기능을 호출하며 "많은"메모리가 필요합니다. 그 블록은 4x4 스레드보다 클 수 없습니다. 그럼에도 불구하고 얻은 속도 향상은 순차 버전에 비해 극적이었습니다.
cibercitizen1

9

9800GT GPU를 가정 해보십시오.

  • 14 개의 멀티 프로세서 (SM)가 있습니다
  • 각 SM에는 8 개의 스레드 프로세서 (AKA 스트림 프로세서, SP 또는 코어)가 있습니다
  • 블록 당 최대 512 개의 스레드 허용
  • warpsize는 32입니다. 즉, 각 14x8 = 112 스레드 프로세서는 최대 32 개의 스레드를 예약 할 수 있습니다.

https://www.tutorialspoint.com/cuda/cuda_threads.htm

블록은 512보다 많은 활성 스레드를 가질 수 없으므로 __syncthreads제한된 수의 스레드 만 동기화 할 수 있습니다. 즉, 600 개의 스레드로 다음을 실행하는 경우 :

func1();
__syncthreads();
func2();
__syncthreads();

커널은 두 번 실행해야하며 실행 순서는 다음과 같습니다.

  1. func1은 처음 512 개의 스레드에 대해 실행됩니다.
  2. func2는 처음 512 개의 스레드에 대해 실행됩니다.
  3. 나머지 스레드에 대해 func1이 실행됩니다.
  4. 나머지 스레드에 대해 func2가 실행됩니다.

노트 :

요점은 __syncthreads블록 전체 작업이며 모든 스레드를 동기화하지는 않습니다.


__syncthreads512 개가 넘는 스레드로 블록을 만들고 워프가 일정을 처리하도록 할 수 있기 때문에 동기화 할 수 있는 정확한 스레드 수에 대해 잘 모르겠습니다 . 이해하기에는 더 정확합니다 : func1은 적어도 처음 512 스레드에 대해 실행 됩니다 .

이 답변을 편집하기 전에 (2010 년) 14x8x32 스레드가을 사용하여 동기화되었음을 측정했습니다 __syncthreads.

누군가가 더 정확한 정보를 위해 이것을 다시 테스트한다면 대단히 감사하겠습니다.


func2 ()가 func1 ()의 결과에 의존하면 어떻게됩니까? 나는 이것이 틀렸다고 생각한다
Chris

@Chris 나는 7 년 전에이 글을 썼지 만, 올바르게 기억한다면 나는 이것에 대한 테스트를했고 gpu보다 더 많은 스레드를 가진 커널이 이런 식으로 행동한다는 결론을 얻었다. 이 사례를 테스트하고 다른 결과에 도달하면이 게시물을 삭제해야합니다.
Bizhan

죄송합니다. GPU가 동시에 112 개의 스레드 만 실행할 수 있다는 것은 잘못된 생각입니다.
Steven Lu

@StevenLu 사용해 보셨습니까? 또한 112 개의 동시 스레드가 GPU에 의미가 있다고 생각하지 않습니다. 112는 스트림 프로세서의 수입니다. 나는 CUDA를 지금 거의 기억할 수 없다 :)
Bizhan

1
@StevenLu 최대 스레드 수는 여기서 문제가 아니며 __syncthreads블록 전체 작업이며 실제로 모든 스레드를 동기화하지 않는다는 사실은 CUDA 학습자에게 성가신 것입니다. 그래서 나는 당신이 나에게 준 정보에 따라 대답을 업데이트했습니다. 정말 감사.
비잔
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.