diff --git a/valence_protocol/Cargo.toml b/valence_protocol/Cargo.toml index 811363b..4ce4b0b 100644 --- a/valence_protocol/Cargo.toml +++ b/valence_protocol/Cargo.toml @@ -20,14 +20,15 @@ uuid = "1.2.1" valence_derive = { version = "0.1.0", path = "../valence_derive" } valence_nbt = { version = "0.5.0", path = "../valence_nbt" } -[dev-dependencies] -rand = "0.8.5" -criterion = "0.4.0" - [[bench]] name = "benches" harness = false +[dev-dependencies] +rand = "0.8.5" +criterion = "0.4.0" +valence_protocol = { version = "0.1.0", path = ".", features = ["compression"] } + [build-dependencies] anyhow = "1.0.65" heck = "0.4.0" diff --git a/valence_protocol/benches/benches.rs b/valence_protocol/benches/benches.rs index eacb49b..00c3dec 100644 --- a/valence_protocol/benches/benches.rs +++ b/valence_protocol/benches/benches.rs @@ -1,14 +1,24 @@ 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}; +use rand::Rng; +use valence_nbt::{compound, List}; +use valence_protocol::block::{BlockKind, BlockState, PropName, PropValue}; +use valence_protocol::packets::s2c::play::{ + ChunkDataAndUpdateLight, ChunkDataAndUpdateLightEncode, SetTabListHeaderAndFooter, + TeleportEntity, +}; +use valence_protocol::text::Color; +use valence_protocol::{ + write_packet, write_packet_compressed, ByteAngle, Decode, Encode, ItemKind, + LengthPrefixedArray, PacketDecoder, PacketEncoder, TextFormat, VarInt, +}; criterion_group! { name = benches; config = Criterion::default() - .measurement_time(Duration::from_secs(3)); - targets = blocks + .measurement_time(Duration::from_secs(5)).confidence_level(0.99); + targets = blocks, packets, var_int } criterion_main!(benches); @@ -95,3 +105,251 @@ fn blocks(c: &mut Criterion) { }); }); } + +fn packets(c: &mut Criterion) { + let mut encoder = PacketEncoder::new(); + + const BLOCKS_AND_BIOMES: [u8; 2000] = [0x80; 2000]; + const SKY_LIGHT_ARRAYS: [LengthPrefixedArray; 26] = + [LengthPrefixedArray([0xff; 2048]); 26]; + + let chunk_data_packet = ChunkDataAndUpdateLightEncode { + chunk_x: 123, + chunk_z: 456, + heightmaps: &compound! { + "MOTION_BLOCKING" => List::Long(vec![123; 256]), + }, + blocks_and_biomes: BLOCKS_AND_BIOMES.as_slice(), + block_entities: &[], + trust_edges: false, + sky_light_mask: &[], + block_light_mask: &[], + empty_sky_light_mask: &[], + empty_block_light_mask: &[], + sky_light_arrays: SKY_LIGHT_ARRAYS.as_slice(), + block_light_arrays: &[], + }; + + let tab_list_header_footer_packet = SetTabListHeaderAndFooter { + header: "this".italic() + " is the " + "header".bold().color(Color::RED), + footer: "this".italic() + + " is the " + + "footer".bold().color(Color::BLUE) + + ". I am appending some extra text so that the packet goes over the compression \ + threshold.", + }; + + let teleport_entity_packet = TeleportEntity { + entity_id: VarInt(123456), + position: [123.0, 456.0, 789.0], + yaw: ByteAngle(42), + pitch: ByteAngle(69), + on_ground: true, + }; + + c.bench_function("encode_chunk_data", |b| { + b.iter(|| { + let encoder = black_box(&mut encoder); + + encoder.clear(); + encoder.append_packet(&chunk_data_packet).unwrap(); + + black_box(encoder); + }); + }); + + c.bench_function("encode_tab_list_header_footer", |b| { + b.iter(|| { + let encoder = black_box(&mut encoder); + + encoder.clear(); + encoder + .append_packet(&tab_list_header_footer_packet) + .unwrap(); + + black_box(encoder); + }); + }); + + c.bench_function("encode_teleport_entity", |b| { + b.iter(|| { + let encoder = black_box(&mut encoder); + + encoder.clear(); + encoder.append_packet(&teleport_entity_packet).unwrap(); + + black_box(encoder); + }); + }); + + encoder.set_compression(Some(256)); + + c.bench_function("encode_chunk_data_compressed", |b| { + b.iter(|| { + let encoder = black_box(&mut encoder); + + encoder.clear(); + encoder.append_packet(&chunk_data_packet).unwrap(); + + black_box(encoder); + }); + }); + + c.bench_function("encode_tab_list_header_footer_compressed", |b| { + b.iter(|| { + let encoder = black_box(&mut encoder); + + encoder.clear(); + encoder + .append_packet(&tab_list_header_footer_packet) + .unwrap(); + + black_box(encoder); + }); + }); + + c.bench_function("encode_teleport_entity_compressed", |b| { + b.iter(|| { + let encoder = black_box(&mut encoder); + + encoder.clear(); + encoder.append_packet(&teleport_entity_packet).unwrap(); + + black_box(encoder); + }); + }); + + let mut decoder = PacketDecoder::new(); + let mut packet_buf = vec![]; + + write_packet(&mut packet_buf, &chunk_data_packet).unwrap(); + + c.bench_function("decode_chunk_data", |b| { + b.iter(|| { + let decoder = black_box(&mut decoder); + + decoder.queue_slice(&packet_buf); + decoder + .try_next_packet::() + .unwrap(); + + black_box(decoder); + }); + }); + + packet_buf.clear(); + write_packet(&mut packet_buf, &tab_list_header_footer_packet).unwrap(); + + c.bench_function("decode_tab_list_header_footer", |b| { + b.iter(|| { + let decoder = black_box(&mut decoder); + + decoder.queue_slice(&packet_buf); + decoder + .try_next_packet::() + .unwrap(); + + black_box(decoder); + }); + }); + + packet_buf.clear(); + write_packet(&mut packet_buf, &teleport_entity_packet).unwrap(); + + c.bench_function("decode_teleport_entity", |b| { + b.iter(|| { + let decoder = black_box(&mut decoder); + + decoder.queue_slice(&packet_buf); + decoder.try_next_packet::().unwrap(); + + black_box(decoder); + }); + }); + + decoder.set_compression(true); + + let mut scratch = vec![]; + + packet_buf.clear(); + write_packet_compressed(&mut packet_buf, 256, &mut scratch, &chunk_data_packet).unwrap(); + + c.bench_function("decode_chunk_data_compressed", |b| { + b.iter(|| { + let decoder = black_box(&mut decoder); + + decoder.queue_slice(&packet_buf); + decoder + .try_next_packet::() + .unwrap(); + + black_box(decoder); + }); + }); + + packet_buf.clear(); + write_packet_compressed( + &mut packet_buf, + 256, + &mut scratch, + &tab_list_header_footer_packet, + ) + .unwrap(); + + c.bench_function("decode_tab_list_header_footer_compressed", |b| { + b.iter(|| { + let decoder = black_box(&mut decoder); + + decoder.queue_slice(&packet_buf); + decoder + .try_next_packet::() + .unwrap(); + + black_box(decoder); + }); + }); + + packet_buf.clear(); + write_packet_compressed(&mut packet_buf, 256, &mut scratch, &teleport_entity_packet).unwrap(); + + c.bench_function("decode_teleport_entity_compressed", |b| { + b.iter(|| { + let decoder = black_box(&mut decoder); + + decoder.queue_slice(&packet_buf); + decoder.try_next_packet::().unwrap(); + + black_box(decoder); + }); + }); +} + +fn var_int(c: &mut Criterion) { + let mut rng = rand::thread_rng(); + + c.bench_function("VarInt::encode", |b| { + b.iter_with_setup( + || rng.gen(), + |i| { + let i: i32 = black_box(i); + + let mut buf = [0; VarInt::MAX_SIZE]; + let _ = black_box(VarInt(i).encode(buf.as_mut_slice())); + }, + ); + }); + + c.bench_function("VarInt::decode", |b| { + b.iter_with_setup( + || { + let mut buf = [0; VarInt::MAX_SIZE]; + VarInt(rng.gen()).encode(buf.as_mut_slice()).unwrap(); + buf + }, + |buf| { + let mut r = black_box(buf.as_slice()); + let _ = black_box(VarInt::decode(&mut r)); + }, + ) + }); +} diff --git a/valence_protocol/src/codec.rs b/valence_protocol/src/codec.rs index 6e188c3..382fdf4 100644 --- a/valence_protocol/src/codec.rs +++ b/valence_protocol/src/codec.rs @@ -179,6 +179,10 @@ impl PacketEncoder { self.buf.split() } + pub fn clear(&mut self) { + self.buf.clear(); + } + #[cfg(feature = "compression")] pub fn set_compression(&mut self, threshold: Option) { self.compression_threshold = threshold;