Skip to content

Commit ddaa4e7

Browse files
committed
bench: bot moving around benchmark
Add benchmarks for the server with bots moving around. Possible limitation: - no check to determine if all the packets have been processed ``` players fastest │ slowest │ median │ mean │ samples │ iters ╰─ n_bots_moving │ │ │ │ │ ├─ 1 34.45 µs │ 397.2 µs │ 109.1 µs │ 118.2 µs │ 100 │ 100 │ alloc: │ │ │ │ │ │ 7 │ 0 │ 7 │ 7.1 │ │ │ 1.328 KB │ 0 B │ 1.328 KB │ 1.365 KB │ │ │ dealloc: │ │ │ │ │ │ 5 │ 0 │ 5 │ 5.1 │ │ │ 1.312 KB │ 0 B │ 1.312 KB │ 1.378 KB │ │ │ grow: │ │ │ │ │ │ 2 │ 0 │ 2 │ 2.14 │ │ │ 128 B │ 0 B │ 128 B │ 1.057 KB │ │ ├─ 2 82.87 µs │ 460.6 µs │ 168.4 µs │ 179.2 µs │ 100 │ 100 │ alloc: │ │ │ │ │ │ 8 │ 8 │ 9 │ 8.38 │ │ │ 1.336 KB │ 1.336 KB │ 1.347 KB │ 1.483 KB │ │ │ dealloc: │ │ │ │ │ │ 5 │ 5 │ 6 │ 5.29 │ │ │ 1.312 KB │ 1.312 KB │ 1.327 KB │ 1.427 KB │ │ │ grow: │ │ │ │ │ │ 3 │ 3 │ 4 │ 3.23 │ │ │ 192 B │ 192 B │ 45.06 KB │ 1.789 KB │ │ ├─ 4 109.7 µs │ 512.8 µs │ 213.4 µs │ 226 µs │ 100 │ 100 │ alloc: │ │ │ │ │ │ 10 │ 10 │ 10 │ 10.81 │ │ │ 1.352 KB │ 1.352 KB │ 1.352 KB │ 1.507 KB │ │ │ dealloc: │ │ │ │ │ │ 5 │ 5 │ 5 │ 5.74 │ │ │ 1.312 KB │ 1.312 KB │ 1.312 KB │ 1.488 KB │ │ │ grow: │ │ │ │ │ │ 5 │ 8 │ 5 │ 5.74 │ │ │ 320 B │ 134.2 KB │ 576 B │ 2.431 KB │ │ ├─ 8 109.8 µs │ 657.4 µs │ 302 µs │ 319.9 µs │ 100 │ 100 │ alloc: │ │ │ │ │ │ 27 │ 23 │ 25 │ 25.44 │ │ │ 3.012 KB │ 2.914 KB │ 2.953 KB │ 3.026 KB │ │ │ dealloc: │ │ │ │ │ │ 17 │ 13 │ 15 │ 15.63 │ │ │ 3.154 KB │ 2.958 KB │ 3.037 KB │ 3.616 KB │ │ │ grow: │ │ │ │ │ │ 22 │ 18 │ 19 │ 19.07 │ │ │ 862 B │ 32.11 KB │ 804 B │ 4.332 KB │ │ ├─ 16 93.83 µs │ 636.2 µs │ 266 µs │ 270.1 µs │ 100 │ 100 │ alloc: │ │ │ │ │ │ 31 │ 31 │ 32 │ 30 │ │ │ 3.539 KB │ 3.508 KB │ 3.545 KB │ 3.586 KB │ │ │ dealloc: │ │ │ │ │ │ 19 │ 28 │ 20 │ 18.05 │ │ │ 3.679 KB │ 27.84 KB │ 3.685 KB │ 3.887 KB │ │ │ grow: │ │ │ │ │ │ 25 │ 24 │ 25 │ 24.14 │ │ │ 1.004 KB │ 63.65 KB │ 1.004 KB │ 8.453 KB │ │ ├─ 32 244 µs │ 1.012 ms │ 505.7 µs │ 537.4 µs │ 100 │ 100 │ alloc: │ │ │ │ │ │ 29 │ 29 │ 27 │ 27.96 │ │ │ 4.522 KB │ 4.522 KB │ 4.478 KB │ 4.626 KB │ │ │ dealloc: │ │ │ │ │ │ 17 │ 17 │ 15 │ 16.48 │ │ │ 4.606 KB │ 4.606 KB │ 4.506 KB │ 6.316 KB │ │ │ grow: │ │ │ │ │ │ 32 │ 33 │ 29 │ 31.55 │ │ │ 1.668 KB │ 46.2 KB │ 1.612 KB │ 25.45 KB │ │ ├─ 64 228.9 µs │ 915.9 µs │ 531.2 µs │ 526.4 µs │ 100 │ 100 │ alloc: │ │ │ │ │ │ 46 │ 43 │ 43 │ 43.78 │ │ │ 9.44 KB │ 7.863 KB │ 7.848 KB │ 7.995 KB │ │ │ dealloc: │ │ │ │ │ │ 33 │ 31 │ 31 │ 32.33 │ │ │ 8.382 KB │ 8.283 KB │ 8.24 KB │ 10.5 KB │ │ │ grow: │ │ │ │ │ │ 66 │ 64 │ 62 │ 64.76 │ │ │ 3.918 KB │ 3.876 KB │ 3.848 KB │ 19.57 KB │ │ ├─ 128 216.6 µs │ 1.871 ms │ 406.3 µs │ 472.5 µs │ 100 │ 100 │ alloc: │ │ │ │ │ │ 61 │ 61 │ 65 │ 65.4 │ │ │ 14.41 KB │ 14.38 KB │ 15.18 KB │ 14.55 KB │ │ │ dealloc: │ │ │ │ │ │ 49 │ 49 │ 53 │ 54.63 │ │ │ 15.36 KB │ 15.28 KB │ 15.34 KB │ 23.73 KB │ │ │ grow: │ │ │ │ │ │ 105 │ 102 │ 102 │ 103.9 │ │ │ 7.86 KB │ 7.804 KB │ 7.829 KB │ 83.93 KB │ │ ╰─ 256 413.2 µs │ 1.839 ms │ 777.6 µs │ 797.6 µs │ 100 │ 100 alloc: │ │ │ │ │ 51 │ 55 │ 54 │ 52.75 │ │ 26.43 KB │ 26.49 KB │ 27.29 KB │ 26.6 KB │ │ dealloc: │ │ │ │ │ 39 │ 43 │ 42 │ 41.11 │ │ 27.02 KB │ 27.13 KB │ 27.26 KB │ 29.37 KB │ │ grow: │ │ │ │ │ 97 │ 102 │ 105 │ 100.6 │ │ 14.41 KB │ 129.8 KB │ 88.11 KB │ 32.09 KB │ │ ```
1 parent 59e19b9 commit ddaa4e7

File tree

10 files changed

+163
-32
lines changed

10 files changed

+163
-32
lines changed

Cargo.lock

Lines changed: 35 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ chunk = { path = "crates/chunk" }
3838
generator = { path = "crates/generator" }
3939
generator-build = { path = "crates/generator-build" }
4040
rayon-local = { path = "crates/rayon-local" }
41+
rust-mc-bot = { git = "https://github.com/andrewgazelka/rust-mc-bot", branch = "optimize" }
4142
glam = "0.26.0"
4243

4344
#evenio = { git = "https://github.com/andrewgazelka/evenio", features = ["rayon"], branch = "fix-collisions-gt-2" }

crates/server/Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,17 @@ io-uring = "0.6.3"
6767

6868
[dev-dependencies]
6969
divan = "0.1.14"
70+
rust-mc-bot.workspace = true
7071
tango-bench = "0.4.0"
7172

7273
[[bench]]
7374
name = "many_zombies"
7475
harness = false
7576

77+
[[bench]]
78+
name = "players"
79+
harness = false
80+
7681
[lints.clippy]
7782
complexity = "deny"
7883

crates/server/benches/players.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use std::{net::SocketAddr, sync::atomic::AtomicU16};
2+
3+
use divan::Bencher;
4+
use libc::{getrlimit, setrlimit, RLIMIT_NOFILE};
5+
use rust_mc_bot::{Address, BotManager};
6+
use server::Game;
7+
8+
static PORT: AtomicU16 = AtomicU16::new(25565);
9+
10+
fn adjust_file_limits() {
11+
unsafe {
12+
let mut limits = libc::rlimit {
13+
rlim_cur: 0, // Initialize soft limit to 0
14+
rlim_max: 0, // Initialize hard limit to 0
15+
};
16+
17+
if getrlimit(RLIMIT_NOFILE, &mut limits) == 0 {
18+
println!("Current soft limit: {}", limits.rlim_cur);
19+
println!("Current hard limit: {}", limits.rlim_max);
20+
} else {
21+
eprintln!("Failed to get the maximum number of open file descriptors");
22+
}
23+
24+
limits.rlim_cur = limits.rlim_max;
25+
println!("Setting soft limit to: {}", limits.rlim_cur);
26+
27+
if setrlimit(RLIMIT_NOFILE, &limits) != 0 {
28+
eprintln!("Failed to set the maximum number of open file descriptors");
29+
}
30+
}
31+
}
32+
33+
fn main() {
34+
// get current limit
35+
36+
adjust_file_limits();
37+
38+
divan::main();
39+
}
40+
41+
const PLAYER_COUNTS: &[u32] = &[1, 2, 4, 8, 16, 32, 64, 128, 256];
42+
43+
#[divan::bench(
44+
args = PLAYER_COUNTS,
45+
)]
46+
fn n_bots_moving(bencher: Bencher, player_count: u32) {
47+
let port = PORT.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
48+
let addr = SocketAddr::from(([127, 0, 0, 1], port));
49+
50+
let mut game = Game::init(addr).unwrap();
51+
52+
let addrs = Address::TCP(addr);
53+
let mut bot_manager = BotManager::create(player_count, addrs, 0, 1).unwrap();
54+
55+
loop {
56+
game.tick();
57+
bot_manager.tick();
58+
59+
if game
60+
.shared()
61+
.player_count
62+
.load(std::sync::atomic::Ordering::Relaxed)
63+
== player_count
64+
{
65+
break;
66+
}
67+
}
68+
69+
// we have completed the login sequence for all bots, now we can start benchmarking
70+
71+
bencher.bench_local(|| {
72+
game.tick();
73+
bot_manager.tick();
74+
});
75+
76+
game.shutdown();
77+
}

crates/server/src/global.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::sync::atomic::AtomicU32;
1+
use std::sync::{atomic::AtomicU32, Arc};
22

33
use evenio::component::Component;
44

@@ -10,11 +10,5 @@ pub struct Shared {
1010
#[derive(Component)]
1111
pub struct Global {
1212
pub tick: i64,
13-
}
14-
15-
#[expect(clippy::derivable_impls, reason = "default impl for explicitness")]
16-
impl Default for Global {
17-
fn default() -> Self {
18-
Self { tick: 0 }
19-
}
13+
pub shared: Arc<Shared>,
2014
}

crates/server/src/lib.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::{
99
cell::UnsafeCell,
1010
collections::VecDeque,
1111
net::ToSocketAddrs,
12-
sync::atomic::AtomicU32,
12+
sync::{atomic::AtomicU32, Arc},
1313
time::{Duration, Instant},
1414
};
1515

@@ -25,7 +25,7 @@ use valence_protocol::{math::Vec3, ByteAngle, VarInt};
2525

2626
use crate::{
2727
bounding_box::BoundingBox,
28-
net::{start_io_thread, ClientConnection, Packets, GLOBAL_C2S_PACKETS},
28+
net::{init_io_thread, ClientConnection, Packets, GLOBAL_C2S_PACKETS},
2929
singleton::{
3030
encoder::{Encoder, PacketMetadata, PacketNecessity},
3131
player_location_lookup::PlayerLocationLookup,
@@ -125,11 +125,8 @@ struct Gametick;
125125
#[derive(Event)]
126126
struct BroadcastPackets;
127127

128-
static SHARED: global::Shared = global::Shared {
129-
player_count: AtomicU32::new(0),
130-
};
131-
132128
pub struct Game {
129+
shared: Arc<global::Shared>,
133130
world: World,
134131
last_ticks: VecDeque<Instant>,
135132
last_ms_per_tick: VecDeque<f64>,
@@ -143,6 +140,10 @@ impl Game {
143140
&self.world
144141
}
145142

143+
pub const fn shared(&self) -> &Arc<global::Shared> {
144+
&self.shared
145+
}
146+
146147
pub fn world_mut(&mut self) -> &mut World {
147148
&mut self.world
148149
}
@@ -190,7 +191,11 @@ impl Game {
190191
}
191192
});
192193

193-
let incoming = start_io_thread(shutdown_rx, address)?;
194+
let shared = Arc::new(global::Shared {
195+
player_count: AtomicU32::new(0),
196+
});
197+
198+
let incoming = init_io_thread(shutdown_rx, address, shared.clone())?;
194199

195200
let mut world = World::new();
196201

@@ -212,7 +217,10 @@ impl Game {
212217
world.add_handler(system::kill_all);
213218

214219
let global = world.spawn();
215-
world.insert(global, global::Global::default());
220+
world.insert(global, global::Global {
221+
tick: 0,
222+
shared: shared.clone(),
223+
});
216224

217225
let bounding_boxes = world.spawn();
218226
world.insert(bounding_boxes, bounding_box::EntityBoundingBoxes::default());
@@ -227,6 +235,7 @@ impl Game {
227235
world.insert(encoder, Encoder::default());
228236

229237
let mut game = Self {
238+
shared,
230239
world,
231240
last_ticks: VecDeque::default(),
232241
last_ms_per_tick: VecDeque::default(),

crates/server/src/net.rs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use valence_protocol::{
3737
};
3838
use valence_registry::RegistryCodec;
3939

40-
use crate::{config, SHARED};
40+
use crate::{config, global};
4141

4242
const DEFAULT_SPEED: u32 = 1024 * 1024;
4343

@@ -76,6 +76,7 @@ pub struct Io {
7676
dec: PacketDecoder,
7777
enc: PacketEncoder,
7878
frame: PacketFrame,
79+
shared: Arc<global::Shared>,
7980
}
8081

8182
pub struct IoWrite {
@@ -266,7 +267,7 @@ impl Io {
266267
}
267268
}
268269

269-
fn new(stream: TcpStream) -> Self {
270+
fn new(stream: TcpStream, shared: Arc<global::Shared>) -> Self {
270271
Self {
271272
stream,
272273
dec: PacketDecoder::default(),
@@ -275,6 +276,7 @@ impl Io {
275276
id: 0,
276277
body: BytesMut::new(),
277278
},
279+
shared,
278280
}
279281
}
280282

@@ -463,7 +465,7 @@ impl Io {
463465
debug!("status");
464466
let status::QueryRequestC2s = self.recv_packet().await?;
465467

466-
let player_count = SHARED.player_count.load(Ordering::Relaxed);
468+
let player_count = self.shared.player_count.load(Ordering::Relaxed);
467469

468470
// 64x64 pixels image
469471
let bytes = include_bytes!("saul.png");
@@ -521,7 +523,11 @@ async fn print_errors(future: impl core::future::Future<Output = anyhow::Result<
521523
pub static GLOBAL_C2S_PACKETS: spin::Mutex<Vec<UserPacketFrame>> = spin::Mutex::new(Vec::new());
522524

523525
#[instrument(skip_all)]
524-
async fn io_thread(tx: flume::Sender<ClientConnection>, address: impl ToSocketAddrs) {
526+
async fn main_loop(
527+
tx: flume::Sender<ClientConnection>,
528+
address: impl ToSocketAddrs,
529+
shared: Arc<global::Shared>,
530+
) {
525531
let listener = match TcpListener::bind(address) {
526532
Ok(listener) => listener,
527533
Err(e) => {
@@ -542,7 +548,7 @@ async fn io_thread(tx: flume::Sender<ClientConnection>, address: impl ToSocketAd
542548
}
543549
};
544550

545-
let process = Io::new(stream);
551+
let process = Io::new(stream, shared.clone());
546552

547553
let tx = tx.clone();
548554

@@ -553,9 +559,10 @@ async fn io_thread(tx: flume::Sender<ClientConnection>, address: impl ToSocketAd
553559
}
554560
}
555561

556-
pub fn start_io_thread(
562+
pub fn init_io_thread(
557563
shutdown: flume::Receiver<()>,
558564
address: impl ToSocketAddrs + Send + Sync + 'static,
565+
shared: Arc<global::Shared>,
559566
) -> anyhow::Result<flume::Receiver<ClientConnection>> {
560567
let (connection_tx, connection_rx) = flume::unbounded();
561568

@@ -567,7 +574,7 @@ pub fn start_io_thread(
567574
.unwrap();
568575

569576
runtime.block_on(async move {
570-
let run = io_thread(connection_tx, address);
577+
let run = main_loop(connection_tx, address, shared);
571578
let shutdown = shutdown.recv_async();
572579

573580
monoio::select! {

crates/server/src/system/player_join_world.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,13 @@ use crate::{
2929
bits::BitStorage,
3030
chunk::heightmap,
3131
config,
32+
global::Global,
3233
singleton::{
3334
encoder::{Encoder, PacketMetadata},
3435
player_lookup::PlayerUuidLookup,
3536
},
3637
system::init_entity::spawn_packet,
37-
FullEntityPose, MinecraftEntity, Player, PlayerJoinWorld, Uuid, SHARED,
38+
FullEntityPose, MinecraftEntity, Player, PlayerJoinWorld, Uuid,
3839
};
3940

4041
#[derive(Query, Debug)]
@@ -49,6 +50,7 @@ pub(crate) struct EntityQuery<'a> {
4950
pub fn player_join_world(
5051
r: Receiver<PlayerJoinWorld, (EntityId, &mut Player, &Uuid)>,
5152
entities: Fetcher<EntityQuery>,
53+
global: Single<&Global>,
5254
lookup: Single<&mut PlayerUuidLookup>,
5355
encoder: Single<&mut Encoder>,
5456
) {
@@ -75,7 +77,9 @@ pub fn player_join_world(
7577
all_entities.append_packet(&pkt).unwrap();
7678
}
7779

78-
SHARED
80+
global
81+
.0
82+
.shared
7983
.player_count
8084
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
8185

0 commit comments

Comments
 (0)