Exercises — CUDA programming model basics
Before we start, let us lock down the one formula the whole page leans on, because every symbol in it must be earned.
Look at the figure: crate , seat , with lockers per crate, lands on locker .

L1 — Recognition
Exercise 1.1 (L1)
Match each term to its home. For Host, Device, Kernel, Warp, say in one phrase what it is.
Recall Solution
- Host ::: the CPU and its system RAM — where
main()runs. - Device ::: the GPU and its VRAM — where kernels run.
- Kernel ::: a
__global__function launched from the host but executed on the device by many threads at once. - Warp ::: a hardware bundle of threads that step through instructions in lockstep (SIMT). See Thread Warps and SIMT.
Exercise 1.2 (L1)
In vectorAdd<<<numBlocks, threadsPerBlock>>>(...), which of the two triple-angle numbers is the grid size and which is the block size?
Recall Solution
- First number,
numBlocks::: the grid size — how many blocks. - Second number,
threadsPerBlock::: the block size — how many threads per block. So the logical order is Grid → Blocks → Threads, exactly the order they appear.
Exercise 1.3 (L1)
Order these memories fastest→slowest: Global Memory, Registers, Shared Memory, Host Memory.
Recall Solution
Registers ( cycle) → Shared Memory ( cycles) → Global Memory ( cycles) → Host Memory ( cycles). Closer to the compute cores = fewer wires to cross = faster. See Memory Hierarchy.
L2 — Application
Exercise 2.1 (L2)
A thread has blockIdx.x = 3, blockDim.x = 256, threadIdx.x = 17. Compute its globalIdx.
Recall Solution
What we did: counted the threads in crates , then added our seat .
Exercise 2.2 (L2)
You have elements and choose . How many blocks do you launch?
Recall Solution
Use ceiling division so no element is left uncovered: Check: . Good — a few spare threads, which the boundary check handles.
Exercise 2.3 (L2)
For a D image of width = 640, a thread computes row = 5, col = 12. What is its flattened globalIdx in a row-major array?
Recall Solution
Row-major means: walk all the way across each finished row before starting the next.
L3 — Analysis
Exercise 3.1 (L3)
With and , exactly how many threads are launched, and how many are idle (do no work) thanks to if (idx < N)?
Recall Solution
. Total threads launched .
Working threads = the ones with , i.e. of them.
Idle threads (indices through ). They pass the if test as false and simply exit.
Exercise 3.2 (L3)
Look at the figure. The tail crate is only partly used. Explain why removing if (idx < N) from the vectorAdd kernel is dangerous, and which thread first misbehaves for .

Recall Solution
Threads come in whole blocks; you cannot launch "exactly ." The last block overshoots to index . Without the guard, thread would read A[1000]/B[1000] and write C[1000] — one element past the array end (valid indices stop at ). That is an out-of-bounds access: crash or corrupted neighbouring memory. The first offender is .
Exercise 3.3 (L3)
A math op costs cycle; a global memory read costs cycles. In naïve vectorAdd, each output needs global reads + global write + add. Roughly what fraction of the time is spent on the actual arithmetic?
Recall Solution
Memory cycles . Arithmetic cycle. Interpretation: vectorAdd is utterly memory-bound — the GPU spends of its time moving data. This is why Memory Hierarchy and coalescing matter more than raw FLOPs here.
L4 — Synthesis
Exercise 4.1 (L4)
Write a kernel scaleAdd computing (a "SAXPY") with a proper index and boundary check. State the launch config for , .
Recall Solution
__global__ void scaleAdd(float a, float *A, float *B, float *C, int N) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < N) {
C[idx] = a * A[idx] + B[idx];
}
}Launch:
Check: . Call: scaleAdd<<<1954,256>>>(a,d_A,d_B,d_C,N);
Exercise 4.2 (L4)
List the six host-side steps (in order) needed to run any kernel on device data, and give the correct cudaMemcpy direction enum for input and output copies.
Recall Solution
- Allocate host memory (
malloc). - Allocate device memory (
cudaMalloc). - Copy inputs Host→Device — enum
cudaMemcpyHostToDevice. - Launch kernel
<<<numBlocks, threadsPerBlock>>>. - Copy results Device→Host — enum
cudaMemcpyDeviceToHost. - Free device (
cudaFree) and host (free) memory.
Exercise 4.3 (L4)
For a D kernel on a image (width=640, height=480) with block dims , compute the grid dimensions (gridX, gridY).
Recall Solution
Total blocks ; total threads , which matches pixels exactly (no idle threads here since both dims divide evenly).
L5 — Mastery
Exercise 5.1 (L5)
A kernel launches with grid blocks, block threads. The thread that should process array index — what are its blockIdx.x and threadIdx.x?
Recall Solution
Invert the index formula. Divide by block size: , so . Verify forward: . ✓
Exercise 5.2 (L5)
Suppose reading from global memory costs cycles but from shared memory costs cycles. A tiling kernel loads each element from global memory once into shared memory, then reuses it times from shared memory. Compare total memory cycles per element against a naïve kernel that reads global memory all times.
Recall Solution
- Naïve: global reads cycles.
- Tiled: global read shared reads cycles.
- Speedup . This is exactly why shared memory exists: pay the expensive off-chip trip once, then reuse cheaply. See Memory Hierarchy and Streaming Multiprocessors.
Exercise 5.3 (L5)
A GPU has SMs and can hold at most resident blocks per SM. You launch a grid of blocks. Are all blocks resident at once? If not, how many "waves" of blocks does the GPU need?
Recall Solution
Max simultaneously resident blocks . Since , not all fit at once. Number of waves: Actually . The GPU processes blocks in waves; the scheduler retires finished blocks and swaps in waiting ones. This is what lets one kernel scale from a small GPU to a huge one without changing code.
Recall Quick self-test recap
Ceiling block count for N=1000, tpb=256 ::: blocks, idle threads.
Global index for block 3, blockDim 256, thread 17 ::: .
Why if (idx < N) ::: last block overshoots array; guard stops out-of-bounds access.
Fastest CUDA memory ::: registers ( cycle), on-chip, in the compute unit.