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

POSIX C Discussion :

thread et temps de calculs


Sujet :

POSIX C

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut thread et temps de calculs
    Bonjour, j'ai deux versions d'un prgm : une version séquentielle et une version en utilisant les threads. Mon pb est que le temps de calcul est un tout petit plus long en utilisant les threads... ce qui n'est pas super (sur mon PC, j'ai deux bi-processeurs). Savez-vous d'où pourrait venir cette lenteur ? D'autant plus que lorsque je fait un "top" dans mon shell, je vois que la valeur de Cpu(s) oscille entre 31% et 36 % (avec les thread et en séquentiel). Bref, j'ai l'impression que mon pgrm ne se parallélise pas. Voici un extrait de mon code avec les thread (je n'ai pas de mutex car les différentes tâches ne partagent pas de données) :

    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
     
    typedef struct
    {
      CVodeMem cvode_mem;
      N_Vector y;
      double t;
      double tout;
      unsigned int nbpar; /* number of the particle */
      double rpm6; /* 6 * rotation per minute */
    } Integ;
     
    void CreateInteg(void * cvode_mem,N_Vector y,double t,double tout,unsigned int
    nbpar,double rpm6,Integ * integ)
    {
      integ->cvode_mem=(CVodeMem) cvode_mem;
      integ->y=y;
      integ->t=t;
      integ->tout=tout;
      integ->nbpar=nbpar;
      integ->rpm6=rpm6;
    }
     
    void * Integration(void * p)
    {
      if(p==NULL)
      {
        fprintf(stderr,"Error in %s %u : p == NULL\n",__FILE__,__LINE__);
        exit(EXIT_FAILURE);
      }
      else
      {
        Integ * pInteg=(Integ * ) p;
        CVodeMem pcvode_mem=pInteg->cvode_mem;
     
        int flag;
        flag=CVodeReInit(pInteg->cvode_mem,pcvode_mem->cv_f,pInteg->t,pInteg->y,CV_SV,pcvode_mem->cv_reltol,pcvode_mem->cv_Vabstol);
        if(flag!=CV_SUCCESS)
        {
          fprintf(stderr,"Error in %s %d : CVodeReInit() failed at theta = %f for the particle %d. Exit program\n",__FILE__,__LINE__,pInteg->rpm6*pInteg->t-180.,pInteg->nbpar);
          exit(EXIT_FAILURE);
        }
     
        flag = CVode(pInteg->cvode_mem, pInteg->tout,pInteg-> y, &pInteg->t,CV_NORMAL);
        if (check_flag(&flag, "CVode", 1))
        {
          fprintf(stderr,"Error in %s : %d : CVode failed at theta = %g for the particle %d\nExit program\n",__FILE__,__LINE__,pInteg->rpm6*pInteg->t-180.,pInteg->nbpar);
          exit(EXIT_FAILURE);     
        }
     
        return NULL;
      }  
    }
    et dans la fonction main() j'ai

    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
     
    pthread_t task[N];
     
        Integ * integ=malloc(N*sizeof(*integ));
        if(integ==NULL)
        {
          MEMERROR;
          exit(EXIT_FAILURE);
        }
     
        while(tout<tfin)
        {
          //printf("theta = %f\n",e->rpm6*tout-180.);
     
          for(i=0;i<N;++i) /* loop on particles */
          {
    	CreateInteg(cvode_mem[i],y[i],t[i],tout,i,e->rpm6,&integ[i]);
     
    	pthread_create(&task[i], NULL, Integration, &integ[i]);
     
    	t[i]=tout;
     
    	pthread_join (task[i], NULL);
     
          } /* end of for(i=0;i<N;++i) */
     
     
     
                          /****  Turbulence  *****/  
     
          for(j=0;j<neq;++j)
          {
            aux3=0.;
    	for(k=0;k<N;++k) aux3+=Ith(y[k],j);
    	for(k=0;k<N;++k) Ith(y[k],j)=Ith(y[k],j)*aux1+aux3*aux2; 
          }
     
          fPrintOutput(fileOutput,tout,y,N,e,mec);
     
          tout += dt;
        } /* end of while(tout<tfin) */
    remarque : j'ai utilisé la fonction pthread_join() car je dois effectuer toutes les tâches avant de faire ma "turbulence". Devrais-je utiliser à la place des thread avec condition (pthread_cond_signal et pthread_cond_wait) ?

    Merci.

  2. #2
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Tu lances une seule thread, tu ne fais à moitié rien puis tu l'attends. Ensuite tu lances une autre thread... Tout est donc fait séquentiellement. Pour profiter du multithread, il t'en faut au moins deux qui font quelque chose.

    Donc une boucle qui lance les threads puis une qui les attends, puis ton calcul final. (En fait, tu as intérêt à ne pas avoir trop de thread non plus, sauf si la majorité est bloquée en attende de quelque chose, IO, mutex, ...)

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    OK, donc je dois modifier mon code de la manière suivante :

    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
     
    while(tout<tfin)
        {
          //printf("theta = %f\n",e->rpm6*tout-180.);
     
          for(i=0;i<N;++i) /* loop on particles */
          {
    	CreateInteg(cvode_mem[i],y[i],t[i],tout,i,e->rpm6,&integ[i]);
     
    	pthread_create(&task[i], NULL, Integration, &integ[i]);
     
    	t[i]=tout;
     
          } /* end of for(i=0;i<N;++i) */
     
          for(i=0;i<N;++i) pthread_join (task[i], NULL);
     
                          /****  Turbulence  *****/  
     
          for(j=0;j<neq;++j)
          {
            aux3=0.;
    	for(k=0;k<N;++k) aux3+=Ith(y[k],j);
    	for(k=0;k<N;++k) Ith(y[k],j)=Ith(y[k],j)*aux1+aux3*aux2; 
          }
     
          fPrintOutput(fileOutput,tout,y,N,e,mec);
     
          tout += dt;
        } /* end of while(tout<tfin) */
    Est-ce correct (en dehos du fait que mon solveur plante si je fais cette méthode) ? Est-ce que je vais gagner du temps ? Ce que j'ai encore du mal à comprendre est comment est lancé le prgm en parallèle ? Avec MPI, l'exécutable est copié dans chaque processeur et ensuite, suivant le rang du processeur on effectue les opérations. Il y a donc plein de tests du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    if(myrank==2) blabla;
    mais là, comment est donnée l'instruction : "effectuer le thread 3 car le threa 2 et 1 sont déjà lancés" (en supposant qu'ils sont effectués dans l'ordre croissant) ?

    Merci.

  4. #4
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par salseropom
    Est-ce correct (en dehos du fait que mon solveur plante si je fais cette méthode) ?
    A première vue oui.

    Est-ce que je vais gagner du temps ?
    Ca devrait sur une machine multiprocesseur, du moins si tes threads ne se synchronisent pas à gogo.

    Ce que j'ai encore du mal à comprendre est comment est lancé le prgm en parallèle ? Avec MPI, l'exécutable est copié dans chaque processeur et ensuite, suivant le rang du processeur on effectue les opérations. Il y a donc plein de tests du genre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    if(myrank==2) blabla;
    mais là, comment est donnée l'instruction : "effectuer le thread 3 car le threa 2 et 1 sont déjà lancés" (en supposant qu'ils sont effectués dans l'ordre croissant) ?
    Je ne comprends pas réellement ta question (mais je n'ai jamais utilisé MPI).

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Salut (et merci encore de ta patience)
    Voilà, si je veux faire un prgm en parallèle avec MPI (qui est une collection de tous plein de fonction) je dois faire plusieurs choses
    1) donner un nom (et un numéro) à chaque processeur
    2) dans mon prgm je dois spécifier le travail de chaque processeur. Par exemple si je veux que le PC 1 fasse l'opération 1 et le PC 2 fasse l'opération 2 je dois écrire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    si(rang du PC == 1) alors faire opération 1
    si(rang du PC == 2) alors faire opération 2
    et j'utilise des fonctions d'envoi et de réception de message pour faire correspondre tous les PC entre eux. A quoi est dû le fait que toutes les tâches s'effectuent en parallèle ? Tout simplement car le fichier exécutable est copié dans chaque PC (c'est donc le même exécutable pour tous les PC) et donc chaque PC exécute le même prgm (en faisant attention aux "si (rang du PC == 1) alors blabla").

    Ma question porte maintenant sur les threads : si j'écris

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    pthread_t ta;
    pthread_t tb;
     
    pthread_create (&ta, NULL, task_a, NULL);
    pthread_create (&tb, NULL, task_b, NULL);
    comment est-ce que le PC sait qu'il doit effectuer ces 2 tâches en parallèle ? Comment est donnée l'instruction ?

    Si j'écris

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    for(i=0;i<N;++i)
    {
      pthread_create (&t[i], NULL, task[i], NULL);
      pthread_join (t[i], NULL);
    }
    pourquoi est-ce du séquentiel mais si j'écris

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    for(i=0;i<N;++i)
      pthread_create (&t[i], NULL, task[i], NULL);
     
    for(i=0;i<N;++i)
      pthread_join (t[i], NULL);
    pourquoi est-ce du parallèle ?

    J'espère avoir été assez explicite dans ma question.

  6. #6
    Membre chevronné
    Homme Profil pro
    Dév. Java & C#
    Inscrit en
    Octobre 2002
    Messages
    1 414
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Dév. Java & C#
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Octobre 2002
    Messages : 1 414
    Points : 1 996
    Points
    1 996
    Par défaut
    Bonjour,

    Dans cette version,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for(i=0;i<N;++i)
    {
      pthread_create (&t[i], NULL, task[i], NULL);
      pthread_join (t[i], NULL);
    }
    Tu crées un thread et tu attends qu'il finisse (fonctin thread_join )pour créer le suivant.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for(i=0;i<N;++i)
      pthread_create (&t[i], NULL, task[i], NULL);
     
    for(i=0;i<N;++i)
      pthread_join (t[i], NULL);
    Avec ce code, tu crées tous les treads puis ensuite tu attends qu'ils finissent.

  7. #7
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    Salut, merci de cette précision. Mais j'ai une autre question de fond : comment est-ce que le PC sait qu'il doit exécuter tous les threads en parallèle ? Est-ce dû au moment de la compilation ? avec l'option -lpthread ?
    Merci.

  8. #8
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par salseropom
    Salut, merci de cette précision. Mais j'ai une autre question de fond : comment est-ce que le PC sait qu'il doit exécuter tous les threads en parallèle ? Est-ce dû au moment de la compilation ? avec l'option -lpthread ?
    Merci.
    pthread_create lui dit de faire en parralele la fonction que tu lui passes et la suite du programme.

    pthread_join lui dit d'attendre que le thread que tu as crée soit terminé.

  9. #9
    Membre éclairé
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    1 298
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 298
    Points : 886
    Points
    886
    Par défaut
    OK.
    Merci à vous !

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

Discussions similaires

  1. temps de calcul RSA
    Par othland dans le forum Langages de programmation
    Réponses: 2
    Dernier message: 13/03/2006, 11h16
  2. Temps de calcul d'un algo
    Par Rémiz dans le forum VB 6 et antérieur
    Réponses: 7
    Dernier message: 23/12/2005, 13h52
  3. temps de calcul sius VC++ !!
    Par Axiome dans le forum MFC
    Réponses: 16
    Dernier message: 13/12/2005, 09h57
  4. Temps de calcul avec deux écrans
    Par Shaga dans le forum OpenGL
    Réponses: 2
    Dernier message: 14/11/2005, 09h24
  5. temps de calculs extremement long !!
    Par salseropom dans le forum C++
    Réponses: 9
    Dernier message: 19/01/2005, 20h12

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