diff --git a/Nvidia_STL.typ b/Nvidia_STL.typ index 4c2b6140240f7f923f3df910e8e11bc943f8a8b7..e1fce06d683898d59383cb1694a2dee6ffdd0f75 100644 --- a/Nvidia_STL.typ +++ b/Nvidia_STL.typ @@ -146,6 +146,59 @@ Le paramètre `stdpar` prend 2 valeurs : #new-section-slide("Comment passer des données au GPU avec les captures") +#slide( + title: "Communiquer des données au GPU", +)[ + Pour rappel, le GPU et CPU ont deux espaces d'adressage distincs. On ne peut + donc pas directement accéder à des données qui se trouve sur la ram de l'_Host_ + depuis le _Device_. + + Quand on passe simplement un itérateur à un algorithme STL, il n'y a rien besoin + de faire. Le compilateur va gérer l'allocation, la copie et la libération des + données sur le device. + + Mais comment faire pour capturer un vecteur par exemple? +] + +#slide(title: "Exemple d'accès illégal")[ +```cpp +std::vector<int> v = {6, 3, 4, 12, 1, 15}; +std::vector<int> idxs(v.size(), 0); + +std::iota(idxs.begin(), idxs.end(), 0); + +int cst = 4; + +std::for_each(std::execution::par_unseq, + idxs.begin(), idxs.end(), + [&v, &cst](int i){ + v[i] += cst; + }); +``` + +Ce code provoque un warning à la compilation et une erreur +`cudaErrorIllegalAddress` à l'exécution. +] + +#slide(title: "Solution")[ +Pour régler ce problème, il suffit de capturer la mémoire par copie. + +```cpp +std::vector<int> v = {6, 3, 4, 12, 1, 15}; +std::vector<int> idxs(v.size(), 0); + +std::iota(idxs.begin(), idxs.end(), 0); + +int cst = 4; + +std::for_each(std::execution::par_unseq, + idxs.begin(), idxs.end(), + [device_v = v.data(), cst](int i) { + device_v[i] += cst; + }); +``` +] + #new-section-slide("Le futur avec C++23 (views et mdspans)") #new-section-slide("Notions à retenir") diff --git a/cpp_basics_for_STL.typ b/cpp_basics_for_STL.typ index cd0bca8907a220af5742d81ad4605db19ef5e740..203fc31fac1615221526ad5a98fe1df315c0f3a2 100644 --- a/cpp_basics_for_STL.typ +++ b/cpp_basics_for_STL.typ @@ -261,19 +261,19 @@ Il existe deux moyens de capturer une variable : == Par copie ```cpp int var = 5; -auto add_cst = [v=var](int i) +auto add_var = [v=var](int i) { return i+v; }; var = 2; -int x = add_cst(10); // x vaut 15 +int x = add_var(10); // x vaut 15 ``` #colbreak() == Par référence ```cpp int var = 5; -auto add_cst = [v=&var](int i) +auto add_var = [v=&var](int i) { return i+*v;}; var = 2; -int x = add_cst(10); // x vaut 12 +int x = add_var(10); // x vaut 12 ``` ]) ] @@ -285,19 +285,19 @@ On peut également copier l'environnement au complet : == Par copie ```cpp int var = 5; -auto add_cst = [=](int i) +auto add_var = [=](int i) { return i+var; }; var = 2; -int x = add_cst(10); // x vaut 15 +int x = add_var(10); // x vaut 15 ``` #colbreak() == Par référence ```cpp int var = 5; -auto add_cst = [&](int i) +auto add_var = [&](int i) { return i+var;}; var = 2; -int x = add_cst(10); // x vaut 12 +int x = add_var(10); // x vaut 12 ``` ]) ] @@ -400,8 +400,8 @@ std::cout << std::endl; )[ - Les collections proposent un itérateur sur le début et la fin avec les méthodes `begin` et `end` -- Un `std::vector` est un tableau de taille dynamique -- Un `std::array` est un tableau statique +- Un `std::vector` est un tableau dynamique et un `std::array` est un tableau + statique - Si l'on est pas responsable des données, il faut utiliser un `std::span` - Les lambdas sont des fonctions anonymes qui peuvent capturer totalement ou partiellement leur environnement @@ -411,6 +411,7 @@ std::cout << std::endl; #box(inset: 5%, columns(2, gutter: 22pt)[ - `iota` - `transform` +- `for_each` #colbreak() - `accumulate` - `remove_if`