OpenMP 开销延迟

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

我对 OpenMP 还比较陌生。掌握了窍门,但偶然发现了一些我需要解释的事情。

可能像大多数用户一样,我最常见的用例是:

#pragma omp for parallel
for( int i = 0; i < iUpperBound; i++ )
{
   // do stuff
}

这就像一个魅力。

我遇到的问题是指定您希望团队中有多少线程来“做这些事情”。据我所知,两种最常见的方法:

  1. omp_set_num_threads( iNbThreadsInTeam );
  2. num_threads 的 pragma omp 并行(iNbThreadsInTeam)

无论哪种方式,我仍然遇到同样的问题:执行时间有明显的额外开销。

例如,在特定的运行中,我的 iUpperBound 比 iNbThreadsInTeam 大多个数量级(因此这不是空闲线程的问题,它们都以 100% 同等工作)。我使用 iNbThreadsInTeam == 22 运行循环。作为参考,如果我按顺序执行相同的循环,则会得到 0.02 秒的执行时间。同时我得到了 0.01 秒的执行时间。没关系,我不会争论我没有获得 22 倍加速的事实。问题是:如果我在调用 omp_set_num_threads() (在 #pragma 之前)之前启动计时器,我会得到 0.03 秒,这比顺序执行时间长,即使有 22 个工作线程也是如此。

当然,尽管 iUpperBound 相对较大,但在这种情况下要做的“事情”非常轻,因此顺序为 0.02,并行为 0.01。并行运行可能还会产生一些额外的开销。 OpenMP 可能更适合更重的“东西”。此外,我们的应用程序对时间要求不高,因此我们的用户甚至不会注意到这种情况下的差异。但我还是对这个 omp_set_num_threads() 延迟很好奇。

文档说它为所有 OMP 调用设置默认值。直观上,当在任何(大多数?)框架/库中设置新的设置值时,它只是相当于在内存中的某处写入一个 int 或一个 float ,以便稍后仅在需要使用该值时才能检索该值(例如,当点击“#pragma omp parallel”行时)。显然,omp_set_num_threads() 的作用远不止于此。这是 OPenMP 用户不应该关心的内部细节。我仍然在徘徊,因为与之相关的成本很高。例如,它是否会抢先重置线程池,以便准备好继续下一个“#pragma omp parallel”调用?这将是一个奇怪的设计选择,因为如果在编译指示行中使用 num_threads 子句,则此设置“工作”将被废弃。

当然,我坦白承认,我们没有按照预期的方式使用 omp_set_num_threads() 。这应该是默认值设置函数,因此不要在每个“#pragma omp ...”行之前显式调用。该函数应该只为整个应用程序调用一次。我们的问题是我们的应用程序分散在各个 VS 项目中,并生成许多不同的 DLL。这为我的第二个小问题铺平了道路:假设我们在 DLL 中静态链接 OMP(OMP 可以拥有自己的 DLL 并动态链接吗?),所有运行 OMP 代码的 DLL 是否应该单独设置它们自己的(本地)默认调用 omp_set_num_threads () 各一次?或者我们可以“神奇地”在调用这些 DLL 的 EXE 中运行一次吗?出于某种原因,我对此表示怀疑,但值得一试;-)

谢谢

ps:我们的应用程序是用 VS2017 构建的,它使用 Visual C++ 2.0 版 2002 年 3 月的 OpenMP 运行时支持库
pps:有 io OMP_NUM_THREADS 环境变量。但这是行不通的:我们显然希望我们的应用程序能够使用 omp_get_num_procs() 动态适应其运行的 CPU,以获得最大性能。

openmp
1个回答
0
投票

您是否精确地计时了一个循环?重复100次,然后划分时间。很少有应用程序只包含一个循环:通常该循环将被执行多次。

下一步:OpenMP 创建一组线程,这需要时间。此后,队伍仅在平行区域之间暂停。所以我会做类似的事情

#pragma omp parallel
#pragma omp single
nthreads = omp_get_num_threads();

只是为了创建团队。然后为循环计时。

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