内部do-while

时间:2015-09-15 21:26:53

标签: c++ for-loop parallel-processing openmp

我正在尝试重构基于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相似。提前致谢。感谢帮助! :)

1 个答案:

答案 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循环不是静态的,否则,在最后一次迭代中可能出现死锁。 我做了一些测试,我认为所提出的解决方案既安全又有效。