LAB / GPU PROGRAMMING

DAY 05 / 30 · FOUNDATIONS & MENTAL MODEL · ~12 MIN READ

Warp divergence

What happens when threads in a warp disagree on a branch, and what that costs.

01 · BREAKING LOCKSTEP

What a branch actually does to a warp

Day 04's deal was lockstep: all 32 lanes fire the same instruction. So what does the hardware do with this perfectly ordinary code?

if (threadIdx % 2 == 0) x = x * 2; else x = x * 3;

Lanes 0, 2, 4… need the first line. Lanes 1, 3, 5… need the second. One warp, one program counter, two different instructions wanted at the same time. The warp can't do that — so it does the only thing lockstep can: both paths, one after the other, with the uninterested lanes masked off. Two passes where the code reads as one.

02 · THE EXPLORABLE

Watch the warp serialize

Run both versions. The divergent one executes the branch in two masked passes — cobalt lanes are computing, dim lanes are sitting out. The uniform one needs just one pass for all 32 lanes. Same math, same warp, twice the clocks.

ONE WARP · A BRANCH · TWO WAYS TO RUN IT
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

computing · masked off

clock passes: 0

press run, then try the other mode

model assumes pre-Volta lockstep · modern chips can interleave independent warps, but a diverged warp still serializes its own paths

03 · THE HONEST FOOTNOTE

It got better. It didn't go away.

Since the Volta generation, warps have independent thread scheduling: the hardware can swap between the two paths at instruction granularity, which keeps certain communication patterns alive that used to deadlock. But the two paths still take turns. Divergence is a throughput problem, not a correctness problem, and no generation has made two passes cost one.

The craft rule that survives every generation: diverge across warps, not within them. If lanes 0–15 want path A and lanes 16–31 want path B, two whole warps each run clean, single-pass code — because the branch lined up with warp boundaries. Data layout decides where branches land, which means data layout decides whether you pay the tax. That thought returns on day 07 with memory.

CHEATSHEET · DAY 05
  • 01A branch is two serialized passes. The warp runs each path with the other lanes masked. Two paths, twice the clocks.
  • 02Masked lanes still cost. They occupy their slot in the warp; they just don't compute. Throughput halves per pass.
  • 03Align branches with warps. If whole warps agree on the branch, nothing serializes. Data layout decides that — not luck.

Next: day 06 turns day 01's latency-hiding argument into arithmetic. How many warps can you actually keep resident on one SM — and what limits them.

get in touch