GPU에 관하여

GPU는 방대한 수학 연산을 가속하기 위해 설계된 전자 회로이다. GPU는 CPU에 비해 수천 개의 작은 코어(모델 및 사용 목적에 따라 다름)를 가지고 있기 때문에 GPU 아키텍처는 병렬 처리에 최적화되어 있다. GPU는 여러 작업을 동시에 처리할 수 있으며 그래픽 및 수학적 워크로드에서 더 빠르다.

GPU vs CPU

기본적인 GPU 구조

Flynn’s Taxanomy

플린의 분류법은 스탠포드 대학교의 마이클 J. 플린이 컴퓨터 아키텍처를 분류한 것이다. 플린의 분류법의 기본 개념은 간단하다. 계산은 순차적으로(한 번에 하나의 스트림) 또는 병렬로(한 번에 여러 스트림) 처리할 수 있는 두 개의 스트림(데이터 및 명령어 스트림)으로 구성된다. 두 개의 데이터 스트림과 이를 처리할 수 있는 두 가지 방법은 플린의 분류법에서 4가지 범주로 이어진다.

Single Instruction Single Data (SISD)

SISD 스트림은 하나의 데이터 스트림에서 싱글 명령어 스트림이 실행되는 구조이다. 이 구조는 싱글 코어 프로세서를 탑재한 단순한 컴퓨터에서 사용된다.

Single Instruction Multiple Data (SIMD)

SIMD 스트림은 싱글 제어 프로세서와 명령어 메모리가 있으므로 특정 시점에 하나의 명령어만 실행할 수 있다. 이 싱글 명령어는 각 코어에서 동시에 복사되어 실행된다. 이는 각 프로세서에 데이터 수준에서 병렬 처리(일명 “데이터 병렬 처리”)를 허용하는 전용 메모리가 있기 때문에 가능하다. SIMD의 근본적인 장점은 데이터 병렬화를 통해 연산을 빠르고(여러 프로세서가 동일한 작업을 수행) 효율적으로(하나의 명령어 단위만 사용) 실행할 수 있다는 것이다.

Multiple Instruction Single Data (MISD)

MISD 스트림은 사실상 SIMD의 정반대이다. MISD에서는 동일한 데이터 스트림에서 여러 명령이 수행된다. 오늘날 MISD의 사용 사례는 매우 제한적이다. 대부분의 실제 애플리케이션은 다른 아키텍처 중 하나를 사용하는 것이 더 적합하다. MIMD 스트림 아키텍처는 데이터와 명령어 스트림 모두에 병렬성을 제공한다. MIMD를 사용하면 여러 프로세서가 서로 다른 데이터 스트림에 대해 독립적으로 명령어 스트림을 실행한다.

왜 SIMD가 GPU에서 가장 좋을까?

많은 일반적인 GPU 컴퓨팅 사용 사례는 기본적으로 동일한 수학적 함수를 대규모로 반복해서 실행하는 것임을 이해하면, 그 답은 직관적으로 이해된다. 이 경우 다수의 프로세서가 여러 데이터 세트에서 동일한 명령어를 실행하는 것이 이상적이다. 예를 들어, 픽셀의 밝기를 조정하는 경우 RGB 값을 사용하는 간단한 연산에 의존한다. 동일한 함수를 여러 번 실행해야 원하는 결과를 얻을 수 있으며, 이러한 사용 사례에는 SIMD가 이상적이다. 반대로 MIMD는 CAD(컴퓨터 지원 설계)와 같이 여러 개의 개별 계산을 실행해야 하는 애플리케이션에 가장 효과적이다.

CUDA에 관하여

  • NVIDIA CUDA Zone
    CUDA의 처리 리소스는 GPU 사용 사례에 맞게 성능을 최적화하도록 설계되었습니다. 계층 구조의 세 가지 기본 구성 요소는 스레드, 스레드 블록 및 커널 그리드이다.

Threads

스레드 또는 CUDA 코어는 NVIDIA GPU에서 부동 소수점 연산을 계산하는 병렬 프로세서이다. GPU에서 처리되는 모든 데이터는 CUDA 코어를 통해 처리한다. 최신 GPU에는 수백 개 또는 수천 개의 CUDA 코어가 있다. 각 CUDA 코어에는 다른 스레드에서 사용할 수 없는 자체 메모리 레지스터가 있다.

컴퓨팅 성능과 CUDA 코어의 관계는 완벽하게 선형적이지는 않지만, 일반적으로 다른 모든 것이 동일하다고 가정할 때, GPU의 CUDA 코어가 많을수록 컴퓨팅 성능이 더 뛰어나다. 그러나 이 생각은 꼭 일반적이지는 않다.

Threads Blocks

스레드 블록 또는 CUDA 블록은 직렬 또는 병렬로 함께 실행할 수 있는 CUDA 코어(스레드)를 그룹화한 것이다. 코어를 논리적으로 그룹화하면 보다 효율적인 데이터 매핑이 가능하다. 스레드 블록은 블록 단위로 메모리를 공유한다. 현재 CUDA 아키텍처는 블록당 스레드 수를 1024개로 제한한다. 주어진 CUDA 블록의 모든 스레드는 동일한 공유 메모리에 액세스할 수 있다.

Kernel Grids

스레드 블록에서 다음 추상화 계층은 커널 그리드이다. 커널 그리드는 동일한 커널에 있는 스레드 블록의 그룹이다. 그리드는 더 큰 규모의 계산(예: 1024개 이상의 스레드가 필요한 계산)을 병렬로 수행하는 데 사용할 수 있지만 서로 다른 스레드 블록은 동일한 공유 메모리를 사용할 수 없기 때문에 블록 수준에서 발생하는 동일한 동기화가 그리드 수준에서는 발생하지 않는다.

Registers

레지스터는 개별 스레드(CUDA 코어)에 할당되는 메모리이다. 레지스터는 “온칩” 메모리에 존재하며 개별 스레드 전용이므로 레지스터에 저장된 데이터는 다른 어떤 데이터보다 빠르게 처리할 수 있다. 레지스터의 메모리 할당은 복잡한 프로세스이며 CUDA 개발자가 작성하는 소프트웨어에 의해 제어되는 것이 아니라 컴파일러에 의해 처리된다.

Read-only Memory

읽기 전용(RO)은 GPU 스트리밍 멀티프로세서의 온칩 메모리이다. CUDA 텍스처 함수를 사용하여 액세스할 수 있는 텍스처 메모리와 같은 특정 작업에 사용된다. 대부분의 경우 읽기 전용 메모리에서 데이터를 가져오는 것이 전역 메모리를 사용하는 것보다 더 빠르고 효율적일 수 있다.

L1 Cache/shared Memory

L1 캐시 및 공유 메모리는 스레드 블록(CUDA 블록) 내에서 공유되는 온칩 메모리이다. L1 캐시 및 공유 메모리는 온칩에 존재하기 때문에 L2 캐시 및 전역 메모리보다 빠르다. L1 캐시와 공유 메모리의 근본적인 차이점은 공유 메모리 사용은 소프트웨어를 통해 제어되는 반면 L1 캐시는 하드웨어에 의해 제어된다.

L2 Cache

L2 캐시는 모든 CUDA 블록의 스레드에서 액세스할 수 있다. L2 캐시는 글로벌 메모리와 로컬 메모리를 모두 저장한다. L2 캐시에서 데이터를 검색하는 것이 글로벌 메모리에서 데이터를 검색하는 것보다 빠르다.

Global Memory

전역 메모리는 장치의 DRAM에 상주하는 메모리이다. CPU에 비유하자면 전역 메모리는 RAM과 비슷한다. 글로벌 메모리에서 데이터를 가져오는 것은 본질적으로 L2 캐시에서 데이터를 가져오는 것보다 느리다.