Skip to content

Instantly share code, notes, and snippets.

@stepancheg
Last active August 29, 2015 14:00
Show Gist options
  • Save stepancheg/11333310 to your computer and use it in GitHub Desktop.
Save stepancheg/11333310 to your computer and use it in GitHub Desktop.
extern crate protobuf; | #include <iostream>
extern crate rand; | #include <fstream>
extern crate time; | #include <random>
| #include <sstream>
use std::io::File; | #include <chrono>
use std::io::MemWriter; |
use std::io::BufReader; | #include <google/protobuf/message.h>
use std::default::Default; | #include <google/protobuf/io/zero_copy_stream_impl.h>
|
use rand::Rng; | #include <stdio.h>
use rand::StdRng; |
use rand::SeedableRng; | #include "perftest_data.pb.h"
|
use protobuf::Message; |
use perftest_data::PerftestData; | using namespace google::protobuf;
| using namespace google::protobuf::io;
mod perftest_data; |
|
| #define FAIL(msg) do { \
| fprintf(stderr, "FAIL: %s\n", msg); exit(1); \
| } while (0)
| #define VERIFY(param) do { \
| if (!(param)) FAIL(#param); \
| } while(0)
|
|
| template <typename TFunc>
fn measure_ns<R>(f: || -> R) -> (u64, R) { | uint64_t measure_ns(TFunc func) {
let start = time::precise_time_ns(); | auto start = std::chrono::system_clock::now();
let r = f(); | func();
(time::precise_time_ns() - start, r) | auto end = std::chrono::system_clock::now();
| return std::chrono::duration_cast<
| std::chrono::nanoseconds>(end - start).count();
} | }
|
| template <typename TFunc>
fn measure_print<R>(title: &str, iter: u64, f: || -> R) -> R { | void measure_print(const std::string& name, unsigned iter, TFunc fun
let (ns, r) = measure_ns(f); | auto ns = measure_ns(func);
let ns_per_iter = ns / iter; | auto ns_per_iter = ns / iter;
println!("{}: {} ns per iter", title, ns_per_iter); | printf("%s: %u ns per iter\n",
r | name.c_str(), (unsigned) ns_per_iter);
} | }
|
| template <typename M>
fn test<M : Message>(name: &str, data: &[M]) { | void test(const char* name, const RepeatedPtrField<M>& data) {
let mut rng: StdRng = SeedableRng::from_seed(&[10, 20]); | std::mt19937 rng;
| std::uniform_int_distribution<std::mt19937::result_type>
| dist(0, data.size() - 1);
|
let mut random_data: Vec<M> = Vec::new(); | RepeatedPtrField<M> randomData;
|
let mut total_size = 0; | auto totalSize = 0;
while total_size < 1000000 { | while (totalSize < 1000000) {
let ref item = data[rng.gen_range(0, data.len())]; | const auto& item = data.Get(dist(rng));
random_data.push(item.clone()); | *randomData.Add() = item;
total_size += item.serialized_size(); | totalSize += item.ByteSize();
} | }
|
let mut writer = MemWriter::new(); | std::string s;
measure_print( | measure_print(
format!("{}: write", name), | std::string() + name + " write",
random_data.len() as u64, | randomData.size(),
|| { | [&] () {
| StringOutputStream ss(&s);
| CodedOutputStream os(&ss);
for m in random_data.iter() { | for (int i = 0; i < randomData.size(); ++i) {
m.write_length_delimited_to_writer(&mut writer); | auto size = randomData.Get(i).ByteSize();
| os.WriteVarint32(size);
| randomData.Get(i).SerializeWithCachedSizes(&os);
} | }
}); | });
|
let buf = writer.unwrap(); | RepeatedPtrField<M> readData;
|
let read_data = measure_print( | measure_print(
format!("{}: read", name), | std::string() + name + " read",
random_data.len() as u64, | randomData.size(),
|| { | [&] () {
let mut r = Vec::new(); | CodedInputStream is((const uint8*) s.data(), s.size());
let mut reader = BufReader::new(buf.as_slice()); | while (is.BytesUntilLimit() > 0) {
let mut coded_input_stream = | uint32 length;
protobuf::CodedInputStream::new(&mut reader); | bool okLength = is.ReadVarint32(&length);
while !coded_input_stream.eof() { | while (is.BytesUntilLimit() > 0) {
r.push(protobuf::parse_length_delimited_from::<M>( | uint32 length;
&mut coded_input_stream)); | bool okLength = is.ReadVarint32(&length);
| VERIFY(okLength);
| auto oldLimit = is.PushLimit(length);
| bool okReadMsg = readData.Add()
| ->MergeFromCodedStream(&is);
| VERIFY(okReadMsg);
| is.PopLimit(oldLimit);
} | }
r |
}); | });
|
| // TODO: compare content
assert_eq!(random_data, read_data); | VERIFY(randomData.size() == readData.size());
|
| auto count = 0;
let merged = measure_print( | measure_print(
format!("{}: read reuse", name), | std::string() + name + " read reuse",
random_data.len() as u64, | randomData.size(),
|| { | [&] () {
let mut reader = BufReader::new(buf.as_slice()); | M msg;
let mut coded_input_stream = | CodedInputStream is((const uint8*) s.data(), s.size());
protobuf::CodedInputStream::new(&mut reader); |
let mut msg: M = Default::default(); |
let mut count = 0; |
while !coded_input_stream.eof() { | while (is.BytesUntilLimit() > 0) {
msg.clear(); | msg.Clear();
coded_input_stream.merge_message(&mut msg); | uint32 length;
| bool okLength = is.ReadVarint32(&length);
| VERIFY(okLength);
| auto oldLimit = is.PushLimit(length);
| bool okReadMsg = msg.MergeFromCodedStream(&is);
| VERIFY(okReadMsg);
| is.PopLimit(oldLimit);
count += 1; | count += 1;
} | }
count |
}); | });
|
assert_eq!(random_data.len(), merged); | VERIFY(randomData.size() == count);
} | }
|
fn main() { | int main() {
let mut is = File::open(&Path::new("perftest_data.pbbin")); | std::ifstream is("perftest_data.pbbin");
let perftest_data = | PerftestData perftestData;
protobuf::parse_from_reader::<PerftestData>(&mut is); | bool ok = perftestData.ParsePartialFromIstream(&is);
| VERIFY(ok);
test("test1", | test("test1",
perftest_data.get_test1()); | perftestData.test1());
test("test_repeated_bool", | test("test_repeated_bool",
perftest_data.get_test_repeated_bool()); | perftestData.test_repeated_bool());
test("test_messages_of_messages", | test("test_messages_of_messages",
perftest_data.get_test_messages_of_messages()); | perftestData.test_messages_of_messages());
| return 0;
} | }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment