반응형
CUDA란?
CUDA(Compute Unified Device Architecture)는 NVIDIA에서 개발한 병렬 컴퓨팅 플랫폼 및 프로그래밍 모델로, 개발자가 GPU(Graphics Processing Unit)를 활용하여 병렬 프로그램을 작성할 수 있게 해줍니다. CUDA는 C, C++, Fortran과 같은 언어를 확장하여 GPU에서 실행되는 코드를 작성할 수 있습니다.
CUDA의 기본 개념
- 호스트(Host): CPU와 메인 메모리를 의미합니다.
- 디바이스(Device): GPU와 GPU 메모리를 의미합니다.
- 커널(Kernel): GPU에서 실행되는 함수입니다.
- 스레드(Thread): GPU에서 실행되는 가장 작은 실행 단위입니다.
- 블록(Block): 여러 스레드로 구성된 그룹입니다.
- 그리드(Grid): 여러 블록으로 구성된 그룹입니다.
CUDA 설치
CUDA를 사용하려면 NVIDIA GPU와 CUDA 툴킷을 설치해야 합니다. 설치 방법은 운영체제에 따라 다르므로 NVIDIA의 공식 문서를 참고하세요.
CUDA 코드 구조
CUDA 프로그램은 호스트 코드와 디바이스 코드로 구성됩니다. 호스트 코드는 CPU에서 실행되고, 디바이스 코드는 GPU에서 실행됩니다.
기본 예제: 벡터 덧셈
벡터 덧셈을 CUDA를 사용하여 병렬로 수행하는 예제입니다.
1. 벡터 덧셈 커널
__global__ void vectorAdd(const int* A, const int* B, int* C, int N) {
int i = blockDim.x * blockIdx.x + threadIdx.x;
if (i < N) {
C[i] = A[i] + B[i];
}
}
2. 호스트 코드
#include <iostream>
#include <cuda_runtime.h>
__global__ void vectorAdd(const int* A, const int* B, int* C, int N);
int main() {
const int N = 1000;
size_t size = N * sizeof(int);
// 호스트 메모리 할당
int* h_A = (int*)malloc(size);
int* h_B = (int*)malloc(size);
int* h_C = (int*)malloc(size);
// 호스트 메모리 초기화
for (int i = 0; i < N; ++i) {
h_A[i] = i;
h_B[i] = i;
}
// 디바이스 메모리 할당
int* d_A;
int* d_B;
int* d_C;
cudaMalloc((void**)&d_A, size);
cudaMalloc((void**)&d_B, size);
cudaMalloc((void**)&d_C, size);
// 호스트 메모리에서 디바이스 메모리로 데이터 복사
cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice);
cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice);
// 커널 실행
int threadsPerBlock = 256;
int blocksPerGrid = (N + threadsPerBlock - 1) / threadsPerBlock;
vectorAdd<<<blocksPerGrid, threadsPerBlock>>>(d_A, d_B, d_C, N);
// 디바이스 메모리에서 호스트 메모리로 결과 복사
cudaMemcpy(h_C, d_C, size, cudaMemcpyDeviceToHost);
// 결과 출력
for (int i = 0; i < N; ++i) {
if (i < 10) {
std::cout << h_C[i] << " ";
}
}
std::cout << std::endl;
// 메모리 해제
cudaFree(d_A);
cudaFree(d_B);
cudaFree(d_C);
free(h_A);
free(h_B);
free(h_C);
return 0;
}
실습 문제
문제 1: CUDA를 사용하여 행렬의 곱 계산하기
다음 코드에서 CUDA를 사용하여 두 행렬의 곱을 병렬로 계산하세요.
main.cu
#include <iostream>
#include <cuda_runtime.h>
__global__ void matrixMul(const int* A, const int* B, int* C, int N) {
int row = blockIdx.y * blockDim.y + threadIdx.y;
int col = blockIdx.x * blockDim.x + threadIdx.x;
if (row < N && col < N) {
int sum = 0;
for (int k = 0; k < N; ++k) {
sum += A[row * N + k] * B[k * N + col];
}
C[row * N + col] = sum;
}
}
int main() {
const int N = 3;
size_t size = N * N * sizeof(int);
// 호스트 메모리 할당
int* h_A = (int*)malloc(size);
int* h_B = (int*)malloc(size);
int* h_C = (int*)malloc(size);
// 호스트 메모리 초기화
for (int i = 0; i < N * N; ++i) {
h_A[i] = 1;
h_B[i] = 2;
}
// 디바이스 메모리 할당
int* d_A;
int* d_B;
int* d_C;
cudaMalloc((void**)&d_A, size);
cudaMalloc((void**)&d_B, size);
cudaMalloc((void**)&d_C, size);
// 호스트 메모리에서 디바이스 메모리로 데이터 복사
cudaMemcpy(d_A, h_A, size, cudaMemcpyHostToDevice);
cudaMemcpy(d_B, h_B, size, cudaMemcpyHostToDevice);
// 커널 실행
dim3 threadsPerBlock(16, 16);
dim3 blocksPerGrid((N + threadsPerBlock.x - 1) / threadsPerBlock.x,
(N + threadsPerBlock.y - 1) / threadsPerBlock.y);
matrixMul<<<blocksPerGrid, threadsPerBlock>>>(d_A, d_B, d_C, N);
// 디바이스 메모리에서 호스트 메모리로 결과 복사
cudaMemcpy(h_C, d_C, size, cudaMemcpyDeviceToHost);
// 결과 출력
for (int i = 0; i < N; ++i) {
for (int j = 0; j < N; ++j) {
std::cout << h_C[i * N + j] << " ";
}
std::cout << std::endl;
}
// 메모리 해제
cudaFree(d_A);
cudaFree(d_B);
cudaFree(d_C);
free(h_A);
free(h_B);
free(h_C);
return 0;
}
이제 스물한 번째 날의 학습을 마쳤습니다. CUDA의 개념과 이를 사용하여 GPU 프로그래밍을 구현하는 방법을 이해하고, 실습 문제를 통해 이를 적용하는 방법을 학습했습니다.
질문이나 피드백이 있으면 언제든지 댓글로 남겨 주세요. 내일은 "Boost 라이브러리 소개 및 활용"에 대해 학습하겠습니다.
반응형
'-----ETC----- > C++ 성능 최적화 및 고급 테크닉 시리즈' 카테고리의 다른 글
[C++ 성능 최적화 및 고급 테크닉] Day 23: 실전 최적화 사례 연구 (2) (0) | 2024.08.01 |
---|---|
[C++ 성능 최적화 및 고급 테크닉] Day 20: OpenMP를 이용한 병렬 프로그래밍 (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] Day 18: 고급 멀티스레딩 기법 (락 프리 프로그래밍) (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] Day 19: 병렬 STL 사용법 (0) | 2024.08.01 |
[C++ 성능 최적화 및 고급 테크닉] Day 16: std::thread와 동기화 기법 (0) | 2024.08.01 |