diff --git a/Examples/makefile b/Examples/makefile index c613d8094c971be3603ea8f58cd506f16d16d23a..d5b7f0efbd028f1d6b49d1d3ef8828ee80bf0117 100644 --- a/Examples/makefile +++ b/Examples/makefile @@ -1,20 +1,23 @@ .PHONY:clean all CC=nvc++ -FLAGS=--std=c++20 -stdpar=gpu +FLAGS=-std=c++20 -stdpar=gpu -O3 -g INCLUDES_WARNINGS:=--diag_suppress useless_using_declaration -all: artefacts/future artefacts/cuda_sum_vec +all: artefacts/future artefacts/cuda_sum_vec artefacts/parallel_sort artefacts/%: artefacts/%.o $(CC) $(FLAGS) $^ -o $@ +artefacts/future.o: future.cpp + $(CC) $(FLAGS) --diag_suppress useless_using_declaration -c $^ -o $@ + artefacts/%.o: %.cpp - $(CC) $(FLAGS) $(INCLUDES_WARNINGS) -c $^ -o $@ + $(CC) $(FLAGS) -c $^ -o $@ artefacts/%.o: %.cu - $(CC) $(FLAGS) $(INCLUDES_WARNINGS) -c $^ -o $@ + $(CC) $(FLAGS) -c $^ -o $@ clean: rm -vf artefacts/** \ No newline at end of file diff --git a/Examples/parallel_sort.cpp b/Examples/parallel_sort.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b2f16b48041fa77f8138013fb9a3da986fc6d3d1 --- /dev/null +++ b/Examples/parallel_sort.cpp @@ -0,0 +1,17 @@ +#include <algorithm> +#include <execution> +#include <iostream> +#include <vector> + +int main() { + std::vector<int> v = {6, 3, 4, 12, 1, 15}; + + std::sort(std::execution::par, + v.begin(), v.end()); + + std::vector<int> v_sorted = {1, 3, 4, 6, 12, 15}; + bool is_sorted = std::equal(std::execution::par_unseq, + v.begin(), v.end(), v_sorted.begin()); + + std::cout << is_sorted << std::endl; +} \ No newline at end of file diff --git a/GPGPU.typ b/GPGPU.typ index d192f6e85780b89ccbbb3f7d985ee89553c17273..de17a79b8a28d4db5f83ad6e932dbd4332ff049e 100644 --- a/GPGPU.typ +++ b/GPGPU.typ @@ -62,7 +62,8 @@ #figure( image("assets/cpu-gpu.svg", width: 70%), - caption: [NVIDIA CUDA Programming Guide version 3.0 - 2010], + caption: [CPU vs GPU Architecture - Source : NVIDIA CUDA Programming Guide version 3.0 - + 2010], ) #link("https://youtu.be/-P28LKWTzrI")[Partenariat Myth Busters & Nvidia] diff --git a/Nvidia_STL.typ b/Nvidia_STL.typ index def78de248aca3fd0f67a458cb7112c8ace63a05..4c2b6140240f7f923f3df910e8e11bc943f8a8b7 100644 --- a/Nvidia_STL.typ +++ b/Nvidia_STL.typ @@ -18,17 +18,131 @@ #new-section-slide("Introduction") -#slide(title: "Contenu")[ - +#slide( + title: "Contenu", +)[ + Maintenant que nous avons les bases nous allons voir comment paralléliser notre + code avec le kit HPC de Nvidia. ] #new-section-slide("Le SDK HPC de Nvidia") -#slide(title: "Le compilateur nvc++")[ +#slide( + title: "À quoi sert ce kit?", +)[ + Ce kit contient : + - des librairies + - des compilateurs (C, C++, Fortran) + - des débogueurs + - des outils de profiling + - des librairies de communication (ex : OpenMPI) + + En résumé, un grand nombre d'outils pour réaliser une application HPC (basé sur + du matériel Nvidia majoritairement). + + #figure( + image("assets/hpc-sdk_content.png"), + caption: "Contenu du HPC SDK de Nvidia - Source : Nvidia", + ) +] + +#slide( + title: "Le compilateur nvc++", +)[ + Dans le cadre de ce cours, nous allons nous concentrer sur le compilateur nvc++. + + Il permet du compiler du C, C++ ou CUDA. + + Ce qui va nous intéresser particulièrement, c'est son support des _Parallel Algorithms_ introduits + avec C++17 +] + +#new-section-slide("Exemple de parallélisation avec nvc++") + +#slide( + title: "Les politiques d'exécution", +)[ + Depuis C++17, les algorithmes de la STL peuvent prendre en paramètre une + politique d'exécution. Cette politique permet d'indiquer au compilateur comment + paralléliser le traitement des données. + + On retrouve 4 politiques : + #box( + columns( + 4, + gutter: 11pt, + )[ + == seq + - Exécution séquentielle simple + #colbreak() + == par + - Exécution en parallèle + #colbreak() + == par_unseq + - Exécution en parallèle avec possibilité d'utiliser des instructions vectorielles + #colbreak() + == unseq (C++ 20) + - Exécution séquentielle avec possibilité d'utiliser des instructions vectorielles + ], + ) +] + +#slide(title: "Exemple d'algorithme STL avec une politique d'exécution")[ +```cpp +std::vector<int> v = {6, 3, 4, 12, 1, 15}; + +std::sort(std::execution::par, + v.begin(), v.end()); + +std::vector<int> v_sorted = {1, 3, 4, 6, 12, 15}; + +bool is_sorted = std::equal(std::execution::par_unseq, + v.begin(), v.end(), + v_sorted.begin()); + +std::cout << is_sorted << std::endl; +``` +] + +#slide( + title: "Compiler avec nvc++", +)[ +Une fois notre code écrit, il faut le compiler avec nvc++ en indiquant comment +le paralléliser. + +```console +nvc++ -std=c++20 -stdpar=gpu -O3 parallel_sort.cpp -o parallel_sort +``` + +Nous avons trois paramètres principaux : +- `-std=c++20` : On utilise le dialecte C++20. +- `-stdpar=gpu` : On veut que le code soit parallélisé sur GPU +- `-O3` : On veut que le compilateur utilise le niveau 3 d'optimisation sur notre + code +] + +#slide( + title: "Les types de parallélisation disponibles", +)[ +Le compilateur nvc++ permet de paralléliser son code sur CPU ou sur GPU. +Le paramètre `stdpar` prend 2 valeurs : +#box( + columns( + 2, + gutter: 22pt, + )[ + == multicore + Le code est parallélisé sur CPU avec la framework Thrust de Nvidia. + #colbreak() + == gpu + Le code est parallélisé sur GPU avec la framework Thrust de Nvidia. Nécessite un + GPU Nvidia avec une architecture Pascal (ex: GTX 1080) ou plus récent. + ], +) ] -#new-section-slide("Exemple de parallélisation sur GPU") +#new-section-slide("Exemple d'analyse d'exécution sur GPU avec nvprof") #new-section-slide("Comment passer des données au GPU avec les captures") diff --git a/assets/hpc-sdk_content.png b/assets/hpc-sdk_content.png new file mode 100644 index 0000000000000000000000000000000000000000..4dba8107d643d120cf0977ac1b06433831755fd9 Binary files /dev/null and b/assets/hpc-sdk_content.png differ