- Parallelism
- 동시에 처리할 수 있는 데이터 or 연산의 양
- CPU have multiple cores, where each has ILP
- ILP는 최대 issue가능한 inst 개수가 4개 정도로, 한계가 있음 (dependency 때문에)
- Clock frequency
- Processing speed
- Pipeline stage를 더 나눠서 단위시간당 처리하는 instruction 갯수를 maximize 해왔음 (Moore’s Law)
- Power wall, 발열량이 많아 한계가 있음
- Memory bandwidth
- Amount of data transferred at a time
- DDR 메모리(DRAM)는 bandwidth에 한계가 있다
- 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
- 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
-Scalable-High-Performance-Computing/images/SHPC-09-1.png)
- General purpose CPU의 구조
- GPU에서는 이정도로 복잡한 CPU가 필요하지 않음
- GPU application의 특징: Data dependency가 없다
- 즉 pixel들, triangle들 사이에 data dependency가 없기 때문
- 이러한 pixel과 triangle들이 millions 가까이 있기 때문에 쉽게 병렬처리 할 수 있음
Shader Core Architecture
-Scalable-High-Performance-Computing/images/SHPC-09-2.png)
- 파이프라인의 한 단계를 수행하는 코어
- 이를 반복적으로 방문하여 여러 스테이지를 수행할 수 있음
Streaming Multiprocessor(SM)
-Scalable-High-Performance-Computing/images/SHPC-09-3.png)
- 이러한 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개의 쓰레드를 동시에 실행할 수 있음
-Scalable-High-Performance-Computing/images/SHPC-09-4.png)
Overall Architecture
-Scalable-High-Performance-Computing/images/SHPC-09-5.png)
SM - Executing Branches
- Branch evaluation 명령어 fetch, decode, execute
- 그 다음 줄 fetch & decode
- true인 경우의 블록이면 1의 결과가 true일 때만 execute
- false인 경우의 블록이면 1의 결과가 false일 때만 execute
- 이렇게 하는 이유: Fetch, Decode가 모든 라인에 대해 무조건 실행되어야 하기 때문
- 이를 Predicated execution(조건부 실행, conditional execution)이라고 부름
- 성능적으로 좋지 않음
- 조건이 늘어날 수록 fetch&decode 해야 하는 명령어의 가능한 수가 2의 승수로 급격하게 증가
- 루프 내에서 조건부 명령어가 두 번 등장하면, 조건부 실행 명령어는 4가지 경우의 수로 분기
- 해당 경우의 수를 모든 스레드가 순차적으로 거쳐야 하므로, 병렬성이 떨어짐
- 전부 result가 같으면 그것만 실행하고 다른 결과는 아예 넘어가는 식의 최적화를 수행하기도 함
-Scalable-High-Performance-Computing/images/SHPC-09-6.png)
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를 잡을 필요가 없고, 레지스터가 내려가지 않으므로 메모리에 저장하는 시간도 필요없음
-Scalable-High-Performance-Computing/images/SHPC-09-7.png)
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를 던져주자
-Scalable-High-Performance-Computing/images/SHPC-09-8.png)
DMA Controller(DMA Engine)
- DMA 전송을 관리하는 장치
- 메모리 주소, 전송할 데이터의 크기, 전송할 위치 등을 제어
- CPU는 단순히 DMA 컨트롤러에 데이터를 전송하라는 명령만 내리고, 나머지는 DMA controller가 수행
- 작업이 완료되면 CPU에게 interrupt를 던져 알려줌
동작 과정
- CPU가 DMA command를 메모리에 작성
- 전송할 데이터의 시작 주소, 데이터 크기, 목적지 주소 등을 전달
- CPU는 작성한 DMA command block을 DMA controller에게 전달
- DMA controller는 메모리 버스를 사용하여 CPU를 방해하지 않고 직접 메모리를 전달
- 그 동안 CPU는 다른 작업을 수행할 수 있음 (메모리 버스를 사용하는 작업은 못할 것)
- DMA controller와 Device controller간의 handshaking이 수반되기도 함
- 데이터 전송이 완료되면 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가 완수되었는지 모른다
- 읽기의 경우 타겟 노드가 자신의 데이터를 읽혔다는 사실을 모르고, 쓰기의 경우 타겟 노드가 해당 데이터가 언제 쓰여질지도 모르고 쓰여졌는지도 모름
- 추가적인 통신 매커니즘, 완료 알림 이벤트 등이 필요함
전통적인 커뮤니케이션
-Scalable-High-Performance-Computing/images/SHPC-09-9.png)
RDMA
-Scalable-High-Performance-Computing/images/SHPC-09-10.png)
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)
-Scalable-High-Performance-Computing/images/SHPC-09-11.png)
GPUDirect RDMA
- 주변의 PCIe 디바이스(e.g. NIC)가 GPU 메모리에 바로 접근
- 한쪽 NIC에서 다른쪽 GPU로 바로 메모리를 공유 가능
- 전통적인 방식: NIC → CPU 메모리 → GPU (복사 너무 많아)
- 이 방식: NIC → GPU
-Scalable-High-Performance-Computing/images/SHPC-09-12.png)
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
-Scalable-High-Performance-Computing/images/SHPC-09-13.png)
- Broadcast: 동일한 정보를 여러 GPU에 전파하는 것
- Scatter: 연속된 정보를 랜덤으로 여러 GPU에게 뿌리는 것
- 규칙성이 있어도 되긴 하지만 아무튼 무조건 sequential은 아니다
- Gather: 여러 GPU로부터 각기 다른 정보를 모으는 것
All-Gather
-Scalable-High-Performance-Computing/images/SHPC-09-14.png)
- 모두가 모두의 정보를 gather하는 것이라 이해할 수 있음
- 각 GPU가 정보를 하나 가지고 있으면 그 정보를 모두 가지게끔 하는 것
All-to-All
-Scalable-High-Performance-Computing/images/SHPC-09-15.png)
- 2차원 배열을 transpose한 것처럼 가지게 되는 것
- Send and receive(point-to-point)로 구현할 수는 있지만 최적화를 통해 더 빠르게 수행 가능
Reduce
-Scalable-High-Performance-Computing/images/SHPC-09-16.png)
- 덧셈에 대해 reduction을 하는 예시
- 모든 GPU의 값을 덧셈하여 하나의 GPU가 갖는 것
All-Reduce
-Scalable-High-Performance-Computing/images/SHPC-09-17.png)
- Reduction한 값을 모두가 갖는 것
- Back propagation을 할 때 많이 사용되는 패턴