2016-11-13 22 views
0

---------------------编辑------------------ -------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。打印取消是打印,但在程序的最开始,这是令人惊讶的。程序在那之后继续运行!

如何确保这是正确的实施? BTW OMP_CANCELLATION设置为true,并且一个小测试程序为相应的函数omp_get_cancellation()返回'1'。

回答

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'循环部分时,代码在'i = 100000000'时需要约11秒。但是在取消它的过程中,我必须永远放弃它。 – algoProg

+0

@algoProg cancelFre是cancalling的频率,我把它放在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

我还是不明白为什么你更喜欢让我和圈外的人在圈外,同时他们可以在循环范围内。如果它们只在循环内部,则不会担心竞争条件,因为它们在每个循环中都是分开的。 –

+0

请看khôinguyễn的答案。有用!!基本上在并行杂注中定义'i'和'piold'。尽管1-4线程的性能仍然不利于顺序。 5-16线性放大(16是最大线程数)。 – algoProg