flatbuffers/tests/rust_usage_test/benches/flexbuffers_benchmarks.rs

296 lines
8.3 KiB
Rust

// 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::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) {
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);