2015-10-22 2 views
0

Я пытаюсь распараллелить этот код с помощью OpenMP.OpenMP-распараллеливание неэффективно

for(t_step=0;t_step<Ntot;t_step++) { 
     // current row 
     if(cur_row + 1 < Npt_x)  cur_row++; 
     else      cur_row = 0; 
     // get data from file which update only the row "cur_row" of array val 
     read_line(f_u, val[cur_row]); 
     // computes 
     for(i=0;i<Npt_x;i++) { 
      for(j=0;j<Npt_y;j++) { 
       i_corrected = cur_row - i; 
       if(i_corrected < 0)  i_corrected = Npt_x + i_corrected; 
       R[i][j] += val[cur_row][0]*val[i_corrected][j]/Ntot; 
      } 
     } 
    } 

с
- вал и R ** объявлен как двойной,
- Npt_x и Npt_y около 500,
- Ntot составляет около 10^6.

Я сделал это

for(t_step=0;t_step<Ntot;t_step++) { 
     // current row 
     if(cur_row + 1 < Npt_x)  cur_row++; 
     else      cur_row = 0; 
     // get data from file which update only the row "cur_row" of array val 
     read_line(f_u, val[cur_row]); 
     // computes 
     #pragma omp parallel for collapse(2), private(i,j,i_corrected) 
     for(i=0;i<Npt_x;i++) { 
      for(j=0;j<Npt_y;j++) { 
       i_corrected = cur_row - i; 
       if(i_corrected < 0)  i_corrected = Npt_x + i_corrected; 
       R[i][j] += val[cur_row][0]*val[i_corrected][j]/Ntot; 
      } 
     } 
    } 

Проблема заключается в том, что он, кажется, не будет эффективным. Есть ли способ использовать OpenMP более эффективно в этом случае?

Многого Thks

+0

Возможно, вы сможете использовать черепицу с использованием цикла использования для улучшения использования кеша. –

+0

Предлагаю вам попробовать инструменты производительности (например, Paraver http://www.bsc.es/computer-sciences/performance-tools/paraver), чтобы изучить производительность этого кода. – Harald

ответ

1

Прямо сейчас, я хотел бы попробовать что-то вроде этого:

for(t_step=0;t_step<Ntot;t_step++) { 
    // current row 
    if(cur_row + 1 < Npt_x) 
     cur_row++; 
    else 
     cur_row = 0; 
    // get data from file which update only the row "cur_row" of array val 
    read_line(f_u, val[cur_row]); 
    // computes 
    #pragma omp parallel for private(i,j,i_corrected) 
    for(i=0;i<Npt_x;i++) { 
     i_corrected = cur_row - i; 
     if(i_corrected < 0) 
      i_corrected += Npt_x; 
     double tmp = val[cur_row][0]/Ntot; 
     #if defined(_OPENMP) && _OPENMP > 201306 
     #pragma omp simd 
     #endif 
     for(j=0;j<Npt_y;j++) { 
      R[i][j] += tmp*val[i_corrected][j]; 
     } 
    } 
} 

Однако, поскольку код будет память связан, что не уверен, что он будет получать вам много параллельного ускорения Однако стоит попробовать.

+0

+1 умное использование '#pragma omp simd' (лучшая функция OpenMP 4.0 imo) и умная реорганизация, чтобы избежать повторных вычислений. К сожалению, OP - подавляющее большинство времени выполнения этой программы, вероятно, будет в вызове 'read_line()', который не является потокобезопасным. Я не могу себе представить, что распараллеливание значительно улучшит эту программу. – NoseKnowsAll

+0

@NoseKnowsВсе, интересно, что вы думаете, что '#pragma omp simd' - самая интересная функция OpenMP 4.0, потому что я считаю ее почти бесполезной, по крайней мере, для компиляторов x86. Возможно, это имеет смысл на других архитектурах, но основные компиляторы x86 C/C++ уже делают автоинтеграцию и те, которые в любом случае не поддерживают OpenMP 4.0. –

+0

С этим решением он работает на 25% быстрее на 16 ядрах (я не пробовал его с меньшим ядром). Но, как упоминалось @NoseKnowsAll, большая часть выполнения расходуется на функцию 'read_line()'. поэтому я не думаю, что смогу добиться большего улучшения. – Jack

Смежные вопросы