/* * Copyright 2018 Google Inc. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #[macro_use] extern crate bencher; use bencher::Bencher; extern crate flatbuffers; #[path = "../../monster_test_generated.rs"] mod monster_test_generated; pub use monster_test_generated::my_game; fn traverse_canonical_buffer(bench: &mut Bencher) { let owned_data = { let mut builder = &mut flatbuffers::FlatBufferBuilder::new(); create_serialized_example_with_generated_code(&mut builder, true); builder.finished_data().to_vec() }; let data = &owned_data[..]; let n = data.len() as u64; bench.iter(|| { traverse_serialized_example_with_generated_code(data); }); bench.bytes = n; } fn create_canonical_buffer_then_reset(bench: &mut Bencher) { let mut builder = &mut flatbuffers::FlatBufferBuilder::new(); // warmup create_serialized_example_with_generated_code(&mut builder, true); let n = builder.finished_data().len() as u64; builder.reset(); bench.iter(|| { let _ = create_serialized_example_with_generated_code(&mut builder, true); builder.reset(); }); bench.bytes = n; } #[inline(always)] fn create_serialized_example_with_generated_code(builder: &mut flatbuffers::FlatBufferBuilder, finish: bool) -> usize{ let s0 = builder.create_string("test1"); let s1 = builder.create_string("test2"); let t0_name = builder.create_string("Barney"); let t1_name = builder.create_string("Fred"); let t2_name = builder.create_string("Wilma"); let t0 = my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{ hp: 1000, name: Some(t0_name), ..Default::default() }); let t1 = my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{ name: Some(t1_name), ..Default::default() }); let t2 = my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{ name: Some(t2_name), ..Default::default() }); let mon = { let name = builder.create_string("MyMonster"); let fred_name = builder.create_string("Fred"); let inventory = builder.create_vector_direct(&[0u8, 1, 2, 3, 4]); let test4 = builder.create_vector_direct(&[my_game::example::Test::new(10, 20), my_game::example::Test::new(30, 40)]); let pos = my_game::example::Vec3::new(1.0, 2.0, 3.0, 3.0, my_game::example::Color::Green, &my_game::example::Test::new(5i16, 6i8)); let args = my_game::example::MonsterArgs{ hp: 80, mana: 150, name: Some(name), pos: Some(&pos), test_type: my_game::example::Any::Monster, test: Some(my_game::example::Monster::create(builder, &my_game::example::MonsterArgs{ name: Some(fred_name), ..Default::default() }).as_union_value()), inventory: Some(inventory), test4: Some(test4), testarrayofstring: Some(builder.create_vector(&[s0, s1])), testarrayoftables: Some(builder.create_vector(&[t0, t1, t2])), ..Default::default() }; my_game::example::Monster::create(builder, &args) }; if finish { my_game::example::finish_monster_buffer(builder, mon); } builder.finished_data().len() // make it do some work // if builder.finished_data().len() == 0 { panic!("bad benchmark"); } } #[inline(always)] fn blackbox<T>(t: T) -> T { // encapsulate this in case we need to turn it into a noop bencher::black_box(t) } #[inline(always)] fn traverse_serialized_example_with_generated_code(bytes: &[u8]) { let m = my_game::example::get_root_as_monster(bytes); blackbox(m.hp()); blackbox(m.mana()); blackbox(m.name()); let pos = m.pos().unwrap(); blackbox(pos.x()); blackbox(pos.y()); blackbox(pos.z()); blackbox(pos.test1()); blackbox(pos.test2()); let pos_test3 = pos.test3(); blackbox(pos_test3.a()); blackbox(pos_test3.b()); blackbox(m.test_type()); let table2 = m.test().unwrap(); let monster2 = my_game::example::Monster::init_from_table(table2); blackbox(monster2.name()); blackbox(m.inventory()); blackbox(m.test4()); let testarrayoftables = m.testarrayoftables().unwrap(); blackbox(testarrayoftables.get(0).hp()); blackbox(testarrayoftables.get(0).name()); blackbox(testarrayoftables.get(1).name()); blackbox(testarrayoftables.get(2).name()); let testarrayofstring = m.testarrayofstring().unwrap(); blackbox(testarrayofstring.get(0)); blackbox(testarrayofstring.get(1)); } fn create_string_10(bench: &mut Bencher) { let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20); let mut i = 0; bench.iter(|| { builder.create_string("foobarbaz"); // zero-terminated -> 10 bytes i += 1; if i == 10000 { builder.reset(); i = 0; } }); bench.bytes = 10; } fn create_string_100(bench: &mut Bencher) { let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20); let s_owned = (0..99).map(|_| "x").collect::<String>(); let s: &str = &s_owned; let mut i = 0; bench.iter(|| { builder.create_string(s); // zero-terminated -> 100 bytes i += 1; if i == 1000 { builder.reset(); i = 0; } }); bench.bytes = s.len() as u64; } fn create_byte_vector_100_naive(bench: &mut Bencher) { let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20); let v_owned = (0u8..100).map(|i| i).collect::<Vec<u8>>(); let v: &[u8] = &v_owned; let mut i = 0; bench.iter(|| { builder.create_vector(v); // zero-terminated -> 100 bytes i += 1; if i == 10000 { builder.reset(); i = 0; } }); bench.bytes = v.len() as u64; } fn create_byte_vector_100_optimal(bench: &mut Bencher) { let builder = &mut flatbuffers::FlatBufferBuilder::new_with_capacity(1<<20); let v_owned = (0u8..100).map(|i| i).collect::<Vec<u8>>(); let v: &[u8] = &v_owned; let mut i = 0; bench.iter(|| { builder.create_vector_direct(v); i += 1; if i == 10000 { builder.reset(); i = 0; } }); bench.bytes = v.len() as u64; } benchmark_group!(benches, create_byte_vector_100_naive, create_byte_vector_100_optimal, traverse_canonical_buffer, create_canonical_buffer_then_reset, create_string_10, create_string_100); benchmark_main!(benches);