OpenMP и общие структуры и указатели

У меня есть функция, которой по ссылке передаются две структуры. Эти структуры состоят из динамически размещаемых массивов. Теперь, когда я пытаюсь внедрить OpenMP, я получаю замедление, а не ускорение. Я думаю, это может быть связано с возможными проблемами обмена. Вот часть кода для вашего прочтения (C):

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 --*/
}

Теперь я пробовал по умолчанию (общий) и общий (mhd), но ни один из них не показывает никаких признаков улучшения. Может быть, поскольку массивы распределены

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

Что, объявляя структуру или указатель на элемент структуры, я на самом деле не разделяю память, а только указатели на нее? О, и nx=389 ny=7 и nz=739 в этом примере. Время выполнения этого раздела в последовательном режиме составляет 0,23 [с] и 0,79 [с] для 8 потоков.


person Lazer    schedule 28.10.2010    source источник


Ответы (3)


Моя проблема сводилась к очень простой ошибке.... clock(). Хотя я защитил свой алгоритм синхронизации, заставив только конкретный поток вычислять время, я забыл одну важную вещь о clock()... он возвращает время настенных часов, которое является общим временем процессора (сумма по активным потокам). Мне нужно было вызвать omp_get_wtime(). Делая это, я внезапно вижу ускорение многих разделов моего кода. Для записи я изменил свой код, чтобы включить

#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

И мой алгоритм синхронизации теперь

    #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");
    }
person Lazer    schedule 02.11.2010

Важным моментом здесь может быть ваша верхняя граница ваших петель. Поскольку вы используете grid->nz и т. д., openMP не может знать, будут ли они меняться или нет для каждой итерации. Загрузите эти значения в локальные переменные и используйте их для условия цикла.

person Jens Gustedt    schedule 28.10.2010
comment
Я пытался сделать именно это... без кубиков с одинаковым временем выполнения. Я также попытался поместить все данные в локальные массивы (rhotemp) и получить к ним доступ вместо значений в структуре с тем же эффектом. - person Lazer; 29.10.2010

Ну, вы также используете удвоение и деление. Можно ли превратить деление в умножение?

Блок с плавающей запятой распределяется между ядрами, и у подразделений нет детерминированного количества циклов до завершения (в отличие от умножения). Таким образом, вы закончите сериализацию для доступа к модулю fp.

Я уверен, что если вы используете целочисленные типы или умножение, вы увидите ускорение.

person ipapadop    schedule 02.11.2010
comment
На самом деле этот раздел кода настраивает обратные помощники, чтобы избежать разделения в остальной части кода. Я поменяю деление на умножение и посмотрю, есть ли изменения. Хотя, если есть, мне просто нужно сериализовать это для цикла. - person Lazer; 02.11.2010
comment
Код по-прежнему работает медленнее, если деление переключается на умножение. И скорость ухудшается с увеличением количества процессоров (скажем, от 2 до 8). - person Lazer; 02.11.2010