The C++ Middleware Writer has advantages over the Boost Serialization library in the following areas:
| Usage | Performance | std::move support | Message support | Boost Intrusive support |
class bus_stop
{
friend class boost::serialization::access;
template
void serialize(Archive & ar, const unsigned int version)
{
ar & latitude;
ar & longitude;
}
gps_position latitude;
gps_position longitude;
protected:
bus_stop(const gps_position & lat_, const gps_position & long_) :
latitude(lat_), longitude(long_)
{}
public:
bus_stop(){}
virtual ~bus_stop(){}
};
Derived classes should include serializations of their base classes.
class bus_stop_corner : public bus_stop
{
friend class boost::serialization::access;
template
void serialize(Archive & ar, const unsigned int version)
{
// serialize base class information
ar & boost::serialization::base_object(*this);
ar & street1;
ar & street2;
}
...
};
With the C++ Middleware Writer, marshalling functions are written and maintained automatically. There's no need to make parallel changes to functions by hand when data members are added or removed from a type. Here's how that example from the Boost tutorial is written with our approach:
class bus_stop
{
gps_position latitude;
gps_position longitude;
protected:
bus_stop(const gps_position & lat_, const gps_position & long_) :
latitude(lat_), longitude(long_)
{}
public:
bus_stop(){}
virtual ~bus_stop(){}
bool Send(Buffer*, bool = false) const;
bool Receive(Buffer*);
};
class bus_stop_corner : public bus_stop
{
...
public:
bool Send(Buffer*, bool = false) const;
bool Receive(Buffer*);
};
The Boost Serialization version has 12 more lines than our version and these are small classes.
There's no need for friend declarations. Did you notice the friend declarations in the Boost Serialization version? Our approach writes the marshalling functions based on the content of the types involved. So there's no need to add friend declarations.
For testing purposes we always build the Boost Serialization library with variant=release and link=static. The tests are run three times in a row using a semicolon on Linux to separate the executions. The fastest time of the three is the only one used in the calculations.
This set of programs serialize/send a list of ints.
Boost versionWith 500,000 elements as input to both programs, the Boost version (using Boost 1.44) is generally between 2.3 and 2.4 times slower than the Ebenezer version and the stripped Boost Serialization executable is more than two times larger than the stripped Ebenezer executable.
The following programs send a list of ints and a deque of ints.
Boost versionWith 500,000 elements of input to both programs, the Boost version (Boost 1.44) is between 2.9 and 3.0 times slower than the Ebenezer version. The stripped Boost Serialization executable is more than two times larger than the stripped Ebenezer executable.
With 500,000 elements as input, the Boost Serialization versions (using Boost 1.44) of both of the above tests are between 3.2 and 4.2 times slower than the corresponding Ebenezer version when -O2 optimization is used. The Boost Serialization executables are both more than two times larger than the Ebenezer versions.
Boost/Windows versionThe following programs load/receive a list of ints.
Boost versionWith a command line argument of 500000 for both programs, the Boost version is between 1.3 and 1.5 times slower than the Ebenezer version and the stripped Boost Serialization executable is more than three times larger than the stripped Ebenezer executable.
We're interested in hearing how the approaches stack up when using other compilers or operating systems. Do we have any strong competition?
The Boost Serialization library (version 1.43) doesn't make use of std::move. The following shows an example of output when the config file parameter Permit-std::move is turned on.
template <typename B>
void
Receive(B* buf, vector<deque<lil_string> >& abt1)
{
uint32_t headCount[2];
buf->Give(headCount[0]);
abt1.reserve(abt1.size() + headCount[0]);
while (headCount[0] > 0) {
--headCount[0];
deque<lil_string> rep4;
buf->Give(headCount[1]);
while (headCount[1] > 0) {
--headCount[1];
lil_string rep5(buf);
rep4.push_back(std::move(rep5));
}
abt1.push_back(std::move(rep4));
}
}
We have a few test results related to Permit-std::move. The tests use a vector<deque<double> >.
The Boost Serialization version is here -- http://webEbenezer.net/posts/mvbst_test.cc The Ebenezer version is here -- http://webEbenezer.net/posts/movingMsgs.hh http://webEbenezer.net/posts/mv_test.ccThe Boost version was 1.3 times slower than the Ebenezer version with Permit-std::move turned off and 1.8 times slower than the Ebenezer version with Permit-std::moved turned on.
Support for Messages:
The Middle language we use offers support for messages that is not available with the Boost Serialization library. For example, the following Middle code has two messages.
msg_manager (unsigned char, vector<string>, unsigned char, bool) @msg_id_middleware_request (short, string) @msg_id_result }Here are the first few lines the C++ Middleware Writer writes given that input:// Generated by the C++ Middleware Writer version 1.12 #include <string> #include <vector> #include <MarshallingFunctions.hh> #include <ReceiveCompressedBuffer.hh> #include <SendCompressedBuffer.hh> uint16_t const msg_id_middleware_request = 1201; uint16_t const msg_id_result = 1202; uint16_t const max_msg_id = 1203;Notice the msg_id... constants that are part of the output. This approach of naming the messages with @msg_id... helps keep things straight about a message's purpose and the constants are useful in application development.
Additionally, when @msg_id... is used, the generated Send functions post the value associated with their message id before posting anything else.
We extend the message support by having an option that automates the calculation of message lengths. The Boost Serialization library has no message length calculation functionality, since it has no message concept in the first place.
Support for Boost Intrusive Containers:
Only the C++ Middleware Writer has support for Boost Intrusive containers. Neither Boost Intrusive nor Boost Serialization offers serialization support for these most useful containers.
Weaknesses of the C++ Middleware Writer
The primary weakness we have is that we don't support some C++ features. We have limited support for user defined templates, nested classes and some other features of the language. We are working on shortening this list.