1. #1
    Nouveau membre du Club
    Profil pro
    Enseignant
    Inscrit en
    septembre 2011
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : septembre 2011
    Messages : 28
    Points : 25
    Points
    25

    Par défaut Performances dégradées en dehors des threads

    Bonjour,

    J'ai multi threadé certaines parties d'un programme d'astronomie que je maintiens et dont certaines boucles de calculs étaient faciles à paralléliser. (simple grosse boucle for avec à l'intérieur des calculs indépendants) J'ai donc utilisé un thread pool pour cela, adapté à mon processeur et c'est génial, la partie que j'ai threadé va plus vite càd qu'il faut moins de temps d'exécution pour réaliser la tache demandée. (sur un 4 core, je gagne entre 30% et 40% de temps d'exécution) Et j'en suis très content car c'était le but initial de mon travail.

    avant:

    Pour chaque frame
    - Fonction1
    - Fonction2
    - Fonction3
    - Fonction4
    - Fonction5
    - Fonction6
    - Fonction7
    - Fonction8
    - Fonction9
    - Fonction10
    Fin pour

    maintenant:

    Pour chaque frame
    - Fonction1
    - Fonction2 threadée
    --- un thread
    --- un thread
    --- un thread
    --- un thread
    - Fonction3
    - Fonction4
    - Fonction5
    - Fonction6 threadée
    --- un thread
    --- un thread
    --- un thread
    --- un thread
    - Fonction7
    - Fonction8
    - Fonction9 threadée
    --- un thread
    --- un thread
    --- un thread
    --- un thread
    - Fonction10
    Fin pour





    J'ai environ 50 grosses fonctions et j'en ai parallélisé 4. (forcément les plus gourmandes en temps)

    Sauf que j'ai remarqué après que tout le reste de mon programme mettait plus de temps à s'exécuter. Je veux dire par la que les parties non threadées, qui ne sont pas pas du tout liées à ma partie threadée s'exécutent entre 5% à 60% moins vite...

    J'ai fais de nombreux tests de comparaison (50x, chacun, dans des conditions strict identiques) avant de vous écrire ce message. J'ai utilisé pour cela std::chrono afin de déterminer le temps mis à l'exécution de toutes mes fonctions, threadées ou non.

    Aussi je suis perdu. Je ne vous ait pas mis de code car il y en a trop à lire pour rentrer dans le projet.

    Est ce que ce que je vous décris peut exister (thread rapide mais reste devient plus lent) ou c'est moi qui ait fait une implémentation bancale ?

    Ce symptôme, s'il existe, a-t-il un nom ? (que je puisse demander à Google de m'aider !)


    Merci pour votre aide !

    Cordialement

  2. #2
    Membre confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    avril 2017
    Messages
    113
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : avril 2017
    Messages : 113
    Points : 538
    Points
    538

    Par défaut

    Citation Envoyé par tickyletroll Voir le message
    (simple grosse boucle for avec à l'intérieur des calculs indépendants) J'ai donc utilisé un thread pool pour cela,
    Bonjour.
    A première vue, pour paralléliser ce genre de boucles, il vaut mieux utiliser OpenMP, et éviter de terminer/recréer les threads entre chaque section parallèle.

    Citation Envoyé par tickyletroll Voir le message
    et c'est génial, la partie que j'ai threadé va plus vite càd qu'il faut moins de temps d'exécution pour réaliser la tache demandée. (sur un 4 core, je gagne entre 30% et 40% de temps d'exécution)
    Sur 4 coeurs, c'est un gain de 400% qui serait génial. 40% c'est plutôt très mauvais (ou alors que le calcul ne se prête pas bien à la parallélisation).
    Tu devrais peut-être poser ton problème sur la section "Programmation parallèle, calcul scientifique et de haute performance (HPC)" du forum.

  3. #3
    Expert éminent
    Homme Profil pro
    Développeur informatique
    Inscrit en
    février 2005
    Messages
    4 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : février 2005
    Messages : 4 391
    Points : 9 801
    Points
    9 801

    Par défaut

    Utilisez un profiler pour voir où et pourquoi les performances se dégradent.

  4. #4
    Nouveau membre du Club
    Profil pro
    Enseignant
    Inscrit en
    septembre 2011
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : septembre 2011
    Messages : 28
    Points : 25
    Points
    25

    Par défaut

    Merci pour vos réponses.

    Je vais m'y atteler de ce pas.

    Cordialement,

  5. #5
    Nouveau membre du Club
    Profil pro
    Enseignant
    Inscrit en
    septembre 2011
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : septembre 2011
    Messages : 28
    Points : 25
    Points
    25

    Par défaut

    Je reviens vers vous.

    J'ai utilisé des debuggers mais je ne vois pas ce qui cloche. Je suis sous linux et j'ai utilisé Valgrind et perf.
    J'ai vu de nombreuses informations, mais rien que ne me parle suite à mon problème.
    En fait, je ne suis pas capable seul de trouver ce qui cloche.
    Avec quel outil (même texte) peut on voir ce qui se passe au niveau des core d'un CPU ?
    DE tous les rapports que j'ai, sur quoi dois je me focaliser ?

    J'ai alors threadé une autre fonction afin d'exécuter une autre boucle plus rapidement.
    (ce n'était pas une boucle de calcul mathématique)

    A nouveau mêmes symptômes:
    - la fonction threadée voit sa durée d'exécution divisée par deux.
    - les autres fonctions voient leur temps d’exécution rallongé de 15 à 300%.

    J'ai exécuté mon code sur différentes machines.
    En mono thread et ensuite avec une grosse fonction coupée en thread.

    Sur des AMD type AMD Athlon(tm) X4 740 socket FM2+ ou AM3+, le symptôme décrit est bien visible.

    Sur un INTEL i5-6500 c'est la catastrophe: les autres fonctions voient leur temps d’exécution rallongé de 300%.

    Mais ...

    Sur un INTEL i5-4460, c'est normal , je veux dire que la partie threadée va deux fois plus vite, et les autres fonctions vont aussi vite que si j'avais lancé mon programme en un bloc mono-thread. HOURA !
    Cela m'a évité de devenir complètement fou car je ne comprenais pas pourquoi en threadant une fonction toutes les autres se voyaient beaucoup ralentir. Un peu j'aurais compris mais beaucoup ... non

    J'ai lancé de nombreux tests sur toutes mes machines avant de vous écrire.

    Je pensais que j'étais entrain d'exploser le cache des CPU, les Intels ont 6Mb de cache chacun et les AMD 4Mb. Mais non, les 2 i5 ont un comportement bien distinct pour une même valeur de cache.

    Pouvez vous m'aider ?



    Cordialement,

  6. #6
    Rédacteur/Modérateur

    Homme Profil pro
    Network game programmer
    Inscrit en
    juin 2010
    Messages
    4 658
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 30
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : juin 2010
    Messages : 4 658
    Points : 18 963
    Points
    18 963

    Par défaut

    Démarrer des threads c'est lent, on ne sait toujours pas si tu utilises une threadpool correctement ou non ni quel(s) mécanisme(s) de synchronisation tu utilises à la fin de tes threads.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  7. #7
    Nouveau membre du Club
    Profil pro
    Enseignant
    Inscrit en
    septembre 2011
    Messages
    28
    Détails du profil
    Informations personnelles :
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : septembre 2011
    Messages : 28
    Points : 25
    Points
    25

    Par défaut

    Je me suis tourné vers github et je me suis basé sur le code suivant :
    https://github.com/progschj/ThreadPool

    J'ai investi dans ce livre: C++_Concurrency_in_Action

    Dans la classe ciblée, j'ai une fonction de calcul computePosition qui traite chacun des éléments que contient la classe. Comme il n'y a aucun lien de traitement d'un élément à un autre, que les éléments sont interchangeables, je me suis dit que découper cette boucle en la traitant avec des threads serait une idée...

    J'ai donc transformé la fonction computePosition pour la rendre thread-safe et c'est cette fonction que j'appelle à travers une fonction wrapper afin de me conformer avec le code ThreadPool de Github.
    J'ai crée un mutex pour éviter que les threads écrivent à la sortie n'importe comment leur résultat dans un vector.

    Ce qui donne en particulier : (j'ai mis une version simplifiée)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    classe StarNavigator
    ...
    public:
            void computePosition(Vec3f pos);
    private:
    	static bool thread_wrapper(StarNavigator *a, unsigned int indice)
    		{return a->computeChunk(indice);};
     
    	bool computeChunk(unsigned int indice);
     
    	ThreadPool * pool=nullptr;
    	std::vector< std::future<bool> > results;
    Le constructeur crée artisanalement pour le moment le ThreadPool:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    pool = new ThreadPool(std::thread::hardware_concurrency());
    ma fonction computePosition est alors appelée dans la boucle principale de mon programme, elle se comporte ainsi:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void StarNavigator::computePosition(Vec3f pos) 
    {
            ....
    	for(unsigned int i=0; i<nbPaquets; i++)
    		this->results.emplace_back( pool->enqueue( StarNavigator::thread_wrapper, this, i) );
     
    	for(auto && result: results)
    		result.get();
    	results.clear();
    }
    la fonction computeChunk réalise un traitement du type:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    void StarNavigator::computeChunk(unsigned int i) 
    {
            ....
            //série de calculs sur l'élément i en question
            //détermination de propriétés de l'objet
            //cela met un certain temps à être fait
            ....
            ....
            mutex.lock();
            ajout dans un vecteur de quelques valeurs
            mutex.unlock();
    }
    C'est artisanal mais cela fait son effet, la durée d'exécution de la fonction computePosition est bien plus courte avec l'utilisation des threads pour réaliser la tâche qui lui est demandée.
    J'ai aussi comparé les sorties de la classe avec les threads, elles correspondent (à la permutation prêt des éléments du vecteur de sortie)


    Merci pour votre aide.

Discussions similaires

  1. Réponses: 0
    Dernier message: 22/04/2014, 18h15
  2. Réponses: 3
    Dernier message: 20/08/2010, 14h11
  3. [reseaux] Gestion des threads en perl
    Par totox17 dans le forum Programmation et administration système
    Réponses: 2
    Dernier message: 28/11/2002, 10h40
  4. Programmer des threads
    Par haypo dans le forum C
    Réponses: 6
    Dernier message: 02/07/2002, 14h53

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