Параллельно с omp

0

Я пытаюсь оптимизировать следующий цикл с помощью OpenMP:

    #pragma omp parallel for private(diff)
    for (int j = 0; j < x.d; ++j) {
        diff = x(example,j) - x(chosen_pts[ndx - 1],j);
        #pragma omp atomic
        d2 += diff * diff;
    }

Но он работает на 4 раза медленнее, чем без #pragma.

РЕДАКТИРОВАТЬ

Как отметил Петр С., совпадение и эрнен, в моем случае xd настолько мала, что параллелизм заставляет мой код работать медленнее. Я также отправляю внешний цикл, возможно, есть много возможностей для многопоточности: (xn превышает 100 миллионов)

float sum_distribution = 0.0;
// look for the point that is furthest from any center
float max_dist = 0.0;

for (int i = 0; i < x.n; ++i) {
    int example = dist2[i].second;
    float d2 = 0.0, diff;
    //#pragma omp parallel for private(diff) reduction(+:d2)
    for (int j = 0; j < x.d; ++j) {
        diff = x(example,j) - x(chosen_pts[ndx - 1],j);

        d2 += diff * diff;
    }
    if (d2 < dist2[i].first) {
        dist2[i].first = d2;
    }

    if (dist2[i].first > max_dist) {
        max_dist = dist2[i].first;
    }

    sum_distribution += dist2[i].first;
}

Если кому-то интересно, вот целая функция: https://github.com/ghamerly/baylorml/blob/master/fast_kmeans/general_functions.cpp#L169, но по мере того, как я измерял, 85% прошедшего времени поступает из этого цикла.

  • 0
    Какова стоимость xd?
  • 2
    Похоже, d2 стал узким местом: все потоки должны иметь доступ к одной и той же памяти. Быстрее было бы позволить каждому потоку отслеживать свою собственную сумму, добавляя эти специфичные для потока суммы вместе, когда цикл завершен. Я думаю, что вы можете сделать это, добавив reduction(+,d2) к первой прагме
Показать ещё 5 комментариев
Теги:
multithreading
openmp

1 ответ

1
Лучший ответ

Да, внешний цикл, как указано, может быть распараллелен с помощью OpenMP. Все переменные, измененные в цикле, являются либо локальными, либо итерационными или используются для агрегирования по циклу. И я полагаю, что вызовы x() при вычислении diff имеют побочных эффектов.

Для правильной и эффективной сборки агрегации вам необходимо использовать цикл OpenMP с предложением о reduction. Для sum_distribution операция сокращения равна +, а для max_dist max. Таким образом, добавление следующей прагмы перед внешним циклом должно выполнять задание:

#pragma omp parallel for reduction(+:sum_distribution) reduction(max:max_dist)

Обратите внимание, что max как операция сокращения может использоваться только с OpenMP 3.1. Это не так уж и ново, поэтому большинство компиляторов с поддержкой OpenMP уже поддерживают его, но не все; или вы можете использовать более старую версию. Поэтому имеет смысл проконсультироваться с документацией для вашего компилятора.

  • 0
    Ваш предложенный код вызывает ошибку ошибки сегментации.
  • 0
    Я не понимаю, почему это может не сработать даже после просмотра вашего реального кода. Вы можете попробовать несколько вещей: проверить, работает ли он только с одним потоком, добавив предложение num_threads(1) к прагме; удалить reduction(max:max_dist) and instead add #pragma omp critical перед вторым оператором if .
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню