繁体   English   中英

稀疏矩阵的多线程程序

[英]Multithreaded Program for Sparse Matrices

我是多线程的新手。 我正在尝试设计一个解决稀疏矩阵的程序。 在我的代码中,我多次将Vector Vector点积和Matix vector product称为子例程,以得出最终解决方案。 我正在尝试使用开放式MP(特别是上述两个子例程)对代码进行并行化。我也有顺序代码,在这些序列化代码之间,我不希望并行化。

我的问题是如何处理调用子例程时创建的线程。 我是否应该在每个子例程调用的末尾放置一个障碍。

另外,我应该在哪里设置线程数?

Mat_Vec_Mult(MAT,x0,rm);
#pragma omp parallel for schedule(static)
for(int i=0;i<numcols;i++)  
    rm[i] = b[i] - rm[i];

#pragma omp barrier


#pragma omp parallel for schedule(static)
for(int i=0;i<numcols;i++)  
    xm[i] = x0[i];
#pragma omp barrier


double* pm = (double*) malloc(numcols*sizeof(double));


    #pragma omp parallel for schedule(static)
for(int i=0;i<numcols;i++)  
    pm[i] = rm[i];
#pragma omp barrier
scalarProd(rm,rm,numcols);

谢谢

编辑:

对于标量点积,我正在使用以下代码:

double scalarProd(double* vec1, double* vec2, int n){
double prod = 0.0;
int chunk = 10; 
int i;
//double* c = (double*) malloc(n*sizeof(double));

omp_set_num_threads(4);

// #pragma omp parallel shared(vec1,vec2,c,prod) private(i)
#pragma omp parallel
{
    double pprod = 0.0;
    #pragma omp for
    for(i=0;i<n;i++) {
        pprod += vec1[i]*vec2[i];
    }

    //#pragma omp for reduction (+:prod)
    #pragma omp critical
    for(i=0;i<n;i++) {
        prod += pprod;
    }
}


return prod;
}

现在,我在ConjugateGradient函数中添加了时间计算代码,如下所示:

start_dotprod = omp_get_wtime();
rm_rm_old = scalarProd(rm,rm,MAT->ncols);
    run_dotprod = omp_get_wtime() - start_dotprod;
fprintf(timing,"Time taken by rm_rm dot product : %lf \n",run_dotprod);        

观察结果:点积所需的时间顺序版本:0.000007s并行版本:0.002110

我正在Intel I7笔记本电脑上的Linux OS上使用gcc -fopenmp命令进行简单的编译。

我目前正在使用大小为n = 5000的矩阵。

总的来说,由于同一个点乘积被调用多次直到实现收敛(大约8万次),所以我的速度正在总体下降。

请提出一些改进。 任何帮助深表感谢!

老实说,我建议在更高层次上并行化。 我的意思是要尽量减少您正在使用的#pragma omp parallel的数量。 每次尝试在线程之间分配工作时,都会产生OpenMP开销。 尝试并尽可能避免这种情况。

因此,至少在您的情况下,我会尝试:

Mat_Vec_Mult(MAT,x0,rm);
double* pm = (double*) malloc(numcols*sizeof(double)); // must be performed once outside of parallel region

// all threads forked and created once here
#pragma omp parallel for schedule(static)
for(int i = 0; i < numcols; i++) {
    rm[i] = b[i] - rm[i]; // (1)
    xm[i] = x0[i];        // (2) does not require (1)
    pm[i] = rm[i];        // (3) requires (1) at this i, not (2)
}  
// implicit barrier at the end of omp for
// implicit join of all threads at the end of omp parallel

scalarProd(rm,rm,numcols);

请注意,我如何表明循环之间实际上并不需要任何障碍。

如果您的大部分时间都花在了此计算阶段,那么您肯定会看到很大的进步。 但是,我有理由相信,您的大部分时间都花在Mat_Vec_Mult() ,也许还scalarProd() ,因此节省的时间可能最少。

** 编辑 **

根据您的编辑,我看到了一些问题。 (1)测试算法性能时,请始终使用-O3进行编译。 (2)您将无法改善耗时.000007秒才能完成的工作; 那几乎是瞬间的。 这可以追溯到我之前说的:尝试在更高级别进行并行化。 CG方法本质上是一种顺序算法,但是肯定有一些研究论文详细介绍了并行CG。 (3)标量积的实现不是最佳的。 确实,我怀疑您对矩阵向量乘积的实现也不是。 我个人将执行以下操作:

double scalarProd(double* vec1, double* vec2, int n) {
    double prod = 0.0;
    int i;

    // omp_set_num_threads(4); this should be done once during initialization somewhere previously in your program
    #pragma omp parallel for private(i) reduction(+:prod)
    for (i = 0; i < n; ++i) {
        prod += vec1[i]*vec2[i];
    }
    return prod;
}

(4)整个库(LAPACK,BLAS等)具有高度优化的矩阵向量,向量向量等操作。 任何线性代数库都必须建立在它们之上。 因此,我建议在开始在此处重新创建转轮并尝试实现自己的车轮之前,请考虑使用这些库之一来进行两项操作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM