Skip to content

Commit

Permalink
perf: use true thread_local (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewgazelka authored Mar 26, 2024
1 parent 763e357 commit 72d6248
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 22 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ jemalloc-ctl = "0.5.4"
# jemalloc uses significantly less memory
#mimalloc = { version = "0.1.39" , default-features = false }

thread_local = { version = "1.1.8", features = ["nightly"] }


[lints.rust]
warnings = "deny"

Expand Down
2 changes: 1 addition & 1 deletion server/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ impl Game {
world.insert(bounding_boxes, bounding_box::EntityBoundingBoxes::default());

let encoder = world.spawn();
world.insert(encoder, Encoder::default());
world.insert(encoder, Encoder);

let mut game = Self {
world,
Expand Down
78 changes: 65 additions & 13 deletions server/src/singleton/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,64 @@
// https://matklad.github.io/2020/10/03/fast-thread-locals-in-rust.html
use std::cell::UnsafeCell;

use anyhow::ensure;
use bytes::{BufMut, Bytes};
use evenio::component::Component;
use thread_local::ThreadLocal;
use valence_protocol::{Encode, Packet, PacketEncoder};
use valence_protocol::{Encode, Packet, VarInt};

#[derive(Default, Component)]
pub struct Encoder {
local: ThreadLocal<UnsafeCell<PacketEncoder>>,
#[derive(Default)]
struct ConstPacketEncoder {
buf: Vec<u8>,
}

impl ConstPacketEncoder {
pub const fn new() -> Self {
Self { buf: Vec::new() }
}

pub fn append_packet<P>(&mut self, pkt: &P) -> anyhow::Result<()>
where
P: Packet + Encode,
{
let start_len = self.buf.len();

pkt.encode_with_id((&mut self.buf).writer())?;

let data_len = self.buf.len() - start_len;

let packet_len = data_len;

ensure!(
packet_len <= valence_protocol::MAX_PACKET_SIZE as usize,
"packet exceeds maximum length"
);

#[allow(clippy::cast_possible_wrap)]
let packet_len_size = VarInt(packet_len as i32).written_size();

self.buf.put_bytes(0, packet_len_size);
self.buf
.copy_within(start_len..start_len + data_len, start_len + packet_len_size);

#[allow(clippy::indexing_slicing)]
let front = &mut self.buf[start_len..];

#[allow(clippy::cast_possible_wrap)]
VarInt(packet_len as i32).encode(front)?;

Ok(())
}
}

#[thread_local]
static ENCODER: UnsafeCell<ConstPacketEncoder> = UnsafeCell::new(ConstPacketEncoder::new());

#[derive(Component)]
pub struct Encoder;

impl Encoder {
#[allow(clippy::unused_self)]
pub fn append<P: Packet + Encode>(&self, packet: &P) -> anyhow::Result<()> {
let encoder = self.local.get_or_default();

// Safety:
// The use of `unsafe` here is justified by the guarantees provided by the `ThreadLocal` and
// `UnsafeCell` usage patterns:
Expand All @@ -34,15 +79,22 @@ impl Encoder {
// Therefore, the use of `unsafe` is encapsulated within this method and does not leak
// unsafe guarantees to the caller, provided the `Encoder` struct itself is used in a
// thread-safe manner.
let encoder = unsafe { &mut *encoder.get() };
let encoder = unsafe { &mut *ENCODER.get() };
encoder.append_packet(packet)
}

pub fn drain(&mut self) -> impl Iterator<Item = bytes::Bytes> + '_ {
self.local.iter_mut().map(|encoder| {
let encoder = encoder.get_mut();
encoder.take().freeze()
})
#[allow(clippy::unused_self)]
pub fn par_drain<F>(&self, f: F)
where
F: Fn(Bytes) + Sync,
{
rayon::broadcast(move |_| {
// Safety:
// ditto
let encoder = unsafe { &mut *ENCODER.get() };
let buf = core::mem::take(&mut encoder.buf);
f(Bytes::from(buf));
});
}
}

Expand Down
8 changes: 4 additions & 4 deletions server/src/system/entity_move_logic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,9 @@ pub fn entity_move_logic(
encoder.append(&look).unwrap();
});

for bytes in encoder.drain() {
player.par_iter().for_each(|(_, player, _)| {
encoder.par_drain(|bytes| {
for (_, player, _) in &player {
let _ = player.packets.writer.send_raw(bytes.clone());
});
}
}
});
}

0 comments on commit 72d6248

Please sign in to comment.