CUDA programming model basics
What is CUDA?
CUDA (Compute Unified Device Architecture) is NVIDIA's parallel computing platform that allows programmers to harness GPU power for general-purpose computation, not just graphics.
WHY it exists: Graphics cards evolved to render millions of pixels in parallel. NVIDIA realized this massive parallelism could solve scientific, AI, and data problems if they gave programmers direct access.
WHAT it provides: A C/C+-like language extension + runtime libraries + compiler (nvcc) that let you write code for the GPU.
HOW it works: You write special functions (kernels) that run on the GPU. You organize work into threads, blocks, and grids. The GPU scheduler distributes these across its hardware.

The CUDA Execution Model: From First Principles
Why Paralelism Requires Structure
The fundamental problem: If you have 10,000 tasks and 10,000 workers, you need:
- A way to identify which worker does task
- A way to coordinate when workers need to share information
- A way to map logical work organization to physical hardware
CUDA solves this with a three-level hierarchy:
Memory Hierarchy
WHY memory matters: Moving data is expensive. A memory access can take 100× longer than a math operation. CUDA provides multiple memory types with different speed/scope tradeoffs.
Writing Your First CUDA Kernel
Vector Addition: The "Hello World" of CUDA
The problem: Add two arrays: C[i] = A[i] + B[i] for i = 0 to N-1
CPU version (sequential):
for (int i = 0; i < N; i++) {
C[i] = A[i] + B[i];
}
// Time: O(N) - one element per iterationCUDA version (parallel):
The Boundary Check: Why if (idx < N)?
The problem: If N = 1000and threadsPerBlock = 256:
- Need 4blocks × 256 threads = 1024 threads total
- But we only have 1000 elements
- Last 24 threads (idx 1000-1023) are extra
Without the check: These threads would access A[1000], A[1001], ... → out of bounds! → crash or garbage data
With the check: Extra threads do nothing (idle). Tiny performance cost, prevents disaster.
Synchronization and Cooperation
Thread Synchronization Within a Block
WHY needed: Threads in a block share resources (shared memory). Without synchronization, race conditions occur.
Derivation - Why reduction is O(log N): Each iteration halves the work. For256 threads: 8 iterations instead of 255sequential additions.
Global Synchronization
Key constraint: __syncthreads() only works within a block. Threads in different blocks cannot synchronize during kernel execution.
WHY: Blocks may execute in any order, or even concurrently on different SMs. Allowing inter-block synchronization would create deadlocks.
HOW to synchronize across blocks: Launch separate kernels. The GPU guarantees all threads from kernel 1 finish before any thread from kernel 2 starts.
Performance Considerations
Memory Coalescing
Coalesced access: Threads in a warp (32 consecutive threads) access consecutive memory addresses → GPU combines into one transaction.
Uncoalesced access: Threads access scattered addresses → GPU makes many small transactions → 10-100× slower.
Occupancy
Occupancy is the ratio of active warps to maximum possible warps on an SM.
WHY it matters: Higher occupancy → more warps available → better latency hiding.
Factors limiting occupancy:
- Registers per thread: More registers → fewer threads fit
- Shared memory per block: More shared memory → fewer blocks fit
- Block size: Too small → wastes resources; too large → limits blocks per SM
Typical goal: 50-75% occupancy is often enough. 100% isn't always necessary for good performance.
Recall Feynman: Explain to a 12-year-old
Imagine you have a huge math worksheet with 10,000 problems. If you do them yourself, it takes forever—one problem at a time.
Now imagine you have a classroom with 10,000 students, and you give each student exactly one problem. They all work at the same time, and suddenly the whole worksheet is done in the time it takes to solve ONE problem!
That's what a GPU does. The "students" are threads—tiny workers. CUDA is how you tell them which problem to solve.
You organize students into groups (blocks) sitting at tables. Students at the same table can share a whiteboard (shared memory) to work together. But students at different tables can't talk to each other until everyone is done.
You also have to be careful: if you have 10,000 problems but10,240 students, the last 240 don't have a problem to solve. You need to tell them "sit this one out" or they'll try to solve imaginary problems and mess things up!
Connections
- GPU Architecture Overview - Hardware foundation for CUDA
- Streaming Multiprocessors - Physical execution units that run blocks
- Memory Hierarchy - Detailed memory performance analysis
- Thread Warps and SIMT - How threads actually execute on hardware
- Parallel Algorithm Design - Strategies for decomposing problems
- OpenCL vs CUDA - Alternative programming models
- Deep Learning Frameworks - TensorFlow/PyTorch use CUDA under the hood
Flashcards
#flashcards/hardware
What is a CUDA kernel? :: A function that runs on the GPU, executed in parallel by many threads. Declared with __global__ keyword.
What is the formula for global thread index in1D?
idx = blockIdx.x * blockDim.x + threadIdx.xWhy do we need if (idx < N) in CUDA kernels? :: Because we launch blocks of fixed size (e.g., 256 threads), we might have more threads than data elements. Extra threads must be prevented from accessing out-of-bounds memory.
What is the difference between host and device in CUDA?
What does <<numBlocks, threadsPerBlock>>> specify?
What is __syncthreads() used for?
Can threads in different blocks synchronize during kernel execution?
What is memory coalescing?
What is __shared__ memory?
What is a warp in CUDA?
How do you calculate the number of blocks needed for N elements?
numBlocks = (N + threadsPerBlock - 1) / threadsPerBlock (ceiling division using integer arithmetic)What are the three levels of CUDA's execution hierarchy?
Why is 256 a common choice for threadsPerBlock?
What is GPU occupancy?
What memory type is fastest in CUDA?
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, GPU aur CPU ka core farak yahi hai ki CPU ke paas thode "smart workers" hote hain jo complex kaam fatafat karte hain, jabki GPU ke paas hazaaron "simple workers" hote hain jo ek-ek chhota kaam karte hain. CUDA basically ek management system hai jo in hazaaron workers ko batata hai ki kya karna hai, kab karna hai aur results kaise share karne hain. Matlab loop mein "yeh kaam 10,000 baar karo" likhne ke bajaye, aap kehte ho "yeh task hai, ab isse ek saath 10,000 threads mein parallel chala do." Yahi parallelism ka asli magic hai.
Ab is parallelism ko manage karne ke liye CUDA ek teen-level hierarchy use karta hai: Grid, Blocks, aur Threads. Thread sabse chhota unit hai jo ek piece of work karta hai, Block ek group hota hai jismein threads aapas mein cooperate kar sakte hain (shared memory aur synchronization ke through), aur Grid saare blocks ka collection hota hai. Physically, grid poore GPU pe map hota hai, blocks SMs pe, aur threads CUDA cores pe. Har thread apna unique global index nikaalta hai is formula se: blockIdx.x × blockDim.x + threadIdx.x — yani "mere block se pehle kitne threads aaye" plus "apne block ke andar meri position." Isse har worker ko pata chalta hai ki usse konsa data process karna hai.
Yeh sab why-matters isliye hai kyunki AI, deep learning, scientific computing aur data processing jaise kaam mein hume massive parallelism chahiye, aur CUDA hume GPU ki us power tak direct access deta hai. Ek important cheez yaad rakhna — memory movement bahut expensive hoti hai, ek memory access kabhi-kabhi math operation se 100 guna zyada time le sakta hai. Isliye CUDA alag-alag memory types deta hai (registers sabse fast, phir shared memory, phir cache, phir slow global memory) taaki aap apne data ko smartly manage karke performance maximize kar sako. Jab tum CUDA achhe se samajh loge, tab tum modern GPU-based computing ka poora foundation samajh jaoge.