Merge commit '0f6aab9da6fe982218a01f4a5b896e65fcced437' as 'third_party/flatbuffers'

This commit is contained in:
Siarhei Fedartsou
2024-06-22 13:33:34 +02:00
1814 changed files with 326902 additions and 0 deletions
@@ -0,0 +1,33 @@
/*
* Copyright 2020 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;
extern crate flatbuffers;
extern crate flexbuffers;
mod flatbuffers_benchmarks;
mod flexbuffers_benchmarks;
#[allow(dead_code, unused_imports)]
#[path = "../../monster_test/mod.rs"]
mod monster_test_generated;
pub use monster_test_generated::my_game;
benchmark_main!(
flatbuffers_benchmarks::benches,
flexbuffers_benchmarks::benches
);
@@ -0,0 +1,269 @@
/*
* 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) -> 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::<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::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::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);
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,
);
@@ -0,0 +1,295 @@
// Copyright 2019 Google LLC
//
// 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
//
// https://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, benchmark_main, Bencher};
use flexbuffers::*;
fn push_vec_u64_to_map(b: &mut Bencher) {
let va = vec![u64::max_value() - 10; 512];
let vb = vec![u64::max_value() - 20; 512];
let vc = vec![u64::max_value() - 30; 512];
let mut n = 0;
b.iter(|| {
let mut fxb = Builder::default();
let mut m = fxb.start_map();
let mut ma = m.start_vector("a");
for &a in va.iter() {
ma.push(a);
}
ma.end_vector();
let mut mb = m.start_vector("b");
for &b in vb.iter() {
mb.push(b);
}
mb.end_vector();
let mut mc = m.start_vector("c");
for &c in vc.iter() {
mc.push(c);
}
mc.end_vector();
m.end_map();
n = fxb.view().len();
});
b.bytes = n as u64;
}
fn push_vec_u64_to_map_reused(b: &mut Bencher) {
let va = vec![u64::max_value() - 10; 512];
let vb = vec![u64::max_value() - 20; 512];
let vc = vec![u64::max_value() - 30; 512];
let mut fxb = Builder::default();
let mut n = 0;
let mut go = || {
let mut m = fxb.start_map();
let mut ma = m.start_vector("a");
for &a in va.iter() {
ma.push(a);
}
ma.end_vector();
let mut mb = m.start_vector("b");
for &b in vb.iter() {
mb.push(b);
}
mb.end_vector();
let mut mc = m.start_vector("c");
for &c in vc.iter() {
mc.push(c);
}
mc.end_vector();
m.end_map();
n = fxb.view().len();
};
go(); // warm up allocations.
b.iter(go);
b.bytes = n as u64;
}
fn push_vec_u64_to_map_direct(b: &mut Bencher) {
let va = vec![u64::max_value() - 10; 512];
let vb = vec![u64::max_value() - 20; 512];
let vc = vec![u64::max_value() - 30; 512];
let mut n = 0;
b.iter(|| {
let mut fxb = Builder::default();
let mut m = fxb.start_map();
m.push("a", &va);
m.push("b", &vb);
m.push("c", &vc);
m.end_map();
n = fxb.view().len();
});
b.bytes = n as u64;
}
fn push_vec_u64_to_map_direct_reused(b: &mut Bencher) {
let va = vec![u64::max_value() - 10; 512];
let vb = vec![u64::max_value() - 20; 512];
let vc = vec![u64::max_value() - 30; 512];
let mut n = 0;
let mut fxb = Builder::default();
let mut go = || {
let mut m = fxb.start_map();
m.push("a", &va);
m.push("b", &vb);
m.push("c", &vc);
m.end_map();
n = fxb.view().len();
};
go(); // warm up allocations.
b.iter(go);
b.bytes = n as u64;
}
fn push_vec_without_indirect(b: &mut Bencher) {
let mut builder = Builder::default();
let mut n = 0;
let mut go = || {
let mut b = builder.start_vector();
for i in 0..1024u16 {
b.push(i);
}
b.push(i64::max_value());
b.end_vector();
n = builder.view().len();
};
go(); // warm up allocations.
b.iter(go);
b.bytes = n as u64;
}
// This isn't actually faster than the alternative but it is a lot smaller.
// Based on the above benchmarks a lot of time is stuck in the `values` stack.
fn push_vec_with_indirect(b: &mut Bencher) {
let mut builder = Builder::default();
let mut n = 0;
let mut go = || {
let mut b = builder.start_vector();
for i in 0..1024u16 {
b.push(i);
}
b.push(IndirectInt(i64::max_value()));
b.end_vector();
n = builder.view().len();
};
go(); // warm up allocations.
b.iter(go);
b.bytes = n as u64;
}
fn example_map<'a>(m: &mut MapBuilder<'a>) {
m.push("some_ints", &[256; 5]);
m.push("some_uints", &[256u16; 5]);
m.push("some_floats", &[256f32; 5]);
m.push("some_strings", "muahahahahaha");
}
fn hundred_maps(b: &mut Bencher) {
let mut builder = Builder::default();
let mut n = 0;
let mut go = || {
let mut v = builder.start_vector();
for _ in 0..100 {
example_map(&mut v.start_map());
}
v.end_vector();
n = builder.view().len();
};
go(); // Warm up allocations.
b.iter(go);
b.bytes = n as u64;
}
fn hundred_maps_pooled(b: &mut Bencher) {
let mut builder = Builder::default();
let mut n = 0;
let mut go = || {
let mut v = builder.start_vector();
for _ in 0..100 {
example_map(&mut v.start_map());
}
v.end_vector();
n = builder.view().len();
};
go(); // Warm up allocations.
b.iter(go);
b.bytes = n as u64;
}
fn make_monster(mut monster: MapBuilder) {
monster.push("type", "great orc");
monster.push("age", 100u8);
monster.push("name", "Mr. Orc");
monster.push("coins", &[1, 25, 50, 100, 250]);
monster.push("color", &[255u8, 0, 0, 0]);
{
let mut weapons = monster.start_vector("weapons");
{
let mut hammer = weapons.start_map();
hammer.push("name", "hammer");
hammer.push("damage type", "crush");
hammer.push("damage", 20);
}
{
let mut axe = weapons.start_map();
axe.push("name", "Great Axe");
axe.push("damage type", "slash");
axe.push("damage", 30);
}
}
{
let mut sounds = monster.start_vector("sounds");
sounds.push("grr");
sounds.push("rawr");
sounds.push("muahaha");
}
}
fn serialize_monsters(b: &mut Bencher) {
let mut builder = Builder::default();
let mut n = 0;
let mut go = || {
let mut monsters = builder.start_vector();
for _ in 0..100 {
make_monster(monsters.start_map())
}
monsters.end_vector();
n = builder.view().len();
};
go(); // Warm up allocations.
b.iter(go);
b.bytes = n as u64;
}
fn validate_monster(r: MapReader<&[u8]>) {
assert_eq!(r.idx("type").as_str(), "great orc");
assert_eq!(r.idx("age").as_u8(), 100);
assert_eq!(r.idx("name").as_str(), "Mr. Orc");
assert!(r
.idx("coins")
.as_vector()
.iter()
.map(|c| c.as_i16())
.eq([1, 25, 50, 100, 250].iter().cloned()));
assert!(r
.idx("color")
.as_vector()
.iter()
.map(|c| c.as_u8())
.eq([255, 0, 0, 0].iter().cloned()));
let weapons = r.idx("weapons").as_vector();
assert_eq!(weapons.len(), 2);
let hammer = weapons.idx(0).as_map();
assert_eq!(hammer.idx("name").as_str(), "hammer");
assert_eq!(hammer.idx("damage type").as_str(), "crush");
assert_eq!(hammer.idx("damage").as_u64(), 20);
let axe = weapons.idx(1).as_map();
assert_eq!(axe.idx("name").as_str(), "Great Axe");
assert_eq!(axe.idx("damage type").as_str(), "slash");
assert_eq!(axe.idx("damage").as_u64(), 30);
assert!(r
.idx("sounds")
.as_vector()
.iter()
.map(|s| s.as_str())
.eq(["grr", "rawr", "muahaha"].iter().cloned()));
}
fn read_monsters(b: &mut Bencher) {
let mut builder = Builder::default();
let mut monsters = builder.start_vector();
for _ in 0..100 {
make_monster(monsters.start_map());
}
monsters.end_vector();
b.bytes = builder.view().len() as u64;
let go = || {
let r = Reader::get_root(builder.view()).unwrap().as_vector();
assert_eq!(r.len(), 100);
for i in 0..100 {
validate_monster(r.idx(i).as_map());
}
};
b.iter(go);
}
benchmark_group!(
benches,
push_vec_u64_to_map,
push_vec_u64_to_map_reused,
push_vec_u64_to_map_direct,
push_vec_u64_to_map_direct_reused,
push_vec_without_indirect,
push_vec_with_indirect,
hundred_maps,
hundred_maps_pooled,
serialize_monsters,
read_monsters,
);
benchmark_main!(benches);