【发布时间】:2016-05-03 12:22:28
【问题描述】:
我有两个程序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;
}
【问题讨论】:
-
改用
std::system("cat /proc/self/status");并查看Cpus_allowed_list的值。也许启用了线程固定。检查环境变量集中是否存在OMP_PROC_BIND、OMP_PLACES或GOMP_CPU_AFFINITY。 -
@HristoIliev 非常感谢这个提示。 Cpus_allowed_list = 1、OMP_PROC_BIND=TRUE 和 OMP_PLACES 和 GOMP_CPU_AFFINITY 未设置。 OMP_PROC_BIND=FALSE 似乎可以解决问题。但是现在我们调用了程序 (A),像这样 OMP_PROC_BIND=FALSE ./A。有没有办法在运行时设置它?
-
运行 A 时不要设置
OMP_PROC_BIND。使用setenv(3)将OMP_PROC_BIND设置为TRUE在生成 B 之前从 A 内部或使用execle(2)/execvpe(2)传递修改子进程的环境。 -
@HristoIliev 非常感谢。这行得通。不幸的是,我无法将您的评论标记为答案。无论如何,您能想到如何避免为工具 A 编写包装脚本来取消设置 OMP_PROC_BIND?
-
你去 - 我在答案中总结了几种方法来做到这一点,而无需与环境打交道。
标签: c++ c linux process openmp