c-openmp没有使用所有线程



我已经使用OpenMP用C编写了并行程序。

我想控制程序正在使用的线程数。

我使用的系统带有:

  • CentOS 6.5版(最终版)
  • icc 14.0.1版(与gcc 4.4.7版兼容)
  • 2个Intel(R)Xeon(R)CPU E5-2620 0@2.00GHz

我运行的程序:

#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
double t1[TABLE_SIZE];
double t2[TABLE_SIZE];
int main(int argc, char** argv) {
omp_set_dynamic(0);
omp_set_nested(0);
omp_set_num_threads(NUM_OF_THREADS);
#pragma omp parallel for default(none) shared(t1, t2) private(i)
for(i=0; i<TABLE_SIZE; i++) {
t1[i] = rand();
t2[i] = rand();
}
for(i=0; i<NUM_OF_REPETITION; i++) {
test1(t1, t2);
}
}
void test1(double t1[], double t2[]) {
int i;
double result;
#pragma omp parallel for default(none) shared(t1, t2) private(i) reduction(+:result)
for(i=0; i<TABLE_SIZE; i++) {
result += t1[i]*t2[i];
}
}

我正在运行在编译时设置TABLE_SIZE(2500、5000、100000、1000000)、NUM_OF_THREADS(1-24)和NUM_OF_REPETION(50000作为50k,100000作为100k,1000000作为1M)的脚本。问题是计算机没有利用所有提供的线程。这个问题似乎取决于TABLE_SIZE。

例如,当我编译TABLE_SIZE=2500的代码时,在NUM_OF_THREADS=20之前一切都很好。然后发生了一些奇怪的事情。当我设置NUM_OF_THREADS=21时,程序仅使用18个线程(我观察htop以查看有多少线程在运行)。当我设置NUM_OF_THREADS=23和NUM_OF_REPETITION=100k时,它使用了18个线程,但如果我在NUM_OF_THREADS=23时将NUM_OF_REPETITION更改为1M,则它使用了19个线程。

当我将TABLE_SIZE更改为5000时,异常地从18个线程开始。我设置了NUM_OF_THREADS=18,在NUM_OF_REPETITION=1M时,程序只使用17个线程。当我设置NUM_OF_THREADS=19和NUM_OF_REPETITION=100k或1M时,它只使用17个线程。如果我将NUM_OF_THREADS更改为24,程序将使用NUM_OF_REPETITION=50k时的20个线程、NUM_OF_REPETITION=100k时的22个线程和NUM_OF_REPETITION=1M时的23个线程。

这种不一致性随着TABLE_SIZE的增加而不断发生。TABLE_SIZE越大(NUM_OF_THREADS越低),不一致发生的速度就越快。

在这篇文章中(OpenMP set_num_threads()不起作用),我读到omp_set_num_threads()设置了程序可以使用的线程的上限。正如您所看到的,我已经禁用了动态团队,程序仍然没有使用所有线程。如果我设置环境变量OMP_NUM_THREADS和OMP_DYNAMIC也没有帮助。

所以我去阅读了一些OpenMP规范3.1。它说程序应该使用omp_set_num_threads()设置的线程数。另外,omp_get_max_threads()函数返回24个可用线程。

如有任何帮助,我们将不胜感激。

我终于找到了解决方案。我设置了KMP_AFFINITY环境变量。如果我将变量设置为";紧凑型";或";散射";(我现在只是对使用所有线程感兴趣)。

这就是文档所要说的(https://software.intel.com/en-us/articles/openmp-thread-affinity-control):

OpenMP线程和关联有两个注意事项:首先,确定要使用的线程数量,其次,如何将线程绑定到特定的处理器核心。

如果未设置KMP_AFFINITY的值,则允许OpenMP运行时为您选择相关性。所选的值取决于CPU体系结构,并且可能会根据该体系结构的各种应用程序认为最有效的亲和性而变化。

另一个来源(https://software.intel.com/en-us/node/522691):

亲和类型:

type=none(默认)

不将OpenMP*线程绑定到特定的线程上下文;但是,如果操作系统支持仿射,编译器仍然使用OpenMP*线程仿射接口来确定机器拓扑。

所以我想,因为我没有设置KMP_AFFINITY,所以OpenMP运行时设置了最有效的关联。如果我错了,请纠正我。

最新更新