Skip to content

Instantly share code, notes, and snippets.

@nojima
Last active August 24, 2016 12:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nojima/005cf04bfa35a1fb971adc43b54abbef to your computer and use it in GitHub Desktop.
Save nojima/005cf04bfa35a1fb971adc43b54abbef to your computer and use it in GitHub Desktop.
#include <chrono>
#include <cstdint>
#include <iostream>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <msgpack.hpp>
#include "test_msgpack.h"
#include "test.pb.h"
static const size_t MSGPACK_OUTPUT_BUFFER_RESERVE_SIZE = 271319041;
static const size_t PROTOBUF_OUTPUT_BUFFER_RESERVE_SIZE = 273154049;
class stopwatch {
std::chrono::time_point<std::chrono::system_clock> start_time;
public:
void start() {
start_time = std::chrono::system_clock::now();
}
int64_t elapsed_msec() const {
using namespace std::chrono;
auto end_time = system_clock::now();
return duration_cast<milliseconds>(end_time - start_time).count();
}
};
class string_buffer {
std::string buffer;
public:
string_buffer() {
buffer.reserve(MSGPACK_OUTPUT_BUFFER_RESERVE_SIZE);
}
void write(const char* str, size_t len) {
buffer.append(str, len);
}
size_t size() const {
return buffer.size();
}
const char* data() const {
return buffer.data();
}
};
struct result {
size_t serialize_msec;
size_t deserialize_msec;
size_t size;
};
template <typename Message>
result measure_msgpack(Message message, unsigned n) {
stopwatch sw;
string_buffer buffer;
sw.start();
{
msgpack::packer<string_buffer> packer(buffer);
for (unsigned i = 0; i < n; ++i) {
packer << message;
}
}
size_t serialize_msec = sw.elapsed_msec();
std::cerr << "msgpack serialize: " << serialize_msec << " msec\n";
sw.start();
{
msgpack::unpacked unpacked;
size_t offset = 0;
Message tmp;
for (unsigned i = 0; i < n; ++i) {
msgpack::unpack(unpacked, buffer.data(), buffer.size(), offset);
msgpack::object obj = unpacked.get();
obj.convert(tmp);
}
}
size_t deserialize_msec = sw.elapsed_msec();
std::cerr << "msgpack deserialize: " << deserialize_msec << " msec\n";
return (result){serialize_msec, deserialize_msec, buffer.size()};
}
template <typename Message>
result measure_protobuf(Message message, unsigned n) {
stopwatch sw;
std::string buffer;
buffer.reserve(PROTOBUF_OUTPUT_BUFFER_RESERVE_SIZE);
sw.start();
{
google::protobuf::io::StringOutputStream raw_output(&buffer);
google::protobuf::io::CodedOutputStream output(&raw_output);
for (unsigned i = 0; i < n; ++i) {
message.SerializeToCodedStream(&output);
}
}
size_t serialize_msec = sw.elapsed_msec();
std::cerr << "protobuf serialize: " << serialize_msec << " msec\n";
Message tmp;
sw.start();
{
google::protobuf::io::ArrayInputStream raw_input(buffer.data(), buffer.size());
google::protobuf::io::CodedInputStream input(&raw_input);
input.SetTotalBytesLimit(1000000000, -1);
for (unsigned i = 0; i < n; ++i) {
auto limit = input.PushLimit(message.ByteSize());
tmp.ParseFromCodedStream(&input);
input.PopLimit(limit);
}
}
size_t deserialize_msec = sw.elapsed_msec();
std::cerr << "protobuf deserialize: " << deserialize_msec << " msec\n";
return (result){serialize_msec, deserialize_msec, buffer.size()};
}
template <typename Func, typename Message>
void measure(Func func, Message message, unsigned n, unsigned m) {
size_t min_serialize_msec = 1000000000;
size_t min_deserialize_msec = 1000000000;
size_t min_size = 1000000000;
for (unsigned i = 0; i < m; ++i) {
result r = func(message, n);
min_serialize_msec = std::min(min_serialize_msec, r.serialize_msec);
min_deserialize_msec = std::min(min_deserialize_msec, r.deserialize_msec);
min_size = std::min(min_size, r.size);
}
std::cerr << "min_serialize_msec: " << min_serialize_msec << " msec\n";
std::cerr << "min_deserialize_msec: " << min_deserialize_msec << " msec\n";
std::cerr << "min_size: " << min_size << " B\n";
}
int main() {
static const unsigned TASK_STR_LEN = 1<<13;
static const unsigned TEST1_REPEAT = 1<<23;
static const unsigned TEST2_REPEAT = 1<<23;
static const unsigned TEST3_REPEAT = 1<<16;
static const unsigned TEST4_REPEAT = 1<<16;
static const unsigned OUTER_LOOP = 10;
char* str = (char*)std::malloc(TASK_STR_LEN);
memset(str, 'a', TASK_STR_LEN);
std::cerr << "\n===== Test1 (unsigned integer) =====\n";
{
test_msgpack::Test1 message(1, 2);
measure(measure_msgpack<test_msgpack::Test1>, message, TEST1_REPEAT, OUTER_LOOP);
}
{
test_proto::Test1 message;
message.set_a(1);
message.set_b(2);
measure(measure_protobuf<test_proto::Test1>, message, TEST1_REPEAT, OUTER_LOOP);
}
std::cerr << "\n===== Test2 (signed integer) =====\n";
{
test_msgpack::Test2 message(-1, -2);
measure(measure_msgpack<test_msgpack::Test2>, message, TEST2_REPEAT, OUTER_LOOP);
}
{
test_proto::Test2 message;
message.set_a(-1);
message.set_b(-2);
measure(measure_protobuf<test_proto::Test2>, message, TEST2_REPEAT, OUTER_LOOP);
}
std::cerr << "\n===== Test3 (string) =====\n";
{
test_msgpack::Test3 message(std::string(str, TASK_STR_LEN));
measure(measure_msgpack<test_msgpack::Test3>, message, TEST3_REPEAT, OUTER_LOOP);
}
{
test_proto::Test3 message;
message.set_str(std::string(str, TASK_STR_LEN));
measure(measure_protobuf<test_proto::Test3>, message, TEST3_REPEAT, OUTER_LOOP);
}
std::cerr << "\n===== Test4 (nested integer+string) =====\n";
{
test_msgpack::Test4 message(
test_msgpack::Test1(1, 2),
test_msgpack::Test2(-1, -2),
test_msgpack::Test3(std::string(str, TASK_STR_LEN)));
measure(measure_msgpack<test_msgpack::Test4>, message, TEST4_REPEAT, OUTER_LOOP);
}
{
test_proto::Test4 message;
message.mutable_test1()->set_a(1);
message.mutable_test1()->set_b(1);
message.mutable_test2()->set_a(-1);
message.mutable_test2()->set_b(-2);
message.mutable_test3()->set_str(std::string(str, TASK_STR_LEN));
measure(measure_protobuf<test_proto::Test4>, message, TEST4_REPEAT, OUTER_LOOP);
}
}
syntax = "proto3";
package test_proto;
message Test1 {
uint32 a = 1;
uint32 b = 2;
}
message Test2 {
sint32 a = 1;
sint32 b = 2;
}
message Test3 {
bytes str = 1;
}
message Test4 {
Test1 test1 = 1;
Test2 test2 = 2;
Test3 test3 = 3;
}
namespace test_msgpack {
struct Test1 {
Test1() {}
Test1(uint16_t a, uint32_t b): a(a), b(b) {}
uint16_t a = 0;
uint32_t b = 0;
MSGPACK_DEFINE(a, b);
};
struct Test2 {
Test2() {}
Test2(int16_t a, int32_t b): a(a), b(b) {}
int16_t a = 0;
int32_t b = 0;
MSGPACK_DEFINE(a, b);
};
struct Test3 {
Test3() {}
explicit Test3(const std::string& str): str(str) {}
std::string str;
MSGPACK_DEFINE(str);
};
struct Test4 {
Test4() {}
Test4(const Test1& test1, const Test2& test2, const Test3& test3):
test1(test1), test2(test2), test3(test3) {}
Test1 test1;
Test2 test2;
Test3 test3;
MSGPACK_DEFINE(test1, test2, test3);
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment