OpenMP proc_bind 子句是否应始终强制请求的绑定?

问题描述 投票:0回答:1

(测试代码位于here,供那些想要阅读或使用它的人使用)。 它包括一个带有

omp_proc_bind(close)
子句的并行区域,以及前面没有的并行区域。在每个并行区域内,它打印实际的线程关联性,以显示是否已实现请求的绑定。 (抱歉,这假设是 Linux,因为我会低调并致电
sched_getaffinity
来调查发生了什么)。

考虑这些代码的执行:-

% OMP_NUM_THREADS=4 ./a.out
omp_get_max_threads() = 4
OMP_PLACES="UNDEFINED", omp_get_num_places() = 0
OMP_PROC_BIND="UNDEFINED", omp_proc_bind() = false
omp_get_num_threads() = 4
0: omp_get_place_num() = -1, {0-287}
1: omp_get_place_num() = -1, {0-287}
2: omp_get_place_num() = -1, {0-287}
3: omp_get_place_num() = -1, {0-287}

Forcing proc_bind(close)
omp_get_num_threads() = 4
0: omp_get_place_num() = -1, {0-287}
1: omp_get_place_num() = -1, {0-287}
2: omp_get_place_num() = -1, {0-287}
3: omp_get_place_num() = -1, {0-287}

这表明显式的

proc_bind
子句已被忽略!

然而,如果我们使用 envirables 强制进行绑定,则显式 proc_bind 子句将受到尊重,并更改预先存在的绑定:-

% OMP_PROC_BIND=spread OMP_NUM_THREADS=4 ./a.out
omp_get_max_threads() = 4
OMP_PLACES="UNDEFINED", omp_get_num_places() = 288
OMP_PROC_BIND="spread", omp_proc_bind() = spread
omp_get_num_threads() = 4
0: omp_get_place_num() = 0, {0}
1: omp_get_place_num() = 72, {72}
2: omp_get_place_num() = 144, {144}
3: omp_get_place_num() = 216, {216}

Forcing proc_bind(close)
omp_get_num_threads() = 4
0: omp_get_place_num() = 0, {0}
1: omp_get_place_num() = 1, {1}
2: omp_get_place_num() = 2, {2}
3: omp_get_place_num() = 3, {3}

AFAICS OpenMP 标准(此处)要求无论环境设置如何,都必须遵守 proc_bind 子句:-

如果并行指令具有 proc_bind 子句,则 proc_bind 子句指定的绑定策略将覆盖 bind-var ICV 的第一个元素指定的策略。

然而,GCC 和 LLVM 似乎都忽略了显式的

proc_bind
子句,除非由于设置了 envirable 而已经存在绑定。 这对我来说似乎是错误的。我是不是错过了什么?

openmp
1个回答
0
投票

好的,我找到了答案,它是“如果通过 envirable 请求绑定,则可以忽略 proc_bind 子句。”

到达那里的路线是

  1. “如果 bind-var 未设置为
    false
    ,则
    proc_bind
    子句将覆盖 bind-var ICV 第一个元素的值;否则,
    proc_bind
    子句无效。” (标准中的此处)。
  2. 在 ICV 初始化规则表(此处)中,我们发现 bind-var 初始值为“实现定义”。

因此,允许实现将 bind-var 的默认设置为

false
,因此,忽略
proc_bind
子句。

这对我来说似乎有些可疑,因为这意味着人们可以编写明确说明其想要的内容的代码,然后在运行时将其忽略,并且,更糟糕的是在调试时,有时会被忽略,而不是其他人,或者与一个编译器,但不是另一个!

© www.soinside.com 2019 - 2024. All rights reserved.