1. CUDA Programming
순차 코드는 host에서, 병렬 코드는 device에서
Open MP의 Fork-Join Model과 유사
2. CUDA Thread Hierarchy
커널 함수가 호스트에서 호출될 때, 많은 수의 스레드가 생성됨
스레드 계층 구조: 스레드 블록 + 그리드
그리드와 스레드 블록 크기를 구하는 built-in 변수
그리드와 스레드 블록은 dim3 타입의 3차원으로 구성
스레드는 서로 구분 위해 고유한 좌표를 필요로 함
Thread 인덱싱
2. CUDA Thread Hierarchy
스레드 블록 크기, 데이터 크기로 grid 크기 결정
데이터의 크기: N, 스레드 블록의 크기: x
3. Global Index 계산
스레드 인덱스, 블록 인덱스로 글로벌 인덱스 결정
int idx = blockdim.x*blockIdx.x + threadIdx.x
ex. if blockIdx = 2, threadIdx = 3
한 블록에 스레드 8개 -> blockdim = 8
idx = 8 * 2 + 3 = 19
4. 2D Grid & 2D Blocks
x축 y축 각각 독립적으로 global index 구하기
__device__ int gelGlobalIdx_2D(const int N)
{
int col = blockdim.x*blockIdx.x + threadIdx.x
int row = blockdim.y*blockIdx.y + threadIdx.y
int index = row*N + col
return index;
}
a[row][column] = a[offset]
offset = column + row*N
(N은 column의 개수)
Example
segmentation fault
방지를 위해 if (idx_x < N && idx_y < M)
조건문이 들어감1. Kernel 코드 작성
디바이스(GPU)에서 실행되는 코드
__global__ voidkernel_name(argument list);
2. Kerenl 함수 한정자
__global__: 호출은 host, 실행은 device에서 하는 함수
__device__: 커널 속에서 실행하는 커널함수
__host__: CUDA와 관련 없는 일반 C 함수
__device__와 __host__는 함께 사용 가능
3. Kernel 호출: C 함수 호출의 확장 형태
커널 호출 시 그리드와 스레드 블록의 크기를 <<<>>>
안에 지정
function.name<<<grid, block>>>(argument list);
ex. 4 * 8 = 32개의 스레드 사용
kernel_name<<<4,8>>>(argument list);
4. Kernel 호출: 비동기적 호출
커널 호출은 호스트 스레드에 대해 비동기적
동기화 함수: cudaDeviceSynchronize()
__host__ __device__ cudaError_tcudaDeviceSynchronize(void);
cudaDeviceSynchronize()
함수를 호출cudaMemcpy()
사용 시, 호스트 쪽에서 묵시적 동기화 -> 데이터 복사 완료까지 application 대기초기화 함수: cudaDeviceRest()
__host__ cudaError_tcudaDeviceReset(void);
5. Multi Stream (Scheduling)
1. 커널 함수 호출 예제
C code
#include <stdio.h>
__global__ void GPUKernel(int arg)
{
printf("Input Value (on GPU)= %d\n", arg);
}
int main(void)
{
printf("Call Kernel Function! \n");
GPUKernel<<<1,1>>>(1);
GPUKernel<<<1,1>>>(2);
cudaDeviceSynchronize();
return 0;
}
Compile
$ nvcc [-arch=sm_70] kernel_test.cu -o kernel_test
[-arch=sm_70]
은 GPU architecture를 지정Result
cudaDeviceSynchronize()
가 없다면, GPUKernel()
은 실행되지 못하고 application이 종료됨cudaDeviceRest()
을 사용해도 됨2. global, device 모두 사용하는 예제
C code
#include <stdio.h>
__global__ void helloFromHost();
__device__ int helloFromDevice(int tid);
int main()
{
helloFromHost<<<1,5>>>();
cudaDeviceReset();
return 0;
}
__global__ void helloFromHost()
{
int tid = threadIdx.x;
printf("Hello world From __global__ kernel: %d\n", tid);
int tid1=helloFromDevice(tid);
printf("tid1 : %d\n", tid1);
}
__device__ int helloFromDevice(int tid)
{
printf("Hello world From __device__ kernel: %d\n", tid);
return tid+1;
}
Result