Проблема компилятора Intel (C ++) с сокращением OpenMP на std :: vector - PullRequest
0 голосов
/ 08 мая 2018

Начиная с OpenMP 4.0, пользовательское сокращение поддерживается. Таким образом, я определил сокращение на std :: vector в C ++ точно с здесь . Он отлично работает с GNU / 5.4.0 и GNU / 6.4.0, но возвращает случайные значения для сокращения с intel / 2018.1.163.

Это пример:

#include <iostream>
#include <vector>
#include <algorithm>
#include "omp.h"

#pragma omp declare reduction(vec_double_plus : std::vector<double> : \
                              std::transform(omp_out.begin(), omp_out.end(), omp_in.begin(), omp_out.begin(), std::plus<double>())) \
                    initializer(omp_priv = omp_orig)

int main() {

    omp_set_num_threads(4);
    int size = 100;
    std::vector<double> w(size,0);

#pragma omp parallel for reduction(vec_double_plus:w)
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < w.size(); ++j)
            w[j] += 1;

    for(auto i:w)
        if(i != 4)
            std::cout << i << std::endl;

    return 0;
}

Каждый поток добавляет 1 ко всем элементам w (свой локальный w), и в конце все они добавляются вместе (сокращение). Результат для всех записей w равен 4 для GNU, но случайный для компилятора intel. Кто-нибудь знает, что здесь происходит?

1 Ответ

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

Это, похоже, ошибка в компиляторе Intel, я могу надежно воспроизвести ее на примере C, не содержащем векторов:

#include <stdio.h>

void my_sum_fun(int* outp, int* inp) {
    printf("%d @ %p += %d @ %p\n", *outp, outp, *inp, inp);
    *outp = *outp + *inp;
}

int my_init(int* orig) {
    printf("orig: %d @ %p\n", *orig, orig);
    return *orig;
}

#pragma omp declare reduction(my_sum : int : my_sum_fun(&omp_out, &omp_in) initializer(omp_priv = my_init(&omp_orig))

int main()
{   
    int s = 0;
    #pragma omp parallel for reduction(my_sum : s)
    for (int i = 0; i < 2; i++)
        s+= 1;

    printf("sum: %d\n", s);
}

Выход:

orig: 0 @ 0x7ffee43ccc80
0 @ 0x7ffee43ccc80 += 1 @ 0x7ffee43cc780
orig: 1 @ 0x7ffee43ccc80
1 @ 0x7ffee43ccc80 += 2 @ 0x2b56d095ca80
sum: 3

Применяет операцию сокращения к исходной переменной до инициализации частной копии из исходного значения. Это приводит к неверному результату.

Вы можете вручную добавить барьер в качестве обходного пути:

#pragma omp parallel reduction(vec_double_plus : w)
{
  #pragma omp for
  for (int i = 0; i < 4; ++i)
    for (int j = 0; j < w.size(); ++j)
      w[j] += 1;
  #pragma omp barrier
}
...