diff --git a/crates/re_query_cache/src/cache_stats.rs b/crates/re_query_cache/src/cache_stats.rs index 3d046515d0c9..31e35e8c9ecd 100644 --- a/crates/re_query_cache/src/cache_stats.rs +++ b/crates/re_query_cache/src/cache_stats.rs @@ -20,6 +20,19 @@ pub fn set_detailed_stats(b: bool) { ENABLE_DETAILED_STATS.store(b, std::sync::atomic::Ordering::Relaxed); } +/// If `true`, will show stats about empty caches too, which likely indicates a bug (dangling bucket). +static SHOW_EMPTY_CACHES: AtomicBool = AtomicBool::new(false); + +#[inline] +pub fn show_empty_caches() -> bool { + SHOW_EMPTY_CACHES.load(std::sync::atomic::Ordering::Relaxed) +} + +#[inline] +pub fn set_show_empty_caches(b: bool) { + SHOW_EMPTY_CACHES.store(b, std::sync::atomic::Ordering::Relaxed); +} + // --- /// Stats for all primary caches. @@ -63,6 +76,15 @@ pub struct CachedEntityStats { pub per_component: Option>, } +impl CachedEntityStats { + #[inline] + pub fn is_empty(&self) -> bool { + // NOTE: That looks non-sensical, but it can happen if the cache is bugged, which we'd like + // to know. + self.total_rows == 0 && self.total_size_bytes == 0 + } +} + /// Stats for a cached component. #[derive(Default, Debug, Clone)] pub struct CachedComponentStats { diff --git a/crates/re_query_cache/src/lib.rs b/crates/re_query_cache/src/lib.rs index c5f95d489438..a87bcc681999 100644 --- a/crates/re_query_cache/src/lib.rs +++ b/crates/re_query_cache/src/lib.rs @@ -9,7 +9,8 @@ mod range; pub use self::cache::{AnyQuery, Caches}; pub use self::cache_stats::{ - detailed_stats, set_detailed_stats, CachedComponentStats, CachedEntityStats, CachesStats, + detailed_stats, set_detailed_stats, set_show_empty_caches, show_empty_caches, + CachedComponentStats, CachedEntityStats, CachesStats, }; pub use self::flat_vec_deque::{ErasedFlatVecDeque, FlatVecDeque}; pub use self::query::{ diff --git a/crates/re_viewer/src/ui/memory_panel.rs b/crates/re_viewer/src/ui/memory_panel.rs index 6aa2725d0511..64127e3e225c 100644 --- a/crates/re_viewer/src/ui/memory_panel.rs +++ b/crates/re_viewer/src/ui/memory_panel.rs @@ -316,65 +316,85 @@ impl MemoryPanel { .on_hover_text("Show detailed statistics when hovering entity paths below.\nThis will slow down the program."); re_query_cache::set_detailed_stats(detailed_stats); - let CachesStats { latest_at, range } = caches_stats; - - // NOTE: This is a debug tool: do _not_ hide empty things. Empty things are a bug. + let mut show_empty_caches = re_query_cache::show_empty_caches(); + re_ui + .checkbox(ui, &mut show_empty_caches, "Show empty caches") + .on_hover_text( + "Show empty caches too.\nDangling buckets are generally the result of a bug.", + ); + re_query_cache::set_show_empty_caches(show_empty_caches); - ui.separator(); + let CachesStats { latest_at, range } = caches_stats; - ui.strong("LatestAt"); - egui::ScrollArea::vertical() - .max_height(200.0) - .id_source("latest_at") - .show(ui, |ui| { - egui::Grid::new("latest_at cache stats grid") - .num_columns(3) - .show(ui, |ui| { - ui.label(egui::RichText::new("Entity").underline()); - ui.label(egui::RichText::new("Rows").underline()) - .on_hover_text("How many distinct data timestamps have been cached?"); - ui.label(egui::RichText::new("Size").underline()); - ui.end_row(); - - for (entity_path, stats) in latest_at { - let res = ui.label(entity_path.to_string()); - entity_stats_ui(ui, res, stats); + if show_empty_caches || !latest_at.is_empty() { + ui.separator(); + ui.strong("LatestAt"); + egui::ScrollArea::vertical() + .max_height(200.0) + .id_source("latest_at") + .show(ui, |ui| { + egui::Grid::new("latest_at cache stats grid") + .num_columns(3) + .show(ui, |ui| { + ui.label(egui::RichText::new("Entity").underline()); + ui.label(egui::RichText::new("Rows").underline()) + .on_hover_text( + "How many distinct data timestamps have been cached?", + ); + ui.label(egui::RichText::new("Size").underline()); ui.end_row(); - } - }); - }); - ui.separator(); + for (entity_path, stats) in latest_at { + if !show_empty_caches && stats.is_empty() { + continue; + } - ui.strong("Range"); - egui::ScrollArea::vertical() - .max_height(200.0) - .id_source("range") - .show(ui, |ui| { - egui::Grid::new("range cache stats grid") - .num_columns(4) - .show(ui, |ui| { - ui.label(egui::RichText::new("Entity").underline()); - ui.label(egui::RichText::new("Time range").underline()); - ui.label(egui::RichText::new("Rows").underline()) - .on_hover_text("How many distinct data timestamps have been cached?"); - ui.label(egui::RichText::new("Size").underline()); - ui.end_row(); - - for (entity_path, stats_per_range) in range { - for (timeline, time_range, stats) in stats_per_range { let res = ui.label(entity_path.to_string()); - ui.label(format!( - "{}({})", - timeline.name(), - timeline.format_time_range_utc(time_range) - )); entity_stats_ui(ui, res, stats); ui.end_row(); } - } - }); - }); + }); + }); + } + + if show_empty_caches || !latest_at.is_empty() { + ui.separator(); + ui.strong("Range"); + egui::ScrollArea::vertical() + .max_height(200.0) + .id_source("range") + .show(ui, |ui| { + egui::Grid::new("range cache stats grid") + .num_columns(4) + .show(ui, |ui| { + ui.label(egui::RichText::new("Entity").underline()); + ui.label(egui::RichText::new("Time range").underline()); + ui.label(egui::RichText::new("Rows").underline()) + .on_hover_text( + "How many distinct data timestamps have been cached?", + ); + ui.label(egui::RichText::new("Size").underline()); + ui.end_row(); + + for (entity_path, stats_per_range) in range { + for (timeline, time_range, stats) in stats_per_range { + if !show_empty_caches && stats.is_empty() { + continue; + } + + let res = ui.label(entity_path.to_string()); + ui.label(format!( + "{}({})", + timeline.name(), + timeline.format_time_range_utc(time_range) + )); + entity_stats_ui(ui, res, stats); + ui.end_row(); + } + } + }); + }); + } fn entity_stats_ui( ui: &mut egui::Ui,