外部调用的OpenMP程序只有一个线程运行,如果被另一个OpenMP程序调用

时间:2016-01-26 19:31:01

标签: c++ c linux process openmp

我有两个程序A和B,用g ++ - 5.1和openmp编译。 代码在Scientific Linux 7.1中运行。

g++ <program>.cpp -fopenmp -o <program>

程序(A)使用std :: system调用启动程序(B)。 程序的调用图如下所示:

|- A
   |- B

程序B应该使用系统上所有可用的CPU内核,但它只使用一个线程。 如果编译的程序A没有-fopenmp标志,那么程序B使用所有可用的核心。

即使程序B不再是A的子进程(std::system("setsid ./B &")),它也只使用一个线程。调用图:

|- B
...
|- A

为什么会出现这种情况?如何在程序A调用时让程序B使用所有内核?

同样奇怪的是,如果调用者没有使用-fopenmp编译,我会得到预期的行为。我尝试过的其他事情:使用execve,posix_spawn生成子进程,在其间有一个bash实例。使用编译器g ++ - 4.8.3也会出现问题。我没有想法。

计划A:A.cpp

#include <cstdlib>

int main(int argc, const char** argv) {
        std::system("setsid ./B  100000000000 &");
}

计划B:B.cpp

#include "omp.h"
#include <cstdlib>
#include <iostream>

// ignore the workload, I just need something to spin the CPU
double workload(size_t num_steps)
{
   size_t i;
   double  x=0;
   double sum = 0.0;
   double step = 1.0 / (double) num_steps;
   #pragma omp parallel private(i,x)
   {
      #pragma omp for reduction(+:sum) schedule(dynamic, 100)
      for (i=0; i<num_steps; i=i+1){
         x=(i+0.5)*step;
         sum = sum + 4.0/(1.0+x*x);
      }
   }
   return step*sum;
}

int main(int argc, const char** argv) {
   size_t a = strtoull(argv[1], NULL, 10);
   std::cout << a << " " << workload(a) << "\n";
   return 0;
}

1 个答案:

答案 0 :(得分:2)

大多数OpenMP运行时库的初始化都发生在它们的构造函数中,这些构造函数在流程生命周期的早期就会执行。因此,不可能阻止OMP_PROC_BIND对程序A的绑定效果,但是可以在产生程序B之前抵消它。有多种方法,但有两种方法立即出现在我的脑海中:

1)在taskset的调用中使用std::system()来覆盖子进程的CPU关联掩码:

std::system("taskset -c 0-63 ./B 100000000000");

-c 0-63参数产生一个64位设置的CPU亲和力掩码,这应该适用于大多数当前的多核系统(除非该程序在Intel Xeon Phi或某些奇特的硬件上运行,例如我们的Bull Coherent Switch耦合胖节点)。显然,如果系统上没有安装taskset(作为util-linux的一部分,它将无法正常工作,它应默认安装在许多系统上)。

2)在调用sched_setaffinity(2)之前,使用pthread_setaffinity_np(3)std::system()重置A的CPU关联掩码。看here寻找灵感。

3)如果你能负担得起外部依赖,hwloc library有一个非常好的API,可以用来获取和操纵CPU亲和力。它也是跨平台的,也适用于Windows。

选项3是最干净的选项,因为您不必在参数taskset或传递给调度程序功能的CPU集中预先硬编码足够宽的掩码。

相关问题