10

Recently, I was made aware of the potential issues of memory alignment for Fixed-size vectorizable Eigen objects.

The correct code as stated in the doc:

class Foo
{
  ...
  Eigen::Vector2d v;
  ...
public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
};
 
...
 
Foo *foo = new Foo;

I would like to know if this code is ok or not?

class Foo2
{
  ...
  Foo foo;
  ...
};
 
...
 
Foo2 *foo = new Foo2; //?

Or should EIGEN_MAKE_ALIGNED_OPERATOR_NEW be again added in the Foo2 class? This is what is suggested here I think:

If we were to add EIGEN_MAKE_ALIGNED_OPERATOR_NEW this would only solve the problem for the Cartographer library itself. Users of the library would also have to add EIGEN_MAKE_ALIGNED_OPERATOR_NEW to classes containing vectorized Cartographer classes. This sounds like a maintenance nightmare.

I have no experience with new operator overloading. I think the question is more general and would somehow be related to how new operator works in C++. For instance is the overloaded new operator in Foo be called by the default new operator in Foo2? What about inheritance? If Foo2 inherits from Foo, should we put also EIGEN_MAKE_ALIGNED_OPERATOR_NEW in Foo2?


Since I was only aware of this topic recently, I did many research and found the following:

  • default alignment on x86-64 is 16 bytes, so it is fine to not have EIGEN_MAKE_ALIGNED_OPERATOR_NEW (if only SSE is enabled)
  • unless your code is compiled for more recent SIMD sets (e.g. AVX2 with -march=native to have all the optimizations on a local computer), EIGEN_MAKE_ALIGNED_OPERATOR_NEW is now needed
  • what about the other architecture? For instance for ARM, any issue if we don't declare EIGEN_MAKE_ALIGNED_OPERATOR_NEW and NEON is enabled?
  • I found suggestion to use template <typename Scalar> using Isometry3 = Eigen::Transform<Scalar, 3, Eigen::Isometry | Eigen::DontAlign> instead of Isometry
  • still need to think on how to be able to easily use Eigen type (e.g. Isometry3d) in the code without the alignment issue. So add a new type MyIsometry3d that inherits from Eigen::Transform<double, 3, Eigen::Isometry | Eigen::DontAlign> for instance?

More generally, I would like to "disable alignment" (or vectorization) in fixed-size Eigen type:

  • I would like to keep the syntax, for instance keeping Isometry3d in the code
  • and not be bothered with alignment issue when using Isometry3d in a class or when using std::vector<Isometry3d>
  • something to tell Eigen to always use unaligned load/store (e.g. _loadu_/_storeu_ for x86-64 intrinsics, what about the other architecture, is there an equivalent?) for all fixed-size Eigen type?
  • else just disable vectorization for fixed-size Eigen type since I believe penalty should be (almost) null between using vectorized instructions and just C++ code for these types
  • so I guess the solution is to use #define EIGEN_UNALIGNED_VECTORIZE 0, is it correct? So I have to put this #define everywhere before any Eigen/Dense include?
  • I don't want to replace everywhere with something like Matrix<double,2,2,DontAlign> or a new class

Finally, looking at Fixed-size vectorizable Eigen objects page, I think some types are missing. For the types I am using:

  • Eigen::Isometry3d, Eigen::Isometry3f?
  • Eigen::AngleAxisd, Eigen::AngleAxisf?
Catree
  • 2,477
  • 1
  • 17
  • 24
  • 1
    Was there ever an answer to this? i've been wondering this myself, having read statements that all classes having such objects as members also need to use the macro. – oarfish Oct 30 '20 at 10:28
  • I've not used Eigen library but I understood a part of your question. I would like to share few things which may help you. **1.** Alignment is important only for performance reasons because later if needed the entire Matrix or parts (ros/columns) of it can be transferred to the machine (CPU/GPU). **2.** In C++ there is a way to align classes same was as another type (class/struct/type) [alignas( type-id )](https://en.cppreference.com/w/cpp/language/alignas) **3.** Alignment is machine dependent but compiler takes care of that and EIGEN_MAKE_ALIGNED_OPERATOR_NEW must be compiler dependent. – Ashutosh Raghuwanshi Nov 09 '20 at 07:09
  • @AshutoshRaghuwanshi Thanks for your comment. For 1. yes alignment requirement matters for performance reason. Actually, for small vector size I believe there should be no noticeable perf diff between loading vector with aligned instruction (`_mm_load`) and without (`_mm_loadu`). Proper solution seems to be to use the C++17 operator new alignment, see: https://eigen.tuxfamily.org/bz/show_bug.cgi?id=1409 Until then, I would like to know if `EIGEN_MAKE_ALIGNED_OPERATOR_NEW` is required only for the class that contains fixed-size Eigen vectors, or as mentioned for all "transitive" classes. – Catree Nov 11 '20 at 11:44
  • @Catree again I am not sure this will help or not but during my research I came across this **EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE_FIXED_SIZE()** at this page - http://eigen.tuxfamily.org/dox-3.2/classEigen_1_1Transform.html#ade92d05728a0223cdbf7096a400d0fdd – Ashutosh Raghuwanshi Nov 11 '20 at 12:27
  • "Alignment is important only for performance reasons" is false. Your code may crash when mixing alignments between translation units or libraries. If you link against libs built with certain alignment, you can't just ignore it. – oarfish May 03 '23 at 10:20

1 Answers1

2

I asked this on the Eigen mailing list, and one maintainer said that the need for this macro is indeed transitive. Foo2 thus will need the macro as well.

oarfish
  • 4,116
  • 4
  • 37
  • 66