AI Infra Interviews logo
GPU & Accelerator Architecture / 01
easy★ EssentialNewNVIDIAGoogleCoreWeave

Walk me through the CUDA execution model: what are grids, blocks and warps, and what does the hardware actually schedule?

A grid is a request, a block is a residency unit, a warp is what the scheduler issues. Which of those pins to an SM, why 32 matters, and how a GPU hides a 600 ns memory latency with no branch predictor and a cache that is tiny per thread.

Updated Sep 2026 · Grounded in real AI infrastructure interview loops and written to a senior-engineer editorial bar, with every number worked and every diagram hand-built.

TL;DR: A kernel launch is a grid of thread blocks; each block is placed whole on one streaming multiprocessor and stays there until it finishes; inside the SM the hardware schedules in warps of 32 threads, one instruction per warp per issue slot. Latency is hidden because an SM holds up to 64 resident warps and switches between them every cycle at zero cost, so while one warp waits 600 ns on HBM, dozens of others issue. The programmer's job is to give the SM enough independent warps, and enough independent work per warp, that the memory pipe never drains.

How to approach it

Say the three programmer-side levels first (grid, block, thread), then immediately translate each into what the hardware does with it, because the interviewer is scoring the translation, not the vocabulary. Ask whether they want the Hopper numbers (132 SMs, 64 warps per SM) or the general model. Work one example kernel through placement: how many blocks land per SM and how many warps that gives the scheduler. Close with the latency-hiding sentence, because that is the idea everything else in GPU performance is built on.

A strong answer

A typical situation: a kernel is launched with 1,024 threads per block because that was the largest number the docs mentioned, it runs at two thirds of the speed of the same kernel at 256, and nobody in the review can say why. The answer is in the placement arithmetic below, and it needs both vocabularies.

The GPU Execution Model has two vocabularies that map onto each other.

On the software side, a launch is kernel<<<gridDim, blockDim>>>. The grid is the whole problem, the block is a group of threads that can share memory and synchronize with __syncthreads(), and the thread is the unit the code is written for. Threads inside a block have an index; blocks inside a grid have an index; nothing in the language says how many run at once.

On the hardware side, an H100 has 132 SMs. When the grid is launched, a hardware work distributor hands blocks to SMs. A block is placed whole on one SM: all of its threads live there, its shared memory is carved from that SM's 228 KB, its registers come from that SM's 64K-entry register file, and it does not migrate. When every thread in the block exits, the resources are freed and the distributor places the next block. Blocks that have not been placed yet are simply waiting; that is why launching 10,000 blocks on 132 SMs is fine and why blocks must not depend on each other running concurrently.

Inside the SM, the unit that gets scheduled is the warp: 32 consecutive threads of a block. The SM has four warp schedulers (four partitions), and each cycle each scheduler picks one eligible resident warp and issues one instruction for all 32 lanes. A thread does not exist to the scheduler; only warps do. This is why a block of 33 threads costs two warps, why divergence inside a warp serializes, and why memory access patterns are judged per warp.

The placement arithmetic is a chain a candidate should be able to do out loud:

SM limits (H100 SXM): 2,048 threads, 64 warps, 32 blocks, 65,536 registers, 228 KB shared per SM

kernel: 256 threads per block, 64 registers per thread, 16 KB shared per block

threads limit:   2,048 ÷ 256                  = 8 blocks
register limit:  65,536 ÷ (256 × 64) = 65,536 ÷ 16,384 = 4 blocks
shared limit:    228 KB ÷ 16 KB               = 14 blocks
resident blocks = min(8, 4, 14)                = 4 blocks
resident warps  = 4 × (256 ÷ 32)               = 32 warps of a possible 64  (50% occupancy)

sanity: registers are the binding limit here, which is the usual case for anything
        beyond a trivial kernel; halving registers per thread would double resident warps

Now the latency question. An HBM access on H100 is on the order of 600 ns, which at 1.8 GHz is about 1,000 cycles. A CPU core spends most of its transistors making sure one thread rarely waits that long: big private caches, out-of-order windows, prefetchers, branch predictors. An SM does none of that per thread. Its L1 is 256 KB shared by up to 2,048 threads, about 128 bytes each, and there is no out-of-order execution. Instead, when a warp issues a load, the scheduler marks it not-eligible and, on the very next cycle, issues from a different warp. Switching warps costs nothing because every resident warp's registers are already in the register file; there is no context to save. With 32 to 64 resident warps each holding several loads in flight, the SM keeps enough bytes moving to cover the latency.

How many bytes must be in flight is another short chain:

per-SM share of bandwidth = 3.35 TB/s ÷ 132 SMs ≈ 25 GB/s per SM
bytes in flight to cover latency = bandwidth × latency = 25 GB/s × 600 ns ≈ 15 KB per SM
with one 16-byte load per thread outstanding: 15 KB ÷ 16 B ≈ 950 threads ≈ 30 warps
sanity: 30 warps is about half the SM's 64, so a kernel at 50% occupancy with one load in
        flight per thread is roughly at the edge; more loads per thread (unrolling) buys
        the same coverage with fewer warps

That last line is the practical lesson: latency hiding comes from parallelism, whether across warps (occupancy) or within a warp (independent loads per thread), and the two are interchangeable. Caches on a GPU exist to save bandwidth on reuse, not to make a single thread fast.

rendering diagram…

The decision this drives: choose block size and register budget so that the SM has enough resident warps, or enough loads per thread, to cover latency, and no more. The reversal condition: a kernel whose per-thread state is large (attention, GEMM tiles), where forcing higher occupancy spills registers to local memory and the extra traffic costs more than the extra warps save. Occupancy and Register Pressure is the whole of that trade, and ptxas -v (via nvcc -Xptxas -v) prints the register count and the spill bytes that decide it, which is faster than reasoning about the source.

What interviewers probe next

  • "Why is a warp 32 threads?" It is the width of the SIMT datapath the scheduler issues to; the software has no say. A block of 100 threads is 4 warps, the last one 4/32 utilized, so pick multiples of 32.
  • "Can two blocks on the same SM talk to each other?" Not through shared memory, which is per block. They can through global memory and atomics, but nothing guarantees they are resident at the same time unless you use cooperative launch.
  • "What happens when a block calls __syncthreads() and one warp has exited?" On current hardware exited threads are treated as arrived; the classic hang is a barrier inside a branch that only some threads take.
  • "Where does a thread block cluster fit?" Hopper adds a level between block and grid: up to 16 blocks guaranteed co-resident on one GPC with distributed shared memory. It is the first time the model has let blocks depend on each other's residency.

Common mistakes

  • Saying the GPU "runs all the threads in parallel." It runs up to 2,048 per SM at a time and queues the rest; the model only works because blocks are independent.
  • Describing warps as a software construct or a "group of 32 threads you pick." Warps are formed by the hardware from consecutive thread indices.
  • Claiming the L1 or L2 cache hides memory latency. It reduces traffic on reuse; latency is hidden by having other warps to issue.
  • Computing occupancy from threads only and forgetting registers, which are the binding limit for almost every real kernel.

Key takeaways

  • Grid is the request, block is the residency unit (whole block on one SM, never moves), warp of 32 is the scheduling unit.
  • H100 SM: 132 SMs, up to 64 warps and 2,048 threads resident, 65,536 registers, 228 KB shared; registers usually decide how many blocks fit.
  • Latency is hidden by switching between resident warps at zero cost; you need about 15 KB in flight per SM to cover 600 ns at H100 bandwidth.
  • Occupancy and per-thread independent loads are interchangeable ways to get those bytes in flight.
That one was free — and so are 10 answers per topic without an account. Signing in doubles that to 20, opens the Plus lessons in the courses, and remembers which topics you keep getting wrong.no card · Google sign-in · nothing to cancel
HOW DID IT GO?
0
READING SIGNED OUT

Signing in doubles your free answers, from 10 to 20 per topic, and the site starts remembering you: mastery per topic, bookmarks, and a next-focus recommendation. Free, no card.

Sign in free

The concepts behind this question

Ranked by how closely each one overlaps this question's topic, so the first card is the thing to read if the answer above moved too fast.

Foundational
🧩 GPU & Accelerator Architecture
GPU Execution ModelA GPU hides memory latency with parallelism instead of caches: thousands of threads in flight, scheduled in warps of 32, pinned to streaming multiprocessors that switch between warps for free whenever one stalls. Every performance conversation in an AI infra loop, from occupancy to why decode is slow, rests on this one mechanism.
Advanced
Kernels & Compilers🔒 Premium
Occupancy and Register PressureOccupancy is the fraction of an SM's 64 warp slots that are resident, and it is capped by the 65,536 registers and 228 KB of shared memory each block consumes. It decides how much memory latency the hardware can hide for free, but the fastest kernels on a GPU routinely run at 25 percent, so the interview skill is knowing when to raise it and when to stop.
Advanced
Kernels & Compilers🔒 Premium
Tiled Matrix MultiplicationA matrix multiply has enough reuse to be compute-bound, but only if the kernel captures that reuse in shared memory and registers instead of re-reading HBM. Tiling is how: a block owns an output tile, streams K-slices of A and B through shared memory, and each thread accumulates a small register tile. It is the live-coding exercise that separates people who know the roofline from people who have climbed it.
Foundational
Kernels & Compilers
CUDA Programming ModelCUDA splits a program into a host that allocates, copies and enqueues work, and a device that runs thousands of identical threads organized as a grid of blocks. Getting the split right, and knowing that a launch returns before the kernel runs, decides whether your first live-coding kernel produces a correct number or a silent zero.
UP NEXT ON YOUR JOURNEY
FEDITOR'S NOTE

Scored on whether the candidate separates the programmer's view (grid, block, thread) from the hardware's view (SM, warp scheduler, register file) and can say in one sentence why oversubscription, not caching, is what hides memory latency.

DISCUSSION · 0

No comments yet — be the first to share your approach.