OpenMP: не удается распараллелить вложенные циклы for

#c #c #parallel-processing #openmp

#c #c #параллельная обработка #openmp

Вопрос:

Я хочу распараллелить цикл с внутренним циклом внутри него. Мой код выглядит так:

     #pragma omp parallel for private(jb,ib) shared(n, Nb, lb, lastBlock, jj, W, WT) schedule(dynamic)   //private(ib, jb) shared(n, Nb, lb, lastBlock, jj, W, WT)       //parallel for loop with omp
    for(jb=0; jb<Nb; jb  )          
    {
            int lbh = (jb==Nb-1) ? lastBlock : lb;
            int ip = omp_get_thread_num();

            packWT(a, n, lb, s, jb, colNr, WT[ip], nr); //pack WWT[jb]      


            for(ib=jb; ib<Nb; ib  )
            {
                    int lbv = (ib==Nb-1) ? lastBlock : lb;

                    multBlock_2x4xk(a, n, jj   ib*lb, jj   jb*lb, W ib*lb*lb, WT[ip], lb, lbv, lbh);    //MULT BLOCK - 2x4xK (W[jb]*W[ib])

            }
    }
 

Я измеряю время, которое proc потратил на вычисление этих циклов. Это то же самое для нескольких потоков, что и для одного потока. Когда я изменяю предложение

 private(jb,ib)
 

для

 private(jb)
 

Все меняется. Я имею в виду, что для нескольких потоков proc вычисляется быстрее, чем для одного потока. В чем проблема?

Комментарии:

1. Здесь не так много, чтобы продолжить — что такое packWT, multBlock, a и т. Д.? — но вам определенно нужно, чтобы ib был закрытым, иначе потоки будут перезаписывать один и тот же индекс цикла. Причина, по которой это быстрее без private(ib), вероятно, заключается в том, что многие ib пропускаются без него…

2. действительно, без private (ib) я получаю неправильные результаты.. Все еще не знаю, почему время одинаково для многих потоков и одного потока…

3. Причин может быть много, но никто из нас не сможет вам ничего сказать без дополнительной информации.

4. Я уже проверил, что это не зависит от того, что функции winthin циклы.

5. Похоже, это зависит от компилятора… Тот же код выполняется под Windows в Visual Studio, но на mac и Linux с gcc это не очень хорошо. Я компилирую это с помощью команды: g -O0 -fopenmp -msse2 …

Ответ №1:

Проблема в том, что ваши внутренние циклы for не имеют канонической формы. Поэтому openmp не удается распараллелить циклы, и ускорение не может быть достигнуто. Циклы должны выглядеть как на следующем рисунке. Где start , idx и inc не разрешается изменять во время параллельной части кода. каноническая форма циклов for

Я думаю, что я определил вашу проблему. Вы вызываете эти функции:

   packWT(a, n, lb, s, jb, colNr, WT[ip], nr); packWT(a, n, lb, s, jb, colNr, WT[ip], nr);
  multBlock_2x4xk(a, n, jj   ib*lb, jj   jb*lb, W ib*lb*lb, WT[ip], lb, lbv, lbh);
 

где одним аргументом является переменная цикла jb, поскольку jb может быть изменен внутри функции (в зависимости от объявления функции), компилятор решает не распараллеливать цикл.
Чтобы избежать этого, скопируйте переменную jb в локальную переменную и передайте локальную переменную функции.