【问题标题】:Persistance of OpenMP thread teams across functions跨功能的 OpenMP 线程团队的持久性
【发布时间】:2012-09-27 05:47:45
【问题描述】:

我有一个用于物理模拟的简单程序。我想知道如何在 OpenMP 中实现某种线程范式。

int main()
{
#define steps (100000)
   for (int t = 0;t < steps; t++)
   {
     firstParallelLoop();
     secondParallelLoop();
     if (!(t%100))
     {
        checkpoint();
     }
   }
}
void firstParallelLoop()
{// In another file.c
  #pragma omp parallel for
   for (int i = 0; i < sizeOfSim;i++)
   {
     //Some atomic floating point ops.
   }
}

以前,我使用 pthreads 并在我的双核笔记本电脑上获得了 1.7 的加速。使用 OpenMP 时,我似乎无法获得任何加速。我怀疑问题在于线程组/池正在迅速被创建和销毁,并带来灾难性的影响。

在我的 pthreads 实现中,我需要确保没有创建新线程,并且我的程序表现为客户端-服务器。在 pthreads 方案中,main() 是一个服务器,对 firstParallelLoop 的调用将释放触发线程重新处理数据的互斥体/信号量。

当我查看 CPU 利用率时,我预计它会超过 30%(4 核,2 是 HT),但它保持在 27 左右...

如何让 OpenMP 做类似的事情?如何让 OpenMP 重用我的线程?

【问题讨论】:

  • 您是否启用了正确的编译器选项? OpenMP 的大多数实现确实会池化线程。
  • 如果您的 CPU 使用率没有增加,那么您可能从未启用过 OpenMP。你的编译选项是什么? sizeOfSim 有多大?
  • sizeOfSim 是一个 10,000 x 10,000 的网格,其中邻居被平均和缩放 (FDTD)。我想我想要弄清楚的是如何调试 OpenMP 正在做什么?我可以强制 OpenMP 池线程吗?
  • 那么您使用的是哪些编译器选项?我仍然怀疑您从未启用过 OpenMP。
  • -ffast-math -mtune=corei7 -march=corei7 -fopenmp 用于 gcc 和 -lmgl -lgomp 用于 ldd

标签: c gcc openmp


【解决方案1】:

GCC OpenMP 运行时libgomp 通过类似于线程池的方式在 POSIX 系统上实现线程组 - 线程仅在遇到第一个并行区域时创建,每个线程运行一个无限工作循环。进入和退出平行区域是通过障碍实现的。默认情况下libgomp 使用忙等待和睡眠的组合来实现屏障。忙等待的数量由OMP_WAIT_POLICY 环境变量控制。如果未指定,则在屏障上等待的线程将忙于等待 300000 次旋转(100000 次旋转/毫秒时为 3 毫秒),然后进入睡眠状态。如果OMP_WAIT_POLICY 设置为active,则忙碌等待时间增加到 30000000000 转(5 分钟,100000 转/秒)。您可以通过将 GOMP_SPINCOUNT 变量设置为繁忙周期数来微调繁忙等待时间(libgomp 假设大约为 100000 转/毫秒,但它可能会因 CPU 的不同而变化 5 倍)。您可以像这样完全禁用睡眠:

OMP_WAIT_POLICY=active GOMP_SPINCOUNT=infinite OMP_NUM_THREADS=... ./program

这会以某种方式改善线程组的启动时间,但会以 CPU 时间为代价,因为空闲线程不会空闲,而是忙于等待。

为了消除开销,您应该以对 OpenMP 更友好的方式重写您的程序。您的示例代码可以这样重写:

int main()
{
#define steps (100000)
   #pragma omp parallel
   {
      for (int t = 0; t < steps; t++)
      {
         firstParallelLoop();
         secondParallelLoop();
         if (!(t%100))
         {
            #pragma omp master
            checkpoint();
            #pragma omp barrier
         }
      }
   }
}
void firstParallelLoop()
{// In another file.c
   #pragma omp for
   for (int i = 0; i < sizeOfSim; i++)
   {
      //Some atomic floating point ops.
   }
}

注意以下两点:

  • 在主程序中插入了一个并行区域。不过,它不是parallel for。团队中的所有线程都会执行外循环steps 次。
  • firstParallelLoop 中的 for 循环仅通过使用 omp for 进行并行处理。因此,如果在 OpenMP 并行外部调用,它将作为串行循环执行,而在从并行区域内部调用时,它将作为并行执行。 secondParallelLoop 中的循环也应该这样做。

主循环中的屏障用于确保其他线程在开始下一次迭代之前等待检查点完成。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 2012-12-26
    • 1970-01-01
    • 2014-11-08
    • 2012-03-08
    • 1970-01-01
    相关资源
    最近更新 更多