OpenMP并行尖峰

时间:2014-06-29 05:32:35

标签: c++ multithreading performance parallel-processing openmp

我在Visual Studio 2010中使用OpenMP来加速循环。

我写了一个非常简单的测试,看看使用OpenMP提高性能。我在空循环上使用omp parallel

int time_before = clock();

#pragma omp parallel for
for(i = 0; i < 4; i++){

}

int time_after = clock();

std::cout << "time elapsed: " << (time_after - time_before) << " milliseconds" << std::endl;

如果没有omp pragma,它一直需要0毫秒才能完成(正如预期的那样),并且使用pragma它通常也需要0。问题是,使用opm pragma偶尔会出现10到32毫秒的尖峰。每当我尝试与OpenMP并行时,我都会得到这些随机峰值,所以我尝试了这个非常基本的测试。尖峰是OpenMP的固有部分,还是可以避免?

并行为我提供了一些循环的速度提升,但这些随机尖峰对我来说太大了,无法使用它。

3 个答案:

答案 0 :(得分:2)

这是非常正常的行为。有时您的操作系统很忙,需要更多时间来生成新线程。

答案 1 :(得分:2)

我想补充kukis的答案:我还要说,峰值的原因是由于OpenMP带来的额外开销。

此外,在进行对性能敏感的测量时,我希望您在启用优化的情况下编译代码。在这种情况下,没有OpenMP的循环只会被编译器优化掉,因此time_beforetime_after之间没有代码。但是,对于OpenMP,至少g ++ 4.8.1(-O3)无法优化代码:循环仍然存在于汇编程序中,并包含用于管理工作共享的其他语句。 (目前我无法与VS一起尝试。)

因此,比较并不公平,因为没有OpenMP的人会完全优化。

编辑: 您还必须记住,OpenMP不会每次都重新创建线程。相反,它使用线程池。因此,如果在循环之前执行omp-construct,则在遇到另一个线程时就会创建线程:

// Dummy loop: Spawn the threads.
#pragma omp parallel for
for(int i = 0; i < 4; i++){
}

int time_before = clock();

// Do the actual measurement. OpenMP re-uses the threads.
#pragma omp parallel for
for(int i = 0; i < 4; i++){
}

int time_after = clock();

在这种情况下,尖峰应该消失。

答案 2 :(得分:2)

如果&#34; OpenMP并行尖峰&#34;,我会称之为&#34;并行开销&#34;,在你的循环中是一个问题,这推断你可能没有足够的要并行化的工作量。仅当您有足够的问题大小时,并行化才会产生加速。您已经展示了一个极端的例子:在并行循环中没有工作。在这种情况下,由于并行开销,您将看到高度波动的时间。

OpenMP&#39; omp parallel for中的并行开销包括几个因素:

  • 首先,omp parallel foromp parallelomp for的总和。
  • 产生或唤醒线程的开销(许多OpenMP实现不会创建/销毁每个omp parallel
  • 关于omp for,(a)将工作负载分配给工作线程的开销, (b)调度(特别是,如果使用动态调度)。
  • omp parallel末尾隐式屏障的开销,除非指定nowait

仅供参考,为了衡量OpenMP的并行开销,以下内容会更有效:

double measureOverhead(int tripCount) {
  static const size_t TIMES = 10000;
  int sum = 0;

  int startTime = clock();
  for (size_t k = 0; k < TIMES; ++k) {
    for (int i = 0; i < tripCount; ++i) {
      sum += i;
    }
  }
  int elapsedTime = clock() - startTime;

  int startTime2 = clock();
  for (size_t k = 0; k < TIMES; ++k) {
  #pragma omp parallel for private(sum) // We don't care correctness of sum 
                                        // Otherwise, use "reduction(+: sum)"
    for (int i = 0; i < tripCount; ++i) {
      sum += i;
    }
  }
  int elapsedTime2 = clock() - startTime2;

  double parallelOverhead = double(elapsedTime2 - elapsedTime)/double(TIMES);
  return parallelOverhead;
}

尝试运行这么小的代码可能需要时间,然后取平均值。此外,至少将最小工作负载放在循环中。在上面的代码中,parallelOverhead是OpenMP的omp parallel for构造的近似开销。