Welcome back. In our last lesson, we quantified the performance of the GPU memory hierarchy, concluding with a stark reality: an access to global memory can cost over 600 clock cycles of latency. In the time a single thread waits for one piece of data from DRAM, a GPU's arithmetic units could have performed hundreds of calculations. For a machine designed for massive throughput, this "memory wall" presents a fundamental challenge. If the processor simply waited, performance would plummet.
This brings us to one of the most elegant and central principles of GPU architecture. Instead of trying to eliminate this unavoidable latency, the GPU is designed to hide it. This lesson delves into the precise mechanism behind this architectural sleight of hand. We will explore how the concurrent execution of many independent groups of threads, known as warps, allows the GPU to keep its computational units busy, even in the face of long memory delays.
The Chasm Between Compute and Memory
Before we see the solution, it's crucial to internalize the scale of the problem. A modern GPU is a paradox: it is an engine of computation that is rarely limited by the speed of its own arithmetic.
Mastering CUDA and High-Performance Computing, Part IV
This article from The Software Frontier vividly frames the core challenge of GPU programming. It argues that modern GPUs are memory-limited, not compute-limited, and traces this limitation back to the physics of data movement.
Read the introduction and the section titled The physics of moving bits through silicon. Focus on the latency figure for DRAM access (400-800 cycles) and the author's description of this as the "central engineering problem of GPU design."
The article drives home a point that is fundamental to your goal of mastering high-performance computing: the bottleneck is almost always the data pipeline, not the functional units themselves. The entire architecture of the Streaming Multiprocessor (SM) is built to "paper over this gap." Let's see how it does it.
The Solution: Orchestrated Parallelism
The GPU's strategy for hiding latency relies on having a large amount of parallel work available at all times. This work is organized according to the thread hierarchy we've discussed, but the fundamental unit of scheduling and execution on the hardware is the warp.
As a brief reminder, a warp is a group of 32 threads that execute the same instruction at the same time. This model is called Single Instruction, Multiple Thread (SIMT). When a kernel is launched, the grid of thread blocks is partitioned into these 32-thread warps. Each SM is then assigned one or more thread blocks, and its resident warps become the pool of work that it can schedule.
The key component responsible for managing this pool of work is the warp scheduler.
The Warp Scheduler in Action
The warp scheduler is the hardware logic on the SM that selects which warp to execute at any given clock cycle. Its operation is surprisingly simple but profoundly effective. On each cycle, the scheduler looks at its pool of resident warps and checks if any are eligible to execute their next instruction. A warp is eligible only if:
- It has a valid next instruction to execute.
- The instruction's input operands are ready (i.e., it's not waiting on a previous instruction's result).
- The required execution unit (e.g., an FP32 core, a load/store unit) is available.
Now, consider what happens when a warp executes an instruction with a long latency, such as LDG (Load from Global memory). The instruction is issued to a load/store unit, and the request for data is sent out towards DRAM. From that moment until the data returns and is written into a register—a process that can take 600+ cycles—that warp is no longer eligible for any subsequent instruction that depends on the loaded data. It has a data dependency that is not yet resolved.
Here is the crucial architectural insight: the warp scheduler does not wait.
Instead of stalling, the scheduler simply marks the waiting warp as ineligible and, on the very next cycle, scans its pool for another warp that is eligible. If it finds one, it issues an instruction from that warp, keeping the execution pipelines fed.
This process is illustrated perfectly in the diagram below.

To see a detailed, step-by-step animation of this process, the following video provides an excellent walkthrough.
03 CUDA Fundamental Optimization Part 1
This video, "CUDA Fundamental Optimization Part 1," offers a clear, visual explanation of the warp scheduling and latency hiding mechanism. The speaker simulates the process clock cycle by clock cycle.
Watch the segment from other work and wait. Follow the example where a simple C++ line is compiled into load and multiply instructions. Observe how the timeline shows Warp 0 stalling after issuing its two load instructions, and how the scheduler immediately switches to other warps (Warp 1, Warp 2, etc.) to fill the execution pipeline. The "big gap of empty space" for Warp 0 is the latency, and the work from other warps fills that gap.
The process described in the video is the heart of the GPU's throughput-oriented design. The GPU effectively interleaves the execution of many warps to hide the latency incurred by any single warp. It's analogous to a master chess player playing multiple games simultaneously; while one opponent is thinking, the master moves to the next board. Here, the "thinking time" is memory latency.
To manage this, the hardware uses a mechanism called a scoreboard. This is a hardware table that tracks the dependencies for every instruction in flight for every active warp. When a warp issues a load, the scoreboard marks the destination register as "not ready." The warp scheduler consults this scoreboard every cycle to determine which warps are eligible to run. When the data finally returns from memory, the scoreboard updates the register's status, and the warp becomes eligible for selection again.
The Need for "Enough" Work
This latency-hiding mechanism has a critical prerequisite: the scheduler must have a sufficiently large pool of eligible warps to choose from.
Imagine a global memory latency of 600 cycles. If you only have a few warps active on an SM, the scheduler might issue instructions for all of them, find they are all stalled waiting for memory, and then have no other work to do. As shown in the Diagram showing latency hiding image, the SM would enter an idle state, and the execution units would go quiet. Performance is lost.
To effectively hide a 600-cycle latency, the SM needs enough other warps to keep the execution pipelines busy for those 600 cycles. This is the primary motivation for launching kernels with a very large number of threads—far more than the number of physical cores on the GPU. The goal is to provide each SM with a deep queue of warps, maximizing the probability that the warp scheduler can always find one that is ready to execute.
How many warps is "enough"? The video presenter gives a target: on most architectures from Kepler to Volta, an SM can support a maximum of 64 resident warps. Since a warp has 32 threads, this corresponds to threads per SM. Achieving a high fraction of this maximum is the first and most important step in GPU optimization.
This concept is formalized by a metric called occupancy.
Mastering CUDA and High-Performance Computing, Part IV
This next section of the same article introduces occupancy as the "arithmetic of latency hiding" and connects it directly to the concepts we've just discussed.
Read the section titled Occupancy: the arithmetic of latency hiding. Pay attention to how occupancy is defined and what physical resources constrain it.
As the article states, occupancy is the ratio of active warps on an SM to the architectural maximum. High occupancy is not a goal in itself, but it is the primary tool for hiding memory latency. If a kernel is memory-bound (which many AI kernels are), low occupancy directly translates to lost performance because the SM will frequently stall, unable to find work to hide the long memory access times.
Conclusion
In this lesson, we have demystified how a GPU maintains high throughput despite enormous memory latency. Instead of waiting, the hardware leverages massive parallelism to find other useful work to do.
Key Takeaways:
- The Problem: Accessing global memory can stall a thread for hundreds of clock cycles, creating a "memory wall" that threatens to idle the GPU's powerful compute units.
- The Strategy: GPUs are designed to hide this latency rather than eliminate it. The core strategy is thread-level parallelism.
- The Mechanism: The warp scheduler on each SM manages a pool of active warps. When a warp stalls (e.g., waiting for a memory load), the scheduler marks it as ineligible and immediately switches to executing instructions from another eligible warp.
- The Prerequisite: This latency-hiding strategy is only effective if the SM has a large pool of active warps to choose from. If all warps are stalled simultaneously, the entire SM becomes idle.
- The Goal for the Programmer: To enable latency hiding, you must launch your kernels with enough threads to create a large number of active warps per SM, ideally approaching the hardware's maximum capacity.
We've established why having many active warps is crucial for performance. In our next lesson, we will dive deeper into the concept of SM Occupancy. We'll explore the specific hardware resources—registers and shared memory—that limit the number of warps that can be active simultaneously, and how to use the CUDA Occupancy Calculator to predict a kernel's theoretical performance.