CUDA 연산 시 그래픽카드의 warp size 만큼 동일한 병렬 연산이 이루어 진다.
(오해의 소지가 있으니 자세히 말하자면, GPU의 코어 숫자 만큼 병렬 연산이 이루어 진다.
내 그래픽 카드인 RTX2070 super의 코어 수는 2560개 이므로, 최대 2560개의 코어를 동시에 사용할 수 있다.
warp_size는 동일 연산이 일어나야 하는 권장 코어 숫자라고 생각하면 쉽다.
2560 / warp_size = 80 이다. 따라서 동시에 80개의 warp들이 병렬 연산이 가능 한데,
80개 중 각각의 warp 에서는 동일 연산이 이루어져야 되는게 좋다는 뜻이다.)
우리가 평소에 잘 사용하는 NVIDIA GTX/RTX nvidia 계열의 그래픽 카드는 warp size가 32다.
만약에 gpu 내부에서 실행되는 함수에서 if else 같은 분기점이 있어서
16개는 더하기 연산이 실행
16개는 빼기 연산이 실행된다면
32개 사이즈가 동시에 실행될 수 있었는데 16개밖에 동시에 실행이 안 되는 것과 마찬가지이므로
성능 손실이 일어난다.
이런 경우를 warp 발산이라고 한다.
(사실 cuda compiler는 이런 경우에 컴파일 시 최적화를 해 주지만, 복잡한 코드 같은 경우에는 최적화가 잘 안 될 수도 있다.)
코드>>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdlib.h>
#include <stdio.h>
__global__ void code_without_warp_divergence()
{
int gid = blockIdx.x * blockDim.x + threadIdx.x;
float a, b;
a = b = 0;
int warp_id = gid / 32;
if (warp_id % 2 == 0)
{
a = 100.0;
b = 50.0;
}
else {
a = 200.0;
b = 75.0;
}
}
__global__ void code_divergence()
{
int gid = blockIdx.x * blockDim.x + threadIdx.x;
float a, b;
a = b = 0;
if (gid % 2 == 0)
{
a = 100.0;
b = 50.0;
}
else {
a = 200.0;
b = 75.0;
}
}
int main()
{
int size = 1 << 22;
dim3 block_size(128);
dim3 grid_size((size + block_size.x - 1) / block_size.x);
code_without_warp_divergence << < grid_size, block_size >> > ();
cudaDeviceSynchronize();
code_divergence << <grid_size, block_size >> > ();
cudaDeviceSynchronize();
cudaDeviceReset();
return 0;
}
|
결과는 다음과 같다.
병렬 연산 시, a,b가 연산되지 않고 놀고 있음을 알 수 있다.
'Cuda' 카테고리의 다른 글
C++ Cuda parallel reduction strategy (0) | 2021.06.01 |
---|---|
C++ Cuda 시스템 정보, GPU 정보 불러오기 (0) | 2021.05.31 |
C++ Cuda CPU와 GPU에서의 연산 속도 비교하기 (0) | 2021.05.30 |
C++ Cuda 메모리 할당에서의 예외 처리 (0) | 2021.05.30 |
C++ Cuda GPU에서의 더하기 연산 (0) | 2021.05.30 |