Почему версия omp медленнее серийной? - PullRequest
0 голосов
/ 27 мая 2018

Это дополнительный вопрос к этому
Теперь у меня есть код:

#include <iostream>
#include <cmath>
#include <omp.h>


#define max(a, b) (a)>(b)?(a):(b)

const int m = 2001;
const int n = 2000;
const int p = 4;

double v[m + 2][m + 2];
double x[m + 2];
double y[m + 2];
double _new[m + 2][m + 2];
double maxdiffA[p + 1];
int icol, jrow;

int main() {
    omp_set_num_threads(p);

    double h = 1.0 / (n + 1);

    double start = omp_get_wtime();

    #pragma omp parallel for private(icol) shared(x, y, v, _new)
    for (icol = 0; icol <= n + 1; ++icol) {
        x[icol] = y[icol] = icol * h;

        _new[icol][0] = v[icol][0] = 6 - 2 * x[icol];

        _new[n + 1][icol] = v[n + 1][icol] = 4 - 2 * y[icol];

        _new[icol][n + 1] = v[icol][n + 1] = 3 - x[icol];

        _new[0][icol] = v[0][icol] = 6 - 3 * y[icol];
    }


    const double eps = 0.01;


    #pragma omp parallel private(icol, jrow) shared(_new, v, maxdiffA)
    {
        while (true) { //for [iters=1 to maxiters by 2]
            #pragma omp single
            for (int i = 0; i < p; i++) maxdiffA[i] = 0;
            #pragma omp for
            for (icol = 1; icol <= n; icol++)
                for (jrow = 1; jrow <= n; jrow++)
                    _new[icol][jrow] =
                            (v[icol - 1][jrow] + v[icol + 1][jrow] + v[icol][jrow - 1] + v[icol][jrow + 1]) / 4;
            #pragma omp for
            for (icol = 1; icol <= n; icol++)
                for (jrow = 1; jrow <= n; jrow++)
                    v[icol][jrow] = (_new[icol - 1][jrow] + _new[icol + 1][jrow] + _new[icol][jrow - 1] +
                                     _new[icol][jrow + 1]) / 4;

            #pragma omp for
            for (icol = 1; icol <= n; icol++)
                for (jrow = 1; jrow <= n; jrow++)
                    maxdiffA[omp_get_thread_num()] = max(maxdiffA[omp_get_thread_num()],
                                                         fabs(_new[icol][jrow] - v[icol][jrow]));

            #pragma omp barrier

            double maxdiff = 0.0;
            for (int k = 0; k < p; ++k) {
                maxdiff = max(maxdiff, maxdiffA[k]);
            }


            if (maxdiff < eps)
                break;
            #pragma omp barrier
            //#pragma omp single
            //std::cout << maxdiff << std::endl;
        }
    }
    double end = omp_get_wtime();
    printf("start = %.16lf\nend = %.16lf\ndiff = %.16lf\n", start, end, end - start);

    return 0;
}

Но почему он работает в 2-3 раза медленнее (32 с против 18 с)чем серийный аналог:

#include <iostream>
#include <cmath>
#include <omp.h>

#define max(a,b) (a)>(b)?(a):(b)

const int m = 2001;
const int n = 2000;
double v[m + 2][m + 2];
double x[m + 2];
double y[m + 2];
double _new[m + 2][m + 2];

int main() {
    double h = 1.0 / (n + 1);

    double start = omp_get_wtime();

    for (int i = 0; i <= n + 1; ++i) {
        x[i] = y[i] = i * h;

        _new[i][0]=v[i][0] = 6 - 2 * x[i];

        _new[n + 1][i]=v[n + 1][i] = 4 - 2 * y[i];

        _new[i][n + 1]=v[i][n + 1] = 3 - x[i];

        _new[0][i]=v[0][i] = 6 - 3 * y[i];
    }

    const double eps=0.01;
    while(true){ //for [iters=1 to maxiters by 2]
        double maxdiff=0.0;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                _new[i][j]=(v[i-1][j]+v[i+1][j]+v[i][j-1]+v[i][j+1])/4;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                v[i][j]=(_new[i-1][j]+_new[i+1][j]+_new[i][j-1]+_new[i][j+1])/4;

        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                maxdiff=max(maxdiff, fabs(_new[i][j]-v[i][j]));

        if(maxdiff<eps) break;
        std::cout << maxdiff<<std::endl;
    }

    double end = omp_get_wtime();
    printf("start = %.16lf\nend = %.16lf\ndiff = %.16lf\n", start, end, end - start);

    return 0;
}

Также интересно, что он работает ЖЕ ВРЕМЯ как версия (я могу опубликовать это здесь, если вы так говорите), которая выглядит так

while(true){ //106 iteratins here!!!
#pragma omp paralell for
for(...)
#pragma omp paralell for
for(...)
#pragma omp paralell for
for(...)
}

Но я думал, чтото, что делает код omp медленным, порождает потоки внутри цикла while 106 раз ... Но нет!Тогда, вероятно, потоки одновременно записывают в одни и те же элементы массива. Но где это происходит?Не вижу, не могли бы вы показать мне, пожалуйста?
Может, это из-за слишком большого количества барьеров?Но Лектор сказал мне, чтобы я реализовал такой код и «проанализировал его». Может быть, ответ таков: «Алгоритм Якоби не предназначен для хорошей параллельной работы»?Или это просто мое хромое кодирование?

Ответы [ 2 ]

0 голосов
/ 31 мая 2018

Таким образом, корень evel был

max(maxdiffA[w],fabs(_new[icol][jrow] - v[icol][jrow]))

, потому что он

#define max(a, b) (a)>(b)?(a):(b)

Вероятно, он создает слишком много ветвлений ('if's) Без этого параллельная версия работает в 8 раз быстрее и загружаетсяПроцессор 68% вместо 99% .. Странная вещь: тот же «макс» не влияет на сериальную версию

0 голосов
/ 27 мая 2018

Я пишу, чтобы вы знали о нескольких ситуациях.Это не коротко, чтобы написать в комментарии, поэтому я решил написать как ответ.

каждый раз, когда создается поток, для его создания требуется некоторое время.если время выполнения вашей программы в одном ядре короткое, то создание потоков увеличит это время для многоядерных.

плюс использование барьера заставит все ваши потоки ждать других, что может быть как-то замедленовниз в процессоре.таким образом, даже если все потоки завершают работу очень быстро, последний из них увеличит общее время выполнения.

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

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

если приведенные выше предложения не дают результата, то это означает, что ваше кодирование требует большего редактирования.

РЕДАКТИРОВАТЬ: Для downvoters, Если вам не нравится сообщение, по крайней мере, будьте вежливы и оставьте комментарий.Или, лучше, дайте свой ответ, чтобы быть полезным для сообщества.

...