【问题标题】:parallelize nested loop in OpenMP and do inner loop with more thread在 OpenMP 中并行化嵌套循环并使用更多线程执行内部循环
【发布时间】:2013-07-22 23:07:46
【问题描述】:

我有这种嵌套循环:我想知道如何以最佳形式并行化它:

  1. 第二个和第三个for 以及第五个和第六个for 运行相同 时间

  2. 第一个和第四个for 串行

如果我有 24 个核心,并且想在 16 个线程之间划分外部并使用其余的与它们一起执行内部 for,例如使用 8 个线程执行第二个 for 而不仅仅是一个线程,我该怎么办?

void main()
{
//first_for
   for(int y=0; y< height; y++)
{
      //second_for 
      for(int x=0; x< width-1; x++)
   {
     func1();
   }
      //third_for
      for(int x=0; x< width-1; x++)
   {
     func2();
   }

}
//fourth_for
   for(int x=0; x<width; x++)
{
     //fifth_for
     for(int y=0; y< height-1; y++)
   {
     func3();
   }
     //sixth_for
     for(int y=0; y< height-1; y++)
   {
     func4();
   }
}
}

【问题讨论】:

  • 但是第一个和第四个是否与其他 4 个同时运行?
  • 第一个 first_for 和之后的第四个_for ? OpenMP 中嵌套循环的最佳处理是什么?
  • 我认为您误解了 OpenMP 的嵌套并行性。如果您在 16 个线程上运行外部循环并在该范围内请求 8 个线程,您将获得(假设您的实现支持嵌套并行)16*8==128 线程总数;也就是说,外 16 根螺纹中的每根都有 8 根内螺纹。在 24 核机器上,这可能总是一个坏主意,因为线程争夺对处理器内核的访问权限,因为它们每个都会破坏其他缓存,等等。
  • 是的@Mark你是对的Mark,以及在for中使用sections指令如何并行执行两个内部for,我注意到你的观点,但我想同时执行这两个for同一时间

标签: c++ c performance openmp


【解决方案1】:

除了已经说过的内容之外,您可能还想显式启用嵌套并行性。可以通过运行时的库调用或环境变量(对于 OpenMP)来执行此操作。

欲了解更多信息,请查看此Oracle Docs

【讨论】:

    【解决方案2】:

    关于并行性介绍,通常说越粗的级别越好,所以如果您可以在扩展良好的粗略级别添加并行指令,为什么还要添加嵌套并行?

    所以基于可以同时运行的内容,我会这样编写主要内容:

    int main()
    {
         //first_for
         #pragma parallel for
         for(int y=0; y< height; y++)
         {
              //second_for and third_for
          for(int x=0; x< width-1; x++)
         {
              func1();
              func2();
    
          }
      }
     //fourth_for
     #pragma parallel for
     for(int x=0; x<width; x++)
     {
          //fifth_for and  //sixth_for
         for(int y=0; y< height-1; y++)
        {
              func3();
              func4();
         }
      }
     return 0;
    }
    
    1. 我们通过合并 2 个内部循环来增加每行和每列的工作量

    2. 我们添加了 openMP 指令以根据您的核心数量将该计算循环拆分为更小的块。

    3. 查看是否可以反转第一个循环,因为取决于您在内部执行的操作以及“图像”在内存中的映射方式,首先处理列可能会导致大量缓存错误....

    编辑

    您可以启用嵌套并行性,但它走错了路,过多的循环和线程访问不同的内存块只会降低性能,您还将拥有一个为 24 核设计的解决方案,可能无法与 32 扩展, 48 核等...但如果您坚持必须设置环境变量或调用 openMP 函数:

     call omp_set_nested()
     or
     set OMP_NESTED=TRUE|FALSE
    

    在您的顶级循环上添加一个 openMP 子句以指定您想要的块大小以便只有 X 线程。

    int  chunckSize = height / X;
    #pragma parallel for schedule ( static , chunckSize)
    

    openMP 线程团队应该由 24 个线程组成,但这样做只有 X 有工作要做。遵循嵌套循环的逻辑。

    但这不是我推荐的解决方案!

    【讨论】:

    • 我想知道这是最好的形式吗?这个问题呢?如果我有 24 个内核并且想在 16 个线程之间划分外层并使用其余部分与它们一起执行内层,例如使用 8 个线程执行第二个而不是一个线程,我该怎么办?
    • 我编辑了我的答案,但是你走的方式会导致奇怪的行为,更多的同步点(加入)等等......,
    猜你喜欢
    • 2015-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多