我是多线程的新手。我正在尝试设计一个解决稀疏矩阵的程序。在我的代码中,我将Vector Vector点积和Matix矢量积作为子程序多次调用以得出最终解。我试图使用open 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操作系统上的gcc -fopenmp命令进行简单编译。
我目前正在使用大小为n = 5000的矩阵。
由于相同的点产品被多次调用直到达到收敛(大约80k次),因此整体速度大幅下降。
请提出一些改进建议。非常感谢任何帮助!
答案 0 :(得分:0)
老实说,我建议在更高级别进行并行化。我的意思是尽量减少您使用的#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()
,所以你节省的时间可能很少。< / p>
** 编辑 **
根据你的编辑,我看到了一些问题。 (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等)具有高度优化的矩阵矢量,矢量矢量等操作。必须在它们上构建任何线性代数库。因此,在您开始重新创建轮子并尝试实现自己的轮子之前,我建议使用其中一个库来执行您的两个操作。