I followed Ben's advice and wrote to the Eigen mailing
list. Here's what I got back, with attachment. I'm going
to do some more profiling in a second, but thought I should
send this now as is.
- Bob
==============from Eigen mailing list=======================
Hi,
Your version #3 is not correct, you have to use y.insert(y.begin(),
x.data(), x.data()+x.size()); With gcc I get the exact same same
result for each version. See attached benchmark file. I also observed
that in some cases clang is able to optimize away memcpy when the copy
is actually not necessary. This is the case in the attached file.
gael
On Thu, May 30, 2013 at 4:58 AM, Bob Carpenter <
ca...@alias-i.com> wrote:
> We refactored our application to use Eigen column vectors
> instead of std::vector and observed a fairly significant
> slowdown. Profiling pointed to the copy constructor for
> Eigen vectors, so I'm wondering if there's something we're
> missing. Here's what I tried.
>
> To copy a column vector
>
> Matrix<double,Dynamic,1> x;
>
> there's the obvious copy constructor:
>
> 1. Matrix<double,Dynamic,1> y(x);
>
> or the direct sizing + memcpy approach:
>
> 2. Matrix<double,Dynamic,1> y(x.size());
> std::memcpy(&y(0),&x(0),x.size() * sizeof(double));
>
> By comparison, we can use an iterator based on the
> memory used for x's values to construct a standard
> vector:
>
> 3. std::vector<double> y(&x(0),&x(0) + x.size());
>
> I timed each version by repeatedly calling it, and found
> the times varied pretty widely:
>
> 1. 26s
> 2. 17s
> 3. 14s
>
> For Matrix<double,Dynamic,Dynamic> on the other hand, the
> copy constructor and the memcpy versions took about the same
> time.
>
> Is there a faster way to copy vectors? I'm guessing we'll have
> the same issue if I were to pass in references, resize them and
> then assign (like copy ctor) or memcpy.
>
> This was using clang++ -O3 on a Macbook Pro with i7 CPU and clang
> version:
>
> Apple clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM
> 3.1svn)
> Target: x86_64-apple-darwin12.3.0
>
> - Bob
>
>
ctor.cpp
#include <Eigen/Dense>
#include <vector>
#include <iostream>
#include <bench/BenchTimer.h>
using namespace Eigen;
EIGEN_DONT_INLINE
double* cp1(const VectorXd& A, int i = 0)
{
VectorXd B(A);
return &B(i);
}
EIGEN_DONT_INLINE
double* cp2(const VectorXd& A, int i = 0)
{
VectorXd B(A.size());
std::memcpy(B.data(), A.data(), A.size()*sizeof(double));
return &B(i);
}
EIGEN_DONT_INLINE
double* cp3(const VectorXd& A, int i = 0)
{
std::vector<double> B;
B.insert(B.begin(), A.data(), A.data()+A.size());
return &B[i];
}
int main(int argc, char** argv)
{
using namespace std;
BenchTimer t1,t2,t3;
int tries = 10;
int rep = 1000;
int n = 100000;
VectorXd A(n);
A.setRandom();
BENCH(t1,tries,rep,cp1(A));
BENCH(t2,tries,rep,cp2(A));
BENCH(t3,tries,rep,cp3(A));
cout << t1.best() << " ; " << t2.best() << " ; " << t3.best() << endl;
}