OpenMP: отменить прагму для ON NUMA

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

Я отредактировал код следующим образом:

#pragma omp parallel for private(i, piold, err) shared(threshold_err) reduction(+:pi) schedule (static)
{
for (i = 0; i < 10000000000; i++){ //1000000000//705035067
piold = pi;
pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1);
err = fabs(pi-piold);
if ( err < threshold_err){
#pragma omp cancel for
}

}
}
pi = 4*pi;

Я компилирую это с LLVM3.9 / Clang4.0. Когда я запускаю его с одним потоком, я получаю ожидаемые результаты с действием отмены прагмы (проверено на версии без отмены прагмы, что приводит к более быстрому запуску).

Но когда я запускаю его с потоками> = 2, программа зацикливается. Я запускаю код на машинах NUMA. Что происходит? Возможно, условие отмены не выполняется! Но тогда код занимает больше времени, чем однопотоковая версия без прагмы !! К вашему сведению, он запускает файл, когда OMP_CANCELLATION = false.


У меня есть следующий код OpenMP. Я использую LLVM-3.9 / Clang-4.0 для компиляции этого кода.

#pragma omp parallel private(i, piold, err) shared(pi, threshold_err)
{
#pragma omp for reduction(+:pi) schedule (static)
for (i = 0; i < 10000000 ; i++){
piold = pi;
pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1);
#pragma omp critical
{
err = fabs(pi-piold);// printf("Err: %0.11f\n", err);
}
if ( err < threshold_err){
printf("Cancelling!\n");
#pragma omp cancel for
}

}
}

К сожалению, я не думаю, что #pragma omp cancel for завершает весь for петля. Я распечатываю err значение в конце, но опять же с параллелизмом это сбивает с толку, какое значение печатается. Окончательное значение err меньше чем threshold_err, Отмена печати — это печать, но в самом начале программы, что удивительно. Программа продолжает работать после этого!

Как убедиться, что это правильная реализация? Кстати, для OMP_CANCELLATION установлено значение true, и небольшая тестовая программа возвращает «1» для соответствующей функции omp_get_cancellation ().

0

Решение

Я понимаю, что отмена omp — это просто сигнал прерывания, он уведомляет, чтобы потом не создавался поток. Потоки, которые все еще работают, будут продолжаться до конца. Увидеть http://bisqwit.iki.fi/story/howto/openmp/ а также http://jakascorner.com/blog/2016/08/omp-cancel.html

На самом деле, на мой взгляд, я вижу в вашем программном продукте приемлемое приближение. Тем не менее, некоторые переменные можно хранить в меньшем объеме. Это мое предложение

#include <iostream>
#include <cmath>
#include <iomanip>

int main() {

long double pi = 0.0;
long double threshold_err = 1e-7;
int cancelFre = 0;

#pragma omp parallel shared(pi, threshold_err, cancelFre)
{
#pragma omp for reduction(+:pi) schedule (static)
for (int i = 0; i < 100000000; i++){
long double piold = pi;
pi += (((i&1) == false) ? 1.0 : -1.0)/(2*i+1);
long double err = std::fabs(pi-piold);
if ( err < threshold_err){

#pragma omp cancel for
cancelFre++;
}

}
}

std::cout << std::setprecision(10) << pi * 4 << " " << cancelFre;

return 0;
}
1

Другие решения

Хорошо, так что я решил это. В моем коде выше проблема была здесь:

err = fabs(pi-piold);

В приведенной выше строке pi изменяется до следующего, если условие изменяется. Также несколько потоков делают то же самое. Как я понимаю, это заставляет программу идти в тупик.

Я решил это, заставив только один поток, мастер, сделать эту проверку:

if(omp_get_thread_num()==0){
err = fabs(pi-piold);
if ( err < threshold_err){
#pragma omp cancel for
}
}

Я мог бы использовать #pragma omp single но это дало ошибку о вложенных прагмах.

Здесь производительность страдает при небольшом количестве потоков (1-4 хуже, чем обычный последовательный код). После этого производительность улучшается. Это не лучшее решение, и кто-то может улучшить это.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector