我正在尝试重构基于OpenMP的程序,并遇到了可怕的可伸缩性问题。以下(显然不是很有意义)OpenMP程序似乎重现了这个问题。当然,可以将微小的示例代码重写为嵌套的for循环,并且可以使用collapse(2)
几乎完美的可伸缩性。但是,我正在处理的原始程序不允许这样做。
因此,我正在寻找一个修复,保持do-while结构。根据我的理解,OpenMP应该足够聪明,以便在迭代之间保持线程活跃,并且我期望良好的可伸缩性。为什么不是这样?
int main() {
const int N = 6000;
const int MAX_ITER = 2000000;
double max = DBL_MIN;
int iter = 0;
do {
#pragma omp parallel for reduction(max:max) schedule(static)
for(int i = 1; i < N; ++i) {
max = MAX(max, 3.3*i);
}
++iter;
} while(iter < MAX_ITER);
printf("max=%f\n", max);
}
我使用Cray编译器版本8.3.4测量了以下运行时。
OMP_NUM_THREADS=1 : 0m21.535s
OMP_NUM_THREADS=2 : 0m12.191s
OMP_NUM_THREADS=4 : 0m9.610s
OMP_NUM_THREADS=8 : 0m9.767s
OMP_NUM_THREADS=16: 0m13.571s
这似乎与this question相似。提前致谢。感谢帮助! :)
答案 0 :(得分:1)
你可以选择这样的事情:
#include <stdio.h>
#include <float.h>
#include <omp.h>
#define MAX( a, b ) ((a)>(b))?(a):(b)
int main() {
const int N = 6000;
const int MAX_ITER = 2000000;
double max = DBL_MIN;
#pragma omp parallel reduction( max : max )
{
int iter = 0;
int nbth = omp_get_num_threads();
int tid = omp_get_thread_num();
int myMaxIter = MAX_ITER / nbth;
if ( tid < MAX_ITER % nbth ) myMaxIter++;
int chunk = N / nbth;
do {
#pragma omp for schedule(dynamic,chunk) nowait
for(int i = 1; i < N; ++i) {
max = MAX(max, 3.3*i);
}
++iter;
} while(iter < myMaxIter);
}
printf("max=%f\n", max);
}
我非常确定可扩展性应该是众所周知的。
注意:由于我意识到外循环(do-while one)的迭代次数对于不同的线程可能有所不同,所以我不得不回到这几次,因此调度至关重要omp for
循环不是静态的,否则,在最后一次迭代中可能出现死锁。
我做了一些测试,我认为所提出的解决方案既安全又有效。