English
Summary
Conclusions
OpenMP makes it possible to parallelize a C++ program with compiler directives according to the fork–join model: the main thread creates a team of threads in a parallel region and waits for it at an implicit barrier. Variables declared outside the region are shared, and those declared inside it are private; the private, firstprivate, lastprivate, and default(none) clauses make this explicit. The for directive distributes iterations among threads, and schedule determines the distribution: static for uniform iterations, dynamic and guided for nonuniform ones. Reductions combine private copies without synchronization, while critical, atomic, and other directives synchronize access to shared data. OpenMP tasks suit recursive algorithms, provided there is a threshold below which the code runs sequentially. The simd directive adds vectorization inside a core. On NUMA systems, data is initialized in parallel (the first-touch policy), and threads are bound to processors with the OMP_PLACES and OMP_PROC_BIND variables. Speedup is measured with a series of runs with different OMP_NUM_THREADS and OMP_SCHEDULE values without recompiling.
Self-check questions
- What parts does OpenMP consist of? What are a directive and a clause?
- Explain the fork–join model. What happens at an implicit barrier?
- How do you enable OpenMP in GCC and in a CMake project? What does the
_OPENMPmacro show? - How is the number of threads in a parallel region determined?
- Which variables in a parallel region are shared and which are private by default?
- How do
private,firstprivate, andlastprivatediffer? Why usedefault(none)? - What are the requirements for a loop parallelized with the
fordirective? - Compare the
static,dynamic, andguidedschedules. What isschedule(runtime)for? - What do the
collapseandnowaitclauses do? - How does the
reductionclause work? What reduction operators exist? How do you declare your own? - How do
criticalandatomicdiffer? What aresingle,masked, andbarrierfor? - How do tasks differ from sections? What do
taskwait,taskgroup, andtaskloopdo? - Why do recursive algorithms with tasks need a threshold?
- What does the
simddirective give compared with automatic vectorization? - What are NUMA and the first-touch policy? How do you initialize data on a NUMA system?
- What do the
OMP_PLACESandOMP_PROC_BINDvariables specify? When do you chooseclose, and whenspread? - How do you check the actual thread binding and the system topology?
Useful links
- OpenMP specifications: https://www.openmp.org/specifications/
- OpenMP reference cards: https://www.openmp.org/resources/refguides/
- GNU libgomp documentation: https://gcc.gnu.org/onlinedocs/libgomp/
- The CMake FindOpenMP module: https://cmake.org/cmake/help/latest/module/FindOpenMP.html
- LLVM OpenMP: https://openmp.llvm.org/
- The hwloc library: https://www.open-mpi.org/projects/hwloc/
- The numactl man page: https://man7.org/linux/man-pages/man8/numactl.8.html
- NUMA memory policies in Linux: https://www.kernel.org/doc/html/latest/admin-guide/mm/numa_memory_policy.html