2010-10-28 53 views
2

J'ai une fonction qui est passée deux structures par référence. Ces structures sont composées de tableaux alloués dynamiquement. Maintenant, quand j'essaie d'implémenter OpenMP, j'obtiens un ralentissement et non une accélération. Je pense que cela peut être attribué à des problèmes de partage possibles. Voici une partie du code pour votre lecture attentive (C):OpenMP et structures partagées et pointeurs

void leap(MHD *mhd,GRID *grid,short int gchk) 
{ 
    /*-- V A R I A B L E S --*/ 
    // Indexes 
    int i,j,k,tid; 
    double rhoinv[grid->nx][grid->ny][grid->nz]; 
    double rhoiinv[grid->nx][grid->ny][grid->nz]; 
    double rhoeinv[grid->nx][grid->ny][grid->nz]; 
    double rhoninv[grid->nx][grid->ny][grid->nz]; // Rho Inversion 
    #pragma omp parallel shared(mhd->rho,mhd->rhoi,mhd->rhoe,mhd->rhon,grid,rhoinv,rhoiinv,rhoeinv,rhoninv) \ 
         private(i,j,k,tid,stime) 
    { 
    tid=omp_get_thread_num(); 
    printf("----- Thread %d Checking in!\n",tid); 
    #pragma omp barrier 
    if (tid == 0) 
    { 
     stime=clock(); 
     printf("-----1) Calculating leap helpers"); 
    } 
    #pragma omp for 
    for(i=0;i<grid->nx;i++) 
    { 
     for(j=0;j<grid->ny;j++) 
     { 
     for(k=0;k<grid->nz;k++) 
     { 
      //  rho's 
      rhoinv[i][j][k]=1./mhd->rho[i][j][k]; 
      rhoiinv[i][j][k]=1./mhd->rhoi[i][j][k]; 
      rhoeinv[i][j][k]=1./mhd->rhoe[i][j][k]; 
      rhoninv[i][j][k]=1./mhd->rhon[i][j][k]; 
     } 
     } 
    } 
    if (tid == 0) 
    { 
     printf("........%04.2f [s] -----\n",(clock()-stime)/CLOCKS_PER_SEC); 
     stime=clock(); 
    } 
    #pragma omp barrier 
    }/*-- End Parallel Region --*/ 
} 

Maintenant, je l'ai essayé par défaut (partagé) et partagée (MHD), mais ne montrent aucun signe d'amélioration. Se pourrait-il que, puisque les tableaux sont attribués

mhd->rho=(double ***)newarray(nx,ny,nz,sizeof(double)); 

en déclarant que la structure ou le pointeur sur l'élément de la structure que je partage pas vraiment la mémoire seulement les pointeurs vers elle? Oh et nx = 389 ny = 7 et nz = 739 dans cet exemple. Le temps d'exécution pour cette section en série est de 0,23 [s] et 0,79 [s] pour 8 threads.

Répondre

1

Mon problème s'est résumée à une erreur très simple .... clock(). Alors que j'ai protégé mon algorithme de synchronisation en ayant seulement un thread spécifique calculer l'heure, j'ai oublié une chose importante à propos de clock() ... il retourne l'heure de l'horloge qui est le temps total du processeur (sommation sur les threads actifs). Ce que j'avais besoin d'appeler était omp_get_wtime(). Ce faisant, je vois soudainement une accélération pour de nombreuses sections de mon code. Pour le disque que j'ai modifié mon code pour inclure

#ifdef _OPENMP 
    #include <omp.h> 
    #define TIMESCALE 1 
#else 
    #define omp_get_thread_num() 0 
    #define omp_get_num_procs() 0 
    #define omp_get_num_threads() 1 
    #define omp_set_num_threads(bob) 0 
    #define omp_get_wtime() clock() 
    #define TIMESCALE CLOCKS_PER_SEC 
#endif 

Et mon algorithme de synchronisation est maintenant

#pragma omp barrier 
    if (tid == 0) 
    { 
     stime=omp_get_wtime(); 
     printf("-----1) Calculating leap helpers"); 
    } 
    #pragma omp for 
    for(i=0;i<grid->nx;i++) 
    { 
     for(j=0;j<grid->ny;j++) 
     { 
      for(k=0;k<grid->nz;k++) 
      { 
       //  rho's 
       rhoinv[i][j][k]=1./mhd->rho[i][j][k]; 
       rhoiinv[i][j][k]=1./mhd->rhoi[i][j][k]; 
       rhoeinv[i][j][k]=1./mhd->rhoe[i][j][k]; 
       rhoninv[i][j][k]=1./mhd->rhon[i][j][k]; 
       // 1./(gamma-1.) 
       gaminv[i][j][k]=1./(mhd->gamma[i][j][k]-1.); 
       gamiinv[i][j][k]=1./(mhd->gammai[i][j][k]-1.); 
       gameinv[i][j][k]=1./(mhd->gammae[i][j][k]-1.); 
       gamninv[i][j][k]=1./(mhd->gamman[i][j][k]-1.); 
      } 
     } 
    } 
    if (tid == 0) 
    { 
     printf("........%04.2f [s] -----\n",(omp_get_wtime()-stime)/TIMESCALE); 
     stime=omp_get_wtime(); 
     printf("-----2) Calculating leap helpers"); 
    } 
0

Un point important ici pourrait être la limite supérieure de vos boucles. Puisque vous utilisez grid->nz etc openMP ne peut pas savoir s'ils changeront ou non pour chaque itération. Chargez ces valeurs dans des variables locales et utilisez-les pour la condition de boucle.

+0

J'ai essayé de faire juste que ... pas de dés en même temps d'exécution. J'ai aussi essayé de mettre toutes les données dans des tableaux locaux (rhotemp) et d'y accéder à la place des valeurs dans la même structure. – Lazer

0

Eh bien, vous utilisez également les doubles et la division. Pouvez-vous faire la division en multiplication?

L'unité à virgule flottante est partagée entre les coeurs et les divisions n'ont pas un nombre déterministe de cycles jusqu'à la fin (par opposition à la multiplication). Donc, vous finissez par sérialiser pour accéder à l'unité fp.

Je suis sûr que si vous utilisez des types entiers ou une multiplication, vous verrez une accélération.

+0

En fait cette section du code met en place les aides inverses afin que la division soit évitée dans le reste du code. Je vais changer la division en multiplication et voir s'il y a un changement. Bien que s'il y a alors je devrai juste sérialiser ceci pour la boucle. – Lazer

+0

Le code s'exécute encore plus lentement si la division est commutée en multiplication. Et la vitesse empire avec plus de processeurs (disons de 2-8). – Lazer