[NVIDIA GPU] Memory Coalescing이란? (Coalesced Memory Access)

지난번에 GPU의 메모리 종류에 대해서 정리를 하였다. Memory Coalescing에 대해서 작성을 하려고 하였으나 모르는 부분이 많아서 먼저 메모리 구조를 알아보았다. CUDA 코딩을 할 때 가장 중요한 부분이 memory coalescing이다. 실제로 성능에 큰 차이가 발생한다. 간단한 vector (x, y, z)를 access 하는 코드를 만들어서 성능 차이를 비교해보았는데 memory coalescing을 고려한 코드와 그렇지 않은 코드의 성능 차이가 최대 50~100% 이상 발생하였다 (이 결과는 개인적으로 궁금해서 작성한 부분이라 실제 성능의 향상 폭은 이보다 작을 수도 이보다 클 수도 있다).

우선 memory coalescing을 설명하기 이전에 warp에 대한 개념이 필요하다. NVIDIA GPU의 경우 32개의 thread 단위로 instruction을 실행하는데 이 32개의 단위를 warp라고 한다. AMD GPU의 경우 64개의 thread가 하나의 instruction을 실행하는데 이 단위를 wavefront 라 한다. GPU의 경우 warp 또는 wavefront의 thread가 모두 같은 instruction을 실행한다.

ns_attach_image_5031480554749531

그림 1: Aligned and Sequential Memory Access

결과적으로 warp의 모든 thread가 같은 memory instruction을 issue 하게 된다. 이렇게 실행된 32개의 memory request가 연속적인 memory address를 가지고 있으며 하나의 cache line을 access 하는 경우를 coalesced memory access라고 한다. 그림 1은 coalesced memory access의 예제를 보여준다. 그림과 같이 warp의 모든 thread가 하나의 cache line을 access 하며 memory access address가 연속적인 것을 볼 수 있다. 이 경우 warp의 모든 thread의 memory instruction을 하나로 합쳐져서 memory request가 생성된다. Warp는 한 번의 memory access만으로 32개 thread의 메모리 request를 모두 처리할 수 있다.

ns_attach_image_5051480554749537

그림 2: Misaligned Access Pattern

그림 2는 그림 1과 다르게 warp의 thread가 access 하는 memory request가 하나의 cache line에 들어 있지 않은 경우이다 (하지만, memory access address는 연속적이다). Address가 연속적이긴 하지만 하나의 cache line에 들어가지 않기 때문에 하나의 warp는 2번의 cache access가 필요하다. 이 경우 하나의 cache line이 아니라 2개의 cache line을 access 해야 한다. 결과적으로 warp에서 하나의 memory instruction을 처리하기 위해서는 총 2번의 memory request를 생성해야 한다. 최소 2개의 cache line을 읽어보는 동안 warp는 실행할 수 없을 수도 있다 (L1은 128byte (4byte * 32) 단위로 cache line이 구성되어 있다. 반면 L2 cache의 경우 32-byte 단위로 cache line이 구성되어있다). 또한, 더 많이 생성된 memory request 처리를 위해서 더 많은 memory bandwidth를 사용해야 한다.

ns_attach_image_5331480555223431

그림 3: Aligned but Not-Sequential Access

그림 3은 memory address가 연속적이지는 않지만 하나의 cache line에 모든 address가 들어가는 경우이다. CUDA compute 2.0 이하의 경우 1개 이상의 memory request가 발생한다. 하지만 CUDA compute 2.0 이상에서는 위와 같은 예제도 하나의 memory address로 합쳐져서 한 번의 memory access만 필요하다. 결과적으로 CUDA compute 2.0 이상의 경우 memory address가 연속적이지 않아도 하나의 cache line만 접근할 경우 coalesced memory access가 가능하다.

하나의 warp에서 여러 번의 memory access가 발생하는 경우를 memory divergence라고 한다 (논문 등에서). 최악의 경우 하나의 memory instruction처리를 위해서 총 32번의 memory request가 필요 할 수도 있다 (Warp의 모든 thread가 각각의 다른 cache line에 접근할 경우). Memory divergence를 최소화하고 CUDA 프로그램 성능을 높이기 위해서는 memory access pattern을 고려하여 CUDA 프로그램을 제작해야 한다.

출처

  1. https://cvw.cac.cornell.edu/gpu/coalesced
  2. http://docs.nvidia.com/cuda/cuda-c-best-practices-guide/#device-memory-spaces

Leave a Comment