2016-11-13 5 views
0

--------------------- EDIT ------------------ -------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. Что происходит? Возможно, условие отмены не выполняется! Но тогда код занимает больше времени, чем однопоточная версия без прагмы-отмены! FYI, он запускает файл, когда 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. Отмена печати печатается, но в самом начале программы, что удивительно. После этого программа продолжает работать!

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

ответ

1

Я понимаю, что omp cancel - это просто сигнал прерывания, он уведомляет об этом, чтобы нить не создавалось позже. Потоки, которые все еще работают, будут продолжаться до конца. См. 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; 
} 
+0

привет спасибо за ответ. Что такое cancelFre? – algoProg

+1

Кроме того, когда я удаляю часть цикла 'cancel for', код занимает ~ 11 секунд с' i = 100000000'. Но с 'cancel for' в нем требуется навсегда, что я должен прервать его. – algoProg

+0

@algoProg ОтменаFre - частота смены канала, я ставлю это прямо после ompcancel, чтобы подсчитать, сколько раз передается сигнал отмены (так что я знаю, что это всего лишь сигнал в конце концов). Я уверен, что смогу пройти цикл. Я также подтверждаю, что на моем ноутбуке работает ваш код. Я просто вижу, что вы разделяете довольно много переменных. –

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 хуже, чем обычный последовательный код). После этого производительность улучшается. Это не лучшее решение, и кто-то наверняка улучшит это.

+0

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

+0

Обратите внимание на ответ khôi nguyễn. Оно работает!! В основном определите 'i' и' piold' внутри параллельной прагмы. Несмотря на то, что производительность в 1-й строке (-ях) по-прежнему отстойна против последовательного. 5-16 масштабируется линейно (16 - это максимальные потоки). – algoProg

Смежные вопросы