我遇到了一个问题:LU分解算法的并行版本与序列同时运行:
void lup_od_omp(double* a, int n){
int i,j,k;
for(k = 0; k < n - 1; ++k)
{
#pragma omp parallel for shared(a,n,k) private(i,j)
for(i = k + 1; i < n; i++)
{
a[i*n + k] /= a[k*n + k];
for(j = k + 1; j < n; j++)
{
a[i*n + j] -= a[i*n + k]*a[k*n + j];
}
}
}}
也许我做错了什么?
答案 0 :(得分:3)
由于您只处理两个内核,因此并行化可能会妨碍矢量化器。 SSE2上的矢量化将为您提供每个操作2个双倍的数据带宽,AVX上的4个数据带宽。
双线程有很多同步开销,这可能会减慢你的速度,特别是如果你松散矢量化。同样由于某种原因,除非#pragma omp
被调用以实际使其使用线程,否则omp_set_num_threads
不会启动任何线程。
另一个与向量化有关的事情是,并非所有编译器都理解a[i*n + j]
旨在解决二维数组,所以最好先将它声明为这样。
以下是对我的Xeon运行良好的代码的略微优化:
void lup_od_omp(int n, double (*a)[n]){
int i,k;
for(k = 0; k < n - 1; ++k) {
// for the vectoriser
for(i = k + 1; i < n; i++) {
a[i][k] /= a[k][k];
}
#pragma omp parallel for shared(a,n,k) private(i) schedule(static, 64)
for(i = k + 1; i < n; i++) {
int j;
const double aik = a[i][k]; // some compilers will do this automatically
for(j = k + 1; j < n; j++) {
a[i][j] -= aik * a[k][j];
}
}
}
}
3000x3000 icc -O2
数组的运行时:
Your code sequential: 0:24.61 99% CPU
Your code 8 threads : 0:05.21 753% CPU
My code sequential: 0:18.53 99% CPU
My code 8 threads : 0:05.42 766% CPU
在另一台机器上,我在AVX上测试了它(256位向量,每个操作4个双倍):
My code on AVX sequential : 0:09.45 99% CPU
My code on AVX 8 threads : 0:03.92 766% CPU
正如您所看到的,我对矢量化器进行了一些改进,但对并行部分没有做太多改进。
答案 1 :(得分:1)
您的代码的主要问题是您以错误的方式分解了工作负载。
对于单个LU分解,您将n-1
次调用并行。每次,并行将进行线程fork和join,这会引入很多开销。特别是当k
很大时,内环(for(i){for(j){...}}
)只包含很少的工作。并行它将是非常低效的。
您可以考虑使用适当的聚集方案来减少开销。有关详细信息,请参阅此幻灯片。
http://courses.engr.illinois.edu/cs554/notes/06_lu_8up.pdf
另一方面,您可以使用现有的性能库来获得LU分解的最大性能,例如英特尔MKL