【问题标题】:OpenMP, dependency graphOpenMP,依赖图
【发布时间】:2017-12-03 20:14:17
【问题描述】:

我用一些旧的 OpenMP 练习来练习一点,但我很难找到特别是 on 的解决方案。

目标是编写与依赖图对应的最简单的 OpenMP 代码。

图表在此处可见:http://imgur.com/a/8qkYb

第一个很简单。

对应如下代码:

#pragma omp parallel
{
#pragma omp simple
  {
#pragma omp task
    {
       A1();
       A2();
    }
#pragma omp task
    {
       B1();
       B2();
    }
#pragma omp task
    {
       C1();
       C2();
    }
  }
}

第二个还是很容易的。

#pragma omp parallel
{
#pragma omp simple
  {
#pragma omp task
    {
       A1();
    }
#pragma omp task
    {
       B1();
    }
#pragma omp task
    {
       C1();
    }
#pragma omp barrier
    A2();
    B2();
    C2();
  }
}

现在是最后一个…… 这让我很烦恼,因为所有函数调用的依赖项数量都不相等。我认为应该明确说明您应该等待哪个任务,但我在 OpenMP 文档中找不到我要查找的内容。

如果有人对这个问题有解释,我将非常感激,因为我已经考虑了一个多月了。

【问题讨论】:

    标签: parallel-processing openmp dependency-graph


    【解决方案1】:

    首先,OpenMP 4.5 规范中没有#pragma omp simple。 我假设您的意思是#pragma omp single

    如果是这样,pragma omp barriersingle 区域内是个坏主意,因为只有一个线程会执行代码并等待所有其他线程,这些线程不执行该区域。

    另外,A2、B2 和 C2 上的第二个不再作为任务并行执行。

    对于您的尖锐问题: 您正在寻找的似乎是 OpenMP Secification pg. 169 上的 Task 构造的 depend 子句。

    Massimiliano for this question 很好地解释了depend 子句及其工作原理。

    【讨论】:

      【解决方案2】:

      一旦你了解了那里发生的事情,最后一个例子就没有那么复杂了:每个任务 Tn 依赖于之前的迭代 T-1_n 及其邻居(T-1_n-1T-1_n+1)。这种模式称为Jacobi stencil。在偏微分方程求解器中很常见。

      正如 Henkersmann 所说,最简单的选择是使用 OpenMP Task 的 depend 子句:

      int val_a[N], val_b[N];    
      #pragma omp parallel
      #pragma omp single
      {
      int *a = val_a;
      int *b = val_b;
      for( int t = 0; t < T; ++t ) {
        // Unroll the inner loop for the boundary cases
        #pragma omp task depend(in:a[0], a[1]) depend(out:b[0])
        stencil(b, a, i);
      
        for( int i = 1; i < N-1; ++i ) {
           #pragma omp task depend(in:a[i-1],a[i],a[i+1]) \
                       depend(out:b[i])
           stencil(b, a, i);
        }
      
        #pragma omp task depend(in:a[N-2],a[N-1]) depend(out:b[N-1])
        stencil(b, a, N-1);
      
        // Swap the pointers for the next iteration
        int *tmp = a;
        a = b;
        b = tmp;
      }
      #pragma omp taskwait
      }
      

      如您所见,OpenMP 任务依赖是点对点的,这意味着您不能用数组区域来表达它们。

      另一种选择,对于这种特定情况来说更简洁一些,是使用屏障间接强制依赖:

      int a[N], b[N];
      #pragma omp parallel
      for( int t = 0; t < T; ++t ) {
        #pragma omp for
        for( int i = 0; i < N-1; ++i ) {
           stencil(b, a, i);
        }
      }
      

      第二种情况会在每次内部循环完成时执行同步屏障。同步粒度更粗,因为每次外循环迭代只有 1 个同步点。但是,如果stencil 函数长且不平衡,则可能值得使用任务。

      【讨论】:

        猜你喜欢
        • 2021-03-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-12
        • 1970-01-01
        • 1970-01-01
        • 2018-05-02
        • 2017-01-06
        相关资源
        最近更新 更多