/* * 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. */ use bencher::{benchmark_group, Bencher}; use flatbuffers; #[allow(dead_code, unused_imports)] #[path = "../../monster_test/mod.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(&[0u8, 1, 2, 3, 4]); let test4 = builder.create_vector(&[ 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 { // 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 = unsafe { my_game::example::root_as_monster_unchecked(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 = unsafe { 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::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::with_capacity(1 << 20); let s_owned = (0..99).map(|_| "x").collect::(); 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::with_capacity(1 << 20); let v_owned = (0u8..100).map(|i| i).collect::>(); 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::with_capacity(1 << 20); let v_owned = (0u8..100).map(|i| i).collect::>(); let v: &[u8] = &v_owned; let mut i = 0; bench.iter(|| { builder.create_vector(v); i += 1; if i == 10000 { builder.reset(); i = 0; } }); bench.bytes = v.len() as u64; } fn create_many_tables(bench: &mut Bencher) { let builder = &mut flatbuffers::FlatBufferBuilder::with_capacity(1 << 20); // We test vtable overhead by making many unique tables of up to 16 fields of u8s. bench.iter(|| { for i in 0..(1u16 << 10) { let t = builder.start_table(); for j in 0..15 { if i & (1 << j) == 1 { builder.push_slot_always(i * 2, 42u8); } } builder.end_table(t); } builder.reset(); }); bench.bytes = 1 << 15; } 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, create_many_tables, );