2016-07-17 1 views
1

У меня есть этот код:OpenMP для цикла с станд :: вектором и скалярной переменной с уменьшением

#pragma omp declare reduction(* : scalar : omp_out *= omp_in)  
scalar like=1; 
vector<scalar>& bigsum; 
#pragma omp parallel for // reduction(* : like)  
for (int m = 0; m < M-1; m++) 
    like *= bigsum[m]; 

Я пытаюсь получить последовательный результат, но это не делает (состояние гонки проблемы), но, как следует Я чиню это? как это видно в коде, у меня есть свой собственный reduction function, но он тоже не работает. Есть ли какой-либо трюк для скалярного и std :: vector, о которых я должен знать?

Скалярная переменная здесь - это только переопределенная плавающая точка, применяя log() для каждого двойника, который я создал, так как существует так много двойных двойных умножений, и результат после того, как пара становится близкой к нулю. Например, делая log(), умножение становится добавлением и т. Д.

Один ответ для последовательного ответа будет таким:

#pragma omp parallel 
    { 
     scalar loc = 1; 
    #pragma omp for 
     for (std::size_t m = 1; m < M;m++) 
     { 
      _flm[m-1] = Qratio[m-1] * k1 + k2; 
      bigsum[m-1] = kappa0omegaproduct + kappa[1] * _flm[m-1]; 
    #pragma omp critical (reduce_product) 
      { 
      like *= bigsum[m-1]; 
      } 
     } 
} 

Этот ответ является правильным, но настолько медленно, что почти в 8 раз медленнее на моем 8 основной машине!

+0

Какой тип 'скаляр'? Какое состояние гонки вы наблюдаете. – Zulan

+0

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

+1

В любом случае, пожалуйста, предоставьте [mcve]. – Zulan

ответ

2

У меня есть ответ через три дня и объяснение того, что я нашел.

Я создал свою собственную функцию снижения, как это:

#pragma omp declare reduction(* : scalar : omp_out *= omp_in) initializer (omp_priv (1)) 

Трюк был omp_priv и, по-видимому инициализации значение снижения важно, я узнал что-нибудь в here.

Я сделал код гораздо проще, применяя мой OpenMP для петель, как это:

#pragma omp parallel for reduction (* : like) 

Очень простой и чистый. Этим новым способом код распараллеливается и работает быстрее, чем то, что у меня было в теле вопроса. К сожалению, он все еще медленнее, чем серийная версия. Может быть, это из-за использования std :: vector или перегруженных арифметических операций очень медленно !? Я не знаю. Код такой большой, что я не могу скопировать его здесь, чтобы он был понятен, и не боль в шее читать другим.

1

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

Ваш второй пример правильный (вы сказали это), но очень медленный из-за критической секции. Почему бы вам не вручную реализовать сокращение OpenMP, указав локальную переменную (например, «local_like») на поток, а затем используя критический раздел после «omp for»?

+0

Да, я должен обновить функцию сокращения. Сначала я должен отлаживать, чтобы понять, почему некоторые из перегруженных функций не вызываются!спасибо, что упомянул об этом. –

+0

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