IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Threads & Processus C++ Discussion :

OpenMP et l'accessibilité des tableaux


Sujet :

Threads & Processus C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Février 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 19
    Par défaut OpenMP et l'accessibilité des tableaux
    Bonjour,

    J'essaie de paralléliser un programme en C qui fait appel à de nombreuses et volumineuses données que je vais chercher dans un fichier et transforme ensuite.

    Il faut que ces grands tableaux soient accessibles de façon par tous les threads pour les lire mais seul un tableau sert à l'écriture des résultats à des endroits différents pour chaque thread.

    Le problème est que ma section parallèle déclarée avec #pragma omp parallel ne contient pas les allocations des tableaux. Ce n'est pas sensé être un problème mais j'obtiens des erreurs de segmentation et des comportements étrange de mon programme.

    Ma question est la suivante : Est ce nécessaire de déclarer une section parallèle qui englobe tout le pré-traitement de mes données pour que openmp sache correctement utiliser mes tableaux ?

    Il est aussi probable qu'une erreur de programmation ce soit insinuée dans cette partie.

    Merci d'avance.

  2. #2
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Par défaut
    Pour répondre à ta question: non.

    L'utilisation la plus simple avec OpenMP est d'ajouter la directive «#pragma omp parallel for» devant les boucles for parallèles (écrites en C++ ou en C99 pour éviter la clause qui déclare les variables en «private»). On peut aussi faire des réductions sur les types de base avec la clause «reduction»

    Voici un exemple simple (la somme des éléments d'un tableau) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // g++ -Wall -Wextra -std=c++11 -fopenmp sum_tab_omp_reduction.cpp -o sum_tab_omp_reduc
    #include <iostream>
    #include <vector>
     
    int main()
    {
    	// Create vector
    	std::vector<int> tab(10); { int value = 0; for (auto & e : tab) { e = value++; } }
    	// Sum of vector tab
    	int sum = 0;
    	#pragma omp parallel for reduction(+:sum)
    	for (std::size_t i = 0; i < tab.size(); ++i) { sum += tab.at(i); }
    	// Display
    	std::cout << "Sum of vector tab is " << sum << std::endl;
    	return 0;
    }
    Voici un programme qui fait la même chose mais qui permet de faire des réductions sur "n'importe quel type" (je le donne à titre d'exemple mais le mieux c'est que tu ne regardes même pas (ou pas tout de suite)) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    // g++ -Wall -Wextra -std=c++11 -fopenmp sum_tab_omp_parallel.cpp -o sum_tab_omp_parallel
    #include <iostream>
    #include <vector>
     
    #if defined(_OPENMP)
    #include <omp.h>
    #endif
     
    int main()
    {
    	// Create vector
    	std::vector<int> tab(10); { int value = 0; for (auto & e : tab) { e = value++; } }
    	// Sum of vector tab
    	int sum = 0;
    	// OpenMP version
    	#if defined(_OPENMP)
    		// This code is executed by all threads
    		#pragma omp parallel shared(sum)
    		{
    			// Get thread's id and number of threads
    			int const id = omp_get_thread_num();
    			int const nbThread = omp_get_num_threads();
    			// Local sum
    			int sumThread = 0.;
    			// Spit data
    			std::size_t const iStart = id * tab.size() / nbThread;
    			std::size_t const iEnd = std::min((id+1) * tab.size() / nbThread, tab.size());
    			// Compute local sum
    			for (auto const & e : tab) { sumThread += e; }
    			// Sum all local sums
    			#pragma omp critical
    			sum += sumThread;
    		}
    	// C++ version
    	#else
    		for (auto const & e : tab) { sum += e; }
    	#endif
    	// Display
    	std::cout << "Sum of vector tab is " << sum << std::endl;
    	return 0;
    }
    Débogue bien ton code séquentiel, tu peux faire une exécution avec valgrind par exemple.
    Vérifie que les performances ne te conviennent pas (avec les bonnes options de compilation)
    Trouve les portions de code qui posent problème (les plus lentes)
    Regarde s'il n'y a pas d'optimisation séquentielle à faire (sens de parcours, algorithme)
    Puis ensuite, parallélise les boucles for avec OpenMP si ce sont bien les boucles for de calcul qui posent problème.

    Tu pourrais peut être donner plus de détails sur ton programme. Notamment sur tes opérations IO et les structures qui servent à stocker les données.

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Février 2011
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2011
    Messages : 19
    Par défaut
    Je suis sûr de mon programme en séquentiel, valgrind passe sans problème et mes flags de compilation semblent bons (-std=c99 -O3 -fopenmp).

    J'ai vérifié chacune de mes variables pour les mettre en private ou shared et ça semble fonctionner maintenant pour la première partie de mon algorithme.

    Espérons que la suite se passe bien.

    Merci de ton aide.

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Février 2010
    Messages
    2 051
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 2 051
    Par défaut
    Citation Envoyé par Ehonn Voir le message
    Voici un exemple simple (la somme des éléments d'un tableau)
    Je m'incruste car ça m'interesse tout ceci
    Ehonn, je viens de regarder le code que tu as mis et ça m'intéresse de bien comprendre ce qui est fait.
    Pourrais tu détailler certains points s'il te plait ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<int> tab(10); { int value = 0; for (auto & e : tab) { e = value++; } }
    par exemple ici je ne comprends déjà pas bien. Je comprends que tu remplis un vecteur avec les nb 1,2,3,4,5,6,7,8,9,10 mais je ne comprends pas l'instruction dans la boucle "for" : for (auto & e : tab)
    --> qu'es ce que c'est que ce truc ?
    --> es ce propre à la parallélisation ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #pragma omp parallel for reduction(+:sum)
    ici je comprends que c'est une instruction propre à openMP mais je ne comprends pas ce que ça signifie vraiment (qu'es ce qui est obligatoire ou non) et que représente ce (+:sum) j'ai l'impression que cette ligne comprends des instruction "#pragma omp parallel" mais aussi des commentaires "for reduction(+:sum)" je me trompe ?

    moi j'aurais fais tab[i] car je ne connaissais pas ".at". Si j'ai bien compris cette fonction permet de vérifier que l'on ne sort pas des limites du vecteur ?
    pourquoi utiliser ceci ? car en paralléle il y a des risques ?
    Si on fait ceci ".at(i)" à la place de "[i]" on va perdre en temps de calcul, du coup au final à t on vraiment gagné du temps par rapport à une boucle for classique avec "[i]" ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    // g++ -Wall -Wextra -std=c++11 -fopenmp sum_tab_omp_reduction.cpp -o sum_tab_omp_reduc
    j'ai une dernière question (car je suis habitué aux IDE), ces commandes sont celles qui faut mettre dans le makefile pour compiler les sources en prenant en compte openMP ?
    Qu'es ce qui est relatif à open ?
    juste "-fopenmp" et "-Wextra" ?
    à quoi sert "-std=c++11" c'est obligatoire ??

    si jamais je veux utiliser openMP avec mon IDE classique es ce possible ?
    mon IDE ne va prendre openMP en compte dans le makefile ? si ?

    merci pour les réponses que tu pourras me donner

  5. #5
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Par défaut
    Citation Envoyé par membreComplexe12 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<int> tab(10); { int value = 0; for (auto & e : tab) { e = value++; } }
    par exemple ici je ne comprends déjà pas bien. Je comprends que tu remplis un vecteur avec les nb 1,2,3,4,5,6,7,8,9,10 mais je ne comprends pas l'instruction dans la boucle "for" : for (auto & e : tab)
    --> qu'es ce que c'est que ce truc ?
    --> es ce propre à la parallélisation ?
    Cela est une syntaxe C++11 et ça permet de remplir le tableau avec les valeurs comprises entre 0 et 9 (value est post incrémenté).
    http://fr.wikipedia.org/wiki/C%2B%2B...es_intervalles

    Voici un lien sur le support de C++11 dans GCC
    http://cpp.developpez.com/redaction/...bdivers/cpp11/

    Citation Envoyé par membreComplexe12 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #pragma omp parallel for reduction(+:sum)
    ici je comprends que c'est une instruction propre à openMP mais je ne comprends pas ce que ça signifie vraiment (qu'es ce qui est obligatoire ou non) et que représente ce (+:sum) j'ai l'impression que cette ligne comprends des instruction "#pragma omp parallel" mais aussi des commentaires "for reduction(+:sum)" je me trompe ?
    Ici on demande a paralléliser la boucle for. Mais si on la parallélise telle quelle #pragma omp parallel for, chaque thread va accéder à la variable sum et il y aura (peut être) des collisions et la valeur de sum ne sera pas celle désirée.
    Par exemple the thread 0 lit la valeur de sum (4 par exemple), the thread 0 fait le calcul sum + tab[i] (4 + 3 = 7),le thread 1 lit la valeur de sum (4), le thread 0 écrit la valeur de sum (7), le thread 1 fait le calcul sum + tab[i] (4 + 2 = 6) (le thread 2 n'a pas recharger la valeur de sum après l'écriture par le thread 0), le thread 1 écrit la valeur de sum (6). Avec la collision, on obtient 6 (4 + 2) (dans cet exemple) au lieu de 9 (4 + 3 + 2).
    Ceci est une réduction, OpenMP va déclarer automatique une variable sum par thread, fait le code demandé. Puis une fois que tous les threads ont fini, il va faire la somme de tous les sum.

    Pour le reste, je répond à cette question dans ton autre post.
    http://www.developpez.net/forums/d13...penmp-boucles/

    Citation Envoyé par membreComplexe12 Voir le message
    moi j'aurais fais tab[i] car je ne connaissais pas ".at". Si j'ai bien compris cette fonction permet de vérifier que l'on ne sort pas des limites du vecteur ?
    pourquoi utiliser ceci ? car en paralléle il y a des risques ?
    Si on fait ceci ".at(i)" à la place de "[i]" on va perdre en temps de calcul, du coup au final à t on vraiment gagné du temps par rapport à une boucle for classique avec "[i]" ?
    Et tu as raison. Il n'y a aucune raison que l'on sorte du tableau ici. De plus, les exceptions dans du code parallèle : une règle simple : tu oublies ^^
    J'ai tapé ce bout de code pour illustrer un rapport de stage. Après la version "finale", je m'en été aperçu dans la version papier mais je n'ai pas fait le changement. Merci pour la remarque

    Citation Envoyé par membreComplexe12 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    // g++ -Wall -Wextra -std=c++11 -fopenmp sum_tab_omp_reduction.cpp -o sum_tab_omp_reduc
    j'ai une dernière question (car je suis habitué aux IDE), ces commandes sont celles qui faut mettre dans le makefile pour compiler les sources en prenant en compte openMP ?
    Qu'es ce qui est relatif à open ?
    juste "-fopenmp" et "-Wextra" ?
    à quoi sert "-std=c++11" c'est obligatoire ??

    si jamais je veux utiliser openMP avec mon IDE classique es ce possible ?
    mon IDE ne va prendre openMP en compte dans le makefile ? si ?
    J'ai tendance à mettre une ligne de compilation en commentaire dans mes fichiers sources car cela permet de faire un copier coller et de tester rapidement. Voici ce que j'utilise :
    -Wall On active "tous" les warnings
    -Wextra Encore plus de warnings
    -std=c++11 à partir de GCC 4.7, -std=c++0x à partir de GCC 4.3 : Utilisation de C++11
    -pedantic Respect de la norme (donné avec -std=)
    -O3 Active tous les optimisation (il existe -O0 (pas d'optimisation), -O1, -O3 et -0s pour optimiser en taille)
    -ffast-math Peut se permettre de changer l'ordre des calculs, à utiliser avec précaution à cause des problèmes d'arrondi
    -fopenmp Active le support d'OpenMP, sinon, les #pragma omp seront ignorés et tu aura un code séquentiel
    Doc GCC - Invoking g++
    Doc GCC - C options
    Doc GCC - C++ options
    En effet, tu dois activer ces options. Les IDE proposent souvent des cases à cocher dans le paramétrage du compilateur.

  6. #6
    Membre éprouvé
    Profil pro
    Inscrit en
    Février 2010
    Messages
    2 051
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 2 051
    Par défaut
    Citation Envoyé par Ehonn Voir le message
    Cela est une syntaxe C++11 et ça permet de remplir le tableau avec les valeurs comprises entre 0 et 9 (value est post incrémenté).
    http://fr.wikipedia.org/wiki/C%2B%2B...es_intervalles
    Voici un lien sur le support de C++11 dans GCC
    http://cpp.developpez.com/redaction/...bdivers/cpp11/
    OK, donc si je fais ceci de manière classique ça ne change pas le fait que ça soit parallélisé
    Citation Envoyé par Ehonn Voir le message
    Ici on demande a paralléliser la boucle for. Mais si on la parallélise telle quelle #pragma omp parallel for, chaque thread va accéder à la variable sum et il y aura (peut être) des collisions et la valeur de sum ne sera pas celle désirée.
    OK je comprends ce que tu veux dire
    Citation Envoyé par Ehonn Voir le message
    Par exemple the thread 0 lit la valeur de sum (4 par exemple), the thread 0 fait le calcul sum + tab[i] (4 + 3 = 7),le thread 1 lit la valeur de sum (4), le thread 0 écrit la valeur de sum (7), le thread 1 fait le calcul sum + tab[i] (4 + 2 = 6) (le thread 2 n'a pas recharger la valeur de sum après l'écriture par le thread 0), le thread 1 écrit la valeur de sum (6). Avec la collision, on obtient 6 (4 + 2) (dans cet exemple) au lieu de 9 (4 + 3 + 2).
    Ceci est une réduction, OpenMP va déclarer automatique une variable sum par thread, fait le code demandé. Puis une fois que tous les threads ont fini, il va faire la somme de tous les sum.
    Pour le reste, je répond à cette question dans ton autre post.
    http://www.developpez.net/forums/d13...penmp-boucles/
    je comprends, merci pour cette explication!
    Citation Envoyé par Ehonn Voir le message
    Et tu as raison. Il n'y a aucune raison que l'on sorte du tableau ici. De plus, les exceptions dans du code parallèle : une règle simple : tu oublies ^^
    J'ai tapé ce bout de code pour illustrer un rapport de stage. Après la version "finale", je m'en été aperçu dans la version papier mais je n'ai pas fait le changement. Merci pour la remarque
    pourquoi on ne met pas d'exception dans les boucles ? je ne vois pas pourquoi...
    Citation Envoyé par Ehonn Voir le message
    J'ai tendance à mettre une ligne de compilation en commentaire dans mes fichiers sources car cela permet de faire un copier coller et de tester rapidement.
    c'est une super idée ça! ça permet notamment aux blaireau comme moi de pouvoir comprendre comment lancer ton programme sans bloquer sur l'aspect compilation
    Citation Envoyé par Ehonn Voir le message
    Voici ce que j'utilise :
    -Wall On active "tous" les warnings
    -Wextra Encore plus de warnings
    -std=c++11 à partir de GCC 4.7, -std=c++0x à partir de GCC 4.3 : Utilisation de C++11
    -pedantic Respect de la norme (donné avec -std=)
    -O3 Active tous les optimisation (il existe -O0 (pas d'optimisation), -O1, -O3 et -0s pour optimiser en taille)
    -ffast-math Peut se permettre de changer l'ordre des calculs, à utiliser avec précaution à cause des problèmes d'arrondi
    -fopenmp Active le support d'OpenMP, sinon, les #pragma omp seront ignorés et tu aura un code séquentiel
    Doc GCC - Invoking g++
    Doc GCC - C options
    Doc GCC - C++ options
    En effet, tu dois activer ces options. Les IDE proposent souvent des cases à cocher dans le paramétrage du compilateur.
    super explications!!!!!!! merci

  7. #7
    Membre Expert Avatar de Ehonn
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2012
    Messages
    788
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2012
    Messages : 788
    Par défaut
    Citation Envoyé par membreComplexe12 Voir le message
    pourquoi on ne met pas d'exception dans les boucles ? je ne vois pas pourquoi...
    Voici des règles simplifiées :
    - On ne peut pas re-envoyer une exception depuis un thread (vers le thread principal).
    - Tu pourrais utiliser les exceptions à l'intérieur des threads (je pense) mais on ne le fait pas pour des questions de performances

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Février 2010
    Messages
    2 051
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 2 051
    Par défaut
    merci

Discussions similaires

  1. Réponses: 4
    Dernier message: 21/09/2004, 21h25
  2. ajouter à la suite des tableaux
    Par vic_cw dans le forum C++
    Réponses: 9
    Dernier message: 22/08/2004, 15h11
  3. [OPENOFFICE] Transformation des tableaux OOo en HTML
    Par GrandFather dans le forum Format d'échange (XML, JSON...)
    Réponses: 3
    Dernier message: 15/05/2004, 18h00
  4. Réponses: 2
    Dernier message: 19/08/2003, 18h04
  5. free sur des tableaux "a moitié dynamiques"
    Par barthelv dans le forum C
    Réponses: 4
    Dernier message: 31/07/2003, 15h30

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo