我在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的固有部分,还是可以避免?
并行为我提供了一些循环的速度提升,但这些随机尖峰对我来说太大了,无法使用它。
答案 0 :(得分:2)
这是非常正常的行为。有时您的操作系统很忙,需要更多时间来生成新线程。
答案 1 :(得分:2)
我想补充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();
在这种情况下,尖峰应该消失。
答案 2 :(得分:2)
如果&#34; OpenMP并行尖峰&#34;,我会称之为&#34;并行开销&#34;,在你的循环中是一个问题,这推断你可能没有足够的要并行化的工作量。仅当您有足够的问题大小时,并行化才会产生加速。您已经展示了一个极端的例子:在并行循环中没有工作。在这种情况下,由于并行开销,您将看到高度波动的时间。
OpenMP&#39; omp parallel for
中的并行开销包括几个因素:
omp parallel for
是omp parallel
和omp for
的总和。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
构造的近似开销。