The Hidden Bottleneck: How GPU Memory Hierarchy Affects Your Computing Experience

The GPU memory hierarchy is increasingly becoming an area of interest for deep learning researchers and practitioners alike. By building an intuition around memory hierarchy, developers can minimize memory access latency, maximize memory bandwidth, and reduce power consumption leading to shorter processing times, accelerated data transfer, and cost-effective compute usage. A thorough understanding of memory architecture will enable developers to achieve peak GPU capabilities at scale.

CUDA (Compute Unified Device Architecture) is a parallel computing platform developed by NVIDIA for configuring GPUs.

The execution of a CUDA program begins when the host code (CPU serial code) calls a kernel function. This function call launches a grid of threads on a device (GPU) to process different data components in parallel.

A thread is comprised of the program’s code, the current execution point in the code, as well as the values of its variables and data structures. A group of threads form a thread block and a group of thread blocks compose the CUDA kernel grid. The software components, threads and thread blocks, correspond directly to their hardware analogs, the CUDA core and the CUDA Streaming Multiprocessor (SM).

All together, these make up the constituent parts of the GPU.

image

Threads are organized into blocks and blocks are organized into grids. Figure taken from the NVIDIA Technical Blog.

image

Figure taken from NVIDIA H100 White Paper.

H100s introduce a new Thread Block Cluster architecture, extending GPU’s physical programming architecture to now include Threads, Thread Blocks, Thread Block Clusters, and Grids.

There are varying degrees of accessibility and duration for memory storage types utilized by a CUDA device. When a CUDA programmer assigns a variable to a specific CUDA memory type, they dictate how the variable is accessed, the speed at which it’s accessed, and the extent of its visibility.

Here’s a quick overview of the different memory types:

image

Figure taken from Chapter 5 of the 4th edition of the textbook, Programming Massively Parallel Processors.

Register memory is private to each thread. This means that when that particular thread ends, the data for that register is lost.

Local memory is also private to each thread, but it’s slower than register memory.

Shared memory is accessible to all threads in the same block and lasts for the block’s lifetime.

Global memory holds data that lasts for the duration of the grid/host. All threads and the host have access to global memory.

Constant memory is read-only and designed for data that does not change for the duration of the kernel’s execution.

Texture memory is another read-only memory type ideal for physically adjacent data access. Its use can mitigate memory traffic and increase performance compared to global memory.

The Speed-Capacity Tradeoff

It is important to understand that with respect to memory access efficiency, there is a tradeoff between bandwidth and memory capacity. Higher speed is correlated with lower capacity.

Registers

Cache Levels

Constant Cache

NVIDIA H100 White Paper.

Hopper, through its H100 line of GPUs, introduced new features to augment its performance compared to previous NVIDIA micro-architectures.

Thread Block Clusters

Asynchronous Execution

Hopper Whitepaper

CUDA Refresher: The CUDA Programming Model | NVIDIA Technical Blog

Similar Posts

Leave a Reply