martin
martin

Reputation: 100

C++ serialization of static array of struct using Cereal

I am using Cereal library for serialization of structured data, to send them over MPI and later on process them on GPU using CUDA. Due to the latter, I cannot use std::vector, because CUDA has problems with dynamic objects. Therefore I am using static arrays of structures.


GOAL

To do binary serialization & deserialization on objects with nested static array of objects.


OBJECTS TO BE SERIALIZED

//==========================================================//
//                  ELEMENT DEFINITION                      //
//==========================================================//
class element{
public:
    //==========================//
    //          CONTENT         //
    //==========================//
    int grid_id;
    int NN_id;
    int debug;

    //==========================//
    //      SERIALIZATION       //
    //==========================//
    // function required by cereal library
    template<class Archive>
    void serialize(Archive & ar){
        ar( grid_id );
        ar( NN_id );
        ar( debug );
    }
};

//==========================================================//
//                      CONTAINER DEFINITION                //
//==========================================================//
class GPU_in_grid : public Managed{
public:
    //==========================//
    //          CONTENT         //
    //==========================//
    int gpu_id;
    element element[GRID_SIZE];        <------ static array of structures
    int debug;


    //==========================//
    //      SERIALIZATION       //
    //==========================//
    template<class Archive>
    void serialize(Archive & ar){
        ar( gpu_id );
        ar( debug );
        ar( element );

    }
};

SERIALIZATION FUNCTIONS

// cereal serialization
#include <cereal/archives/binary.hpp>
#include <cereal/archives/portable_binary.hpp>
//#include <cereal/archives/xml.hpp>

template<typename data_type>
int Process::serialize(data_type * data, char *serial_data, int *size){
    // serialize the data
    std::ostringstream oss(std::ios::binary);
    cereal::BinaryOutputArchive ar(oss);
    //cereal::XMLOutputArchive ar(std::cout);
    ar(*data);
    std::string s=oss.str();
    *size = s.length();
    strncpy(serial_data, s.c_str(), s.length());
    std::cout << "buffer["<< s.length() << "] >> " << s << std::endl;
    s.clear();
    return _SUCCESS_;
};

template<typename data_type>
int Process::deserialize(data_type * data, char *serial_data, int size){
    // create temporary buffer to store the received data
    char * buf=new char[size];
    strncpy(buf, serial_data, size);
    std::istringstream iss(std::string(serial_data, size), std::ios::binary);
    cereal::BinaryInputArchive arin(iss);
    arin(*data);
    // clean buffer
    delete[] buf;
    return _SUCCESS_;
};

DEBUGGING OUTPUT

cpu_mem BEFORE serialization
    cpu_mem.debug = -1
    cpu_mem.gpu_id = -5
    cpu_mem.element[0].NN_id = 1  
    cpu_mem.element[0].debug = 2  
buffer[248] >> ��������           <------ binary format
cpu_mem AFTER deserialization
    cpu_mem.debug = -1            <----- CORRECT
    cpu_mem.gpu_id = -5           <----- CORRECT
    cpu_mem.element[0].NN_id = 0  <----- INCORRECT
    cpu_mem.element[0].debug = 0  <----- INCORRECT

If I play around a bit with the streams, I can print out the serialized object as XML, to check whether the serialization is successful.

<?xml version="1.0" encoding="utf-8"?>
<cereal>
    <value0>
        <gpu_id>-5</gpu_id>               <----- CORRECT
        <debug>-1</debug>                 <----- CORRECT
        <element>
            <value0>
                <grid_id>0</grid_id>
                <NN_id>1</NN_id>          <----- CORRECT
                <debug>2</debug>          <----- CORRECT
            </value0>
            <value1>
                <grid_id>32522</grid_id>
                <NN_id>2</NN_id>
                <debug>4612412</debug>
            </value1>
        </element>
    </value0>
</cereal>

PROBLEM

The above outputs shows, that deserialization correctly recognizes variables in the container (class GPU_in_grid) but cannot deserialize the lower levels of my structure, namely static array of structures -> element[].

Upvotes: 1

Views: 1994

Answers (1)

martin
martin

Reputation: 100

For some unknown reason to me, the strncpy() malfunctions. The content of the string differs from the content of the array, EVEN if I keep eye on '\0', which need to be appended at the end of the char array, shown here http://www.cplusplus.com/reference/string/string/copy/ .

I have ended up using std::string.copy() instead, which performs as expected, as long as you add '\0' at the end of the char array.

the above code works then just fine.

Upvotes: 1

Related Questions