본문 바로가기
-----ETC-----/C++ 성능 최적화 및 고급 테크닉 시리즈

[C++ 성능 최적화 및 고급 테크닉] Day 21: CUDA를 이용한 GPU 프로그래밍

by cogito21_cpp 2024. 8. 1.
반응형

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 라이브러리 소개 및 활용"에 대해 학습하겠습니다.

반응형