Performance enhancements for #141 (#173)

This PR also includes the Criterion benchmark.

## Before this commit
> Benchmarking BlockState::to_kind
> Benchmarking BlockState::to_kind: Warming up for 3.0000 s Benchmarking
BlockState::to_kind: Collecting 100 samples in estimated 20.045 s (273k
iterations) Benchmarking BlockState::to_kind: Analyzing
> BlockState::to_kind     time:   [68.925 µs 69.202 µs 69.477 µs]
> 
> Found 5 outliers among 100 measurements (5.00%)
>   4 (4.00%) high mild
>   1 (1.00%) high severe

## After this commit
> Benchmarking BlockState::to_kind
> Benchmarking BlockState::to_kind: Warming up for 3.0000 s Benchmarking
BlockState::to_kind: Collecting 100 samples in estimated 20.010 s (3.8M
iterations) Benchmarking BlockState::to_kind: Analyzing
> BlockState::to_kind     time:   [1.5814 µs 1.5859 µs 1.5912 µs]
> change: [-97.692% -97.678% -97.666%] (p = 0.00 < 0.05)
>                         Performance has improved.
> Found 4 outliers among 100 measurements (4.00%)
>   4 (4.00%) high mild

Co-authored-by: Ryan Johnson <ryanj00a@gmail.com>
This commit is contained in:
Terminator 2022-12-19 15:25:26 +01:00 committed by GitHub
parent aeea435a7e
commit c4ed95a7d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 117 additions and 5 deletions

View file

@ -22,6 +22,11 @@ valence_nbt = { version = "0.5.0", path = "../valence_nbt" }
[dev-dependencies] [dev-dependencies]
rand = "0.8.5" rand = "0.8.5"
criterion = "0.4.0"
[[bench]]
name = "benches"
harness = false
[build-dependencies] [build-dependencies]
anyhow = "1.0.65" anyhow = "1.0.65"

View file

@ -0,0 +1,97 @@
use std::time::Duration;
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use valence_protocol::block::{PropName, PropValue};
use valence_protocol::{BlockKind, BlockState, ItemKind};
criterion_group! {
name = benches;
config = Criterion::default()
.measurement_time(Duration::from_secs(3));
targets = blocks
}
criterion_main!(benches);
fn blocks(c: &mut Criterion) {
let states = BlockKind::ALL.map(BlockKind::to_state);
c.bench_function("BlockState::from_kind", |b| {
b.iter(|| {
for kind in black_box(BlockKind::ALL) {
black_box(BlockState::from_kind(kind));
}
});
});
c.bench_function("BlockState::to_kind", |b| {
b.iter(|| {
for state in black_box(states) {
black_box(state.to_kind());
}
});
});
c.bench_function("BlockState::get", |b| {
b.iter(|| {
for state in black_box(states) {
black_box(state.get(PropName::Note));
}
});
});
c.bench_function("BlockState::set", |b| {
b.iter(|| {
for state in black_box(states) {
black_box(state.set(PropName::Note, PropValue::Didgeridoo));
}
});
});
c.bench_function("BlockState::is_liquid", |b| {
b.iter(|| {
for state in black_box(states) {
black_box(state.is_liquid());
}
});
});
c.bench_function("BlockState::is_opaque", |b| {
b.iter(|| {
for state in black_box(states) {
black_box(state.is_opaque());
}
})
});
c.bench_function("BlockState::is_replaceable", |b| {
b.iter(|| {
for state in black_box(states) {
black_box(state.is_replaceable());
}
})
});
c.bench_function("BlockState::luminance", |b| {
b.iter(|| {
for state in black_box(states) {
black_box(state.luminance());
}
})
});
c.bench_function("BlockKind::to_item_kind", |b| {
b.iter(|| {
for kind in black_box(BlockKind::ALL) {
black_box(kind.to_item_kind());
}
});
});
c.bench_function("BlockKind::from_item_kind", |b| {
b.iter(|| {
for kind in black_box(ItemKind::ALL) {
black_box(BlockKind::from_item_kind(kind));
}
});
});
}

View file

@ -2,7 +2,7 @@ use std::collections::BTreeSet;
use heck::{ToPascalCase, ToShoutySnakeCase}; use heck::{ToPascalCase, ToShoutySnakeCase};
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::quote; use quote::{quote, ToTokens};
use serde::Deserialize; use serde::Deserialize;
use crate::ident; use crate::ident;
@ -80,12 +80,22 @@ pub fn build() -> anyhow::Result<TokenStream> {
let state_to_kind_arms = blocks let state_to_kind_arms = blocks
.iter() .iter()
.map(|b| { .map(|b| {
let min = b.min_state_id();
let max = b.max_state_id();
let name = ident(b.name.to_pascal_case()); let name = ident(b.name.to_pascal_case());
quote! { let mut token_stream = TokenStream::new();
#min..=#max => BlockKind::#name,
let min_id = b.min_state_id();
let max_id = b.max_state_id();
if min_id == max_id {
quote!(#min_id).to_tokens(&mut token_stream);
} else {
for id in min_id..max_id {
quote!(#id | ).to_tokens(&mut token_stream);
}
quote!(#max_id).to_tokens(&mut token_stream);
} }
quote!(=> BlockKind::#name,).to_tokens(&mut token_stream);
token_stream
}) })
.collect::<TokenStream>(); .collect::<TokenStream>();