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

Multithreading Discussion :

Différences de performances entre thread principal et QThread


Sujet :

Multithreading

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Inscrit en
    Juillet 2007
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 26
    Par défaut Différences de performances entre thread principal et QThread
    Bonjour à tous,

    Voilà j'ai un petit soucis que je n'arrive pas à régler, et j'en appelle donc à vos conseils ou avis. Un même code exécuté dans le main() ou dans le run() d'un QThread ne prend pas du tout le même temps d'exécution :/
    La portion de code utilisée :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    GameOptions go;
        go.minCardLvl = 0;
        go.maxCardLvl = 1;
        go.gameRules = 0;
        go.gainMode = 0;
        MinMaxTree *minmaxtree = new MinMaxTree();
        minmaxtree->setBoard(new GameBoard());
        minmaxtree->setGameOptions(&go);
        minmaxtree->setBlueCC( new CardCollection("0 1 2 3 4 ") );
        minmaxtree->getBestMove();
    Si celle-ci est exécutée dans le main alors il faudra 1,5 secondes à la fonction getBestMove() pour retourner une valeur.

    La même chose, dans un QThread :
    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
     
    class TestAI : public QThread {
    public:
        TestAI(QObject *parent=0) : QThread(parent) {
     
        }
     
    protected:
        void run() {
            GameOptions go;
            go.minCardLvl = 0;
            go.maxCardLvl = 1;
            go.gameRules = 0;
            go.gainMode = 0;
            MinMaxTree *minmaxtree = new MinMaxTree();
            minmaxtree->setBoard(new GameBoard());
            minmaxtree->setGameOptions(&go);
            minmaxtree->setBlueCC( new CardCollection("0 1 2 3 4 ") );
            minmaxtree->getBestMove();
        }
    };
     
    TestAI ai;
    ai.start();
    Prend 17 secondes!
    J'ai essayé de voir du côté des signaux/slots puisque le GameBoard utilise ce mécanisme en interne pour détecter les changements de score, mais rien ne change en l'enlevant..
    En rajoutant moveToThread(this) dans le run et le parent aux différents QObjects utilisés, idem je n'arrive pas à retrouver les performances de l'algo appelé dans le main()

    Vous avez une petite idée? là je sèche :/
    Merci

  2. #2
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Je ne sais pas comment est implémenté QThread, mais tu peux avoir des impacts sur les perfs si tu as beaucoup d'allocation dynamique (new/delete) dans tes différents thread. D'une façon plus globale, le ralentissement peut être lié à des appels systèmes protégés contre l'accès concurrent.
    Tes synchronisations si tu en as ou celles des mécanismes internes de Qt si ça existe peuvent aussi avoir un impact sur tes perfs.

  3. #3
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Salut.
    C'est bizarre comme différence
    Déjà tu compile bien en release? (on ne sais jamais)

    Si oui, je ne voie pas de raison à part un truc comme de la protection contre l'accès concurrent ou de la synchronisation inter thread.

    Sans savoir ce que fait tes classes, je ne pourrais pas en dire plus.

  4. #4
    Membre averti
    Inscrit en
    Juillet 2007
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 26
    Par défaut
    Bonjour,

    Oui je compile bel et bien en release, cela dit j'ai recompilé Qt pour retirer quelques dépendances, mais surtout du côté de WebKit, j'essaierai avec une release "propre" de Qt, on ne sais jamais.
    Pour ce qui est des new / delete il y en a, pas mal (chaque carte jouée, voir plus bas), ça me fait penser que je pourrais améliorer ça, est ce que ça pourrait en être la cause?
    L'algo exécuté dans le thread est assez simple, c'est un appel récursif qui permet de visualiser et tester toutes les possibilités d'un jeu de carte, au niveau mémoire tout est créé dans le même thread (j'ai vérifié avec currentThreadId() ), aucun sémaphores ni mutex ni autre n'est mis en place puisque pas nécessaires.

    Voici les classes principales :
    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
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
     
    class GameCard : public QObject {
        Q_OBJECT
        GameCard(int cardId, QObject *parent) : QObject(parent) { ... }
    signals:
       void flipped();
    }
     
    class GameBoard : public QObject {
     
        ...
        void addCard(int card, int cell) {
            GameCard *newCard = new GameCard(card, this);
            _cells[cell].setCard( newCard );
            connect(newCard , SIGNAL(flipped()),
                        this, SLOT(on_card_flipped());
        }
     
        void on_card_flipped() {
           //mise à jour des scores
        }
     
    }
     
    class MinMaxTree : public QObject {
        Q_OBJECT
    public:
        MinMaxTree(QObject *parent = 0);
        ~MinMaxTree();
     
        /**
         * @fn getBestMove
         * @brief Returns the MinMaxNode corresponding to the best calculated move.
         */
        MinMaxNode getBestMove() {
           //création du noeud racine
           ...
           buildTree( root, 0);
           //calculs
           return bestMove;
        }
     
     
       ...
     
    private:
        GameBoard *_board; 
     
        ...
     
        float buildTree(MinMaxNode *node, short depth) {
            foreach(int card, _cardCollection) {
                foreach(int cell, _emptyCells) {
                    _board->addCard(card, cell);
     
                    //appel récursif jusqu'à la profondeur souhaitée
                    buildTree( ..., depth+1);
                   //calcul du résultat ...
     
                   //retour à la position précédente
                   _board->undo();
     
                }
            }
            return valeur du coup;
        }
     
    }
     
    MinMaxTree érite de QObject car il connecte le signal flipped des GameCard selon les GameOptions choisies.
    Vous trouverez les appels dans mon premier mail, l'objet GameOptions défini les règles du jeu, l'object CardCollection les cartes sur lesquelles buildTree boucle.

    Les GameCards, une fois détruites ne sont pas "disconnected" du slot du GameBoard, est ce grave? j'imagine que c'est fait automatiquement dans le destructeur de QObject, je me trompe?

    Du coup, tous les objets sont créés et ont un parent appartenant au même thread et donc c'est très bizarre!

    Merci

  5. #5
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 035
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 035
    Par défaut
    Un cas possible est une erreur mémoire ou une variable non initialisé. Parfois ça fait des truc bizarre sans planter l'application :/

    Si tu est sous linux, je te conseil d'essayer valgrind. Tu pourras récupérer un callgraph et regarder où tu perd du temps. Mais surtout tu saura si tu fait des erreurs mémoires.

    Il existe aussi gprof mais je ne connait pas.

  6. #6
    Membre averti
    Inscrit en
    Juillet 2007
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 26
    Par défaut
    Rebonjour,

    Je viens de tester avec Qt 4.7 tout propre, et bien rien ne change
    Je travaille sous Windows, je chercherai des équivalent à ces softs, merci

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par cb-bk Voir le message
    Pour ce qui est des new / delete il y en a, pas mal (chaque carte jouée, voir plus bas), ça me fait penser que je pourrais améliorer ça, est ce que ça pourrait en être la cause?
    C'est une cause à ne pas écarter si tu as des allocations dynamiques dans plusieurs threads concurremment. L'allocation dynamique peut masquer des synchronisations OS qui sont là pour éviter des corruptions. Essais d'ôter de tes threads les allocations new/delete explicites et implicites (par expl, ajouter un noeud à une liste, agrandir un vecteur, les chaines de caractères, etc.).
    Voir ici. Ca n'a pas rapport avec Qt, mais cela donne des conseils de bon sens.

  8. #8
    Membre averti
    Inscrit en
    Juillet 2007
    Messages
    26
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 26
    Par défaut
    oh oh oh ^^
    J'ai retiré tous les new dans le code du thread et tadam! Le temps d'éxecution devient équivalent! Le problème venait donc de cela, je ne l'aurai pas cru, vu la différence de perfs, en tout cas merci!

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [PC portable] Différence de performance entre processeur 2 Ghz et 2,5 GHz
    Par debdev dans le forum Ordinateurs
    Réponses: 5
    Dernier message: 02/11/2009, 12h41
  2. Différence de performance entre localhost et serveur
    Par Borowsky dans le forum Décisions SGBD
    Réponses: 5
    Dernier message: 10/09/2009, 00h56
  3. Interaction entre thread principal et thread secondaire
    Par mehdi_me85 dans le forum Threads & Processus
    Réponses: 37
    Dernier message: 28/05/2009, 15h08
  4. Réponses: 14
    Dernier message: 12/04/2009, 20h47
  5. Différence de performance entre JOIN et Subselect ?
    Par guidav dans le forum Requêtes
    Réponses: 1
    Dernier message: 20/07/2007, 10h01

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