嵌套循环,内循环并行化,重用线程

时间:2014-12-07 12:02:52

标签: c multithreading gcc optimization openmp

免责声明:以下示例只是一个快速了解问题的虚拟示例。如果您正在考虑现实问题,请考虑任何动态编程。

问题: 我们有一个n * m矩阵,我们想要复制上一行中的元素,如下面的代码所示:

for (i = 1; i < n; i++)
    for (j = 0; j < m; j++)
        x[i][j] = x[i-1][j];

方法 外循环迭代必须按顺序执行,它们将按顺序执行。 内环可以并行化。我们希望最大限度地减少创建和杀死线程的开销,因此我们只想创建一次线程组,但是,这在OpenMP中似乎是一项不可能完成的任务。

#pragma omp parallel private(j)
{
   for (i = 1; i < n; i++)
   {   
      #pragma omp for scheduled(dynamic)
      for (j = 0; j < m; j++)
         x[i][j] = x[i-1][j];
   }
}

当我们在外部循环上应用ordered选项时,代码将以顺序方式执行,因此不会有性能提升。 我正在寻找上述场景的解决方案,即使我不得不使用一些解决方法。

我正在添加我的实际代码。这实际上比seq慢。版。请查看:

/* load input */
for (i = 1; i <= n; i++)
    scanf ("%d %d", &in[i][W], &in[i][V]);

/* init */
for (i = 0; i <= wc; i++)
    a[0][i] = 0;

/* compute */
#pragma omp parallel private(i,w)
{
    for(i = 1; i <= n; ++i) // 1 000 000
    {
        j=i%2;
        jn = j == 1 ? 0 : 1;

        #pragma omp for
        for(w = 0; w <= in[i][W]; w++) // 1000
            a[j][w] = a[jn][w];

        #pragma omp for
        for(w = in[i][W]+1; w <= wc; w++) // 350 000
            a[j][w] = max(a[jn][w], in[i][V] + a[jn][w-in[i][W]]);
    }
}

至于测量,我使用的是这样的东西:

double t;
t = omp_get_wtime();
// ...
t = omp_get_wtime() - t;

1 个答案:

答案 0 :(得分:1)

总结OpenMP中针对这种特殊情况的并行化:这是不值得的。

<强>为什么吗 内循环中的操作很简单。代码是使用-O3编译的,因此max()调用可能已替换为函数体的代码。 隐式屏障的开销可能足够高,以补偿性能增益,并且总体开销足够高,使得并行代码甚至比顺序代码更慢。 我也发现,这种结构没有真正的性能提升:

#pragma omp parallel private(i,j)
{ 
   for (i = 1; i < n; i++)
   {   
      #pragma omp for
      for (j = 0; j < m; j++)
         x[i][j] = x[i-1][j];
   }
}

因为它的表现类似于这个

for (i = 1; i < n; i++)
{   
   #pragma omp parallel for private(j)
   for (j = 0; j < m; j++)
      x[i][j] = x[i-1][j];
}

感谢GCC libgomp中的内置线程重用,根据这篇文章:http://bisqwit.iki.fi/story/howto/openmp/

由于外部循环不能被并行化(没有ordered选项),因此看起来无法使用OpenMP显着提高相关程序的性能。如果有人觉得我做错了,而且有可能,我很乐意看到并测试解决方案。