skills/gpu/gpu-memory-model/SKILL.md
GPU memory model skill for SIMT execution and memory hierarchy. Use when analyzing warp divergence, memory coalescing, shared memory bank conflicts, cache behavior, atomics, or occupancy tradeoffs. Activates on queries about SIMT, warp coalescing, bank conflicts, wavefront, GPU occupancy, or memory-bound kernels.
npx skillsauth add mohitmishra786/low-level-dev-skills gpu-memory-modelInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Explain the GPU execution and memory model for agents optimizing kernels: SIMT execution, warp (32) vs wavefront (64) divergence costs, global memory coalescing rules, shared memory bank conflicts, L1/L2 cache behavior, atomic memory ordering, and the occupancy-vs-latency-hiding tradeoff.
GPU hardware
├── Device
│ └── SM / CU (Streaming Multiprocessor / Compute Unit)
│ ├── Warp schedulers (NVIDIA) or Wavefront schedulers (AMD)
│ │ └── Warp/Wavefront (32 or 64 threads in lockstep)
│ ├── Register file (partitioned per thread)
│ ├── Shared memory / LDS (per SM)
│ └── L1 cache (often shared with shared memory)
└── L2 cache (device-wide) → DRAM/HBM
SIMT (Single Instruction, Multiple Threads): one instruction stream drives a warp/wavefront; each thread has its own registers and thread ID but executes the same instruction in lockstep.
| Vendor | Unit size | Name | |--------|-----------|------| | NVIDIA | 32 threads | Warp | | AMD | 64 threads | Wavefront |
Implications:
When threads in a warp take different branches, the hardware serializes paths:
// Divergent: half warp does A, half does B → 2x instruction issue
if (threadIdx.x % 2 == 0) {
result = expensive_a(data[idx]);
} else {
result = expensive_b(data[idx]);
}
// Non-divergent: all threads same path
result = expensive_a(data[idx]);
Mitigations:
?: (trade compute for uniformity)if (data[i] < threshold) per thread with scattered outcomesDivergence cost ≈ sum of paths taken (not max).
NVIDIA coalescing rule (simplified): threads in a warp accessing consecutive 4-byte words → single 128-byte transaction.
// Coalesced: consecutive threads → consecutive addresses
int idx = blockIdx.x * blockDim.x + threadIdx.x;
float val = data[idx];
// Uncoalesced: stride access
float val = data[threadIdx.x * stride]; // stride > 1
// Partially coalesced: misaligned start
float val = data[base + threadIdx.x * 3];
AoS vs SoA impact:
// AoS — poor coalescing when reading one field
struct Particle { float x, y, z; };
float x = particles[i].x; // threads read with stride 3
// SoA — coalesced
float x = pos_x[i];
Shared memory is divided into 32 banks (4-byte words). Simultaneous accesses to different addresses in the same bank serialize.
__shared__ float tile[32][32];
// Bank conflict: all threads access tile[threadIdx.x][0]
// 32 threads, 32 banks, but column 0 → same bank per row offset
float val = tile[threadIdx.x][0];
// Fix: pad columns to break bank alignment
__shared__ float tile[32][33]; // +1 padding
Detection: Nsight Compute l1tex__data_bank_conflicts_pipe_lsu_mem_shared_op_ld.sum or NCU shared load conflict metrics.
| Level | Scope | Notes | |-------|-------|-------| | L1 | Per-SM | Often unified with shared mem; configurable split | | L2 | Device-wide | Cache lines typically 128 bytes | | Texture/L1 readonly | Per-SM | Cached read-only path for uniform access |
Cache-friendly patterns:
// Cache-friendly tile load
for (int t = 0; t < num_tiles; t++) {
__shared__ float smem[TILE][TILE];
smem[ty][tx] = global[row * N + t * TILE + tx];
__syncthreads();
// compute from smem — L1/L2 only hit on first load per tile
}
GPU atomics (atomicAdd, atomicCAS, atomicExch) provide sequential consistency among threads targeting the same address, but high contention serializes execution.
// Bad: all threads atomic to one counter
atomicAdd(&global_sum, local_val);
// Better: per-block reduction, one atomic per block
__shared__ float block_sum;
// ... warp reduce to block_sum ...
if (threadIdx.x == 0)
atomicAdd(&global_sum, block_sum);
HIP/CUDA memory fences:
__threadfence_block(); // visible to threads in same block
__threadfence(); // visible to all threads on device
__threadfence_system(); // visible to host (expensive)
Occupancy tradeoff
├── High occupancy → more warps to hide memory latency
│ └── Costs: fewer registers/SM, less shared mem per block
└── Low occupancy + high ILP → enough independent instructions per warp
└── Works for compute-bound kernels with deep pipelines
Decision tree:
Memory-bound kernel?
├── Yes → maximize active warps (occupancy), coalesce, tile with shared mem
└── No (compute-bound) → may lower occupancy if registers enable more ILP
# Measure achieved occupancy
ncu --metrics sm__warps_active.avg.pct_of_peak_sustained_active ./app
Rule of thumb: memory-bound kernels need occupancy ≥ 50%; compute-bound may run well at 25% with sufficient instruction-level parallelism.
| Symptom | Likely cause | Check |
|---------|--------------|-------|
| Low DRAM throughput | Uncoalesced access | NCU memory workload analysis |
| Shared load stalls | Bank conflicts | Pad arrays; change access pattern |
| High stall: barrier | Missing __syncthreads or divergence at barrier | synccheck |
| Atomic bottleneck | Too many contended atomics | Hierarchical reduction |
| Low occupancy | Register/shared mem pressure | launch__occupancy_limit_* metrics |
| Symptom | Cause | Fix | |---------|-------|-----| | 10x slower after SoA→AoS change | Strided coalescing broken | Keep hot fields in SoA layout | | Tiled matmul slower than naive | Bank conflicts in shared tile | Pad shared array columns | | Identical code, different perf NVIDIA vs AMD | Warp 32 vs wavefront 64 | Retune block size and reductions | | Atomics correct but slow | Global contention | Block-level reduce first | | High L2 hit but still slow | L2 bandwidth saturated | Reduce total bytes moved |
skills/gpu/cuda — practical kernel patterns using this modelskills/gpu/cuda-profiling — metrics to validate coalescing and occupancyskills/gpu/hip-rocm — AMD wavefront-specific tuningskills/low-level-programming/cpu-cache-opt — CPU cache concepts (analogous)skills/low-level-programming/simd-intrinsics — vector width on CPU sideskills/profilers/hardware-counters — general cache miss measurementdevelopment
QEMU/KVM skill for virtualization and kernel development. Use when running qemu-system-x86_64 with KVM, configuring virtio devices, VFIO passthrough, QMP monitor, libvirt, or booting custom kernels. Activates on queries about QEMU, KVM, virtio, VFIO, virsh, virt-install, or -kernel -append.
development
Hardware virtualization internals skill for Intel VT-x and AMD-V. Use when studying VMCS/VMCB, EPT/NPT page tables, VMEXIT handling, APIC virtualization, or building minimal hypervisors. Activates on queries about VMX, SVM, VMCS, EPT, NPT, VMEXIT, or type-1 hypervisor.
testing
Linux containers internals skill for namespaces, cgroups, and OCI. Use when understanding clone/unshare namespaces, cgroups v2 limits, overlayfs, runc, seccomp profiles, capabilities, or escape mitigations. Activates on queries about namespaces, cgroups, overlayfs, runc, seccomp-bpf, OCI spec, or container escape.
tools
Reverse engineering skill for binary analysis. Use when decompiling with Ghidra, analyzing with radare2, scripting RE tools, triaging with strings/file/xxd, or diffing binaries. Activates on queries about Ghidra, radare2, r2, decompiler, Binary Ninja, Diaphora, or stripped binary analysis.