OpenMP parallel for inside do-while
OpenMP parallel for inside do-while
我正在尝试重构基于 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 相似。提前致谢。感谢帮助! :)
你可以这样做:
#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)的迭代次数对于不同的线程可能不同,所以我不得不多次回到这个问题上,这一点至关重要omp for
循环的调度不是静态的,否则,在最后一次迭代时可能会出现死锁。
我做了一些测试,我认为建议的解决方案既安全又有效。
我正在尝试重构基于 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 相似。提前致谢。感谢帮助! :)
你可以这样做:
#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)的迭代次数对于不同的线程可能不同,所以我不得不多次回到这个问题上,这一点至关重要omp for
循环的调度不是静态的,否则,在最后一次迭代时可能会出现死锁。
我做了一些测试,我认为建议的解决方案既安全又有效。