矩阵的乘法。性能

时间:2012-03-20 12:25:55

标签: c++ performance

我有一个方形矩阵乘法程序。它还,我认为程序的性能由公式(运算次数)/(运行时间)决定。为什么矩阵的增长维度会降低性能?感谢。

#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;

}

4 个答案:

答案 0 :(得分:9)

我想你在问为什么每秒浮点运算的平均数(FLOPS)会随着矩阵大小的增加而减少。

答案是:缓存。您正在使用的“天真”矩阵乘法方法对于缓存性能来说非常糟糕;随着矩阵的增长,你将增加缓存未命中数。

如果您决定自己编写(而不是使用现有的线性代数库),则应调查“阻塞”,也称为“循环平铺”。参见例如http://en.wikipedia.org/wiki/Loop_tiling。基本思想是将操作分解为与缓存大小相对应的较小块。

答案 1 :(得分:3)

我认为这更多是缓存一致性问题 - 您选择用于存储的格式不是连续的,具有非恒定的步幅和两个间接级别。选择fortran / BLAS兼容的布局,然后链接到工业级BLAS / GEMM实现(ACML,ATLAS),您应该看到相反的结果:更大的问题具有更高的持续翻牌率。

乘法矩阵是一个经过充分研究的问题,并且有很好的库选项。

答案 2 :(得分:1)

我不明白你的观点:

  • 如果n更大,那么您的最后一个循环(使用ijk)具有n * n * n复杂度。
  • 但您之前的循环(使用ij)也会增加n*n的复杂性

然后qty_of_operation不是你所假设的。然后你的表现会下降。此外,使用更大的内存块可能会受到一些惩罚。

此外,您获得的是“真实”时间,而不是“cpu”时间,这是不同的,特别是在运行多个进程时...在Unix中,只需在启动代码之前使用time命令

答案 3 :(得分:0)

随着矩阵大小的增加,CPU需要做更多的工作(浮点计算),这会线性增加时间(到元素的数量 - 而不是行或列)。

你还有更多的内存来遍历这意味着你在浏览内存时会得到更多的缓存未命中因此每条指令的周期数会增加。

最后你应该看看像升级ublas这样的库,当你需要它的时候,你正在努力做到这一点。

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

编辑:你也在迭代数组三次,所以任何增加都会被放大。