Skip to content

About

Three HPC labs - OpenMP, MPI and OpenACC - with real cluster job output and a parser that mines it into speedup tables.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Parallel Programming — OpenMP, MPI and OpenACC

Three HPC lab assignments from Parallel Programming (Applied Mathematics, second year, third trimester, UPF, spring 2023), together with the real job output recorded on the UPF HPC-DTIC cluster and a Python script that mines those outputs into timing and speedup tables.

Honest attribution, up front

The skeleton code in every exercise was provided by the course. The student's contribution is the parallelisation — the OpenMP directives, the MPI decomposition and communication, the OpenACC data clauses, the bug fixes, and the experiment design behind the measurements. Wherever an unmodified handout copy of a file survives on disk, this repository points at the exact lines that changed; where it does not, that is stated rather than guessed.

Two files carry an explicit third-party byline that was left untouched:

File Provenance
labs/lab1-openmp/4_product/product.c header: "Written by Tim Mattson, April 2007"
labs/lab1-openmp/3_histogram/random.c linear congruential generator from Numerical Recipes, ch. 7

The five bug*.c programs in labs/lab2-mpi/3_bugs/ are the well-known deliberately-broken MPI teaching examples; the exercise is to find and fix the defect, so the diff against the broken original is the work, not the file.

What is in here

Lab Technology Compiler / toolchain Exercises
labs/lab1-openmp OpenMP (shared memory) gcc -fopenmp, GCC 10.2.0 Cholesky factorisation, task-parallel Sudoku solver, histogram synchronisation study, producer/consumer
labs/lab2-mpi MPI (distributed memory) mpicc, OpenMPI 4.1.2 Ping-pong bandwidth, MPI-IO parallel file read, a five-part debugging exercise, 2-D heat stencil with MPI_Alltoallw
labs/lab3-openacc OpenACC (directives, CPU and GPU targets) pgcc, NVHPC 21.9 / CUDA 11.4.3 Delaunay triangulation of a sensor field

The technology per lab was determined by reading the sources, not assumed. Note in particular that lab 3 is OpenACC, not OpenMP: delaunay.c includes <omp.h>, but only to call omp_get_wtime() for timing — every parallel construct in it is #pragma acc.

labs/          sources + the SLURM .cmd job script actually submitted, one dir per lab
results/       a curated sample of the recorded .out/.err files (49 of 271)
analysis/      parse_results.py — reads .out files, prints Markdown timing tables
docs/          the three lab reports the students submitted (PDF)

How to run it

These are the commands the job scripts record.

# Lab 1 — OpenMP, one node
cd labs/lab1-openmp/1_cholesky && make && OMP_NUM_THREADS=8 ./cholesky 3000
cd labs/lab1-openmp/2_sudoku   && make && OMP_NUM_THREADS=4 ./sudoku
cd labs/lab1-openmp/3_histogram && make && OMP_NUM_THREADS=16 ./histogram
cd labs/lab1-openmp/4_product  && make && OMP_NUM_THREADS=2 ./product   # requires exactly 2

# Lab 2 — MPI
cd labs/lab2-mpi/1_rates   && make && mpirun -np 2 ./sendrecvp          # 2 nodes, 1 rank each
cd labs/lab2-mpi/2_polling && make && mpirun -np 4 ./count              # needs votations.dat in cwd
cd labs/lab2-mpi/3_bugs    && make && mpirun -np 2 ./bug1               # bug4 needs exactly 4
cd labs/lab2-mpi/4_stencil && make stencil_alltoallw \
    && mpirun -np 256 ./stencil_alltoallw 4096 10 1000 16 16            # n energy iters px py

# Lab 3 — OpenACC, two targets from the same source
cd labs/lab3-openacc/1_triangulation
make cpu && ./delaunay 5000 2000 1500     # pgcc -ta=multicore
make gpu && ./delaunay 5000 2000 1500     # pgcc -ta=tesla:managed
python txt2img.py image                   # renders the image.txt the run wrote

On the cluster each of these went through SLURM. The job.cmd next to every exercise is the script as last submitted, e.g.:

sbatch labs/lab2-mpi/4_stencil/job.cmd   # 16 nodes, 256 tasks, 32 tasks/node, 3 h

Requirements: an OpenMP-capable C compiler for lab 1; an MPI implementation for lab 2; the NVIDIA HPC SDK (pgcc/nvc) plus a CUDA-capable GPU for lab 3's -ta=tesla target. txt2img.py needs matplotlib and numpy.

Results

Every number below was read out of a .out file recorded on the cluster in May–June 2023. Regenerate them with:

python analysis/parse_results.py           # parses ./results
python analysis/parse_results.py <dir>     # parses any tree of .out files

The tables in this README come from running that script over the full original job archive (271 .out files); results/ ships a 49-file sample so the script still has something to chew on.

Lab 3 — OpenACC: multicore CPU vs GPU (the headline result)

job_new.cmd builds the same source twice, -ta=multicore then -ta=tesla:managed, and runs both back to back, so each .out file is a matched pair.

Points Image CPU total (s) GPU total (s) Total speedup close points triangulation image generation
100 200×150 0.221 0.050 4.39× 267.12× 0.52× 4.50×
100 800×800 0.850 0.184 4.62× 148.84× 0.52× 5.04×
100 2000×1500 3.207 0.775 4.14× 167.42× 0.53× 4.21×
1000 200×150 15.087 0.558 27.02× 160.41× 27.18× 20.57×
1000 800×800 20.067 1.003 20.01× 85.12× 27.36× 12.40×
1000 2000×1500 41.379 2.120 19.52× 231.92× 27.75× 16.75×
5000 200×150 1753.599 51.145 34.29× 84.40× 34.30× 22.05×
5000 800×800 1695.470 52.825 32.10× 44.00× 32.38× 20.70×
5000 2000×1500 1858.979 57.142 32.53× 43.13× 33.47× 23.28×

The single largest measured saving: the triangulation kernel at 5000 points drops from 1736.24 s to 51.87 s. The < 1× entries are honest — at 100 points the triangulation is so short (~16 ms) that host-to-device transfer dominates and the GPU loses. Triangle counts are identical on both targets (189 / 1982 / 9978 for 100 / 1000 / 5000 points), which is the correctness check.

Lab 2 — 2-D stencil, strong scaling (n = 4096, 1000 iterations)

Processes (px×py) alltoallw comp. (s) comm. (s) point-to-point comp. (s) Speedup (alltoallw)
1 (1×1) 347.777 0.001 346.583 1.00×
4 (2×2) 117.053 1.787 116.625 2.97×
16 (4×4) 31.127 6.246 31.107 11.17×
64 (8×8) 16.645 1.758 16.159 20.89×

The collective MPI_Alltoallw halo exchange is statistically indistinguishable from hand-rolled point-to-point at every size measured — the report's own conclusion, and the numbers bear it out. The lab 2 report also quotes 13.23 s / 13.13 s at 256 processes (speedup 26.29× / 26.40×); no surviving .out file backs those two figures — the only 256-process job that left artefacts here (out_stencil_336323) segfaulted and was killed at the wall-time limit.

Lab 1 — histogram: four ways to synchronise 10⁶ increments into 50 buckets

Aggregated over the 6 recorded runs (job.cmd requests --cpus-per-task=16; the two oldest job ids may predate that setting):

Variant min (s) mean (s) max (s) Speedup vs sequential
Sequential 0.001578 0.001810 0.002280 1.00×
#pragma omp critical 0.018305 0.097697 0.206385 0.019×
omp_lock_t array 0.019994 0.344148 0.832712 0.005×
reduction(+:hist[:50]) 0.000397 0.001085 0.001873 1.67×

A deliberately negative result, and the point of the exercise: with 20 000 increments per bucket and essentially no arithmetic per iteration, any mutual-exclusion scheme is 10–200× slower than doing nothing in parallel. Only the array reduction — which gives each thread a private histogram and merges once — beats the serial loop, and only modestly. (The lock variant is additionally penalised by a code defect; see the lab 1 README.)

Lab 1 — Cholesky factorisation, n = 3000, OpenMP

Job Init (s) Cholesky (s) L = Uᵀ (s) B = LU (s) A ≟ B (s)
314723 0.317 14.439 0.059 23.506 0.008
314724 0.354 15.630 0.062 26.387 0.009
314725 0.346 15.283 0.056 24.280 0.008
314726 0.325 15.033 0.057 25.936 0.008
314727 0.362 15.958 0.059 29.539 0.008
314920 0.327 27.423 0.054 42.751 0.014

All six runs print Matrices are equal. These six files are exactly the static row of the scheduler sweep in docs/lab1-report.pdf (chunk sizes 1/5/10/25/50). The recorded files contain no sequential baseline — see Limitations — so no speedup can be computed from them. The report's own strong-scaling table, measured separately, gives:

Cores 1 2 4 8 16
Cholesky speedup 0.96× 0.77× 1.49× 2.51× 5.78×
Matrix-multiply speedup 0.99× 0.71× 1.41× 1.61× 5.50×

and finds schedule(dynamic) with chunk size 1 best for both phases (13.36 s / 23.26 s at 8 cores).

Lab 2 — ping-pong bandwidth between two nodes

Best sweep (out_sendrecv_331559, the run reproduced in the report):

Elements (doubles) Round trip (s) Rate (MB/s)
1 0.000003 2.71
1 024 0.000010 791.06
32 768 0.000094 2 663.57
262 144 0.000673 2 971.68
1 048 576 0.002674 2 992.00
8 388 608 0.023010 2 781.42

Peak ≈ 2 992 MB/s ≈ 23.4 Gbps, against the cluster's documented 56 Gbps interconnect — under half of nominal, as the report notes.

Lab 2 — MPI-IO polling

4 ranks, votations.dat (800 000 bytes = 50 000 × 16-byte records), read collectively with MPI_File_set_view + MPI_File_read_all:

Rank 0 1 2 3 Total
Votes counted 12 342 580 12 494 495 12 667 760 12 416 870 49 921 705

The local counts sum exactly to the MPI_Allreduce total, in all 11 recorded runs, which are byte-identical.

Lab 1 — Sudoku and producer/consumer

  • Sudoku (OpenMP tasks, --cpus-per-task=4): solved in 3.32–4.07 s across 7 runs (mean 3.65 s). No sequential baseline was recorded. The report is candid that the workload is too small for the task overhead to pay off.
  • Producer/consumer (omp sections, 2 threads, N = 10 000): 0.000174 s, sum 191.945870. One recorded run.

Lab 2 — the debugging exercise, by outcome

analysis/parse_results.py classifies each of the 182 job .out files in 3_bugs/ (183 files, one of which is the make.out build log) by reading its content — the job script was edited in place, so file names only carry the SLURM job id and say nothing about which bug was being chased:

Exercise correct wrong result hang incomplete total
bug1 1 – 6 – 7
bug2 10 – – – 10
bug3 18 24 – 31 73
bug4 4 19 – 16 39
bug5 12 – – – 12
mpirun launch failure – – – – 22
empty (killed at wall clock) – – – – 12
unrecognised / unattributable – – – – 7

That distribution is the story of the exercise: bug1 is a two-line tag mismatch and cost 7 runs; bug3 and bug4 are subtler and cost 73 and 39. The wrong result verdicts are decided arithmetically — bug3 must end with Final sum exactly twice the initialised sum, and 24 runs did not.

Authors

  • José Mª Pérez Clar — repository owner
  • Martí Oms Graells — lab partner, co-author of all three labs and all three reports

Skeleton code, exercise statements and the deliberately-buggy MPI programs are the property of the Parallel Programming course, Universitat Pompeu Fabra. product.c is by Tim Mattson (2007); random.c follows Numerical Recipes.

About

Three HPC labs - OpenMP, MPI and OpenACC - with real cluster job output and a parser that mines it into speedup tables.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages