GPU 간의 효율적인 통신은 병렬 컴퓨팅 성능을 최대한 활용하기 위한 중요한 요소이다. 이를 위해 다양한 통신 기법이 사용되며, 이러한 기법들은 여러 GPU를 사용하는 복잡한 애플리케이션에서 매우 중요하다. 여기서는 GPU 간 통신 기법에 대해 상세히 설명한다.

1. GPU 간 직접 메모리 접근 (GPUDirect)

GPUDirect Memory Access (GPUDirect RDMA)

GPUDirect RDMA(Remote Direct Memory Access)는 CPU의 관여 없이 GPU와 다른 디바이스(다른 GPU 포함) 간에 직접 대용량 데이터를 전송할 수 있는 기술이다. 이 방식은 CPU의 개입을 최소화하여 지연 시간을 줄이고, 데이터 전송 속도를 증가시킨다.

// Pseudocode for GPUDirect RDMA
cudaMemcpy(DstPointer, SrcPointer, Size, cudaMemcpyDeviceToDevice);

GPUDirect Peer-to-Peer

같은 시스템 내에 있는 두 개 이상의 GPU 간에 직접 통신 하는 방식이다. 한 GPU의 메모리를 다른 GPU가 직접 접근할 수 있게 하여 효율적인 데이터 전송을 가능하게 한다.

// Enabling Peer-to-Peer access
cudaSetDevice(GPU0);
cudaDeviceEnablePeerAccess(GPU1, 0);

cudaSetDevice(GPU1);
cudaDeviceEnablePeerAccess(GPU0, 0);

NVLink는 NVIDIA에서 개발한 고속 인터커넥트로, 여러 GPU 간의 대역폭 높은 통신을 지원한다. NVLink를 사용하면 PCIe보다 훨씬 빠른 속도로 데이터를 전송할 수 있다. NVLink는 CUDA 프레임워크 내에서 자동으로 관리되며, 개발자가 직접 개입할 필요가 거의 없다.

// No explicit code needed typically as NVLink is managed by CUDA framework

3. Unified Memory and Managed Memory

통합 메모리(Unified Memory) 및 관리형 메모리(Managed Memory)는 CPU와 여러 GPU 간의 메모리를 통합하여 쉽게 관리할 수 있도록 하는 기술이다. 이를 통해 메모리 복잡성을 줄이고, 성능 향상을 도모할 수 있다.

// Example code for Unified Memory
float *d_data;
cudaMallocManaged(&d_data, N * sizeof(float));

// Code to utilize d_data

4. MPI (Message Passing Interface)

다중 GPU 클러스터 환경에서는 Message Passing Interface (MPI)를 사용하여 GPU 간 데이터를 교환하는 것이 일반적이다. 이는 특히 분산 클러스터에서 많이 사용된다.

// Pseudocode for MPI communication
MPI_Send(buffer, count, MPI_FLOAT, dest, tag, MPI_COMM_WORLD);
MPI_Recv(buffer, count, MPI_FLOAT, source, tag, MPI_COMM_WORLD, &status);

5. NCCL (NVIDIA Collective Communications Library)

NCCL은 NVIDIA에서 제공하는 라이브러리로, 여러 GPU 간 효율적인 데이터 공유를 위한 통신 패턴을 제공한다. 이 라이브러리는 싱글 머신에서 여러 개의 GPU가 협력하여 작업을 수행하는 경우에 특히 유용하다.

#include <nccl.h>

// Initialization
ncclComm_t comm;
ncclCommInitRank(&comm, nRanks, ncclId, rank);

// Scatter/Gather Example
ncclGroupStart();
ncclBcast(data, count, ncclFloat, root, comm, stream);
ncclGroupEnd();

6. CUDA Streams and Async Operations

CUDA Stream과 비동기 연산을 사용하면 데이터 전송과 커널 실행을 겹쳐서 성능을 극대화할 수 있다. GPU 간 통신을 최적화하는 방법 중 하나는 이 비동기 방식의 원리를 잘 이해하고 활용하는 것이다.

cudaMemcpyAsync(dst, src, size, cudaMemcpyDeviceToDevice, stream);
kernel<<<blocks, threads, 0, stream>>>(parameters);

7. Multi-GPU Programming Models

Multi-GPU 프로그래밍 모델은 GPU 간의 통신을 효율적으로 진행하기 위해 다양한 추상화를 제공한다. 아래는 대표적인 프로그래밍 모델들이다:


위에서 설명한 여러 기술과 프로그래밍 모델을 결합하면 다양한 GPU와 시스템 간의 통신을 최적화할 수 있다. 결론적으로, GPU 간 통신을 효율적으로 구현하기 위해서는 각각의 기법과 기술을 적절히 이해하고, 상황에 맞는 최적의 방법을 선택하는 것이 중요하다.