Key Performance Factors

  1. Parallelism
    • 동시에 처리할 수 있는 데이터 or 연산의 양
    • CPU have multiple cores, where each has ILP
      • ILP는 최대 issue가능한 inst 개수가 4개 정도로, 한계가 있음 (dependency 때문에)
  2. Clock frequency
    • Processing speed
    • Pipeline stage를 더 나눠서 단위시간당 처리하는 instruction 갯수를 maximize 해왔음 (Moore’s Law)
    • Power wall, 발열량이 많아 한계가 있음
      • 코어를 늘려야 함
  3. Memory bandwidth
    • Amount of data transferred at a time
    • DDR 메모리(DRAM)는 bandwidth에 한계가 있다
  4. Memory latency
    • Time for each data element to be transferred
    • DDR 메모리는 다른 메모리에 비해 latency가 길다 (Memory wall)
      • Memory wall: 메모리가 프로세서 성능을 못따라가는 것을 의미. 지금은 Moore’s law가 중단되어 있으니, 단일 프로세서의 성능은 멈춰져 있고 이를 따라잡고 있어 크게 문제되지는 않음
    • CPU가 이러한 latency를 숨겨야 함 (hiding)
      • On-chip cache
      • Out of order execution
      • Simultaneous multithreading
        • Memory latency가 있는 동안 다른 쓰레드의 inst를 실행할 수 있음
  • Different applications are sensitive to different performance factors
  • Different architectures address these factors in different ways

Accelerators

  • 범용 CPU에 비해 특정한 작업을 더 효율적으로 수행할 수 있는 하드웨어
  • Graphics Processing Units(GPUs)
    • Parallelism
      • massive하게 되어 있음
      • 엄청 많은 코어
    • Clock frequency
      • 상대적으로 낮음
      • 일꾼(core)이 많으니 상관 없음
    • Memory bandwidth
      • High bandwidth memory
      • GDDR / HBM2 stacked memory
        • 추가) Stacked memory : 3D 메모리 스택 기술 사용. 메모리 칩을 수직으로 쌓음
        • Banking이랑 다르게 아예 물리적 칩을 수직으로 쌓아서 집적도와 데이터 전송 속도를 향상시키는 것이 목적임
    • Memory latency
      • DDR이랑 비슷한 성능
      • Hardware multithreading을 통한 hiding이 가능해서 상관 없음

Usecase: Rendering

  • 3D 모델을 2차원 이미지로 만드는 것
  • 보통 표면에 triangle mesh를 덮어서 수행
  • 파이프라인 stage를 거침
    • Vertex processing Geometry processing Rasterization Pixel processing Output merging
    • 과거에는 특수한 하드웨어를 사용했음
    • 그러나 특정 스테이지들이 programmable하고, 이를 대상으로 범용 하드웨어를 사용해도 성능이 비슷하다는 사실 발견
      • vertex, geometry, pixel 등의 부분

Shader

  • 랜더링 파이프라인의 각 스테이지를 실행하는 프로그램
  • GPU에서 실행됨

Architecture

General-Purpose CPU

  • General purpose CPU의 구조
  • GPU에서는 이정도로 복잡한 CPU가 필요하지 않음
    • GPU application의 특징: Data dependency가 없다
    • 즉 pixel들, triangle들 사이에 data dependency가 없기 때문
    • 이러한 pixel과 triangle들이 millions 가까이 있기 때문에 쉽게 병렬처리 할 수 있음

Shader Core Architecture

  • 파이프라인의 한 단계를 수행하는 코어
  • 이를 반복적으로 방문하여 여러 스테이지를 수행할 수 있음

Streaming Multiprocessor(SM)

  • 이러한 core를 여러 개 배치하여 병렬화 가능함
  • 이를 Streaming Multiprocessor(SM)라고 부름
    • 내부적으로 많은 Shader core(ALU)를 가지고 있음
      • 각 코어가 하나의 쓰레드를 실행하므로, SIMT(Single Instruction, Multiple Thread)라고 부르기도 함
      • NVIDIA가 괜히 용어를 만들어낸 것
    • ALU들이 하나의 pc를 공유
    • 여러 ALU 사이의 SIMD processing
Warp
  • 한번에 실행되는 여러 쓰레드의 묶음
  • Context switch의 단위
    • 하나의 SM은 여러 warp를 스케쥴링할 수 있음
  • 예를 들어 32개의 코어로 구성된 SM은 32개 스레드의 warp를 실행할 수 있음
    • 하나의 SM이 여러 warp를 번갈아 가며 하나 이상의 warp를 실행할 수도 있음
Multiple SM
  • 여러개의 SM을 병렬로 실행할 수도 있음
  • 예를 들어 32개의 코어로 구성된 SM이 4개 있는 경우, 총 4개의 warp, 즉 128개의 쓰레드를 동시에 실행할 수 있음

Overall Architecture

SM - Executing Branches

  1. Branch evaluation 명령어 fetch, decode, execute
  2. 그 다음 줄 fetch & decode
    1. true인 경우의 블록이면 1의 결과가 true일 때만 execute
    2. false인 경우의 블록이면 1의 결과가 false일 때만 execute
  • 이렇게 하는 이유: Fetch, Decode가 모든 라인에 대해 무조건 실행되어야 하기 때문
  • 이를 Predicated execution(조건부 실행, conditional execution)이라고 부름
    • 성능적으로 좋지 않음
      • 조건이 늘어날 수록 fetch&decode 해야 하는 명령어의 가능한 수가 2의 승수로 급격하게 증가
      • 루프 내에서 조건부 명령어가 두 번 등장하면, 조건부 실행 명령어는 4가지 경우의 수로 분기
      • 해당 경우의 수를 모든 스레드가 순차적으로 거쳐야 하므로, 병렬성이 떨어짐
    • 전부 result가 같으면 그것만 실행하고 다른 결과는 아예 넘어가는 식의 최적화를 수행하기도 함

SM - Hardware Context Switch

  • 하나의 SM이 하나 이상의 warp를 실행할 수 있음
    • 예를 들어 아래 그림처럼 warp 0을 실행했는데, 메모리 fetch라서 시간이 너무 오래 걸린다 하자
    • 기다리는 동안 warp1에 다른 걸 실행시킬 수 있다
    • 대체로 같은 프로그램을 실행하기 때문에 아래 그림처럼 계속 stall되어서 많은 warp를 실행하게 됨
  • Warp 간의 context switching은 하드웨어로 수행됨
    • 하드웨어 컨택스트 풀(레지스터 풀)이 존재
    • 각 워프가 필요한 만큼 해당 컨텍스트를 reserve
      • 워프의 최대 갯수는 정해져 있는데, 레지스터 사용 갯수에 따라 실제로 사용하는 갯수는 달라질 수 있음 (어떤 워프가 레지스터를 많이 가져간다고 하면 실제 최대갯수가 4개여도 2개밖에 안돌아갈수도 있음)
      • 워프가 많을수록 동시에 많은 쓰레드를 실행할 수 있으니 최대화하는 것이 좋음
    • CPU의 컨택스트 스위칭보다 훨씬 효율적
      • CPU의 경우, interrupt를 발생시키면 OS가 스케쥴링 및 레지스터 저장 및 복원을 수행
      • GPU의 경우, 하드웨어로 수행되므로 OS가 CPU를 잡을 필요가 없고, 레지스터가 내려가지 않으므로 메모리에 저장하는 시간도 필요없음

GPU Summary

  • Exploits massive data parallelism
    • Many simple compute units
    • SIMD (a single program counter)
      • 전통적인 SIMD와의 공통점
        • SM마다 program counter가 하나
        • 단일 명령어로 다수 데이터 처리
        • 병렬 처리
      • 전통적인 SIMD와 다른 점
        • 못들음
        • 아마 워크 단위가 스레드인점이 다르지 않을까. 전통적인 SIMD는 벡터 레지스터 단위로 병렬처리
    • Many threads and no synchronization between threads
      • 하는 방법은 못들었음
  • Hardware context switch

DMA (Direct Memory Access)

Idea

  • 하드 디스크에서 메인 메모리로 데이터를 옮겨오는 것이 사이클 낭비적
    • CPU가 여러 명령어를 메모리로 날려서 메모리 address를 증가시키고 몇 개의 바이트가 이동했는지 관리해야 한다
  • 이 작업을 CPU 대신 DMA 컨트롤러가 대신 해주고 다 끝나면 CPU한테 interrupt를 던져주자

DMA Controller(DMA Engine)

  • DMA 전송을 관리하는 장치
  • 메모리 주소, 전송할 데이터의 크기, 전송할 위치 등을 제어
  • CPU는 단순히 DMA 컨트롤러에 데이터를 전송하라는 명령만 내리고, 나머지는 DMA controller가 수행
  • 작업이 완료되면 CPU에게 interrupt를 던져 알려줌

동작 과정

  1. CPU가 DMA command를 메모리에 작성
    • 전송할 데이터의 시작 주소, 데이터 크기, 목적지 주소 등을 전달
  2. CPU는 작성한 DMA command block을 DMA controller에게 전달
  3. DMA controller는 메모리 버스를 사용하여 CPU를 방해하지 않고 직접 메모리를 전달
    • 그 동안 CPU는 다른 작업을 수행할 수 있음 (메모리 버스를 사용하는 작업은 못할 것)
    • DMA controller와 Device controller간의 handshaking이 수반되기도 함
  4. 데이터 전송이 완료되면 DMA controller가 CPU에게 interrupt를 전송

Cache Coherence Problems in DMA

  • Private cache의 값과 메모리의 값이 다를 수 있음
    • 프로세서나 I/O device의 쓰기 작업이 다른 프로세서에는 보이지 않음
    • DMA는 특히 CPU 캐시의 존재를 모르고 있기 때문에 이 문제가 더 심각해짐
      • 예를 들어 CPU가 특정 메모리 영역을 캐시에 보관하고 해당 데이터를 수정한 후, 데이터가 메모리로 플러시되지 않았다면 이러한 사항을 모른 채 메모리에서 오래된 데이터를 읽어서 device(하드디스크)에게 전달하게 됨
      • 혹은 CPU가 읽기요청을 했는데, DMA 작업이 완료되고 나서 메인 메모리(DMA로 쓴 곳)를 읽지 않고 캐시를 읽어버리면 오래된 값을 읽게 됨
    • Stale value를 가지고 있는 것
  • 해결책
    • Flushing pages: Cache를 flush한 뒤 DMA
    • Uncacheable memory region: DMA하는 영역은 cache에 넣지 말라고 보호
    • Uncacheable operations: 캐시되지 않는 방식으로 처리되는 연산을 사용
    • Passing I/O data through caches: I/O 장치와의 데이터 전송 과정에서 캐시를 통과하여 처리

Remote Direct Memory Access

  • 하나의 노드에서 다른 노드로 가는 메모리 전송을 어느 쪽의 CPU도 개입하지 않고 수행
    • 네트워크 상의 한 컴퓨터에서 다른 컴퓨터의 메모리에 직접 접근
    • Infiniband 등의 특수 NIC 필요
  • NIC가 데이터를 바로 전송할 수 있게 하여 application 메모리와 OS의 data buffer간의 copy 연산이 필요하지 않게 됨
    • CPU, cache, context switch 없이 수행가능
    • 데이터 전송이 병렬적으로 수행됨
  • 문제: Single sided communications
    • 수신자(Target node)는 request가 완수되었는지 모른다
    • 읽기의 경우 타겟 노드가 자신의 데이터를 읽혔다는 사실을 모르고, 쓰기의 경우 타겟 노드가 해당 데이터가 언제 쓰여질지도 모르고 쓰여졌는지도 모름
    • 추가적인 통신 매커니즘, 완료 알림 이벤트 등이 필요함

전통적인 커뮤니케이션

RDMA

NVIDIA GPUDirect

  • Network adapter와 스토리지 디바이스가 GPU 메모리에 직접적으로 읽기와 쓰기를 할 수 있음
  • GPUDirect Storage
  • GPUDirect RDMA

GPUDirect Storage

  • Local, remote 스토리지와 GPU 간의 직접 데이터 전송을 가능하게 함
  • CPU 메모리의 Bounce buffer를 제거하여 DMA engine이 GPU에서 바로 데이터를 읽어올 수 있게 함
    • Bounce buffer: 비호환 장치의 직접 데이터 전송이 불가할 때 사용되는 메모리 영역 (GPU - Storage 간 데이터 전송에서 CPU 메모리를 임시사용 바운스 버퍼로 동작)
    • 전통적인 방식: 데이터가 스토리지 장치에서 CPU로 전송되고, CPU가 메모리로 데이터를 복사한 후 메모리에서 GPU로 전달 (스토리지 CPU 메모리 GPU)
    • GPUDirect Storage 방식: 데이터가 스토리지 장치에서 GPU 메모리로 바로 전달 (스토리지 GPU)

GPUDirect RDMA

  • 주변의 PCIe 디바이스(e.g. NIC)가 GPU 메모리에 바로 접근
  • 한쪽 NIC에서 다른쪽 GPU로 바로 메모리를 공유 가능
    • 전통적인 방식: NIC CPU 메모리 GPU (복사 너무 많아)
    • 이 방식: NIC GPU

Collective Communication between GPUs

  • GPU간의 collective communication이 필요함
    • Collective communication : Point-to-point communication과 달리, broadcasting과 같이 여럿이서 한꺼번에 통신하는 것을 의미
      • Point to point 통신을 이용하면 비효율적임
      • 통신 패턴을 이용한 최적화가 불가능
  • MPI collective communication library
    • CPU 통신에 사용 가능한 API function
    • 여러 통신 패턴에 사용 가능
      • Broadcast, Scatter, Gather, All-Gather, All-to-All, Reduce, All-Reduce
  • NVIDIA collective communication library (NCCL), MS collective communication library (MSCCL), ROCm collective communication library (RCCL)
    • MPI collective communication API를 본따 GPU 버전으로 만든 것들
    • GPU들 간의 통신 지원

Collective communications

Broadcast, Scatter, Gather

  • Broadcast: 동일한 정보를 여러 GPU에 전파하는 것
  • Scatter: 연속된 정보를 랜덤으로 여러 GPU에게 뿌리는 것
    • 규칙성이 있어도 되긴 하지만 아무튼 무조건 sequential은 아니다
  • Gather: 여러 GPU로부터 각기 다른 정보를 모으는 것

All-Gather

  • 모두가 모두의 정보를 gather하는 것이라 이해할 수 있음
  • 각 GPU가 정보를 하나 가지고 있으면 그 정보를 모두 가지게끔 하는 것

All-to-All

  • 2차원 배열을 transpose한 것처럼 가지게 되는 것
  • Send and receive(point-to-point)로 구현할 수는 있지만 최적화를 통해 더 빠르게 수행 가능

Reduce

  • 덧셈에 대해 reduction을 하는 예시
  • 모든 GPU의 값을 덧셈하여 하나의 GPU가 갖는 것

All-Reduce

  • Reduction한 값을 모두가 갖는 것
  • Back propagation을 할 때 많이 사용되는 패턴