OpenMP并行尖峰
OpenMP parallel spiking
我在Visual Studio 2010中使用OpenMP来加速循环。
我写了一个非常简单的测试来观察使用OpenMP的性能提升。我在空循环上使用omp parallelint 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固有的一部分,还是可以避免?
并行的for在一些循环中给了我很大的速度提升,但是这些随机尖峰太大了,我无法使用它
这是很正常的行为。有时候你的操作系统很忙,需要更多的时间来生成新的线程。
我想补充一下kukis的答案:我还想说,峰值的原因是由于OpenMP带来的额外开销。
此外,由于您正在进行性能敏感的测量,我希望您在编译代码时打开了优化。在这种情况下,没有OpenMP的循环只是由编译器优化出来,因此在time_before
和time_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();
在这种情况下,峰值应该消失。
如果"OpenMP并行尖峰",我称之为"并行开销",是你循环中的一个问题,这就推断出你可能没有足够的工作负载来并行化。只有在问题规模足够大的情况下,并行化才能提高速度。您已经展示了一个极端的例子:在并行循环中没有工作。在这种情况下,由于并行开销,您将看到高度波动的时间。
OpenMP的omp parallel for
中的并行开销包括以下几个因素:
- 首先,
omp parallel for
是omp parallel
和omp for
的和。 生成或唤醒线程的开销(许多OpenMP实现不会创建/销毁每个 - 关于
omp for
, (a)向工作线程调度工作负载的开销,(b)调度(特别是如果使用动态调度)。 - 除非指定了
nowait
,否则omp parallel
末尾的隐式屏障的开销。
omp parallel
)。供参考,为了测量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;
}
尝试运行这些小代码5次,然后取平均值。此外,至少将最小的工作负载放入循环中。在上面的代码中,parallelOverhead
是OpenMP的omp parallel for
构造的近似开销。
- OpenMP:并行更新数组总是需要减少数组吗
- 如何使用OpenMP并行这两个循环
- 如何使用OpenMP并行化此矩阵时间矢量运算
- 如何使用OpenMP使这个循环并行
- 为什么 openmp 的并行不适用于矢量化色彩空间转换?
- 在C++中使用并行化的预期速度是多少(不是 OpenMp,而是 <thread>)
- OpenMP 与有序和关键指令并行
- OpenMP for 循环并行性问题
- 两个连续的 OpenMP 并行区域会相互减慢速度
- 如何使用 OpenMP 并行化最近邻搜索
- 并行块(线程清理器)之外的 OpenMP 中的争用条件;误报?
- openmp c++ 中并行块内 lambda 函数的奇怪行为
- 如何使用 OpenMP 正确并行化 for 循环?
- 为什么 std::chrono 在测量循环和编译器优化的并行 OpenMP 的执行时间时不起作用?
- OpenMP并行发送哪些元素
- 对于openMP来说,有什么建议可以将以下代码与openMP并行
- 使用openmp实现并行广度优先搜索
- 是否可以使用OpenMP并行化一个列表,该列表可以在每次迭代中添加新元素
- std::lock_guard 在 OpenMP 并行中
- 并行OpenMP缩减vs.函数定义