diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e2f5dd2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +result \ No newline at end of file diff --git a/docs/figs/b_gflops.png b/docs/figs/b_gflops.png new file mode 100644 index 0000000..21046af Binary files /dev/null and b/docs/figs/b_gflops.png differ diff --git a/docs/figs/b_time.png b/docs/figs/b_time.png new file mode 100644 index 0000000..cf2fd86 Binary files /dev/null and b/docs/figs/b_time.png differ diff --git a/docs/figs/la_gflops.png b/docs/figs/la_gflops.png new file mode 100644 index 0000000..8d3684b Binary files /dev/null and b/docs/figs/la_gflops.png differ diff --git a/docs/figs/la_time.png b/docs/figs/la_time.png new file mode 100644 index 0000000..d508206 Binary files /dev/null and b/docs/figs/la_time.png differ diff --git a/docs/figs/mnk_gflops_b100.png b/docs/figs/mnk_gflops_b100.png new file mode 100644 index 0000000..5895de0 Binary files /dev/null and b/docs/figs/mnk_gflops_b100.png differ diff --git a/docs/figs/mnk_gflops_b1000.png b/docs/figs/mnk_gflops_b1000.png new file mode 100644 index 0000000..1262346 Binary files /dev/null and b/docs/figs/mnk_gflops_b1000.png differ diff --git a/docs/figs/mnk_time_b100.png b/docs/figs/mnk_time_b100.png new file mode 100644 index 0000000..5919517 Binary files /dev/null and b/docs/figs/mnk_time_b100.png differ diff --git a/docs/figs/mnk_time_b1000.png b/docs/figs/mnk_time_b1000.png new file mode 100644 index 0000000..a9086d3 Binary files /dev/null and b/docs/figs/mnk_time_b1000.png differ diff --git a/docs/figs/pq_gflops.png b/docs/figs/pq_gflops.png new file mode 100644 index 0000000..d7a3051 Binary files /dev/null and b/docs/figs/pq_gflops.png differ diff --git a/docs/figs/pq_glfops.png b/docs/figs/pq_glfops.png new file mode 100644 index 0000000..2ba8c0e Binary files /dev/null and b/docs/figs/pq_glfops.png differ diff --git a/docs/figs/pq_time.png b/docs/figs/pq_time.png new file mode 100644 index 0000000..e92a09d Binary files /dev/null and b/docs/figs/pq_time.png differ diff --git a/docs/report.md b/docs/report.md new file mode 100644 index 0000000..abae1a7 --- /dev/null +++ b/docs/report.md @@ -0,0 +1,51 @@ +# Introduction +In this report, we present the results of a benchmark study on three variations of the distributed matrix-matrix multiplication (GEMM) algorithm: blocking peer-to-peer communication, blocking collective communication, and non-blocking peer-to-peer communication. The GEMM operation is a fundamental operation in high performance scientific computing, and these three algorithms represent different approaches to implementing it in a distributed environment. The goal of the study was to assess the scalability of the algorithms and the impact of their different approaches on performance. The results of the study will provide insights into the strengths and limitations of the different algorithms and guide the development of future high performance scientific computing applications. The VITE visualizer will not be used in this report, as its usability is not good. + +# Methodology +We implemented and benchmarked three variations of the distributed matrix-matrix multiplication (GEMM) algorithm in C using the OpenMPI library. The algorithms were compiled with the smpicc compiler and executed on truite.enseeiht.fr, a machine with two Intel Xeon E5-2620 (totaling 32 cores). For each combination of the number of nodes (`p` and `q`), the problem dimensions (`m`, `n` and `k`) and “hyperparameters” such as the look-ahead `la` and the square block dimension `b`, we recorded the execution speeds and plotted them using matplotlib in python. All runs were repeated 5 times (`--niter`) to denoise the plots. + +# Results +## Scalability according to `m`, `n` and `k` +We decide that `m` = `n` = `k` (for simplicity). +We also set `p` = 10, `q` = 10, `la` = 10 and `np` = 100. + +Here are our results for `b` = 100: + +![mnk_time_b100.png](figs/mnk_time_b100.png) +![mnk_gflops_b100.png](figs/mnk_gflops_b100.png) + +And for `b` = 1000: + +![mnk_time_b1000.png](figs/mnk_time_b1000.png) +![mnk_gflops_b1000.png](figs/mnk_gflops_b1000.png) + +From these plots we conclude that the Non-blocking peer-to-peer communications algorithm (`p2p-i-la`) scales way better than the two others algorithms. The Blocking peer-to-peer communication (`p2p`) and Blocking collective communication (`bcast`) have similar performances, although `bcast` seems slightly better. We also do not observe a decreasing yield with respect to Gflops, these algorithms seem fully scalable from the resources (truite.enseeiht.fr) we have at our disposal. + +## Scalability according to `p`, `q` and `np` +We decide that `q` = 1 and `np` = `q` (for simplicity). +We also set `la` = 10, `b` = 100, `n` = 1000, `m` = 1000 and `k` = 1000. + +![pq_time.png](figs/pq_time.png) +![pq_gflops.png](figs/pq_gflops.png) + +From these plots we conclude that low and high numbers of nodes is not beneficial for performance. This seems natural and we deduce that optimal performance is achieved when `p` is equal to our number of cpu cores (32 in our case as we only have one machine). + +## Impact of look-ahead `la` +In the Non-blocking peer-to-peer communications algorithm (`p2p-i-la`) we define a lookahead value `la`, which is the number of blocks to overlap communication and computation. This can help our algorithm to be more efficient by caching our next operations. + +![la_time.png](figs/la_time.png) +![la_gflops.png](figs/la_gflops.png) + +From these figures, we conclude that it is not useful to select a lookahead value exceeding 10. The performance gain seems to stagnate after this critical value of 10 (even at very high lookahead values such as 10000). + +## Impact of block dimension `b` +We set `la` = 10, `np` = 16, `p` = 4, `q` = 4, `n` = 5000, `m` = 5000 and `k` = 5000. + +![b_time.png](figs/b_time.png) +![b_gflops.png](figs/b_gflops.png) + +From these figures, we guess that low and high values of `b` seem to hurt performance. We deduce that well chosen values of b (approximately such that `b` = `n`/`np`) allow for optimal performances. + +# Conclusion +In conclusion, this report presents the results of a benchmark study on three variations of the distributed matrix-matrix multiplication (GEMM) algorithm. The results of the study provide insights into the strengths and limitations of the different algorithms and guide the development of future high-performance scientific computing applications. It was observed that the Non-blocking peer-to-peer communications algorithm (`p2p-i-la`) scales better than the other two algorithms, blocking peer-to-peer communication (`p2p`) and blocking collective communication (`bcast`). It was also observed that the optimal performance is achieved when the number of nodes (`p`) is equal to the number of CPU cores. Additionally, the study also concludes that it is not useful to select a lookahead value exceeding 10 in the Non-blocking peer-to-peer communications algorithm and the performance gain seems to stagnate after this critical value. The parameter of block dimension `b` also has impact on the algorithm performance. + diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..af9faf5 --- /dev/null +++ b/flake.lock @@ -0,0 +1,64 @@ +{ + "nodes": { + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1701473968, + "narHash": "sha256-YcVE5emp1qQ8ieHUnxt1wCZCC3ZfAS+SRRWZ2TMda7E=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "34fed993f1674c8d06d58b37ce1e0fe5eebcb9f5", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1702312524, + "narHash": "sha256-gkZJRDBUCpTPBvQk25G0B7vfbpEYM5s5OZqghkjZsnE=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "a9bf124c46ef298113270b1f84a164865987a91c", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "dir": "lib", + "lastModified": 1701253981, + "narHash": "sha256-ztaDIyZ7HrTAfEEUt9AtTDNoCYxUdSd6NrRHaYOIxtk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e92039b55bcd58469325ded85d4f58dd5a4eaf58", + "type": "github" + }, + "original": { + "dir": "lib", + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-parts": "flake-parts", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..3adefd0 --- /dev/null +++ b/flake.nix @@ -0,0 +1,34 @@ +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-parts.url = "github:hercules-ci/flake-parts"; + }; + + outputs = inputs@{ nixpkgs, flake-parts, ... }: + flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ "x86_64-linux" "aarch64-linux" ]; + + perSystem = { pkgs, system, ... }: { + devShells.default = pkgs.mkShell { packages = with pkgs; [ pandoc ]; }; + + packages.report = pkgs.stdenvNoCC.mkDerivation { + name = "report"; + + src = ./docs; + dontUnpack = true; + buildInputs = with pkgs; [ pandoc ]; + + buildPhase = '' + pandoc $src/report.md -s -o index.html --katex + ''; + + installPhase = '' + mkdir -p $out + cp -r $src/figs $out/figs + cp index.html $out/index.html + ''; + }; + }; + }; +} +