/* Generic tree structures for storage of spatial data. * Copyright (C) 2023 Alexander Pyattaev * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion}; use rand::rngs::SmallRng; use rand::SeedableRng; use spatialtree::coords::*; use spatialtree::*; const N_LOOKUPS: usize = 40; type DataType = u8; fn generate_area_bounds(rng: &mut SmallRng, depth: u8) -> (OctVec, OctVec) { let cmax = ((1usize << depth as usize) - 1) as DataType; let min = rand_cv( rng, OctVec::new([0, 0, 0], depth), OctVec::new([cmax - 2, cmax - 2, cmax - 2], depth), ); let max = rand_cv( rng, min + OctVec::new([1, 1, 1], depth), OctVec::new([cmax, cmax, cmax], depth), ); (min, max) } struct ChuChunk { a_index: u8, b_index: u8, material_index: u16, } impl Default for ChuChunk { fn default() -> ChuChunk { ChuChunk { a_index: 1, b_index: 2, material_index: 3, } } } fn create_and_fill_octree(num_chunks: u32, depth: u8) -> OctTree { let mut rng = SmallRng::seed_from_u64(42); let mut tree: OctTree = OctTree::with_capacity(num_chunks as usize, num_chunks as usize); let cmax = ((1usize << depth as usize) - 1) as u8; for _c in 0..num_chunks { let qv: CoordVec<3> = rand_cv( &mut rng, OctVec::new([0, 0, 0], depth), OctVec::new([cmax, cmax, cmax], depth), ); tree.insert(qv, |_p| C::default()); } tree } fn bench_lookups_in_octree(tree: &OctTree, depth: u8) { let mut rng = SmallRng::seed_from_u64(42); for _ in 0..N_LOOKUPS { let (min, max) = generate_area_bounds(&mut rng, depth); for i in tree.iter_chunks_in_aabb(min, max) { black_box(i); } } } fn bench_mut_lookups_in_octree(tree: &mut OctTree, depth: u8) { let mut rng = SmallRng::seed_from_u64(42); for _ in 0..N_LOOKUPS { let (min, max) = generate_area_bounds(&mut rng, depth); for i in tree.iter_chunks_in_aabb_mut(min, max) { i.1.material_index = i.1.material_index.wrapping_add(1); i.1.a_index = i.1.a_index.wrapping_add(1); i.1.b_index = i.1.b_index.wrapping_add(1); } } } pub fn tree_iteration(c: &mut Criterion) { let mut group = c.benchmark_group("mutable iteration"); for (&depth, samples_num) in [4u8, 6, 8].iter().zip([100, 40, 10]) { group.significance_level(0.1).sample_size(samples_num); let num_chunks: u32 = 2u32.pow(depth as u32).pow(3) / 10; group.bench_with_input(BenchmarkId::from_parameter(depth), &depth, |b, &depth| { let mut tree = create_and_fill_octree::(num_chunks, depth); b.iter(|| { bench_mut_lookups_in_octree(&mut tree, depth); }); black_box(tree); }); } group.finish(); let mut group = c.benchmark_group("immutable iteration"); for (&depth, samples_num) in [4u8, 6, 8].iter().zip([100, 40, 10]) { group.significance_level(0.1).sample_size(samples_num); let num_chunks: u32 = 2u32.pow(depth as u32).pow(3) / 10; group.bench_with_input(BenchmarkId::from_parameter(depth), &depth, |b, &depth| { let tree = create_and_fill_octree::(num_chunks, depth); b.iter(|| { bench_lookups_in_octree(&tree, depth); }); }); } group.finish(); } pub fn tree_creation(c: &mut Criterion) { let mut group = c.benchmark_group("tree creation"); for (&depth, samples_num) in [4u8, 6, 8].iter().zip([100, 40, 10]) { group.significance_level(0.1).sample_size(samples_num); group.bench_with_input(BenchmarkId::from_parameter(depth), &depth, |b, &depth| { let volume = 2u32.pow(depth as u32).pow(3); let num_chunks: u32 = volume / 10; //println!("Creating {num_chunks} voxels out of {volume} possible"); b.iter(|| { let t = create_and_fill_octree::(num_chunks, depth); black_box(t); }); }); } group.finish(); } criterion_group!(benches, tree_creation, tree_iteration); criterion_main!(benches);