Jerry's Log

CUDA

contents

CUDA (Compute Unified Device Architecture)NVIDIA가 만든 병렬 컴퓨팅 플랫폼이자 애플리케이션 프로그래밍 인터페이스(API) 모델입니다. 이를 통해 소프트웨어 개발자는 CUDA가 지원되는 그래픽 처리 장치(GPU)를 범용 처리(GPGPU, General-Purpose computing on Graphics Processing Units)에 사용할 수 있습니다.

간단히 말해, CUDA는 그래픽 카드의 엄청난 병렬 처리 능력을 잠금 해제하여 표준 CPU보다 훨씬 빠르게 복잡한 수학 문제를 해결할 수 있게 해줍니다.


1. 핵심 철학: CPU vs. GPU

CUDA를 이해하려면 하드웨어의 차이점을 이해해야 합니다.

CUDA는 다리(Bridge)입니다. C, C++, Python, Fortran 코드가 이 수천 개의 GPU 코어에 명령을 내릴 수 있게 해줍니다.


2. CUDA 아키텍처: 하드웨어 및 소프트웨어 계층

A. 하드웨어 관점 (GPU)

CUDA 관점에서 GPU는 계층적으로 구성됩니다.

  1. SM (스트리밍 멀티프로세서): NVIDIA GPU의 기본 구성 블록입니다. GPU는 많은 SM을 포함합니다. 각 SM은 많은 CUDA 코어를 포함합니다.
  2. CUDA 코어: 정수 및 부동 소수점 연산을 실행하는 작은 유닛입니다.
  3. 텐서 코어 (Tensor Cores): 최신 GPU(Volta, Ampere, Hopper 등)에 있는 특수 코어로, 행렬 곱셈(AI/딥러닝)을 위해 특별히 설계되었습니다.
  4. RT 코어: 레이 트레이싱(Ray Tracing)을 위한 특수 코어입니다.
  5. 메모리:
    • 글로벌 메모리 (VRAM): 크지만(예: 24GB), 모든 코어가 접근 가능하며 느립니다(높은 지연 시간).
    • 공유 메모리 (L1 캐시): 각 SM _내부_에 위치한 작고 매우 빠른 메모리입니다. 블록 내의 스레드들이 서로 통신하는 데 사용할 수 있습니다.
    • 레지스터: 스레드별로 비공개인 가장 빠른 메모리입니다.

B. 소프트웨어 관점 (그리드)

CUDA 프로그램(커널)을 실행할 때, 작업은 논리적으로 나뉩니다.

  1. 스레드 (Thread): 실행의 가장 작은 단위입니다. 각 스레드는 동일한 코드를 다른 데이터에 대해 실행합니다.
  2. 블록 (Block): 스레드들의 그룹입니다(예: 128개 또는 256개 스레드). 블록 내의 스레드들은 동일한 SM에서 실행되며 메모리를 공유할 수 있습니다.
  3. 그리드 (Grid): 블록들의 모음입니다. 이것은 해결하려는 전체 문제를 나타냅니다.

3. CUDA 프로그램의 작동 방식 (워크플로우)

일반적인 CUDA 프로그램은 호스트-디바이스 모델을 따릅니다.

CUDA 프로그램의 4단계:

  1. 메모리 할당: CPU가 cudaMalloc을 사용하여 GPU(VRAM)에 메모리를 할당합니다.
  2. 데이터 복사: CPU가 시스템 RAM의 입력 데이터를 GPU VRAM으로 복사합니다(cudaMemcpy 사용).
  3. 커널 실행: CPU가 GPU에게 수천 개의 스레드에 걸쳐 함수(커널)를 실행하라고 지시합니다. GPU가 숫자를 처리하는 동안 CPU는 다른 작업을 계속할 수 있습니다.
  4. 복사 및 회수: GPU 작업이 완료되면, CPU는 결과를 VRAM에서 시스템 RAM으로 다시 복사해 옵니다.

4. 코딩 예제 (CUDA C++)

두 개의 거대한 배열을 더하는(벡터 덧셈) 간단한 예제입니다.

표준 C++ (CPU):

void add(int n, float *x, float *y) {
  for (int i = 0; i < n; i++)
    y[i] = x[i] + y[i];
}

CUDA C++ (GPU):

// 커널 (GPU에서 실행됨)
// __global__은 이 함수가 디바이스에서 실행되고 호스트에서 호출됨을 컴파일러에 알립니다.
__global__ void add(int n, float *x, float *y) {
  // 이 스레드에 대한 전역 인덱스 계산
  int index = blockIdx.x * blockDim.x + threadIdx.x;
  int stride = blockDim.x * gridDim.x;

  // 각 스레드가 특정 요소를 처리
  for (int i = index; i < n; i += stride)
    y[i] = x[i] + y[i];
}

// 메인 함수 (호스트)
add<<>>(N, x, y); // 커널 실행 (Launch)
cudaDeviceSynchronize(); // GPU가 끝날 때까지 대기

5. CUDA가 승리한 이유 (생태계)

CUDA(2007년) 이전에는 GPU를 수학 연산에 사용하려면 그래픽 API(OpenGL/DirectX)를 해킹하여 GPU가 데이터 포인트를 "픽셀"인 것처럼 착각하게 만들어야 했습니다. CUDA는 이를 C 코드처럼 보이게 만들었습니다.

오늘날 CUDA가 지배적인 이유는 생태계 때문입니다.

6. 단점과 과제

요약

CUDA는 현대 AI 폭발의 연료가 된 "비법 소스"입니다. GPU를 게이머를 위한 장난감에서 과학자를 위한 슈퍼컴퓨터로 변화시킴으로써, 이전에는 계산이 불가능했던 거대 신경망(ChatGPT 같은)의 학습을 가능하게 했습니다.

references