Eigen fixed-size matrices in shared memory using boost interprocess
Asked Answered
A

1

0

I like to place Eigen fixed-size matrices into the shared memory. But on execution I am getting the following error:

 /usr/include/eigen3/Eigen/src/Core/DenseStorage.h:78:
 Eigen::internal::plain_array<T, Size, MatrixOrArrayOptions, 16>::plain_array() 
 [with T = double; int Size = 2; int MatrixOrArrayOptions = 0]: 
 Assertion `(reinterpret_cast<size_t>(eigen_unaligned_array_assert_workaround_gcc47(array)) & 0xf) == 0 && 
 "this assertion is explained here: " 
 "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" 
 " **** READ THIS WEB PAGE !!! ****"' failed.
 Aborted (core dumped)

Using the Eigen define EIGEN_DONT_ALIGN using cmake with add_definitions(-DEIGEN_DONT_ALIGN) fixes my problem but I like to know what problem rises and what are the downsides.

There is my example:

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/algorithm/string.hpp>
#include <Eigen/Dense>

using namespace boost::interprocess;
using namespace boost::container;

typedef managed_shared_memory::segment_manager                         segment_manager_t;
typedef scoped_allocator_adaptor<allocator<void, segment_manager_t> >  void_allocator;
typedef void_allocator::rebind<Eigen::Matrix<double,2,1>>::other       eigen_allocator;
typedef vector<Eigen::Matrix<double,2,1>, eigen_allocator>             eigen_vector;


class CheckPoints {
public:
    bool valid;
    eigen_vector points;

    typedef void_allocator allocator_type;

    //Since void_allocator is convertible to any other allocator<T>, we can simplify
    //the initialization taking just one allocator for all inner containers.
    CheckPoints ( const allocator_type &void_alloc )
        :  valid ( true ), points ( void_alloc ) {}

    CheckPoints ( CheckPoints const& other, const allocator_type &void_alloc )
        :  valid ( other.valid ), points ( other.points, void_alloc ) {}

    friend std::ostream &operator << ( std::ostream &os, const CheckPoints &o ) {
        os << o.valid;
        for ( size_t i = 0; i < o.points.size(); i++ )
            os << ", <" << o.points[i] ( 0,0 ) << ", " << o.points[i] ( 1,0 ) << ">";
        return os;
    }
};

typedef void_allocator::rebind<CheckPoints>::other    checkpoints_allocator;
typedef vector<CheckPoints, checkpoints_allocator>    checkpoints_vector;

class Trajectories {
public:
    Trajectories ( const void_allocator &void_alloc )
        : trajectory ( void_alloc )
    {}
    Eigen::Matrix<double,2,1> base;
    checkpoints_vector trajectory;

    friend std::ostream &operator << ( std::ostream &os, const Trajectories &o ) {
        os << "base: " << o.base << std::endl;
        for ( size_t i = 0; i < o.trajectory.size(); i++ ) os << o.trajectory[i]  << std::endl;
        return os;
    }
};


int main ( int argc, char **argv ) {

    using namespace boost::interprocess;
    //Remove shared memory on if called with c or clear
    if ( argc > 1 && (boost::iequals ( "clear", argv[1] ) || boost::iequals ( "c", argv[1] ) ) ) {
        std::cout << "Remove shared memory" << std::endl;
        shared_memory_object::remove ( "MySharedMemory" );
    }

    //Create shared memory
    managed_shared_memory segment ( open_or_create,"MySharedMemory", 16*1024*1024 );

    //An allocator convertible to any allocator<T, segment_manager_t> type
    void_allocator alloc_inst ( segment.get_segment_manager() );

    Trajectories *trajectories = segment.find_or_construct<Trajectories> ( "Trajectories" ) ( alloc_inst );
    if ( trajectories->trajectory.size() != 10 ) {
        std::cout << "Create Data" << std::endl;
        trajectories->trajectory.resize ( 10 );
        for ( size_t i = 0; i < trajectories->trajectory.size(); i++ ) {
            trajectories->trajectory[i].points.resize ( i+1 );
            for ( size_t j = 0; j < trajectories->trajectory[i].points.size(); j++ ) {
                trajectories->trajectory[i].points[j] ( 0,0 ) = j*2;
                trajectories->trajectory[i].points[j] ( 1,0 ) = j*2+1;
            }
        }
    } else {
        std::cout << "Data Exists" << std::endl;
    }
    std::cout << *trajectories << std::endl;
}
Australoid answered 21/1, 2015 at 11:36 Comment(0)
P
0

As explained when following the link provided in the error message, you have to use a memory aligned allocator for eigen_vector, for instance the one provided by Eigen: Eigen::aligned_allocator.

Working around this issue by disabling alignment with EIGEN_DONT_ALIGN also disable Eigen's explicit vectorization. Actually it is enough to disable static alignment only with EIGEN_DONT_ALIGN_STATICALLY in which case you loose vectorization for small fixed size matrices only. A third and even better option would be to use a non aligned type:

typedef vector<Eigen::Matrix<double,2,1,Eigen::DontAlign>, eigen_allocator>             eigen_vector;

in which case you loose vectorization for these objects only.

Putnam answered 21/1, 2015 at 15:59 Comment(2)
Thanks, but does anyone know if the boost::interprocess::allocator is good enough? I like to know if I will have troubles with my approach in the future?Australoid
My edit should answer your concerns though everything is already explained in the link I pasted before.Putnam

© 2022 - 2024 — McMap. All rights reserved.