SIMT Execution and Warp Divergence

Keywords: simt execution model divergence,warp divergence branch,predicated execution gpu,branch reconvergence hardware,warp voting functions

SIMT Execution and Warp Divergence characterizes the single-instruction-multiple-thread execution model where all threads in a warp must execute same instruction, forcing serialized computation of divergent control flow and enabling fine-grained synchronization via warp voting functions.

SIMT Execution Model Fundamentals

- Warp Definition: 32 threads executing in lockstep (Ampere, Hopper). All threads execute same instruction simultaneously (same program counter).
- Program Counter Synchronicity: All threads in warp share PC. Branches create divergence; some threads take branch, others don't.
- Instruction Level Parallelism (ILP): Warp issues 1-4 instructions per cycle (depending on available execution units, latency). Dual-issue allows concurrent FP32 + memory operations.
- SIMT vs SIMD: SIMT scalar (each thread has scalar registers), SIMD vector (threads share vector registers). SIMT simpler programming model.

Warp Divergence at Branch Points

- Branch Condition: if (thread_id < 16) {...}. Some threads take branch, others skip.
- Divergence Impact: Warp serializes: execute if-branch code with active threads masking (inactive threads stall). Then execute else-branch for alternate threads.
- Serial Execution: Both branches executed sequentially (not parallel). Effective throughput halved if 50/50 branch distribution (worst case).
- Convergence Stack: Hardware maintains predication masks tracking which threads active. Stack-based mechanism (IPDOM tree) manages nesting.

Predicated Execution

- Predicate Register: Boolean flag per thread (32-bit register with predicate bits). Instruction conditional on predicate (@p0 instruction executes if p0 true for thread).
- Predication Implementation: All instructions in branch executed, but predicate masks results. Inactive threads produce side effects (state unchanged).
- Branch Elimination: Small if-else blocks predicated (no explicit branch). Reduces branch misprediction penalty, enables better ILP.
- Predicate Overhead: Extra instruction (set predicate), + masked instruction execution (no branch, but no result storage). Faster than explicit branch if block small (<4 instructions).

Branch Reconvergence via IPDOM Stack

- Instruction Level Dominance (IPDOM): Reverse dominance in CFG (control flow graph). IPDOM identifies post-dominating blocks (executed after all branches reconverge).
- Reconvergence Point: IPDOM target = block where all branches from divergence point rejoin. All threads active again.
- Stack Mechanism: Upon branch, hardware pushes divergence info (predicate masks, target) on stack. Upon reaching reconvergence, pops stack.
- Nesting Complexity: Nested divergence (if within if) creates stack depth > 1. Deep nesting (>8 levels) possible but rare.

Warp Voting Functions

- __ballot_sync(mask, predicate): Ballot across warp. Returns 32-bit integer with bit i set if thread i's predicate true. Mask specifies participating threads.
- __any_sync(mask, predicate): Reduction AND. Returns 1 if any thread's predicate true, else 0 across masked warp.
- __all_sync(mask, predicate): Reduction AND. Returns 1 if all threads' predicate true, else 0.
- Use Cases: ballot() for warp-level histogram; any() for early exit (any thread found solution); all() for synchronization (all threads ready).

Avoiding Divergence via Data-Dependent Branching Analysis

- Divergence Detection: Profiler reports "warp stall due to branch" metric. Indicates branch frequency and impact.
- Data-Dependent Patterns: Analysis of branch conditions determines if thread divergence likely. Example: if (array[tid] > threshold) may have high divergence if array values random.
- Sorting Trick: For highly-divergent conditionals, sort data by condition value. Clusters threads with same condition together (better branch prediction, less divergence).
- Early Exit: Loop termination conditions checked via ballot(). Mask inactive threads (data processed), continue active threads. Reduces warp idleness.

Structured vs Unstructured Control Flow

- Structured Flow: Single entry/exit loops, if-else blocks. Compiler easily determines reconvergence points. Simple hardware handling.
- Unstructured Flow: Multiple exits (break, return), goto statements. Complicates reconvergence analysis. Modern GPUs handle but with overhead.
- Best Practice: Favor structured loops/conditionals. Avoid deep nesting. Minimize branches in hot kernels.

Performance Implications

- Branch Prediction: Modern GPUs (Hopper) have branch predictors similar to CPUs. Predicted branches have <5 cycle penalty (vs ~15 cycles misprediction).
- Occupancy Trade-off: Loop divergence (some threads exit early) may limit occupancy (warps with all threads done freed). Improved throughput overall.
- Warp Efficiency Metric: Percentage of threads executing useful work. Divergence reduces warp efficiency (inactive threads masked). Target >80% warp efficiency.

Want to learn more?

Search 13,225+ semiconductor and AI topics or chat with our AI assistant.

Search Topics Chat with CFSGPT