diff --git a/Cargo.lock b/Cargo.lock index 1a85c8b54b23..c93b19ca821e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2871,6 +2871,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "ntapi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc" +dependencies = [ + "winapi", +] + [[package]] name = "num" version = "0.4.0" @@ -3894,6 +3903,7 @@ dependencies = [ "re_format", "re_log", "smallvec", + "sysinfo", "wasm-bindgen", ] @@ -4822,6 +4832,20 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "sysinfo" +version = "0.28.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f69e0d827cce279e61c2f3399eb789271a8f136d8245edef70f06e3c9601a670" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "winapi", +] + [[package]] name = "system-deps" version = "6.0.3" diff --git a/crates/re_memory/Cargo.toml b/crates/re_memory/Cargo.toml index b05c08c9b61a..9e9a765140d9 100644 --- a/crates/re_memory/Cargo.toml +++ b/crates/re_memory/Cargo.toml @@ -33,6 +33,7 @@ smallvec = "1.10" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] backtrace = "0.3" memory-stats = "1.0" +sysinfo = { version = "0.28.3", default-features = false } # web dependencies: [target.'cfg(target_arch = "wasm32")'.dependencies] diff --git a/crates/re_memory/src/lib.rs b/crates/re_memory/src/lib.rs index 44b4701c78a3..2dcfc69d2b79 100644 --- a/crates/re_memory/src/lib.rs +++ b/crates/re_memory/src/lib.rs @@ -7,6 +7,7 @@ mod allocation_tracker; mod memory_history; mod memory_limit; mod memory_use; +mod ram_warner; pub mod util; #[cfg(not(target_arch = "wasm32"))] @@ -23,7 +24,7 @@ use backtrace_web::Backtrace; pub use { accounting_allocator::AccountingAllocator, memory_history::MemoryHistory, - memory_limit::MemoryLimit, memory_use::MemoryUse, + memory_limit::MemoryLimit, memory_use::MemoryUse, ram_warner::*, }; /// Number of allocation and their total size. diff --git a/crates/re_memory/src/ram_warner.rs b/crates/re_memory/src/ram_warner.rs new file mode 100644 index 000000000000..989cdeedc48c --- /dev/null +++ b/crates/re_memory/src/ram_warner.rs @@ -0,0 +1,61 @@ +/// Amount of available RAM on this machine. +#[cfg(not(target_arch = "wasm32"))] +pub fn total_ram_in_bytes() -> u64 { + use sysinfo::SystemExt as _; + + let mut sys = sysinfo::System::new_all(); + sys.refresh_all(); + + let total_memory = sys.total_memory(); + + re_log::debug!( + "Total RAM: {}", + re_format::format_bytes(sys.total_memory() as _) + ); + + total_memory +} + +/// Amount of available RAM on this machine. +#[cfg(target_arch = "wasm32")] +pub fn total_ram_in_bytes() -> u64 { + 1_u64 << 32 +} + +// ---------------------------------------------------------------------------- + +pub struct RamLimitWarner { + total_ram_in_bytes: u64, + limit: u64, + has_warned: bool, +} + +impl RamLimitWarner { + pub fn warn_at_fraction_of_max(fraction: f32) -> Self { + let total_ram_in_bytes = total_ram_in_bytes(); + let limit = (fraction as f64 * total_ram_in_bytes as f64).round() as _; + Self { + total_ram_in_bytes, + limit, + has_warned: false, + } + } + + /// Warns if we have exceeded the limit. + pub fn update(&mut self) { + if !self.has_warned { + let used = crate::MemoryUse::capture(); + let used = used.counted.or(used.resident); + if let Some(used) = used { + if 0 <= used && self.limit <= used as u64 { + self.has_warned = true; + re_log::warn!( + "RAM usage is {} (with a total of {} system RAM). You may want to start Rerun with the --memory-limit flag to limit RAM usage.", + re_format::format_bytes(used as _), + re_format::format_bytes(self.total_ram_in_bytes as _), + ); + } + } + } + } +} diff --git a/crates/re_viewer/Cargo.toml b/crates/re_viewer/Cargo.toml index 33d7c73da078..24a2c6ff4694 100644 --- a/crates/re_viewer/Cargo.toml +++ b/crates/re_viewer/Cargo.toml @@ -99,8 +99,8 @@ rfd = "0.11" serde = { version = "1", features = ["derive"] } slotmap = { version = "1.0.6", features = ["serde"] } smallvec = { version = "1.10", features = ["serde"] } -time = { workspace = true, default-features = false, features = ["formatting"] } thiserror.workspace = true +time = { workspace = true, default-features = false, features = ["formatting"] } uuid = { version = "1.1", features = ["serde", "v4", "js"] } vec1 = "1.8" wgpu.workspace = true diff --git a/crates/re_viewer/src/app.rs b/crates/re_viewer/src/app.rs index cbc71213c532..1d17fa48e7c9 100644 --- a/crates/re_viewer/src/app.rs +++ b/crates/re_viewer/src/app.rs @@ -57,6 +57,7 @@ const MAX_ZOOM_FACTOR: f32 = 4.0; pub struct App { build_info: re_build_info::BuildInfo, startup_options: StartupOptions, + ram_limit_warner: re_memory::RamLimitWarner, re_ui: re_ui::ReUi, /// Listens to the local text log stream @@ -127,6 +128,7 @@ impl App { Self { build_info, startup_options, + ram_limit_warner: re_memory::RamLimitWarner::warn_at_fraction_of_max(0.75), re_ui, text_log_rx, component_ui_registry: Default::default(), @@ -416,6 +418,11 @@ impl eframe::App for App { fn update(&mut self, egui_ctx: &egui::Context, frame: &mut eframe::Frame) { let frame_start = Instant::now(); + if self.startup_options.memory_limit.limit.is_none() { + // we only warn about high memory usage if the user hasn't specified a limit + self.ram_limit_warner.update(); + } + if self.icon_status == AppIconStatus::NotSetTryAgain { self.icon_status = setup_app_icon(); } diff --git a/crates/re_viewer/src/web.rs b/crates/re_viewer/src/web.rs index 28dfee609af8..eb879b32f3f7 100644 --- a/crates/re_viewer/src/web.rs +++ b/crates/re_viewer/src/web.rs @@ -33,7 +33,12 @@ pub async fn start( Box::new(move |cc| { let build_info = re_build_info::build_info!(); let app_env = crate::AppEnvironment::Web; - let startup_options = crate::StartupOptions::default(); + let startup_options = crate::StartupOptions { + memory_limit: re_memory::MemoryLimit { + // On wasm32 we only have 4GB of memory to play around with. + limit: Some(3_500_000_000), + }, + }; let re_ui = crate::customize_eframe(cc); let url = url.unwrap_or_else(|| get_url(&cc.integration_info));