Last active
August 24, 2016 12:46
-
-
Save nojima/005cf04bfa35a1fb971adc43b54abbef to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#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); | |
} | |
} |
This file contains hidden or 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
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; | |
} |
This file contains hidden or 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
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