CUDA Memory Hierarchy
- Per-Thread (local Memory)
- Registers
- 가장 빠르고, 가장 작은 메모리
- 보통 블록 1개가 8k-64k 32bit register를 사용한다.
- 각 SM 내부에 존재
- thread들이 register를 나누어서 가져간다.(register의 영역을 나누어서 사용)
따라서 context switching이 필요 없다.
- Local Memory
- Off-chip memory
- SM 내부에 없고, DRAM 영역 내부에 존재
- register에 다 올라가지 못하는 것들은 Local Memory에 올려서 동작
- Register에 비해 느리지만 더 많은 공간을 활용할 수 있다.(크게 제약이 없다.)
- Off-chip memory
- Registers
- Per-Block (shared Memory)
- Shared Memory(__shared__)
- On-chip memory
- SM 내부에 존재해 빠르지만 공간이 적다.
- 블록 안의 모든 thread들이 공유한다.(모든 thread가 접근이 가능하다.)
- thread 간의 communication가능
- SM 내부의 block들이 shared memory 공간을 나누어서 활용(block 개수 제한)
- On-chip memory
- Shared Memory(__shared__)
- Per-Gird (global Memory)
- Global Memory
- 모든 thread가 활용할 수 있다.
- off-chip memory
- 가장 느리지만 가장 큰 공간을 가진다.
- Host에서 접근이 가능하다.
- Constant Memory
- 읽기 전용 메모리 : 읽을 수만 있다.
- 선언은 global로 하고 host를 통해 초기화 한다.
- 공간이 적지만 빠르다.
- 이 영역을 위한 캐시가 존재한다.(캐시 영역 지원)
- 기본적으로 DRAM에 저장되어 있지만 할당되어 있는 cache가 존재해서 자주 읽어오는 값들을 저장해놓으면 빠르게 가져가 활용할 수 있다.(인자 값과 같은 것들..)
- 이 영역을 위한 캐시가 존재한다.(캐시 영역 지원)
- 읽기 전용 메모리 : 읽을 수만 있다.
- Texture Memory
- Constant memory와 비슷
- 2차원 array를 다루는 것에 최적화
- Hardware 필터링 제공
- 기본적으로 graphic에 활용되므로 cuda에서 많이 사용하지는 않는다.
- Global Memory
GPU Caches (Hardware Manage)
- L1 cache
- SM마다 존재한다.
- Shared memory와 같은 공간에 존재
- 따라서 L1 cache를 더 사용할 수도 사용하지 않을 수도 있다.
- Shared memory 공간으로 활용하기도 한다.
- L2 cache
- SM 내부에 있는 것이 아니라 바깥쪽에 존재하는 캐시
- Shared by all SM
- Read-only constant and texture caches
Physical Location of CUDA Memories
- On-chip memory(In each SM)
- Registers
- Shared Memory
- Constant cache, Texture cache
- Off-chip memory
- Local memory
- Global memory
- Constant memory and Texture memory
- L2 cache
그렇다면 각각 Memory Model이 성능에 어떤 영향을 미치는지 알아보자.
일단 각각 Memory Model을 잘 이해하고 적당한 공간에 가져다가 사용해야 한다.
(Design your kernel and block)
무작정 많은 스레드를 사용한다고 성능이 좋아지는 것은 아니다.
결론적으로 Activie Wrap과 Activie Block이 많아야 성능이 좋아질 수 있다.
Activie Wrap
- 일부 thread가 요구하는 register 공간 할당받지 못할 수 있다.
- (#thread in a block) * (register per thread) > registers in a SM
- Active warp
- wrap 내부의 모든 스레드들이 요구하는 register 공간을 가져야 한다.
- Activie warp을 늘리기 위해 적당한 register 공간을 배분해야 한다.
Activie Block
- 하나의 블록에서 메모리 자원이 요구되는 것들을 모두 가지고 있는 것(?)
- Register - all warps in a block are active wrap
- Shared memory space
- SM 내의 Active blocks은 동시에 실행될 수 있다.
- Activie Block을 늘리기 위해 적당한 Shared memory 공간을 배분해야 한다.
Occupancy(얼마나 가득 차 있는가)
= (# of active warp) / (# of maximum warps)
이론적으로 가능한 warp에 비해 active warp이 얼마나 존재하는가
많은 active block이 있을수록 높은 성능의 병렬 처리가 될 수 있는 확률이 높다.
kernal과 thread layout을 최대한 많은 active warp을 낼 수 있도록 설계해야 한다.
- thread당 register의 수
- block당 thread의 수
- block당 shared memory 크기
CUDA C/C++의 Device에 가보면 Max Used Register를 통해 사용되는 Register의 수를 제한할 수 있다.
Occupancy Calculator
설계된 kernel과 thread layout에 따른 occupancy를 계산해준다. (참고만 하도록 하자.)
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1\tools
경로에 들어가 보면 엑셀 파일로 calculator가 존재한다.
'School Study > Multi Core Programming' 카테고리의 다른 글
CUDA Stream & Concurrent Execution (0) | 2019.05.21 |
---|---|
Synchronization in CUDA (0) | 2019.05.21 |
Maximizing Memory Throughput (0) | 2019.05.14 |
CUDA Execution Model (0) | 2019.05.07 |
CUDA Thread (0) | 2019.04.23 |