Question bank — CUDA cores and execution model
This is a misconception clinic for CUDA cores and the execution model. Every item below targets a specific trap — a place where intuition from CPUs, from raw arithmetic, or from marketing numbers leads you astray. Read the question, guess before you reveal, then check your reasoning against the answer.
Before we start, a quick vocabulary refresh so nothing below uses a term you haven't pinned down:
Recall The five words every trap below leans on
CUDA core ::: A single arithmetic-logic unit (ALU) that does one FP32 or integer op per clock — not a full CPU-style core. Warp ::: A fixed group of 32 threads that execute the same instruction in lockstep under one shared scheduler. SM (Streaming Multiprocessor) ::: The real "processor" unit — a bundle of 64–128 CUDA cores plus schedulers, registers, and shared memory. SIMT ::: Single Instruction, Multiple Thread — one instruction drives many threads, but each thread keeps its own register state and can diverge. Occupancy ::: How many warps are resident on an SM relative to the maximum — the fuel supply for latency hiding.
True or false — justify
Recall A CUDA core is a small CPU core.
False. ::: A CUDA core is just an ALU — it has no instruction decoder, no branch predictor, and no private cache. It shares all control logic with 31 other cores in its warp, so it cannot run an independent instruction stream the way a CPU core can.
Recall A GPU with 16,384 CUDA cores can run 16,384 fully independent programs at once.
False. ::: Cores are yoked together in warps of 32 under shared control, so you get at most (cores ÷ 32) independent instruction streams, and even those are grouped per SM. Independence lives at the warp level, not the core level.
Recall If an SM has 128 cores and a warp is 32 threads, one warp instruction finishes in a quarter of a cycle.
False. ::: A warp instruction is atomic per issue — its minimum latency is one cycle. Extra cores give the SM throughput (it can issue several warps' instructions the same cycle), not lower latency for any single warp.
Recall The warp size of 32 was derived from a particular SM's core count.
False. ::: 32 is a fixed hardware convention — a power of two that simplifies address masking and thread indexing, inherited from the 8/16/32 SIMD lineage. SMs with 64 or 128 cores still use 32-thread warps; they just issue more warps per cycle.
Recall In SIMT, threads in a warp physically
cannot take different branches.
False. ::: They can diverge — each thread owns its register state. But when they do, the warp serialises: it runs the if path with the else-threads masked off, then the else path with the if-threads masked off. Divergence is legal but slow, not forbidden.
Recall Doubling the number of resident warps always doubles memory-latency hiding.
False. ::: Only up to the point where the latency window is fully covered (). Beyond that, extra warps sit idle — they add nothing because the ALUs were already kept busy. See occupancy.
Recall A block always runs on exactly one SM.
True. ::: A block is guaranteed to reside on a single SM for its whole lifetime — that is why its threads can share fast shared memory and synchronise with barriers. The grid, by contrast, spreads across all SMs.
Recall Coalesced access means the threads read the
same address.
False. ::: Coalescing means threads read consecutive addresses (thread 0 → A[0], thread 1 → A[1], …) so the hardware fuses them into one 128-byte transaction. All-reading-the-same address is a broadcast, a different (also efficient) pattern.
Recall Transaction efficiency
is measured in gigabytes per second. False. ::: is dimensionless — bytes over bytes, a fraction between 0 and 1. Effective bandwidth is times peak DRAM bandwidth; itself is just the wastage ratio.
Recall SIMT and SIMD are the same thing with a different name.
False. ::: In SIMD one instruction fills fixed vector lanes with no per-lane control flow. In SIMT each thread has its own program counter and register state and may diverge — the hardware masks lanes to fake independence. SIMT is SIMD with a per-thread illusion of freedom.
Spot the error
Recall "To hide 200-cycle memory latency with
schedulers and compute cycles per warp, I need warps." Error: dropped the scheduler count. ::: warps. Each cycle the SM can issue warp-instructions, so the latency window has capacity , not just .
Recall "My SM caps at 64 resident warps and I computed
, so I'll just raise occupancy to 80 warps." Error: 64 is a hard ceiling. ::: You cannot exceed the SM's resident-warp cap. Since , full hiding is impossible by adding warps — you must instead raise compute intensity (do more work per memory op) to lower .
Recall "Uncoalesced access is at most 2× slower because the data is still in DRAM."
Error: transactions multiply. ::: A stride-32 pattern turns one 128-byte transaction into up to 32 transactions for the same useful bytes, so falls from to — up to 32× slower, not 2×.
Recall "I'll use 2000 threads per block to maximise parallelism."
Error: block cap is 1024. ::: A single block holds at most 1024 threads (it must fit on one SM). Massive parallelism comes from launching many blocks in the grid, not from oversized blocks.
Recall "The warp scheduler pays a big context-switch cost each time it swaps warps, so swapping is expensive."
Error: zero-overhead switching. ::: All resident warps have their registers already loaded in the SM's register file. Switching warps is free — the scheduler just picks a different ready warp next cycle. This is the whole point of keeping many warps resident.
Recall "A CUDA core computes
sin(x) in one cycle just like a multiply."
Error: wrong unit. ::: CUDA cores handle FP32 FMA, integer, and logic ops. Transcendentals like sin/exp run on separate special-function units (SFUs) on the SM, at lower throughput — not on the CUDA cores.
Why questions
Recall Why does branchy, per-element-different code kill GPU performance?
::: Because a warp shares one instruction stream. When threads diverge, the hardware runs each path sequentially with the other threads masked off — an if/else split can halve throughput, and deep nesting compounds it. GPUs win only when the same instruction applies to all 32.
Recall Why organise threads into blocks at all instead of one flat pool?
::: Blocks give a scalability abstraction: 1000 blocks run on a 10-SM GPU (100 blocks/SM) or an 80-SM GPU (~12 blocks/SM) with no code change. They also define the scope of shared memory and barrier synchronisation. See parallel patterns.
Recall Why does raising compute intensity
help more than adding warps once you hit the warp cap? ::: Because shrinks as grows. If you can't add warps (cap reached), lowering the requirement is the only lever left — do more arithmetic per memory fetch so fewer warps are needed to cover the same stall.
Recall Why is a warp exactly 32 and not, say, 30?
::: 32 is a power of two, which makes thread-index computation and lane-masking a matter of cheap bit operations (masking, shifting) rather than division. Non-powers-of-two would complicate every address-generation step in hardware.
Recall Why do registers being "per-thread" limit how many threads can be resident?
::: The SM has a fixed register file (~65,536 32-bit registers on many recent SMs). If each thread grabs many registers, fewer threads fit: roughly registers per thread for resident threads. Register-hungry kernels therefore lower occupancy and weaken latency hiding.
Recall Why does memory coalescing matter
specifically at the warp level? ::: Because the hardware inspects the 32 addresses a warp requests together and tries to fuse them into minimal 128-byte transactions. Coalescing is a property of the warp's collective access pattern, not of any single thread's access.
Edge cases
Recall A warp launches but only 20 of its 32 threads pass
if (i < N). What do the other 12 do?
::: They are masked off — they still occupy their lanes and consume the cycle, but their results are discarded. The warp cannot run faster than 32-wide; the extra 12 lanes are simply wasted work at the array tail.
Recall You launch a grid where
N is not a multiple of the block size. Is that a bug?
::: No — the standard idiom numBlocks = (N + threadsPerBlock - 1) / threadsPerBlock rounds up, launching a few extra threads, and the if (i < N) guard masks the overhang. The final warp is partly masked, which is normal.
Recall A block has 100 threads. How many warps does it use, and what happens to the leftover lanes?
::: warps (96 + 4 threads). The fourth warp runs with only 4 active lanes and 28 masked-off — wasted capacity. This is why block sizes are usually chosen as multiples of 32.
Recall Every thread in a warp reads the identical address
A[0]. Coalesced or catastrophic?
::: Neither wasteful — this is a broadcast. The hardware fetches the 128-byte line once and hands the value to all 32 threads, so stays high. Uniform reads are efficient; it's scattered reads that hurt.
Recall All 32 threads in a warp diverge to 32
different code paths. Worst-case slowdown? ::: Up to 32× — the warp must serialise all 32 paths one at a time, running each with a single active lane. This is the pathological limit of branch divergence.
Recall What happens to latency hiding when a kernel has only ONE resident warp?
::: There is nothing to switch to. The moment that warp stalls on memory (100–400 cycles), the SM's ALUs sit idle the whole time — no hiding at all. This is why single-warp kernels waste the GPU almost completely, a key lesson for training kernels.
Recall A double-precision (FP64) op is issued. Does every CUDA core handle it at full FP32 rate?
::: No. FP64 runs on separate, far fewer double-precision units on the SM. On consumer GPUs FP64 throughput can be a small fraction (e.g. 1/32) of FP32 — so a DP-heavy kernel bottlenecks even with cores "available."