2012-03-20 124 views
1

我有一個方案矩陣乘法。另外,我認爲該程序的性能按公式(操作次數)/(運行時間)計算。爲什麼矩陣的增長維度會降低性能?謝謝。矩陣的乘法。性能

#include <stdio.h> 
#include <stdlib.h> 
#include <iostream> 
#include <sys/time.h> 
using namespace std; 

double getsec(){ 
    struct timeval t; 
    gettimeofday(&t,NULL); 
    return t.tv_sec+t.tv_usec*0.000001; 
} 

int main(int argc, char* argv[]) 
{ 
double begintime=getsec(); 

int n; 
if(argc==2)n=atoi(argv[1]); 
else n=3; 

int**a=new int*[n]; 
double**b=new double*[n]; 
double**c=new double*[n]; 
for (int i=0;i<n;i++){ 
    a[i]=new int [n]; 
    b[i]=new double [n]; 
    c[i]=new double [n]; 
} 

for (int i=0;i<n;i++) 
    for(int j=0;j<n;j++){ 
     a[i][j]=i+1; 
     b[i][j]=1/(j+1.); 
     c[i][j]=0; 
    } 

for (int i=0;i<n;i++) 
    for(int j=0;j<n;j++) 
     for(int k=0;k<n;k++) 
     c[i][j]+=a[i][k]*b[k][j]; 

double qty_of_operations = (double)2*n*n*n; 

cout<<n<<" c11="<<c[0][0]<<" c1n="<<c[0][n-1]<<" cn1="<<c[n-1][0]<<" cnn="<<c[n-1][n-1]<<" "<<qty_of_operations/(getsec()-begintime)<<endl; 
return 0; 

}

+2

我不明白你的問題。你問爲什麼隨着矩陣大小的增加運行時間增加了? – 2012-03-20 12:27:53

+0

不,我的意思是,爲什麼表現下降。 (in flops) – 2012-03-20 12:30:22

+0

爲什麼標記爲C++?目前有C代碼和一個「cout」。按照111111的建議查看Boost.uBLAS。 – 2012-03-20 12:33:26

回答

9

我想你是問爲什麼平均每秒浮點運算次數(FLOPS)隨着矩陣大小的增加而下降。

答案是:緩存。您正在使用的矩陣乘法的「幼稚」方法對高速緩存性能而言非常糟糕;隨着矩陣的增長,您將會增加緩存未命中的數量。

如果您決定自己寫(而不是使用現存的線性代數庫),您應該研究「阻塞」,也稱爲「循環平鋪」。見例如http://en.wikipedia.org/wiki/Loop_tiling。基本思想是將操作分解爲與緩存大小相對應的較小塊。

+0

+1用於緩存問題。 – ALOToverflow 2012-03-20 12:40:29

+0

本文將討論CPU緩存對矩陣乘法的影響。本文使用矩陣乘法作爲示例,並展示了基本算法的一些修改以獲得一些速度改進。 O(N^3)http://lwn.net/Articles/255364/ – JoeD 2012-03-20 16:17:58

0

由於矩陣規模的增大則有更多的工作(浮點Calcs(計算))爲CPU做的,即線性增加的時間(以元素數目號碼 - 未行或COLS )。

您還有更多的內存可以遍歷,這意味着您在遍歷內存時獲得更多的緩存未命中,以便每條指令的週期數增加。

最後,你應該看看像ublas助推器這樣的圖書館,當你需要它的時候,你會這麼做。

http://www.boost.org/doc/libs/1_49_0/libs/numeric/ublas/doc/index.htm

編輯:你也迭代雖然陣3次,任何增加被放大。

+0

實際上它是O(n * n * n)而不是O(3n)。 – dbrank0 2012-03-20 12:36:07

+0

以下是測量結果: 20個元素1.28287e +08個觸發器 500個項目爲1.54018e +08個觸發器 爲2.20877e +06個觸發器的2800個項目 – 2012-03-20 12:36:26

+0

聽起來是正確的。 @dbrank我沒有說O(3n)我寫得非常糟糕,我的意思是增加了三次。 – 111111 2012-03-20 12:38:54

3

我認爲這更多的是緩存一致性問題 - 您選擇用於存儲的格式不是連續的,有非恆定的跨度和兩個間接層次。選擇Fortran/BLAS兼容佈局,然後鏈接工業強度的BLAS/GEMM實現(ACML,ATLAS),您應該看到相反的結果:較大的問題具有較高的持續觸發率。

乘法矩陣是一個深入研究的問題,並且有很好的庫選項。

1

我不明白你的意思:

  • 如果n越大,那麼你有你的最後一個循環(使用ijk),具有n * n * n複雜性。
  • 但是你以前的循環(與ij)也加n*n

複雜那麼qty_of_operation是不是你認爲什麼。然後你的表現就會下降。另外,使用更大的內存塊可能會有一些處罰。另外,你會得到「真實」的時間,而不是「cpu」時間,這是不同的,特別是當有多個進程正在運行時......在Unix中,在啓動代碼之前,只需使用time命令即可。