blob: 6792a07891aef21af89f9bbd7a0a8ec18f26a214 [file] [log] [blame]
// Copyright 2025 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#[macro_use]
mod _macros;
mod log;
mod mesh;
mod minecraft;
use core::mem::MaybeUninit;
use criterion::{Criterion, black_box, criterion_group, criterion_main};
use fidl_next::{DecoderExt as _, EncoderExt as _, Wire};
use rand::rngs::StdRng;
use rand::{Rng, SeedableRng as _};
pub trait Generate {
fn generate(rng: &mut impl Rng) -> Self;
}
impl Generate for bool {
fn generate(rng: &mut impl Rng) -> Self {
rng.random_bool(0.5)
}
}
impl Generate for u32 {
fn generate(rng: &mut impl Rng) -> Self {
rng.random()
}
}
impl<T: Generate> Generate for Box<T> {
fn generate(rng: &mut impl Rng) -> Self {
Box::new(T::generate(rng))
}
}
impl<T: Generate> Generate for Option<T> {
fn generate(rng: &mut impl Rng) -> Self {
if rng.random_bool(0.5) { Some(T::generate(rng)) } else { None }
}
}
impl<T: Generate, const N: usize> Generate for [T; N] {
fn generate(rng: &mut impl Rng) -> Self {
let mut result = MaybeUninit::<[T; N]>::uninit();
for i in 0..N {
unsafe {
result.as_mut_ptr().cast::<T>().add(i).write(T::generate(rng));
}
}
unsafe { result.assume_init() }
}
}
fn generate_vec<T: Generate>(rng: &mut impl Rng, size: usize) -> Vec<T> {
let mut result = Vec::with_capacity(size);
for _ in 0..size {
result.push(T::generate(rng));
}
result
}
fn make_rng() -> StdRng {
// Nothing up my sleeve: seed is first 32 bytes of pi
StdRng::from_seed([
0x32, 0x43, 0xF6, 0xA8, 0x88, 0x5A, 0x30, 0x8D, 0x31, 0x31, 0x98, 0xA2, 0xE0, 0x37, 0x07,
0x34, 0x4A, 0x40, 0x93, 0x82, 0x22, 0x99, 0xF3, 0x1D, 0x00, 0x82, 0xEF, 0xA9, 0x8E, 0xC4,
0xE6, 0xC8,
])
}
fn bench_rust<T, D>(c: &mut Criterion, name: &str, input: T, input_size: usize, default: D)
where
T: fidl::encoding::TypeMarker,
for<'a> &'a T: fidl::encoding::Encode<T, fidl::encoding::NoHandleResourceDialect>,
T::Owned: fidl::encoding::Decode<T, fidl::encoding::NoHandleResourceDialect>,
D: 'static + Fn() -> T::Owned,
{
let mut decode_buf = Vec::new();
let mut decode_handle_buf = Vec::new();
fidl::encoding::Encoder::<'_, fidl::encoding::NoHandleResourceDialect>::encode::<T>(
&mut decode_buf,
&mut decode_handle_buf,
&input,
)
.unwrap();
c.bench_function(&format!("rust/{name}/encode/{input_size}x"), move |b| {
let mut buf = Vec::new();
let mut handle_buf = Vec::new();
b.iter(|| {
buf.clear();
handle_buf.clear();
black_box(
fidl::encoding::Encoder::<'_, fidl::encoding::NoHandleResourceDialect>::encode::<T>(
&mut buf,
&mut handle_buf,
black_box(&input),
),
)
.unwrap();
});
});
c.bench_function(
&format!("rust/{name}/decode_natural/{input_size}x"),
move |b| {
b.iter(|| {
let mut out = default();
black_box(fidl::encoding::Decoder::<'_, fidl::encoding::NoHandleResourceDialect>::decode_with_context::<T>(
fidl::encoding::Context {
wire_format_version: fidl::encoding::WireFormatVersion::V2,
},
black_box(&decode_buf),
&mut decode_handle_buf,
&mut out,
)).unwrap();
});
}
);
}
fn bench_rust_next<T>(c: &mut Criterion, name: &str, input: T, input_size: usize)
where
T: 'static
+ fidl_next::EncodeRef<Vec<fidl_next::Chunk>>
+ for<'de> fidl_next::FromWire<<T::Encoded as Wire>::Decoded<'de>>,
T::Encoded: for<'a> fidl_next::Decode<&'a mut [fidl_next::Chunk]>,
{
let mut decode_chunks = Vec::new();
decode_chunks.encode_next(&input).unwrap();
c.bench_function(&format!("rust_next/{name}/encode/{input_size}x"), move |b| {
let mut chunks = Vec::new();
b.iter(|| {
chunks.clear();
black_box(chunks.encode_next(black_box(&input))).unwrap();
});
});
let decode_wire_chunks = decode_chunks.clone();
c.bench_function(&format!("rust_next/{name}/decode_wire/{input_size}x"), move |b| {
b.iter_batched_ref(
|| decode_wire_chunks.clone(),
|decode_chunks| {
let chunks = black_box(decode_chunks).as_mut_slice();
black_box(chunks.decode::<T::Encoded>()).unwrap();
},
criterion::BatchSize::SmallInput,
);
});
c.bench_function(&format!("rust_next/{name}/decode_natural/{input_size}x"), move |b| {
b.iter_batched_ref(
|| decode_chunks.clone(),
|decode_chunks| {
let chunks = black_box(decode_chunks).as_mut_slice();
let value = chunks.decode::<T::Encoded>().unwrap();
black_box(value.take::<T>());
},
criterion::BatchSize::SmallInput,
);
});
}
fn bench_log(c: &mut Criterion) {
const INPUT_SIZES: [usize; 4] = [1, 10, 100, 1000];
for input_size in INPUT_SIZES {
bench_rust(c, "log", log::generate_input_rust(input_size), input_size, || {
fidl_test_benchmark::Logs { logs: Vec::new() }
});
bench_rust(c, "mesh", mesh::generate_input_rust(input_size), input_size, || {
fidl_test_benchmark::Mesh { triangles: Vec::new() }
});
bench_rust(c, "minecraft", minecraft::generate_input_rust(input_size), input_size, || {
fidl_test_benchmark::Players { players: Vec::new() }
});
bench_rust_next(c, "log", log::generate_input_rust_next(input_size), input_size);
bench_rust_next(c, "mesh", mesh::generate_input_rust_next(input_size), input_size);
bench_rust_next(
c,
"minecraft",
minecraft::generate_input_rust_next(input_size),
input_size,
);
}
}
criterion_group!(benchmark, bench_log);
criterion_main!(benchmark);