Self-Assessment Quiz: GPU Computing
Twenty questions to confirm the concepts landed — the host/device model, the two roads (OpenACC and CUDA Fortran), and above all the data-movement discipline that decides whether an offload is worth doing. Aim for 16 or more. Reason the code questions by hand; the answer key and a topic map are at the end.
Question 1
A GPU differs from a CPU chiefly in that it is optimized for: - A. Low latency on a single thread of execution - B. High throughput across thousands of simple cores doing the same operation - C. Large caches and branch prediction for irregular code - D. Running the operating system
Question 2
In accelerator programming, the host and the device are: - A. Two names for the same processor - B. The CPU (+ its RAM) and the GPU (+ its own memory), with separate memory spaces - C. Two GPUs in the same machine - D. The compiler and the linker
Question 3
The single most important consequence of host and device having separate memory is: - A. The GPU is always faster - B. Data must be explicitly copied between them before and after a kernel runs - C. You cannot use Fortran on a GPU - D. The CPU is idle during a kernel
Question 4
Which OpenACC directive offloads the following loop to the GPU, running its iterations in parallel?
- A. !$omp parallel do
- B. !$acc parallel loop
- C. !$acc data
- D. !$cuf kernel
Question 5
The OpenACC data clause for an array the kernel only reads as input is:
- A. copyout
- B. create
- C. copyin
- D. present
Question 6
The purpose of an !$acc data region around a time loop is to:
- A. Make the loop run in parallel
- B. Keep arrays resident on the device so they are transferred once, not every step
- C. Allocate host memory
- D. Synchronize CPU threads
Question 7
True or false, with justification: OpenACC directives are structured comments, so a source file with !$acc
directives still compiles and runs correctly (on the CPU) with a compiler that ignores them.
Question 8
In CUDA Fortran, a kernel is a subroutine marked:
- A. attributes(host)
- B. attributes(device)
- C. attributes(global)
- D. pure
Question 9
A CUDA Fortran kernel must be defined:
- A. Inside the main program's contains
- B. As a module procedure
- C. In a separate file only
- D. As an internal function
Question 10
In CUDA Fortran, the correct global index for a thread is:
- A. i = blockIdx%x*blockDim%x + threadIdx%x
- B. i = (blockIdx%x - 1)*blockDim%x + threadIdx%x
- C. i = blockIdx%x + threadIdx%x
- D. i = threadIdx%x*gridDim%x + blockIdx%x
Question 11
Why does CUDA Fortran's index formula subtract 1 from blockIdx%x, unlike CUDA C's?
- A. Fortran arrays start at 0
- B. CUDA Fortran's threadIdx%x and blockIdx%x are one-based, matching Fortran arrays
- C. It is a bug that everyone copies
- D. To skip the first block
Question 12
In the launch call k<<<nblocks, tpb>>>(...), the two numbers are:
- A. Grid dimensions in x and y
- B. Number of blocks, and threads per block
- C. Input and output sizes
- D. The compute capability
Question 13
Why does a kernel launched with more threads than data elements need an if (i <= n) guard?
- A. To make it run faster
- B. So the extra threads (whose index exceeds n) do not read or write out of bounds
- C. To synchronize the threads
- D. To free device memory
Question 14
In a GPU program, the usual performance bottleneck is: - A. The on-device arithmetic - B. The host–device data transfer across the bus - C. The compiler - D. Printing the results
Question 15
A stencil offload transfers the whole field to the device and back every time step. The likely result is: - A. A large speedup - B. The GPU version is slower than the CPU version, because transfers dominate - C. A compile error - D. Exactly the CPU speed
Question 16
True or false, with justification: "My kernel runs 20× faster than the CPU loop" guarantees the whole program runs about 20× faster.
Question 17
Which computation is the best fit for a GPU? - A. A 15-iteration loop where each step depends on the last - B. A recursive traversal with data-dependent branching - C. The same five-point stencil applied to ten million grid cells, swept thousands of times - D. Reading a configuration file
Question 18
"Warp divergence" hurts GPU performance because: - A. The GPU runs out of memory - B. Threads in a lock-step group take different branches, so the hardware runs the paths serially - C. The bus is too slow - D. Fortran is column-major
Question 19
Compared with OpenACC, CUDA Fortran is: - A. More portable, less control - B. NVIDIA-only, more explicit control over kernels and device memory - C. Unable to use device memory - D. A directive-based standard
Question 20
You keep a field resident on the device but must write a frame to disk every 500 steps. The directive that
refreshes the host copy without ending the data region is:
- A. !$acc end data
- B. !$acc update self(field)
- C. !$acc parallel loop
- D. !$acc create(field)
Answer Key
| Q | Ans | Why |
|---|---|---|
| 1 | B | A GPU is a throughput machine — thousands of simple cores doing the same operation on much data. |
| 2 | B | Host = CPU + RAM; device = GPU + its own memory; the two are separate address spaces. |
| 3 | B | Separate memory means data must be explicitly copied across the bus before and after a kernel. |
| 4 | B | !$acc parallel loop offloads the following loop and runs its iterations in parallel on the device. |
| 5 | C | copyin moves a read-only input to the device with no copy-back. |
| 6 | B | A data region keeps arrays resident, so they cross the bridge once (in/out) rather than every step. |
| 7 | True | Directives are comments; a non-OpenACC compiler ignores them and the code runs correctly on the CPU. |
| 8 | C | attributes(global) marks a kernel — called from the host, run on the device. |
| 9 | B | Kernels must be module procedures, not internal contains procedures of the program. |
| 10 | B | CUDA Fortran is one-based, so i = (blockIdx%x - 1)*blockDim%x + threadIdx%x. |
| 11 | B | threadIdx%x/blockIdx%x are one-based in CUDA Fortran (matching Fortran arrays), so subtract 1. |
| 12 | B | The launch config is <<<number of blocks, threads per block>>>. |
| 13 | B | Extra threads have i > n; without the guard they access out of bounds. |
| 14 | B | The host–device bus is far slower than device memory; transfers usually dominate. |
| 15 | B | Per-step transfers swamp a cheap stencil, so the GPU version runs slower than the CPU one. |
| 16 | False | Offloading speeds only the offloaded part; serial work and transfers cap the whole-program speedup (Amdahl). |
| 17 | C | Large, regular, data-parallel, heavily reused on the device — the ideal GPU workload. |
| 18 | B | Divergent branches within a warp run serially, so a branchy warp runs at a fraction of peak. |
| 19 | B | CUDA Fortran is NVIDIA-only and explicit; OpenACC is portable and directive-based. |
| 20 | B | !$acc update self (a.k.a. update host) refreshes the host copy without ending residency. |
Topics to review by question
- Q1–3 → §35.1 (the GPU, host/device, separate memory).
- Q4–7 → §35.2 (OpenACC directives, data clauses, data regions).
- Q8–13 → §35.3 (CUDA Fortran kernels, one-based indexing, launch config, the tail guard).
- Q14–16 → §35.4 (host–device transfer as the bottleneck; Amdahl still rules).
- Q17–18 → §35.5 (when GPUs help vs hurt; warp divergence).
- Q19 → §35.2 vs §35.3 (the OpenACC/CUDA Fortran trade).
- Q20 → §35.4 (
update selffor output from a resident field).
Scored below 16? The two ideas most worth rereading are the host/device split with its one commandment — move data across the bridge as rarely as possible (Q3, 6, 14, 15, 20) — and the one-based CUDA Fortran thread index (Q10, 11). They are where correctness and performance actually live in this chapter.