2016-11-16 13 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