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

  1. #21
    Expert éminent
    On n'utilise pas le même vocabulaire, j'ai l'habitude dans mon boulot de toujours parler en terme de performance et je me rend compte que cela impacte sur le choix de mes mots qui s'éloignent un peu du cas purement littéraire.

    Alors oui dans le sens du terme le main sera visité par l'ordonnanceur dans sa file d'ordonnancement, mais non il n'y aura aucune action d'effectuée en raison de son état de sommeil (autre qu'un changement de position dans la queue). Donc c'est ce que j'appelle un cas de non ordonnancement car c'est entièrement invisible (c'est de l'ordre de deux à trois instructions CPU).

    Pour éclairer mes propos je vais donc définir ce que je cachais sous les termes d'ordonnancement. Un traitement d'ordonnancement notable dans la courbe du temps, à savoir un chargement ou déchargement de contexte.

    Et concernant le 2 changements de contexte et pas 1, mea culpa ! On est bien d'accord qu'il y aura chargement de contexte du thread à la création puis rechargement du main à sa destruction.

    Sinon je suis aussi abasourdi par ce 78ms pour une création de thread vide... Même si on part du principe que l'OS n'est pas temps réel c'est extrèmement long. La création d'un processus léger comme un thread est de l'ordre de la dizaine de microseconde (donc 10^3 de moins).

    Citation Envoyé par moktar_bouain Voir le message
    T'as une méthode pour faire ça?
    Il n'y a pas de méthodes autre que de configurer l'OS et son ordonnanceur pour obtenir que les tâches ne soient pas préemptées. Ou bien de voir si l'OS te propose un ordonnanceur différent de celui qui est utilisé de base.
    Mais dans tous les cas tu seras tout de même préempté par les tâches systèmes qui possèdent le plus haut niveau de priorité, et donc à moins de lancer ton programme à un niveau noyau tu ne pourras jamais obtenir un comportement d'interdiction de préemption parfait.

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  2. #22
    Membre émérite
    Citation Envoyé par transgohan Voir le message
    Si le thread est en mode attaché le main est donc en état d'endormissement.
    Il n'est réveillé que sur réception de certains signaux en provenance de son thread lancé ou d'un process extérieur (chose assez rare sauf si vous l'avez explicitement programmé).
    Non tu te trompes, un thread en mode attaché (au sens threads POSIX, je commence à penser qu'on ne parle peut-être pas de la même chose, d'autant que tu bosses dans l'embarqué) n'est absolument pas endormis. Il s'exécute comme en mode détaché, peut-être préempté etc. exactement de la même manière qu'en mode détaché.

    La notion attached/detached ne concerne que la terminaison du thread. Un thread en mode "detached" a toutes ses ressources libérées dès sa terminaison ; pas besoin de pthread_join(). In thread en mode "attached" a ses ressources libérées quand l'autre thread fait un pthread_join(). C'est la seule différence.

  3. #23
    Expert éminent
    Je n'aime pas associer un main à l'état de thread, cela porte à confusion comme dans ton message.
    Le main s'attache un thread et attend sa terminaison. Le main est donc endormi. Mais aucunement le thread sinon on a un joli lot de zombie. ^^

    Donc je parlais d'un traitement main passif où tu te places en situation de pthread_join après le pthread_create (le cas littéraire classique en gros).
    Su le pthread_join le main est donc en état d'endormissement.

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  4. #24
    Membre émérite
    Ok donc, mais "detached" a un sens bien particulier quand on parle de pthreads et ce n'est pas ce sens que tu employais, ce qui porte à confusion.

  5. #25
    Expert éminent
    Quel est cet autre sens ?
    En mode détaché (ou detached si tu préfères), le main ne se souci plus du thread créé dans ce mode. Ils tournent donc en parallèle et le process ne se termine que lorsque les deux se terminent. (enfin là j'ai un doute... A moins qu'en mode détaché il s'associe son propre contexte de type process ?)
    J'ai beau me relire je ne vois pas ce qu'on peut interpréter autrement.

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  6. #26
    Nouveau Candidat au Club
    Bonjour,

    Merci pour tous ces interprétations
    Mais pour se focaliser sur le problème: j'ai deux threads (y compris le MAIN) qui s'exécutent en parallèle, donc le temps d'exécution doit diminuer, dans le pire des cas il reste inchangeable. Y-a-t il une explication pour ça??
    Rq: je mesure les temps avec les fonctions gettimeofday() et clock().


    Salutaions,
    Moktar.

  7. #27
    Membre émérite
    Citation Envoyé par transgohan Voir le message
    Quel est cet autre sens ?
    En mode détaché (ou detached si tu préfères), le main ne se souci plus du thread créé dans ce mode. Ils tournent donc en parallèle et le process ne se termine que lorsque les deux se terminent.
    Ce que tu ne comprends pas c'est que ce comportement, tu l'as de toute façon, que le thread soit créé en mode détaché ou non. La SEULE différence, c'est qu'en mode détaché on ne fait pas de join. En mode non détaché, il faut faire un join à un moment où à un autre, mais RIEN ne t'empêche de faire autre chose avant... Toi tu supposes que parce qu'on est en mode non détaché, alors le thread principal fait un join immédiatement après avoir créé le thread. C'est une possibilité, mais certainement pas une obligation.

  8. #28
    Expert éminent
    gettimeofday est une mesure glissante (basé sur un serveur de temps), ce n'est pas du tout fiable pour de la mesure. Il vaut mieux préférer des mesures calquées sur des horloges CPU, tu as des registres de temps sur des architectures x86 par exemple. Mais je te rassure cela n'explique pas les écarts que tu as.
    Pour l'explication du "mesure glissante" il faut comprendre qu'une seconde mesurée n'est pas forcement une seconde réelle. L'horloge se décale au fur et à mesure du temps et se resynchronise via un serveur de temps. La resynchronisation se fait en douceur ce qui provoque un rattrapage du temps. Par exemple si tu mesures 9h24 et 14secondes à un instant t mais qu'en fait tu es désynchronisé d'une seconde à ce même instant, si le serveur de temps te resynchronise la seconde suivante tu liras 9h24 et 16secondes au lieu de 15secondes.

    Je ne saurai te dire pour clock par contre ne l'ayant jamais utilisé.

    Après on ne peut pas tellement t'en dire plus sur le pourquoi des 60% de différence. Il nous faudrait savoir quelles fonctions tu utilises, si tu as des traitements parallèles au sein de ce thread (création de nouveaux threads ? Utilisation d'openMP ou autre ?), ect.
    L'utilisation de la librairie pthread va te sécuriser certaines fonctions en rajoutant des protections par mutex et de la synchronisation par signaux. Ce n'est pas gratuit tout ça.

    Comme précédemment demandé il nous faudrait un exemple minimal qu'on puisse exécuter pour se rendre compte de ton souci.

    Edit :
    Citation Envoyé par matafan Voir le message
    Ce que tu ne comprends pas c'est que ce comportement, tu l'as de toute façon, que le thread soit créé en mode détaché ou non. La SEULE différence, c'est qu'en mode détaché on ne fait pas de join. En mode non détaché, il faut faire un join à un moment où à un autre, mais RIEN ne t'empêche de faire autre chose avant... Toi tu supposes que parce qu'on est en mode non détaché, alors le thread principal fait un join immédiatement après avoir créé le thread. C'est une possibilité, mais certainement pas une obligation.
    Je partais du cas simple d'école.
    C'est comme quand on conduit une voiture, on peut soit prendre chacun la sienne, soit remplir les sièges passagers. Mais il va de soit qu'on sait que les deux solutions existent, c'est trivial.

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  9. #29
    Membre émérite
    Pour répondre à ta question moktar_bouain, si tu as vraiment 60% de perf en moins alors il est probable que tu ais un problème algorithmique et que tes deux threads ne travaillent pas vraiment en même temps. Ca, ou bien tu n'as qu'un CPU dans ta machine... Bien sûr avec un seul CPU (sauf hyperthreading), on ne peut pas faire tourner deux threads en même temps.

    Pour ta remarque sur les 78 ms pour ne rien faire : quand tu utilises la libpthreads, tu as pas mal d'initialisation au début du programme (avant le main() ; ce n'est pas de ton recours). C'est ça qui prend tu temps, pas vraiment le pthread_create() en lui même.

    Edit : d'ailleurs je n'ai pas trop compris ton histoire de mutex dans main(). Tu créé des threads pour faire des traitements en parallèle. Si tu ajoutes un mutex pour ne pas que tes threads tournent en parallèle, où est l’intérêt ? Tu as certainement besoin de mutex pour protéger certaines ressources, mais tu dis avoir protégé tout ton main par un mutex.

  10. #30
    Membre confirmé
    Citation Envoyé par moktar_bouain Voir le message
    Mais pour se focaliser sur le problème: j'ai deux threads (y compris le MAIN) qui s'exécutent en parallèle, donc le temps d'exécution doit diminuer, dans le pire des cas il reste inchangeable.
    Un speedup n'a rien d'automatique en parallélisant, voir les cas de "false sharing" de ligne de cache par exemple. Donc non dans le pire des cas c'est bien plus lent, et ce n'est pas "rare".

  11. #31
    Nouveau Candidat au Club
    Bonsoir à tous,

    Je crois que j'ai trouvé la cause de cette augmentation.
    En fait, je crois que cette augmentation est due à cause de la commutation entre le thread et la fonction main() (changement de contexte).
    Dans mon programme je fais la suite :

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    for(i = 0; i< 22; i++)
    {
    for(j= 0; j<18; j ++)
    {  .
        .
        .
       pthread_create(&thread, NULL, Encode, (void*)t);
         .
         .
    }
    }

    Ce qui augmente énormément le temps d'exécution, est ce que ce logique ça??.
    Alors, puisqu'il n y' a pas resume() et suspend() avec pthread,est ce qu'il y a une méthode qui permet de faire ça:

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    pthread_create(&thread, NULL, Encode, (void*)t);
     for(i = 0; i< 22; i++)
    {
    for(j= 0; j<18; j ++)
    {  .
        .
        .
      appele_de_thread()
         .
         .
    }
    }

    Bien sur pour éviter la création de thread dans la boucle.
    Je compte sur vous
    Moktar

  12. #32
    Expert éminent
    Donc ton temps provient bien d'une création de N threads au sein de ton traitement.
    Comme précédemment dit il ne faut pas paralléliser n'importe quoi, n'importe comment.
    A noter que ce n'est pas le temps de création des threads qui te pose problème, les ordonnanceurs sont assez intelligent pour ne pas créer tous les threads d'un coup. Si tu demandes la création de 120 threads il va peut être en créer 30 puis attendre la fin de ces threads avant d'autoriser la création des autres.

    Il faut vérifier que ton traitement est assez long par rapport à la charge imposée par les changements de contexte.
    Mais aussi que ton architecture peut supporter tout ça (sur un processeur monocoeur c'est pas tellement intelligent de lancer 64 threads pour un traitement il peut être plus rapide de tout faire dans un seul).

    Pour l'aspect pratique de création / exécution avec la librairie pthread tu peux l'émuler avec un mutex initialisé à 0. La première instruction de ton main_thread devra prendre ce mutex, ce dernier étant à 0 le thread va s'endormir à peine créé. Tu peux donc ensuite via ton main rendre ce mutex pour réveiller le thread quand bon te semble.

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  13. #33
    Nouveau Candidat au Club
    Bonjour

    Donc ton temps provient bien d'une création de N threads au sein de ton traitement.
    Comme précédemment dit il ne faut pas paralléliser n'importe quoi, n'importe comment.
    A noter que ce n'est pas le temps de création des threads qui te pose problème, les ordonnanceurs sont assez intelligent pour ne pas créer tous les threads d'un coup. Si tu demandes la création de 120 threads il va peut être en créer 30 puis attendre la fin de ces threads avant d'autoriser la création des autres.
    En fait, ce vrai que j'ai créé plus de 120 threads, exactement 396 thread. Mais, ils n'arrivent pas à s'exécuter en parallèle puisque à chaque incrémentation d'un boucle le programme exécute seulement un thread en parallèle avec le main(). C'est à dire j'ai créé 396 qui s'exécutent l'un après les autres. Donc l'ordonnanceur a toujours le Main() avec un thread, et non pas comme tu as dit 120 threads.

    Il faut vérifier que ton traitement est assez long par rapport à la charge imposée par les changements de contexte.
    Mais aussi que ton architecture peut supporter tout ça (sur un processeur monocoeur c'est pas tellement intelligent de lancer 64 threads pour un traitement il peut être plus rapide de tout faire dans un seul).
    Oui, le traitement traitement est assez long par rapport à la charge imposée par les changements de contexte.
    Je travaille sur un architecture multi-coeur (2 coeurs) .

  14. #34
    Expert éminent
    Donc c'est normal que tu obtiennes des temps augmentés.
    Tu as ton temps de calcul séquentiel + le temps de création et destruction de 396 threads + les accès en mémoire partagée.

    Tu utilises des threads sans aucun parallélisme, c'est une... abération.
    A ce niveau autant remplacer ton pthread_create par un simple appel de fonction et revenir à du séquentiel (que tu n'as en fait jamais quitté !).

    Si tu veux paralléliser il ne faut pas attendre la fin des threads au sein de ta boucle mais après celle-ci afin d'exécuter plusieurs threads en parallèle.
    Et après on rentre dans le gros boulot de la parallélisation, à savoir la protection des variables partagées(accès concurrentiels à une zone mémoire en écriture, voire en lecture aussi si elle peut être modifiée), la gestion de la charge (nombre de tâche à un instant t) et l'ordonnancement des tâches (si des tâches ont besoin du résultat d'autres tâches pour faire leur traitement).

    « Toujours se souvenir que la majorité des ennuis viennent de l'espace occupé entre la chaise et l'écran de l'ordinateur. »
    « Le watchdog aboie, les tests passent »

  15. #35
    Expert éminent sénior
    Citation Envoyé par moktar_bouain Voir le message
    puisqu'il n y' a pas resume() et suspend() avec pthread,est ce qu'il y a une méthode qui permet de faire ça:

    Code :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    pthread_create(&thread, NULL, Encode, (void*)t);
     for(i = 0; i< 22; i++)
    {
    for(j= 0; j<18; j ++)
    {  .
        .
        .
      appele_de_thread()
         .
         .
    }
    }
    Oui: Tu dois faire un modèle Producteur/Consommateur. Généralement je fais ça avec deux sémaphores et un buffer circulaire.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.