Last active
November 8, 2018 20:59
-
-
Save yuvalif/aa3691c62959b1a9d7dbf7adceac0c78 to your computer and use it in GitHub Desktop.
boost::circular_buffer serialization benchmark
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// boost::circular_buffer serialization | |
// using: g++ (GCC) 8.2.1 20181011 (Red Hat 8.2.1-4) | |
// | |
// g++ -Wall -O2 -o cb_serialization cb_serialization.cpp -lboost_serialization | |
// g++ -Wall -O2 -DUSE_BINARY -o cb_serialization cb_serialization.cpp -lboost_serialization | |
// | |
// | |
#include <boost/circular_buffer.hpp> | |
#include <boost/serialization/split_free.hpp> | |
#include <sstream> | |
#include <iostream> | |
#include <cstdlib> | |
#include <random> | |
#include <chrono> | |
#include <fstream> | |
#include <boost/archive/text_oarchive.hpp> | |
#include <boost/archive/text_iarchive.hpp> | |
// implement serialization for boost::circular_buffer | |
namespace boost { namespace serialization { | |
template <class Archive, class T> | |
void save(Archive& ar, const circular_buffer<T>& b, const unsigned int /* version */) | |
{ | |
typename circular_buffer<T>::size_type size = b.size(); | |
ar << b.capacity(); | |
ar << size; | |
#ifdef USE_BINARY | |
const typename circular_buffer<T>::const_array_range one = b.array_one(); | |
const typename circular_buffer<T>::const_array_range two = b.array_two(); | |
ar.save_binary(one.first, one.second*sizeof(T)); | |
ar.save_binary(two.first, two.second*sizeof(T)); | |
#else | |
while (size > 0) { | |
--size; | |
ar << b[size]; | |
} | |
#endif | |
} | |
template <class Archive, class T> | |
void load(Archive& ar, circular_buffer<T>& b, const unsigned int /* version */) | |
{ | |
typename circular_buffer<T>::capacity_type capacity; | |
typename circular_buffer<T>::size_type size; | |
ar >> capacity; | |
b.set_capacity(capacity); | |
ar >> size; | |
b.clear(); | |
#ifdef USE_BINARY | |
const typename circular_buffer<T>::pointer buff = new T[size*sizeof(T)]; | |
ar.load_binary(buff, size*sizeof(T)); | |
b.insert(b.begin(), buff, buff+size); | |
delete[] buff; | |
#else | |
T elem; | |
while (size > 0) { | |
--size; | |
ar >> elem; | |
b.push_front(elem); | |
} | |
#endif | |
} | |
template<class Archive, class T> | |
inline void serialize(Archive & ar, circular_buffer<T>& b, const unsigned int version) | |
{ | |
split_free(ar, b, version); | |
} | |
} } // end namespace boost::serialization | |
int main(int argc, char** argv) | |
{ | |
if (argc != 2) { | |
std::cout << "usage: " << argv[0] << " <buffer size>" << std::endl; | |
return 1; | |
} | |
const auto buffer_size = std::atoi(argv[1]); | |
if (buffer_size <= 0) { | |
std::cout << "invalid buffer size" << std::endl; | |
return 1; | |
} | |
// Seed with a real random value, if available | |
std::random_device r; | |
// Choose a randomly whether to push or pop | |
std::default_random_engine e(r()); | |
std::uniform_int_distribution<int> uniform_dist(1, 10); | |
boost::circular_buffer<double> cb1(buffer_size); | |
for (auto i = 0; i < buffer_size; ++i) { | |
auto draw = uniform_dist(e); | |
if (draw < 8) | |
cb1.push_back(i); | |
else | |
cb1.pop_front(); | |
} | |
#ifdef USE_BINARY | |
std::cout << "binary serialization..." << std::endl; | |
#else | |
std::cout << "text serialization..." << std::endl; | |
#endif | |
{ | |
// memory storage - low overhead | |
std::stringstream ss; | |
boost::archive::text_oarchive oa(ss); | |
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); | |
boost::serialization::serialize(oa, cb1, 0); | |
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); | |
std::cout << "low overhead serialization for buffer: " << buffer_size << " took: " << | |
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl; | |
boost::circular_buffer<double> cb2(0); | |
boost::archive::text_iarchive ia(ss); | |
begin = std::chrono::steady_clock::now(); | |
boost::serialization::serialize(ia, cb2, 0); | |
end = std::chrono::steady_clock::now(); | |
std::cout << "low overhead deserialization for buffer: " << buffer_size << " took: " << | |
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl; | |
if (cb1 != cb2) { | |
std::cout << "circular buffer did not recover correctly" << std::endl; | |
} | |
} | |
{ | |
// file storage - high overhead | |
{ | |
std::ofstream ofs("cb.tmp"); | |
boost::archive::text_oarchive oa(ofs); | |
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); | |
boost::serialization::serialize(oa, cb1, 0); | |
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); | |
std::cout << "high overhead serialization for buffer: " << buffer_size << " took: " << | |
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl; | |
} | |
{ | |
std::ifstream ifs("cb.tmp"); | |
boost::circular_buffer<double> cb2(0); | |
boost::archive::text_iarchive ia(ifs); | |
std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); | |
boost::serialization::serialize(ia, cb2, 0); | |
std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); | |
std::cout << "high overhead deserialization for buffer: " << buffer_size << " took: " << | |
std::chrono::duration_cast<std::chrono::microseconds> (end - begin).count() << " usec" << std::endl; | |
if (cb1 != cb2) { | |
std::cout << "circular buffer did not recover correctly" << std::endl; | |
} | |
} | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment