使用gsl_matrix打开MP比顺序慢

时间:2014-06-28 10:23:15

标签: openmp gsl

我使用gsl(GNU Scienctific Library)和open mp创建了一个简单的c程序。在这个简单的程序中,我想测试顺序和并行的执行时间。以下是程序片段 main.c

#include "omp.h"
#include <stdio.h>
#include <gsl/gsl_matrix.h>
#include <time.h>

int main() 
{
    omp_set_num_threads(4);
    int n1=10000, n2=10000;
    gsl_matrix *A = gsl_matrix_alloc(n1, n2);

    int i,j;
    struct timeval tv1, tv2, tv3, tv4;

    gettimeofday(&tv1, 0);

    for(i=0; i<n1; i++) 
    {
        for(j=0; j<n2; j++)
        {
            gsl_matrix_set(A, i, j, i*j*1000000);
        }
    }

    gettimeofday(&tv2, 0);
    long elapsed = (tv2.tv_sec-tv1.tv_sec)*1000000 + tv2.tv_usec-tv1.tv_usec;

    printf("Sequential Duration:%ldms\n", elapsed); 

    gettimeofday(&tv3, 0);
    #pragma omp parallel for private(i,j)
    for(i=0; i<n1; i++) 
    {
        for(j=0; j<n2; j++)
        {
            gsl_matrix_set(A, i, j, i*j*1000000);
        }
    }

    gettimeofday(&tv4, 0);
    elapsed = (tv4.tv_sec-tv3.tv_sec)*1000000 + tv4.tv_usec-tv3.tv_usec;
    printf("  Parallel Duration:%ldms\n", elapsed);

    return 0;
}

然后我使用以下命令编译了上面的代码:

gcc -fopenmp main.c -o test -lgsl -lgslcblas -lm

以下是该计划的结果:

Sequential Duration:11980106ms
Parallel Duration:20624043ms

为什么,并行部分比顺序部分慢。我该如何优化此代码?感谢

3 个答案:

答案 0 :(得分:3)

正如你所写的那样,j变量在所有线程之间共享,因此线程会不断地覆盖其他线程状态,导致它们迭代它们已经覆盖的值。

尝试与openmp并行化时,应始终最小化变量的范围。将j的范围移动到循环中或明确标记为私有:

#pragma omp parallel for private(j)

时钟也会计算处理器时间而不是实时,您可能想要使用gettimeofday

你的矩阵太小而无法从并行化中获益,线程开销将占主导地位。将它增加到~10000x10000即可开始看到。

答案 1 :(得分:0)

这里的问题是你不知道程序gsl_matrix_set对A做了什么。你不知道它是否是线程安全的。要更改该矩阵中的一个元素,您需要将整个矩阵提供给例程,而不是仅提供元素的索引。这通过虚假分享来嗅见(参见例如this answer)。

我会试试这个

gsl_matrix_set(A[i][j],i*j*1000000);

如果这不起作用,你感兴趣的只是串行和并行之间的时差我会做

A[i][j] = i*j*1000000

答案 2 :(得分:-1)

在线程部分,试试这个:

#pragma omp parallel private(i,j)
for(i=0; i<n1; i++) 
{
    for(j=0; j<n2; j++)
    {
        gsl_matrix_set(A, i, j, i*j*1000000);
    }
}

#pragma omp parallel for 
for(i=0; i<n1; i++) 
{
    for(j=0; j<n2; j++)
    {
        gsl_matrix_set(A, i, j, i*j*1000000);
    }
}