【问题标题】:OpenMP tasks - why a segmentation fault appears for larger number of iterations ~10k?OpenMP 任务 - 为什么会出现大量迭代〜10k 的分段错误?
【发布时间】:2017-10-24 20:39:24
【问题描述】:

我正在使用以下代码来查找使用 OpenMP 任务构造的数组元素的总和。
代码在 n = 10000 之前产生正确的结果。

但除此之外,我遇到了分段错误。使用gdb,我发现故障发生在对reduce() 的递归调用之一中。输入数组分配没有问题,我已经验证过了。

有人对可能出现的问题有什么建议吗?

int reduce (int *arr, unsigned long int n)
{   
    int x;
    if (n <= 0)
        return 0;

    #pragma omp parallel
    {   
        #pragma omp single nowait
        {   
            #pragma omp task shared(x)
            x = reduce(arr, n-1) + arr[n-1];
            #pragma omp taskwait
        }
    }
    return x;
}

【问题讨论】:

  • n&lt; 0 时,它是unsigned,怎么会变成&lt; 0
  • 增加你的堆栈大小,看看OMP_STACKSIZE
  • 请格式化您的代码。这太丑了,很痛。

标签: c parallel-processing segmentation-fault openmp


【解决方案1】:

您似乎正在通过函数调用的递归深度遇到“堆栈溢出”。请记住,大多数 openmp pragma 会自己生成函数,这可能会干扰尾递归优化。

如果你通过 valgrind 运行,它应该警告你堆栈溢出。

【讨论】:

  • 如果使用GCC或Clang,也可以编译链接-fsanitize=address。它将检测程序并捕获与 valgrind 类似的问题,但要快一些。
【解决方案2】:

dlasalle 关于实际错误是正确的。

但是,关于如何使用 OpenMP 任务还有两个基本问题。您在每个递归调用中生成一个并行区域。这意味着您使用嵌套的并行区域。默认情况下,嵌套并行在 OpenMP 中被禁用,在这里没有意义。您希望在递归期间生成的所有任务都由同一线程池执行。为此,您必须将 parallel/single 移到递归之外,例如

int reduce_par(int* arr, unsigned long int n)
{
    int x;
    if (n <= 0)
        return 0;
    #pragma omp task shared(x)
    x = reduce_par(arr, n - 1) + arr[n - 1];
    #pragma omp taskwait
    return x;
}

int reduce(int* arr, unsigned long int n)
{
    #pragma omp parallel
    {
        #pragma omp single nowait
        {
            reduce_par(arr, n);
        }
    }
}

即使这不会出现段错误,即使您有无限数量的内核、无限的内存带宽并且没有线程创建开销,这仍然不会从并行化中提供任何性能优势。要弄清楚这一点,请绘制任务及其操作图并添加依赖项。尝试在尊重任务依赖关系的时间轴上排列图的节点,看看是否可以并行计算任何东西。

并行求和的正确解决方案是带有reduce 子句的parallel for 工作共享结构。如果你必须使用任务,你需要使用分而治之,例如为数组的两半生成两个任务。为了获得合理的性能,您必须以最小的工作负载大小停止任务创建/递归,以保持开销可控。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-19
    • 2020-05-17
    • 1970-01-01
    • 1970-01-01
    • 2011-04-23
    相关资源
    最近更新 更多