2

我有一个用于 N 皇后计算的简单 C 程序。我使用 OpenMP 将其并行化。现在我想同时执行串行和并行版本并计算加速。关键是我不想为串行代码创建一个新文件,或者只是将我的解决方案复制到一个没有 OpenMP 指令的新函数。我想要做的是,保留一个函数,并从主函数中告知何时将其作为串行执行,何时作为并行执行。我虽然使用预处理器,但我确定它是否可能,如果是,我该如何实现它。

void solve() 
{
    int i;

    #if PARALLEL == 1
      #pragma omp parallel for
    #endif
    for(i = 0; i < size; i++) {
        int *queens = (int*)malloc(sizeof(int)*size);
        setQueen(queens, 0, i);
        free(queens);
    }
}


int main()
{
   ...

    #define PARALLEL 0
    st_start = clock();
    solve();
    st_end = clock();

    #define PARALLEL 1
    pt_start = omp_get_wtime();
    solve();
    pt_end = omp_get_wtime();

    ...
}
4

3 回答 3

1

编辑:我想到了一种使用预处理器来做到这一点的方法。这以使编译和链接稍微复杂一些为代价解决了重复代码的问题。它使用的功能是,如果在编译器中未启用 OpenMP,则会忽略 OpenMP 结构。

#include <stdlib.h>

void setQueen(int* x, int y, int z) {
   /*code*/
}
#if defined _OPENMP
void solve_parallel(const int size)
#else
void solve_serial(const int size)
#endif
{
    int i;
    #pragma omp parallel for      
    for(i = 0; i < size; i++) {
        int *queens = (int*)malloc(sizeof(int)*size);
        setQueen(queens, 0, i);
        free(queens);
    }
}

编译

gcc -O3 -c foo.c -o solve_serial
gcc -O3 -fopenmp -c foo.c solve_parallel

然后,您可以使用类似于以下功能的主功能,并在solve_serial 和solve_parallel 目标文件中使用函数指针和链接。

另一种选择是像这样传递线程数:

void solve(const int nthreads)
{
    int i;
    const int size = 10;
    #pragma omp parallel for num_threads(nthreads)
    for(i = 0; i < size; i++) {
        int *queens = (int*)malloc(sizeof(int)*size);
        setQueen(queens, 0, i);
        free(queens);
    }
}

但是,即使对于 nthreads=1,编译器也必须插入 OpenMP 结构,与不使用 OpenMP 编译相比,这会降低性能,因此会产生有偏差的比较。

一个更公平的解决方案是定义两个有和没有 OpenMP 的函数,然后使用一个函数指针数组(见下文)。当您想要比较一个函数的多个变体以进行优化时,这会更有用。

#include <stdlib.h>
#include <omp.h>
void solve_parallel(const int size)
{
    int i;
    #pragma omp parallel for
    for(i = 0; i < size; i++) {
        int *queens = (int*)malloc(sizeof(int)*size);
        setQueen(queens, 0, i);
        free(queens);
    }
}

void solve_serial(const int size)
{
    int i;
    for(i = 0; i < size; i++) {
        int *queens = (int*)malloc(sizeof(int)*size);
        setQueen(queens, 0, i);
        free(queens);
    }
}

int main(void) {
    const int size = 100;
    int i;
    double dtime[2];
    void (*solve[2])(int);

    solve[0] = solve_serial;
    solve[1] = solve_parallel;

    solve[1](size);  /* run OpenMP once to warm it up */

    for(i=0; i<2; i++) {
        dtime[i] = omp_get_wtime();
        solve[i](size);
        dtime[i] = omp_get_wtime() - dtime[i];
    }

    return 0;
}
于 2013-12-04T12:24:28.250 回答
0

不幸的是,你不能那样做。

预处理器只是扫描你的代码并替换#stuff。完成后,编译器编译代码,#this 没有任何内容

因此,在您发布的代码中,预处理器从第一行开始,如果 PARALLEL 为 1,则执行 #pragma 代码,然后在 main 处继续,将 PARALLEL 定义为 0,然后定义为 1。

它不是从 main 开始然后进入solve();

你可能想看看OpenMP:conditional use of #pragma

你可以试试

void solve(int paral) 
{
    int i;


    #pragma omp parallel for if (paral == 1)

    for(i = 0; i < size; i++) {
        int *queens = malloc(sizeof(int)*size);
        setQueen(queens, 0, i);
        free(queens);
    }
}

我没有尝试过这段代码,也没有使用 OMP 的经验,不过......

于 2013-12-04T11:19:24.387 回答
0

调用预处理器,这是编译过程的第一部分;就在那里,所有的包含都被解决了,所有的前驱指令都被解决了,常量被它们的值替换等等......

因此,您不能使用预处理器指令来做出运行时决策,而只能做出编译时决策。

于 2013-12-04T17:05:48.327 回答