[英]OpenMP matrix multiplication takes more time than expected
我正在編寫一個 OpenMP 程序來將兩個矩陣相乘。 這個想法是每個線程計算每個單元格結果的一部分。 然后,在那之后,我為每個單元格添加這些結果以獲得乘法結果。
問題是,當我使用大型矩陣(512x512 或 1024x1024)時,該程序需要很長時間。 實際上,當我使用 5 個線程使用大小為 1024x1024 的矩陣時,需要 43 秒,而使用 1 個線程則需要 14 秒。
我在想這可能是導致巨大延遲的關鍵部分。
這是代碼:
#include <stdio.h>
#include <stdlib.h>
#include <omp.h>
int ** make_array(int n,int m,int f)
{
int i,j;
int *linear, **arr;
linear = malloc(sizeof(int)*m*n);
arr = malloc(sizeof(int *)*n);
for(i = 0;i<n;++i) arr[i] = &linear[i*m];
if(f == 0)
{
for(i=0;i<n;++i)
for(j=0;j<m;++j) arr[i][j] = 0;
return arr;
}
for(i=0;i<n;++i)
for(j=0;j<m;++j) arr[i][j] = 1+i;
return arr;
}
void printMat(int **mat, int n)
{
int i,j;
for(i = 0; i < n; ++i)
{
for(j = 0; j < n;++j)
{
printf("%d ",mat[i][j]);
}
printf("\n");
}
}
int main (int argc, char *argv[])
{
int n; /// matrix dimension
scanf("%d", &n);
double TIME = 0;
int **a,**b,**c;
a = make_array(n,n,1);
b = make_array(n,n,1);
c = make_array(n,n,0);
int i,j,k;
#pragma omp parallel private(i,j,k) shared(a,b,c,TIME)
{
double start = omp_get_wtime();
int **local;
local = make_array(n,n,0);
for(i = 0; i < n; ++i)
{
for(j = 0; j <n; ++j)
{
local[i][j] = 0;
#pragma omp for schedule(static)
for(k = 0; k < n; ++k)
{
local[i][j]+= a[i][k] * b[k][j];
}
}
}
for(i = 0; i <n;++i)
{
for(j = 0; j < n; ++j)
{
#pragma omp critical
c[i][j] += local[i][j];
}
}
double end = omp_get_wtime();
if(TIME < end - start)
{
#pragma omp critical
TIME = end - start;
}
}
printf("%f \n", TIME);
}
任何幫助將非常感激。
這段代碼有很多問題。
並行化方法效率很低:
對於每個可能的i
和j
,您將一個非常小的工作共享給多個線程。 此外,在並行 for 循環的末尾有一個隱式障礙。 因此,線程之間的通信可能比實際計算花費更多的時間。
臨界區通常很慢(通常使用鎖來實現)。 在這里,您可以用原子操作替換它。
使用 k 個線程,代碼需要 k 次更多 memory 並且很可能是 memory 綁定的(因為緩存和要填充的更多數據,更不用說現在昂貴的額外頁面錯誤)。
因此,您需要重新設計並行化方法。 例如,您可以在基於i
的循環上移動#pragma omp for schedule(static)
。 或者,您可以將矩陣分成塊並在線程之間共享工作。
請使用BLAS庫進行矩陣乘法。 它們比這段代碼優化得多。
以下是一些其他問題的列表:
malloc
但沒有free
的)。TIME
的條件存在競爭條件。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.