Skip to content

Commit

Permalink
Refactor benchmarking code and remove unused chunk_io benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
Mili committed Mar 2, 2025
1 parent 9857b1d commit 3bc764d
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 45 deletions.
4 changes: 0 additions & 4 deletions pumpkin-world/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,3 @@ temp-dir = "0.1.14"
[[bench]]
name = "chunk_noise_populate"
harness = false

[[bench]]
name = "chunk_io"
harness = false
1 change: 1 addition & 0 deletions pumpkin-world/benches/bench_root/session.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1 change: 0 additions & 1 deletion pumpkin-world/benches/chunk_io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ fn criterion_benchmark(c: &mut Criterion) {

/// This is the code to run the test
/// with out BulkAPI PR.
///
// fn criterion_benchmark(c: &mut Criterion) {
// let temp_dir = TempDir::new().unwrap();
// let level = Arc::new(Dimension::OverWorld.into_level(temp_dir.path().to_path_buf()));
Expand Down
79 changes: 48 additions & 31 deletions pumpkin-world/benches/chunk_noise_populate.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::{fs, path::PathBuf, sync::Arc};
use std::{fs, num::NonZeroU8, path::PathBuf, sync::Arc};

use criterion::{Criterion, criterion_group, criterion_main};
use pumpkin_util::math::vector2::Vector2;
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
use pumpkin_util::math::{position, vector2::Vector2};
use pumpkin_world::{
GlobalProtoNoiseRouter, GlobalRandomConfig, NOISE_ROUTER_ASTS, bench_create_and_populate_noise,
chunk::ChunkData, global_path, level::Level,
chunk::ChunkData, cylindrical_chunk_iterator::Cylindrical, global_path, level::Level,
};
use temp_dir::TempDir;
use tokio::sync::RwLock;

fn bench_populate_noise(c: &mut Criterion) {
Expand All @@ -19,50 +20,51 @@ fn bench_populate_noise(c: &mut Criterion) {
});
}

const MIN_POS: i32 = -4;
const MAX_POS: i32 = 4;

async fn test_reads(root_dir: PathBuf, positions: &[Vector2<i32>]) {
let level = Level::from_root_folder(root_dir);
async fn test_reads(level: Arc<Level>, positions: Vec<Vector2<i32>>) {
let (send, mut recv) = tokio::sync::mpsc::channel(positions.len());

let fetching_level = level.clone();
tokio::spawn(async move { fetching_level.fetch_chunks(&positions, send).await });

let rt = tokio::runtime::Handle::current();
let (send, mut recv) = tokio::sync::mpsc::channel(10);
level.fetch_chunks(positions, send, &rt);
while let Some(x) = recv.recv().await {
// Don't compile me away!
let _ = x;
}
level.clean_memory();
}

async fn test_writes(root_dir: PathBuf, chunks: &[(Vector2<i32>, Arc<RwLock<ChunkData>>)]) {
let level = Level::from_root_folder(root_dir);
for (pos, chunk) in chunks {
level.write_chunk((*pos, chunk.clone())).await;
}
async fn test_writes(level: Arc<Level>, chunks: Vec<(Vector2<i32>, Arc<RwLock<ChunkData>>)>) {
level.write_chunks(chunks).await;
}

// Depends on config options from `./config`
fn bench_chunk_io(c: &mut Criterion) {
// System temp dirs are in-memory, so we cant use temp_dir
let root_dir = global_path!("./bench_root");
fs::create_dir(&root_dir).unwrap();
let temp_dir = TempDir::new().unwrap();
let root_dir = temp_dir.path().to_path_buf();

let chunk_positions =
(MIN_POS..=MAX_POS).flat_map(|x| (MIN_POS..=MAX_POS).map(move |z| Vector2::new(x, z)));
let async_handler = tokio::runtime::Builder::new_current_thread()
.build()
.unwrap();
let level = Arc::new(Level::from_root_folder(root_dir.clone()));

println!("Initializing data...");
// Initial writes
let mut chunks = Vec::new();
let mut positions = Vec::new();

async_handler.block_on(async {
let rt = tokio::runtime::Handle::current();
let (send, mut recv) = tokio::sync::mpsc::channel(10);
// Our data dir is empty, so we're generating new chunks here
let level = Level::from_root_folder(root_dir.clone());
level.fetch_chunks(&chunk_positions.collect::<Vec<_>>(), send, &rt);
let level = level.clone();
tokio::spawn(async move {
let cylindrical = Cylindrical::new(Vector2::new(0, 0), NonZeroU8::new(32).unwrap());
let chunk_positions = cylindrical.all_chunks_within();
level.fetch_chunks(&chunk_positions, send).await;
level.clean_chunks(&chunk_positions).await;
level.clean_memory();
});
while let Some((chunk, _)) = recv.recv().await {
let pos = chunk.read().await.position;
chunks.push((pos, chunk));
Expand All @@ -71,16 +73,31 @@ fn bench_chunk_io(c: &mut Criterion) {
});
println!("Testing with {} chunks", chunks.len());

chunks.sort_unstable_by_key(|chunk| chunk.0.x * chunk.0.x + chunk.0.z * chunk.0.z);
positions.sort_unstable_by_key(|pos| pos.x * pos.x + pos.z * pos.z);

// These test worst case: no caching done by `Level`
c.bench_function("write chunks", |b| {
b.to_async(&async_handler)
.iter(|| test_writes(root_dir.clone(), &chunks))
});
for n_chunks in vec![8, 32, 128] {
let chunks = &chunks[..n_chunks];
let positions = &positions[..n_chunks];
c.bench_with_input(
BenchmarkId::new("write_chunks", n_chunks),
&chunks,
|b, chunks| {
b.to_async(&async_handler)
.iter(|| test_writes(level.clone(), chunks.to_vec()))
},
);

c.bench_function("read chunks", |b| {
b.to_async(&async_handler)
.iter(|| test_reads(root_dir.clone(), &positions))
});
c.bench_with_input(
BenchmarkId::new("read_chunks", n_chunks),
&positions,
|b, positions| {
b.to_async(&async_handler)
.iter(|| test_reads(level.clone(), positions.to_vec()))
},
);
}

fs::remove_dir_all(&root_dir).unwrap();
}
Expand Down
16 changes: 7 additions & 9 deletions pumpkin-world/src/level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ impl Level {
self.loaded_chunks.shrink_to_fit();
}
}

pub async fn write_chunks(&self, chunks_to_write: Vec<(Vector2<i32>, Arc<RwLock<ChunkData>>)>) {
if chunks_to_write.is_empty() {
return;
Expand All @@ -290,14 +290,12 @@ impl Level {
let level_folder = self.level_folder.clone();

trace!("Writing chunks to disk {:}", chunks_to_write.len());
tokio::spawn(async move {
if let Err(error) = chunk_saver
.save_chunks(&level_folder, chunks_to_write)
.await
{
log::error!("Failed writing Chunk to disk {}", error.to_string());
}
});
if let Err(error) = chunk_saver
.save_chunks(&level_folder, chunks_to_write)
.await
{
log::error!("Failed writing Chunk to disk {}", error.to_string());
}
}

async fn load_chunks_from_save(
Expand Down

0 comments on commit 3bc764d

Please sign in to comment.