2016-11-16 134 views
1

我使用Eigen进行类似于Cholesky更新的操作,这意味着在固定大小矩阵(通常是Matrix4d)的列上存在大量AXPY(总和加上标量乘)。简而言之,它是3倍更昂贵的访问的矩阵4的列比到Vector 4.Eigen:对矩阵的列访问速度很慢4

典型地,下面的代码:

for(int i=0;i<4;++i) L.col(0) += x*y[i]; 

比下面的代码少3倍高效:

for(int i=0;i<4;++i) l4 += x*y[i]; 

,其中L是典型的大小为4,X,Y的一个矩阵和L4 4.

此外大小的矢量,在第一行代码所花费的时间不依赖于米atrix存储组织(ColMajor的RowMajor)。

在Intel i7(2.5GHz)上,向量操作大约需要0.007us,矩阵操作需要0.02us(通过重复100000次同样的操作完成定时)。我的应用程序需要数千次这样的操作,希望远低于毫秒。

问题:在访问我的4x4矩阵的列时,我做了一些不正确的事情?有什么需要做的,使第一行代码更有效率?用于定时

完整代码如下:

#include <iostream> 
#include <Eigen/Core> 
#include <vector> 
#include <sys/time.h> 

typedef Eigen::Matrix<double,4,1,Eigen::ColMajor> Vector4; 
//typedef Eigen::Matrix<double,4,4,Eigen::RowMajor,4,4> Matrix4; 
typedef Eigen::Matrix<double,4,4,Eigen::ColMajor,4,4> Matrix4; 

inline double operator- ( const struct timeval & t1,const struct timeval & t0) 
{ 
    /* TODO: double check the double conversion from long (on 64x). */ 
    return double(t1.tv_sec - t0.tv_sec)+1e-6*double(t1.tv_usec - t0.tv_usec); 
} 

void sumCols(Matrix4 & L, 
       Vector4 & x4, 
       Vector4 & y) 
{ 
    for(int i=0;i<4;++i) 
    { 
     L.col(0) += x4*y[i]; 
    } 
} 

void sumVec(Vector4 & L, 
      Vector4 & x4, 
      Vector4 & y) 
{ 
    for(int i=0;i<4;++i) 
    { 
     //L.tail(4-i) += x4.tail(4-i)*y[i]; 
     L   += x4   *y[i]; 
    } 
} 

int main() 
{ 
    using namespace Eigen; 

    const int NBT = 1000000; 

    struct timeval t0,t1; 

    std::vector<  Vector4> x4s(NBT); 
    std::vector<  Vector4> y4s(NBT); 
    std::vector<  Vector4> z4s(NBT); 
    std::vector<  Matrix4> L4s(NBT); 

    for(int i=0;i<NBT;++i) 
    { 
    x4s[i] = Vector4::Random(); 
    y4s[i] = Vector4::Random(); 
    L4s[i] = Matrix4::Random(); 
    } 

    int sample = int(z4s[55][2]/10*NBT); 
    std::cout << "*** SAMPLE = " << sample << std::endl; 

    gettimeofday(&t0,NULL); 
    for(int i=0;i<NBT;++i) 
    { 
     sumCols(L4s[i], x4s[i], y4s[i]); 
    } 
    gettimeofday(&t1,NULL); 
    std::cout << (t1-t0) << std::endl; 
    std::cout << "\t\t\t\t\t\t\tForce check" << L4s[sample](1,0) << std::endl; 

    gettimeofday(&t0,NULL); 
    for(int i=0;i<NBT;++i) 
    { 
     sumVec(z4s[i], x4s[i], y4s[i]); 
    } 
    gettimeofday(&t1,NULL); 
    std::cout << (t1-t0) << std::endl; 
    std::cout << "\t\t\t\t\t\t\tForce check" << z4s[sample][2] << std::endl; 

    return -1; 
} 
+0

你是如何编译的? – Joel

+0

g ++ -O3 -I/usr/include/eigen3。我在Linux 14.04上,3.2.0 Eigen和4.8.4 gcc。我也在同一台电脑上获得类似的结果与铛。 – NMsd

+0

我无法复制。生成的ASM对于每个版本都完全相同。你可以用'g ++ -O3 -DNDEBUG -s'自己检查并在生成的asm文件中搜索'sumCols'和'sumVec'。 – ggael

回答

1

正如我在评论说,所产生的组件用于两个功能完全相同。

问题在于,您的基准测试存在偏见,因为L4sz4s大4倍,因此您在矩阵情况下比在向量情况下获得更多缓存未命中。

+0

确实。我现在改变了工作台以避免矩阵L的缓存(即,只有一个L和NBT向量y全部应用于唯一的L)。差异消失。感谢您花时间看看它,并抱歉这是一个错误的问题。 – NMsd