gcc openmp thread повторно использовать - PullRequest
3 голосов
/ 31 января 2012

Я использую gcc-реализацию openmp, чтобы попытаться распараллелить программу. По сути, задача заключается в добавлении прагм omp для ускорения работы программы, которая находит дружных чисел .

Была дана оригинальная серийная программа (показанная ниже, за исключением 3 строк, которые я добавил с комментариями в конце). Мы должны сначала парализовать только внешний цикл, а затем только внутренний цикл. Внешний цикл был прост, и я приблизился к идеальному ускорению для данного числа процессоров. Что касается внутреннего цикла, я получаю гораздо худшую производительность, чем оригинальная последовательная программа. По сути, я пытаюсь сократить переменную суммы.

Глядя на использование процессора, я использую только ~ 30% на ядро. Что может быть причиной этого? Постоянно ли программа создает новые потоки каждый раз, когда сталкивается с предложением omp параллельно для предложения? Есть ли намного больше накладных расходов при создании барьера для сокращения? Или это может быть проблема доступа к памяти (например, кэш-памяти)? Из того, что я прочитал с большинством реализаций потоков openmp, повторно используются сверхурочные (например, в пуле), поэтому я не уверен, что первая проблема в том, что не так.

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <omp.h>
#define numThread 2
int main(int argc, char* argv[]) {
    int ser[29], end, i, j, a, limit, als;
    als = atoi(argv[1]);
    limit = atoi(argv[2]);
    for (i = 2; i < limit; i++) {
        ser[0] = i;
        for (a = 1; a <= als; a++) {
            ser[a] = 1;
            int prev = ser[a-1];
            if ((prev > i) || (a == 1)) {
                end = sqrt(prev);
                int sum = 0;//added this
                #pragma omp parallel for reduction(+:sum) num_threads(numThread)//added this
                for (j = 2; j <= end; j++) {
                    if (prev % j == 0) {
                        sum += j;
                        sum += prev / j;
                    }
                }
                ser[a] = sum + 1;//added this
            }
        }
        if (ser[als] == i) {
            printf("%d", i);
            for (j = 1; j < als; j++) {
                printf(", %d", ser[j]);
            }
            printf("\n");
        }
    }
}

1 Ответ

7 голосов
/ 31 января 2012

OpenMP thread teams создаются при входе в параллельную секцию. Это действительно означает, что создание потока повторяется каждый раз при запуске внутреннего цикла.

Чтобы разрешить повторное использование потоков, используйте большую параллельную секцию (для управления временем жизни команды) и определенно управляйте параллелизмом для внешних / внутренних циклов, например:

Время выполнения для test.exe 1 1000000 сократилось с 43 до 22 с использованием этого исправления (и число потоков отражает определенное значение numThreads + 1

PS Возможно, заявив об очевидном, не похоже, что распараллеливание внутреннего цикла является мерой эффективности звука. Но в этом, вероятно, весь смысл этого упражнения, и я не буду критиковать этот вопрос.

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include <omp.h>

#define numThread 2
int main(int argc, char* argv[]) {
    int ser[29], end, i, j, a, limit, als;
    als = atoi(argv[1]);
    limit = atoi(argv[2]);
#pragma omp parallel num_threads(numThread)
    {
#pragma omp single
        for (i = 2; i < limit; i++) {
            ser[0] = i;
            for (a = 1; a <= als; a++) {
                ser[a] = 1;
                int prev = ser[a-1];
                if ((prev > i) || (a == 1)) {
                    end = sqrt(prev);
                    int sum = 0;//added this
#pragma omp parallel for reduction(+:sum) //added this
                    for (j = 2; j <= end; j++) {
                        if (prev % j == 0) {
                            sum += j;
                            sum += prev / j;
                        }
                    }
                    ser[a] = sum + 1;//added this
                }
            }
            if (ser[als] == i) {
                printf("%d", i);
                for (j = 1; j < als; j++) {
                    printf(", %d", ser[j]);
                }
                printf("\n");
            }
        }
    }
}
...