Skip to content

Commit ca9fcfb

Browse files
committed
Added uninitialized memory optimization
- When the unsafe_optimizations flag is toggled on uninitialized memory is allocated to avoid zeroing the array of AABBs for all the boxes, this improves performance when building an index
1 parent 84d4140 commit ca9fcfb

3 files changed

Lines changed: 21 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ All notable changes to the static_aabb2d_index crate will be documented in this
1313
1_000_000 items).
1414
- Avoid some allocations when building an index by determining the exact length of the
1515
`level_bounds` array before constructing it (performance improvement).
16+
- Added uninitialized memory optimization when the feature flag `unsafe_optimizations` is on. This
17+
further improves performance when building an index by avoiding zeroing the array of AABBs
18+
allocated for the all the boxes. Care was taken to avoid undefined behavior due to reading from or
19+
creating references to any uninitialized memory.
1620

1721
## 1.0.0 - 2023-03-02
1822

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ spatial ordering. This is a rust port of the excellent
77
[flatbush](https://github.com/mourner/flatbush) javascript library.
88

99
By default no unsafe code is used (`#![forbid(unsafe_code)]` is applied). Some unsafe optimizations
10-
can be enabled by toggling on the `unsafe_optimizations` flag.
10+
can be enabled by toggling on the `unsafe_optimizations` flag. Note the API is still safe when this
11+
flag is enabled, all optimizations are internal to the library. Currently the unsafe code is used
12+
to eliminate slice bounds checking and utilize uninitialized memory to avoid zeroing arrays when
13+
allocated.
1114

1215
## Quick Links
1316

src/static_aabb2d_index.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,15 +47,11 @@ where
4747
node_size: usize,
4848
num_items: usize,
4949
level_bounds: Box<[usize]>,
50-
/// boxes holds the tree data (all nodes and items)
5150
#[cfg(feature = "unsafe_optimizations")]
5251
boxes: Box<[std::mem::MaybeUninit<AABB<T>>]>,
5352
#[cfg(not(feature = "unsafe_optimizations"))]
5453
boxes: Box<[AABB<T>]>,
55-
/// indices is used to map from sorted indices to indices ordered according to the order items
56-
/// were added
5754
indices: Box<[usize]>,
58-
// used to keep track of the current position for boxes added
5955
pos: usize,
6056
}
6157

@@ -106,14 +102,14 @@ where
106102
node_size: usize,
107103
num_items: usize,
108104
level_bounds: Box<[usize]>,
109-
/// boxes holds the tree data (all nodes and items)
110105
boxes: Box<[AABB<T>]>,
111-
/// indices is used to map from sorted indices to indices ordered according to the order items
112-
/// were added
113106
indices: Box<[usize]>,
114107
}
115108

116-
// get_at_index and set_at_index helper functions to toggle bounds checking at compile time
109+
// Helper functions to toggle bounds checking/uninitialized memory handling. NOTE: the functions are
110+
// not marked unsafe to facilitate easy global usages since we never rely on these functions
111+
// throwing a panic (so with unsafe_optimizations feature on we assume correct bounds and
112+
// initialization).
117113
#[cfg(not(feature = "unsafe_optimizations"))]
118114
#[inline(always)]
119115
fn get_at_index<T>(container: &[T], index: usize) -> &T {
@@ -315,6 +311,7 @@ where
315311
}
316312

317313
#[cfg(feature = "unsafe_optimizations")]
314+
// SAFETY: All the item boxes are initialized (all elements from index 0 to num_items - 1).
318315
let item_boxes: &mut [AABB<T>] =
319316
unsafe { std::mem::transmute(&mut self.boxes[0..self.num_items]) };
320317

@@ -350,8 +347,12 @@ where
350347
);
351348

352349
#[cfg(feature = "unsafe_optimizations")]
350+
// SAFETY: All boxes are initialized.
353351
let boxes: Box<[AABB<T>]> = unsafe { std::mem::transmute(self.boxes) };
354352

353+
#[cfg(not(feature = "unsafe_optimizations"))]
354+
let boxes = self.boxes;
355+
355356
return Ok(StaticAABB2DIndex {
356357
node_size: self.node_size,
357358
num_items: self.num_items,
@@ -441,8 +442,12 @@ where
441442
}
442443

443444
#[cfg(feature = "unsafe_optimizations")]
445+
// SAFETY: All boxes are initialized.
444446
let boxes: Box<[AABB<T>]> = unsafe { std::mem::transmute(self.boxes) };
445447

448+
#[cfg(not(feature = "unsafe_optimizations"))]
449+
let boxes = self.boxes;
450+
446451
Ok(StaticAABB2DIndex {
447452
node_size: self.node_size,
448453
num_items: self.num_items,

0 commit comments

Comments
 (0)