OpenMP сокращение изнутри параллельного региона - PullRequest
0 голосов
/ 10 марта 2020

Как сделать OpenMP редукцией (суммой) внутри параллельного региона? (Результат необходим только для главного потока).

Прототип алгоритма:

#pragma omp parallel
{
    t = omp_get_thread_num();

    while iterate 
    {
        float f = get_local_result(t);

        // fsum is required on master only
        float fsum = // ? - SUM of f

        if (t == 0):
            MPI_Bcast(&fsum, ...);
}

Если у меня есть область OpenMP внутри while iterate l oop, параллельные области на каждой итерации убивают производительность ...

1 Ответ

0 голосов
/ 11 марта 2020

Вот самый простой способ сделать это:

    float sharedFsum = 0.f;
    float masterFsum;

    #pragma omp parallel
    {
        const int t = omp_get_thread_num();

        while(iteration_condition)
        {
            float f = get_local_result(t);

            // Manual reduction
            #pragma omp update
            sharedFsum += f;

            // Ensure the reduction is completed
            #pragma omp barrier

            #pragma omp master
            MPI_Bcast(&sharedFsum, ...);

            // Ensure no other threads update sharedFsum during the MPI_Bcast
            #pragma omp barrier
        }
    }

Операции atomi c могут быть дорогостоящими, если у вас много потоков (например, сотен). Лучший подход - позволить среде выполнения выполнить сокращение за вас. Вот лучшая версия:

    float sharedFsum = 0;

    #pragma omp parallel
    {
        const int threadCount = omp_get_num_threads();
        float masterFsum;

        while(iteration_condition)
        {
            // Execute get_local_result on each thread and
            // perform the reduction into sharedFsum
            #pragma omp for reduction(+:sharedFsum) schedule(static,1)
            for(int i=0 ; i<threadCount ; ++i)
                sharedFsum += get_local_result(i);

            #pragma omp master
            {
                MPI_Bcast(&sharedFsum, ...);

                // sharedFsum must be reinitialized for the next iteration
                sharedFsum = 0.f;
            }

            // Ensure no other threads update sharedFsum during the MPI_Bcast
            #pragma omp barrier
        }
    }

Примечания:

  • t не защищен в вашем коде, используйте private(t) в разделе #pragma omp parallel чтобы избежать неопределенного поведения из-за состояния гонки. В качестве альтернативы, вы можете использовать переменные области видимости.

  • #pragma omp master следует отдавать предпочтение условному идентификатору потока.

параллельно накладные расходы региона на каждой итерации убивают производительность ...

В большинстве случаев это происходит из-за (неявной) синхронизации / обмена данными или дисбаланса работы. Приведенный выше код может иметь ту же проблему, поскольку он довольно синхронный. Если это имеет смысл в вашем приложении, вы можете сделать его немного менее синхронным (и, следовательно, возможно, более быстрым), удаляя или перемещая барьеры относительно скорости MPI_Bcast и get_local_result. Однако это не так просто сделать правильно . Один из способов сделать это - использовать задачи OpenMP и мультибуферизацию .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...