Eigen vs Matlab:并行化矩阵乘法

时间:2015-02-02 19:12:32

标签: c++ matlab c++11 eigen

我想比较矩阵乘法中 Matlab 的速度与Intel(R)Core(TM)i7-4770 CPU上 Eigen 3 的速度3.40GHz。代码包括 Eigen

#include <iostream>
#include "Eigen/Dense"
#include <chrono>
#include <omp.h>


using namespace std;
using namespace Eigen;

const int dim=100;

int main()
{
    std::chrono::time_point<std::chrono::system_clock> start, end;

    int n;
    n = Eigen::nbThreads();
    cout<<n<<"\n";

    Matrix<double, Dynamic, Dynamic> m1(dim,dim);
    Matrix<double, Dynamic, Dynamic> m2(dim,dim);
    Matrix<double, Dynamic, Dynamic> m_res(dim,dim);

    start = std::chrono::system_clock::now();

    for (int i = 0 ; i <100000; ++i) {
        m1.setRandom(dim,dim);
        m2.setRandom(dim,dim);
        m_res=m1*m2;

    }

    end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end-start;

    std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";

    return 0;
}

使用g++ -O3 -std=c++11 -fopenmp进行编译,并使用OMP_NUM_THREADS=8 ./prog执行。 在Matlab中我使用

function mat_test(N,dim)
%
% N:    how many tests
% dim:  dimension of the matrices

tic
parfor i=1:N
     A = rand(dim);
     B = rand(dim);
     C = A*B;
end
toc

结果是: Matlab 为9s, Eigen 为36s。我在 Eigen 案例中做错了什么?我可以排除矩阵的动态分配。此外,仅使用3个线程而不是8个。

修改

也许我没有足够清楚地说明:任务是乘以10000倍dim = 100的双值矩阵,每次随机填充,而不是一次。使用Eigen尽可能快地完成。如果Eigen不能应付Matlab,你会建议什么选择?

2 个答案:

答案 0 :(得分:6)

下面是一个更好的代码版本,可以合理地使用Eigen。总结一下:

  • setRandom()移到基准测试循环之外。 setRandom()调用系统rand()函数,这个函数速度很慢。
  • 使用.noalias()来避免创建临时(仅当右侧是产品时才有意义)
  • 将OMP_NUM_THREADS设置为真正的内核数,而不是超线程数。 (在你的情况下为4)
  • 您的CPU支持仅由Eigen的devel分支支持的AVX和FMA(将变为3.3),因此请使用devel分支并使用-mavx-mfma编译器选项启用它们(关于仅与SSE相比,x3.5加速)

代码:

#include <iostream>
#include "Eigen/Dense"
#include <chrono>

using namespace std;
using namespace Eigen;

const int dim=100;

int main()
{
    std::chrono::time_point<std::chrono::system_clock> start, end;

    int n;
    n = Eigen::nbThreads();
    cout << n << "\n";

    Matrix<double, Dynamic, Dynamic> m1(dim,dim);
    Matrix<double, Dynamic, Dynamic> m2(dim,dim);
    Matrix<double, Dynamic, Dynamic> m_res(dim,dim);

    start = std::chrono::system_clock::now();

    m1.setRandom();
    m2.setRandom();

    for (int i = 0 ; i <100000; ++i) {
      m_res.noalias() = m1 * m2;
    }

    end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end-start;

    std::cout << "elapsed time: " << elapsed_seconds.count() << "s\n";

    return 0;
}

答案 1 :(得分:1)

除了在循环之外移动随机化(在Eigen和Matlab中),正如ggael建议的那样,在Matlab中用parfor替换for,因为在本征代码中,您按顺序处理矩阵。

我不确定Matlab如何并行化其代码:也许多个线程在同一对矩阵上工作,并在完成时切换到下一个矩阵;也许每个线程处理它自己的一对矩阵。可以说后者可能更快,因为更好地使用核心特定的缓存。