如何通过循环将 OpenMP 线程拆分为子团队
How to split OpenMP threads into subteams over a loop
假设我有一个内部使用 #pragma omp parallel
的函数。
void do_heavy_work(double * input_array);
我现在想 do_heavy_work
上许多 input_arrays
因此:
void do_many_heavy_work(double ** input_arrays, int num_arrays)
{
for (int i = 0; i < num_arrays; ++i)
{
do_heavy_work(input_arrays[i]);
}
}
假设我有 N
个硬件线程。上面的实现将导致 num_arrays
调用 do_heavy_work
以串行方式发生,每个调用在内部使用所有 N
线程来执行它想要的任何并行操作。
现在假设当 num_arrays > 1
时,在这个外部循环上并行化实际上比在 do_heavy_work
中在内部并行化更有效。我现在有以下选择。
- 将
#pragma omp parallel for
放在外循环并设置OMP_NESTED=1
。但是,通过设置 OMP_NUM_THREADS=N
,我最终会生成大量线程 (N*num_arrays
)。
- 同上,但关闭嵌套并行。当
num_arrays < N
. 时,这会浪费可用内核
理想情况下,我希望 OpenMP 将其 OMP_NUM_THREADS
线程团队拆分为 num_arrays
个子团队,然后每个 do_heavy_work
可以在其分配的子团队中线程化(如果有的话)。
实现此目标的最简单方法是什么?
(为了讨论的目的,我们假设 num_arrays
不一定事先知道,而且我不能更改 do_heavy_work
本身的代码。代码应该适用于许多机器所以 N
应该可以自由指定。)
OMP_NUM_THREADS
可以设置为一个列表,从而指定每一层嵌套的线程数。例如。 OMP_NUM_THREADS=10,4
将告知 OpenMP 运行时使用 10 个线程执行外部并行区域,每个嵌套区域将使用 4 个线程执行,总共最多同时执行 40 个 运行 个线程。
或者,您可以使用类似于以下代码的代码使您的程序自适应:
void do_many_heavy_work(double ** input_arrays, int num_arrays)
{
#pragma omp parallel num_threads(num_arrays)
{
int nested_team_size = omp_get_max_threads() / num_arrays;
omp_set_num_threads(nested_team_size);
#pragma omp for
for (int i = 0; i < num_arrays; ++i)
{
do_heavy_work(input_arrays[i]);
}
}
}
如果 OMP_NUM_THREADS
的值不能被 num_arrays
整除,此代码将不会使用所有可用线程。如果每个嵌套区域有不同数量的线程没问题(这可能导致某些数组的处理速度比其他数组快),请想出如何分配线程并相应地在每个线程中设置 nested_team_size
的想法。从并行区域内调用 omp_set_num_threads()
只会影响调用线程启动的嵌套区域,因此您可以有不同的嵌套团队大小。
假设我有一个内部使用 #pragma omp parallel
的函数。
void do_heavy_work(double * input_array);
我现在想 do_heavy_work
上许多 input_arrays
因此:
void do_many_heavy_work(double ** input_arrays, int num_arrays)
{
for (int i = 0; i < num_arrays; ++i)
{
do_heavy_work(input_arrays[i]);
}
}
假设我有 N
个硬件线程。上面的实现将导致 num_arrays
调用 do_heavy_work
以串行方式发生,每个调用在内部使用所有 N
线程来执行它想要的任何并行操作。
现在假设当 num_arrays > 1
时,在这个外部循环上并行化实际上比在 do_heavy_work
中在内部并行化更有效。我现在有以下选择。
- 将
#pragma omp parallel for
放在外循环并设置OMP_NESTED=1
。但是,通过设置OMP_NUM_THREADS=N
,我最终会生成大量线程 (N*num_arrays
)。 - 同上,但关闭嵌套并行。当
num_arrays < N
. 时,这会浪费可用内核
理想情况下,我希望 OpenMP 将其 OMP_NUM_THREADS
线程团队拆分为 num_arrays
个子团队,然后每个 do_heavy_work
可以在其分配的子团队中线程化(如果有的话)。
实现此目标的最简单方法是什么?
(为了讨论的目的,我们假设 num_arrays
不一定事先知道,而且我不能更改 do_heavy_work
本身的代码。代码应该适用于许多机器所以 N
应该可以自由指定。)
OMP_NUM_THREADS
可以设置为一个列表,从而指定每一层嵌套的线程数。例如。 OMP_NUM_THREADS=10,4
将告知 OpenMP 运行时使用 10 个线程执行外部并行区域,每个嵌套区域将使用 4 个线程执行,总共最多同时执行 40 个 运行 个线程。
或者,您可以使用类似于以下代码的代码使您的程序自适应:
void do_many_heavy_work(double ** input_arrays, int num_arrays)
{
#pragma omp parallel num_threads(num_arrays)
{
int nested_team_size = omp_get_max_threads() / num_arrays;
omp_set_num_threads(nested_team_size);
#pragma omp for
for (int i = 0; i < num_arrays; ++i)
{
do_heavy_work(input_arrays[i]);
}
}
}
如果 OMP_NUM_THREADS
的值不能被 num_arrays
整除,此代码将不会使用所有可用线程。如果每个嵌套区域有不同数量的线程没问题(这可能导致某些数组的处理速度比其他数组快),请想出如何分配线程并相应地在每个线程中设置 nested_team_size
的想法。从并行区域内调用 omp_set_num_threads()
只会影响调用线程启动的嵌套区域,因此您可以有不同的嵌套团队大小。