Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eigen aligned memory allocator #414

Merged
merged 10 commits into from
Jun 20, 2015
Merged

Eigen aligned memory allocator #414

merged 10 commits into from
Jun 20, 2015

Conversation

jslee02
Copy link
Member

@jslee02 jslee02 commented Jun 17, 2015

This pull request resolves memory alignment issues with Eigen objects in DART.

Also, some helper types and functions are defined for convenience such as Eigen::aligned_vector and Eigen::make_aligned_shared(). One thing I'm not sure is the namespace and names of them. dart::aligned_vector or dart::aligned::vector are alternatives I can imagine. Any thought on this?

Related issues: #413

@jslee02 jslee02 added this to the Release DART 5.0 milestone Jun 17, 2015
@jturner65
Copy link

i lifted the following from MRPT and put it in the Utils namespace :

/** Helper types for STL containers with Eigen memory allocators - from MRPT. */
     template <class TYPE1, class TYPE2 = TYPE1>
     struct aligned_containers
     {
             typedef std::pair<TYPE1, TYPE2> pair_t;
             typedef std::vector<TYPE1, Eigen::aligned_allocator<TYPE1> > vector_t;
             typedef std::deque<TYPE1, Eigen::aligned_allocator<TYPE1> > deque_t;
             typedef std::list<TYPE1, Eigen::aligned_allocator<TYPE1> > list_t;
             typedef std::map<TYPE1, TYPE2, std::less<TYPE1>, Eigen::aligned_allocator<std::pair<const TYPE1, TYPE2> > > map_t;
             typedef std::multimap<TYPE1, TYPE2, std::less<TYPE1>, Eigen::aligned_allocator<std::pair<const TYPE1, TYPE2> > > multimap_t;
     };

and then map declarations go from something like this :
typedef std::map<std::string, SkelBodyNode> BodyMap;

to this :
typedef dart::utils::aligned_containers<std::string, SkelBodyNode>::map_t BodyMap;

and this seemed to work nicely.

Edit: this also serves as a 1-stop solution for allocators for any stl containers.

@jturner65
Copy link

also, don't forget the following :
#include<Eigen/StdVector>
for the helper function for stl vectors of Eigen constructs.

Eigen::aligned_allocator<std::pair<const _Key, _Tp>>>;

template<typename _Tp, typename... _Args>
inline std::shared_ptr<_Tp> make_aligned_shared()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not clear on what the purpose of this overload is. Normally with variadic templates, an argument-free overload is used to terminate the template recursion, but we're not actually using template recursion in this case.

Also, this version is using regular std::make_shared instead of std::allocate_shared, which seems to defeat the entire purpose, doesn't it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's not for template recursion.

I found that make_aligned_shared(...) doesn't work for WeldJoint::Property; there was compiler error as:

/usr/include/eigen3/Eigen/src/Core/util/Memory.h:731: error: call to implicitly-deleted copy constructor of 'std::_Sp_counted_ptr_inplace<dart::dynamics::WeldJoint::Properties, Eigen::aligned_allocator<dart::dynamics::WeldJoint::Properties>, __gnu_cxx::_Lock_policy::_S_atomic>'
        ::new( p ) T( value );
                   ^  ~~~~~

I put this argument-free overloaded function to make make_aligned_shared(...) looks like working with WeldJoint::Property temporally. Once the solution is found, this function should be removed.

It seems this error is present on gcc but not on clang. I've tried to figure out the reason of errors but couldn't find yet. Could you take a look at this problem?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not getting that issue on GCC with 64-bit Ubuntu 14.04. Was there a particular platform it was happening on with GCC? I've tried constructing it in a variety of ways with a variety of different arguments for WeldJoint::Properties, but it's not triggering a compilation error for me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And is it only WeldJoint?

One thing we could try is adding WeldJoint(const WeldJoint& _other) = default; to the definition of WeldJoint. If it's really nothing more than an implicitly deleted copy constructor, then that should do the trick.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I see. The implicitly deleted copy constructor belongs to the templated class inside of <Eigen/.../util/Memory.h>, not to WeldJoint::Properties. It seems really strange that this is happening specifically for WeldJoint::Properties. I'm thinking this must be an internal compiler error.

What happens when we make the no-argument version of Eigen::make_aligned_shared() use std::allocate_shared<_Tp>( Eigen::aligned_allocator<_Tp>() )? Does the same error happen? I'm kind of concerned that using regular make_shared defeats the point of having the Eigen::make_aligned_shared() function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when we make the no-argument version of Eigen::make_aligned_shared() use std::allocate_shared<_Tp>( Eigen::aligned_allocator<_Tp>() )? Does the same error happen?

Yes. It seems the variadic template function generates exactly same function with no-argument version of Eigen::make_aligned_shared() when there is no argument, which should do.

I tracked down the history of Eigen's aligned_allocator since the error is caused in it. I found that the Eigen::aligned_allocator is not compatible with C++11 yet. Here are the related issues: [1], [2].

There was an intermediate patch for this in Eigen 3.1.0 but removed in Eigen 3.2.1, and the new patch is applied to the default branch but not to any released version yet. Ubuntu 14.04 is fine since it has Eigen 3.1.0. But Ubuntu 14.10 and 15.04 causes compilation error since they have Eigen 3.2.1 and Eigen 3.2.2, respectively.

I copied new aligned_allocator from Eigen's default branch and made DART to use it if the installed Eigen is greater than 3.2.1. This should be removed once the new aligned_allocator is released.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahhhh, well that explains a lot of things. I should have known better than to think it was internal compiler error; I'm just getting too accustomed to compilers having bizarre bugs or incompatibility related to C++11.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, I thought that too. So I double checked it with clang on linux and mac because clang seems more compatible than others to me. Once I observed that clang also complains similarly, I started to investigate on Eigen.

Beside on the compilation issue, I confirmed that the memory alignment issue is also resolved on Ubuntu 32-bit 15.04. So I believe this PR is ready to merge.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me 👍

@mxgrey
Copy link
Member

mxgrey commented Jun 18, 2015

I've added the alignment macro in a couple more places that it happened to be needed and changed a couple more STL containers to their aligned versions.

I also added a copy constructor for MultiDofJoint::UniqueProperties, because it turns out that VS2013 doesn't properly support copy construction for std::array yet. It's not related to the Eigen alignment issue, but it is related to the incomplete C++11 support in Visual Studio (and it seemed a bit too small for its own pull request).

jslee02 added a commit that referenced this pull request Jun 20, 2015
@jslee02 jslee02 merged commit 2d316e9 into release-5.0 Jun 20, 2015
jslee02 added a commit that referenced this pull request Jun 20, 2015
@jslee02 jslee02 deleted the eigen_aligned_allocator branch June 21, 2015 02:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants