OpenMP:ON NUMA

时间:2016-11-13 07:32:02

标签: c++ openmp cancellation numa

--------------------- EDIT -------------------------

我编写了如下代码:

#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编译它。当我用一个线程运行它时,我得到预期的结果与pragma取消操作(检查非pragma取消版本,导致更快的运行)。

但是当我用线程&gt; = 2运行它时,程序进入循环。我在NUMA机器上运行代码。怎么了?也许取消条件不满意!但是代码需要比单线程非pragma-cancel版本更长的时间!仅供参考,它在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”。

2 个答案:

答案 0 :(得分:1)

据我所知,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 :(得分:1)

好的,所以我解决了。在上面的代码中,问题出在这里:

err = fabs(pi-piold);

如果条件发生变化,上面的行pi会在以下行中更改。多个线程也是如此。据我所知,这使程序陷入僵局。

我通过强制只有一个线程master来解决这个问题:

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

我本来可以使用#pragma omp single但是它给出了嵌套编译指示的错误。

这里性能受到低线程数的影响(1-4比正常的顺序代码差)。之后性能提高。这不是最好的解决方案,有人可以肯定地改进这个。