From 9b9568a48f7959253897dc02c9d27c7eab9a7cb6 Mon Sep 17 00:00:00 2001 From: iximeow Date: Fri, 6 Feb 2026 07:22:52 +0000 Subject: [PATCH] awful (2): prevent alloc elimination and size better I'd tested the commit introducing this hack with one additional detail I'd overlooked: an `eprintln!("balloon: {:p}", balloon.as_ptr())`. This prevented rustc/LLVM from optimizing out the allocation. Of course, it would be unsightly to have a random `eprintln!()` committed so I removed that in the PR, not realizing the allocation was optimized out entirely. Along the way testing on a racklette showed at least one case where the balloon wasn't sufficiently large, so grow it a bit. RFD 413 estimates Propolis heap as 512 MiB at worst, which we're still under. --- bin/propolis-server/src/lib/initializer.rs | 5 +++++ bin/propolis-server/src/lib/vm/ensure.rs | 20 +++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/bin/propolis-server/src/lib/initializer.rs b/bin/propolis-server/src/lib/initializer.rs index c93908100..c082fdc3e 100644 --- a/bin/propolis-server/src/lib/initializer.rs +++ b/bin/propolis-server/src/lib/initializer.rs @@ -686,6 +686,11 @@ impl MachineInitializer<'_> { &mut wanted_heap, ) .await?; + info!( + self.log, + "raised balloon size"; + "ballon_size" => wanted_heap + ); self.block_backends.insert(backend_id.clone(), backend.clone()); let block_dev: Arc = match device_interface { diff --git a/bin/propolis-server/src/lib/vm/ensure.rs b/bin/propolis-server/src/lib/vm/ensure.rs index 022a876a9..508807167 100644 --- a/bin/propolis-server/src/lib/vm/ensure.rs +++ b/bin/propolis-server/src/lib/vm/ensure.rs @@ -664,9 +664,23 @@ async fn initialize_vm_objects( // This should be able to be removed when we are confident we can // actually brk() at runtime without starving ourselves out. // - // As one last step, include an extra 16 MiB of heap as space we might want - // when running `propolis-server`, handling HTTP requests, etc. - let balloon = vec![0u8; wanted_heap + 16 * propolis::common::MB]; + // As one last step, include an extra 134 MiB in the balloon. In the happy + // case, even just 16 MiB was sufficient for Oximeter and regular check-ins + // with Propolis. In at least one case, though, we saw a Propolis with a + // heap about 126 MiB larger than the balloon had wanted. We don't know what + // happened to grow the heap like that, but size against the worst case for + // now for safety. + // + // All in all the worst case balloon puts propolis-server's heap a bit over + // (around 483 MiB + 30MiB) the RFD 413 expectation of 0.5 GiB for Propolis + // memory. + let balloon_size = wanted_heap + 134 * propolis::common::MB; + info!(log, "inflating balloon"; + "balloon_size" => balloon_size); + let balloon = vec![0u8; balloon_size]; + // Do a volatile access to the Vec to make sure Rust doesn't optimize it + // out... + unsafe { std::ptr::read_volatile(balloon.as_ptr()) }; std::mem::drop(balloon); Ok(res)