From 069291d6d883707172abda43c2f0ccda2aec70ab Mon Sep 17 00:00:00 2001 From: Clar Fon <15850505+clarfonthey@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:15:00 -0400 Subject: [PATCH] Reduce compile time of bevy_ptr::OwnedPtr::make function (#15644) ## Methodology A good metric that correlates with compile time is the amount of code generated by the compiler itself; even if the end binary is exactly the same size, having more copies of the same code can really slow down compile time, since it has to figure out whether it needs to include them or not. The measurement for this used was the [`cargo-llvm-lines` crate](https://docs.rs/crate/cargo-llvm-lines) which can measure which functions are generating the most lines of LLVM IR, which generally means more code compiled. The example compiled was the `breakout` game, to choose something that touches a decent portion of the engine. ## Solution Based upon the measurements, `bevy_ptr::OwnedPtr::make` was taking up 4061 lines of LLVM IR in the example code. So, I separated part of this function into a less-monomorphised version to reduce the amount of generated code. This was by far the most lines emitted by any single function. ## Results After this change, only 2560 lines are emitted, accounting for a 36% decrease. I tried timing the results and it seemed like it did decrease compile times a bit, but honestly, the data is really noisy and I can't be bothered to compile bevy for hours on end to get enough data points. The tweak feels like an improvement, so, I'll offer it, however small. --- crates/bevy_ptr/src/lib.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ptr/src/lib.rs b/crates/bevy_ptr/src/lib.rs index f816b35be6..d767a25d4c 100644 --- a/crates/bevy_ptr/src/lib.rs +++ b/crates/bevy_ptr/src/lib.rs @@ -397,13 +397,23 @@ impl<'a, T: ?Sized> From<&'a mut T> for PtrMut<'a> { } impl<'a> OwningPtr<'a> { + /// This exists mostly to reduce compile times; + /// code is only duplicated per type, rather than per function called. + /// + /// # Safety + /// + /// Safety constraints of [`PtrMut::promote`] must be upheld. + unsafe fn make_internal(temp: &mut ManuallyDrop) -> OwningPtr<'_> { + // SAFETY: The constraints of `promote` are upheld by caller. + unsafe { PtrMut::from(&mut *temp).promote() } + } + /// Consumes a value and creates an [`OwningPtr`] to it while ensuring a double drop does not happen. #[inline] pub fn make) -> R, R>(val: T, f: F) -> R { - let mut temp = ManuallyDrop::new(val); // SAFETY: The value behind the pointer will not get dropped or observed later, // so it's safe to promote it to an owning pointer. - f(unsafe { PtrMut::from(&mut *temp).promote() }) + f(unsafe { Self::make_internal(&mut ManuallyDrop::new(val)) }) } }