pBook‎ > ‎Matrix C++ Lib‎ > ‎

Runtime alignment error

posted Sep 17, 2015, 2:26 AM by Javad Taghia

http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html


The solution is to let class Foo have an aligned "operator new", as we showed in the previous section.

Should I then put all the members of Eigen types at the beginning of my class?

That's not required. Since Eigen takes care of declaring 128-bit alignment, all members that need it are automatically 128-bit aligned relatively to the class. So code like this works fine:

class Foo
{
double x;
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};

What about dynamic-size matrices and vectors?

Dynamic-size matrices and vectors, such as Eigen::VectorXd, allocate dynamically their own array of coefficients, so they take care of requiring absolute alignment automatically. So they don't cause this issue. The issue discussed here is only with fixed-size vectorizable matrices and vectors.

So is this a bug in Eigen?

No, it's not our bug. It's more like an inherent problem of the C++98 language specification, and seems to be taken care of in the upcoming language revision: see this document.

What if I want to do this conditionnally (depending on template parameters) ?

For this situation, we offer the macro EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign). It will generate aligned operators like EIGEN_MAKE_ALIGNED_OPERATOR_NEW if NeedsToAlign is true. It will generate operators with the default alignment if NeedsToAlign is false.

Example:

template<int n> class Foo
{
typedef Eigen::Matrix<float,n,1> Vector;
enum { NeedsToAlign = (sizeof(Vector)%16)==0 };
...
Vector v;
...
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF(NeedsToAlign)
};
...
Foo<4> *foo4 = new Foo<4>; // foo4 is guaranteed to be 128bit-aligned
Foo<3> *foo3 = new Foo<3>; // foo3 has only the system default alignment guarantee

Other solutions

In case putting the EIGEN_MAKE_ALIGNED_OPERATOR_NEW macro everywhere is too intrusive, there exists at least two other solutions.

Disabling alignment

The first is to disable alignment requirement for the fixed size members:

This has for effect to disable vectorization when using v. If a function of Foo uses it several times, then it still possible to re-enable vectorization by copying it into an aligned temporary vector:

void Foo::bar()
{
// use av instead of v
...
// if av changed, then do:
v = av;
}

Private structure

The second consist in storing the fixed-size objects into a private struct which will be dynamically allocated at the construction time of the main object:

struct Foo_d
{
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
...
};
struct Foo {
Foo() { init_d(); }
~Foo() { delete d; }
void bar()
{
// use d->v instead of v
...
}
private:
void init_d() { d = new Foo_d; }
Foo_d* d;
};

The clear advantage here is that the class Foo remains unchanged regarding alignment issues. The drawback is that a heap allocation will be required whatsoever.



Passing objects by value is almost always a very bad idea in C++, as this means useless copies, and one should pass them by reference instead.

With Eigen, this is even more important: passing fixed-size vectorizable Eigen objects by value is not only inefficient, it can be illegal or make your program crash! And the reason is that these Eigen objects have alignment modifiers that aren't respected when they are passed by value.

So for example, a function like this, where v is passed by value:

void my_function(Eigen::Vector2d v);

needs to be rewritten as follows, passing v by reference:

void my_function(const Eigen::Vector2d& v);

Likewise if you have a class having a Eigen object as member:

struct Foo
{
};
void my_function(Foo v);

This function also needs to be rewritten like this:

void my_function(const Foo& v);

Note that on the other hand, there is no problem with functions that return objects by value.

Comments