Skip to content

Commit

Permalink
integrate back into memory panel
Browse files Browse the repository at this point in the history
  • Loading branch information
teh-cmc committed Apr 16, 2024
1 parent 4364b16 commit 55df6d5
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 107 deletions.
1 change: 1 addition & 0 deletions crates/re_viewer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ re_log_encoding = { workspace = true, features = [
re_log_types.workspace = true
re_memory.workspace = true
re_query_cache.workspace = true
re_query_cache2.workspace = true
re_renderer = { workspace = true, default-features = false }
re_smart_channel.workspace = true
re_space_view.workspace = true
Expand Down
6 changes: 2 additions & 4 deletions crates/re_viewer/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ impl App {
#[cfg(not(target_arch = "wasm32"))]
UICommand::PrintPrimaryCache => {
if let Some(ctx) = store_context {
let text = format!("{:?}", ctx.recording.query_caches());
let text = format!("{:?}", ctx.recording.query_caches2());
self.re_ui
.egui_ctx
.output_mut(|o| o.copied_text = text.clone());
Expand Down Expand Up @@ -1414,9 +1414,7 @@ impl eframe::App for App {

// NOTE: Store and caching stats are very costly to compute: only do so if the memory panel
// is opened.
let store_stats = self
.memory_panel_open
.then(|| store_hub.stats(self.memory_panel.primary_cache_detailed_stats_enabled()));
let store_stats = self.memory_panel_open.then(|| store_hub.stats());

// do early, before doing too many allocations
self.memory_panel
Expand Down
146 changes: 46 additions & 100 deletions crates/re_viewer/src/ui/memory_panel.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use std::sync::atomic::AtomicBool;

use itertools::Itertools;
use re_data_store::{DataStoreConfig, DataStoreRowStats, DataStoreStats};
use re_format::{format_bytes, format_uint};
use re_memory::{util::sec_since_start, MemoryHistory, MemoryLimit, MemoryUse};
use re_query_cache::{CachedComponentStats, CachedEntityStats, CachesStats};
use re_query_cache2::{CachedComponentStats, CachesStats};
use re_renderer::WgpuResourcePoolStatistics;
use re_viewer_context::store_hub::StoreHubStats;

Expand All @@ -15,13 +14,6 @@ use crate::env_vars::RERUN_TRACK_ALLOCATIONS;
pub struct MemoryPanel {
history: MemoryHistory,
memory_purge_times: Vec<f64>,

/// If `true`, enables the much-more-costly-to-compute per-component stats for the primary
/// cache.
prim_cache_detailed_stats: AtomicBool,

/// If `true`, will show stats about empty primary caches too, which likely indicates a bug (dangling bucket).
prim_cache_show_empty: AtomicBool,
}

impl MemoryPanel {
Expand Down Expand Up @@ -49,12 +41,6 @@ impl MemoryPanel {
self.memory_purge_times.push(sec_since_start());
}

#[inline]
pub fn primary_cache_detailed_stats_enabled(&self) -> bool {
self.prim_cache_detailed_stats
.load(std::sync::atomic::Ordering::Relaxed)
}

#[allow(clippy::too_many_arguments)]
pub fn ui(
&self,
Expand Down Expand Up @@ -91,6 +77,8 @@ impl MemoryPanel {
gpu_resource_stats: &WgpuResourcePoolStatistics,
store_stats: Option<&StoreHubStats>,
) {
_ = self;

ui.strong("Rerun Viewer resource usage");

ui.separator();
Expand All @@ -115,7 +103,7 @@ impl MemoryPanel {

ui.separator();
ui.collapsing("Primary Cache Resources", |ui| {
self.caches_stats(ui, re_ui, &store_stats.recording_cached_stats);
Self::caches_stats(ui, &store_stats.recording_cached_stats);
});

ui.separator();
Expand Down Expand Up @@ -319,27 +307,15 @@ impl MemoryPanel {
});
}

fn caches_stats(&self, ui: &mut egui::Ui, re_ui: &re_ui::ReUi, caches_stats: &CachesStats) {
use std::sync::atomic::Ordering::Relaxed;

let mut detailed_stats = self.prim_cache_detailed_stats.load(Relaxed);
re_ui
.checkbox(ui, &mut detailed_stats, "Detailed stats")
.on_hover_text("Show detailed statistics when hovering entity paths below.\nThis will slow down the program.");
self.prim_cache_detailed_stats
.store(detailed_stats, Relaxed);

let mut show_empty = self.prim_cache_show_empty.load(Relaxed);
re_ui
.checkbox(ui, &mut show_empty, "Show empty caches")
.on_hover_text(
"Show empty caches too.\nDangling buckets are generally the result of a bug.",
);
self.prim_cache_show_empty.store(show_empty, Relaxed);

fn caches_stats(ui: &mut egui::Ui, caches_stats: &CachesStats) {
let CachesStats { latest_at, range } = caches_stats;

if show_empty || !latest_at.is_empty() {
let latest_at = latest_at
.iter()
.filter(|(_, stats)| stats.total_indices > 0)
.collect_vec();

if !latest_at.is_empty() {
ui.separator();
ui.strong("LatestAt");
egui::ScrollArea::vertical()
Expand All @@ -350,27 +326,36 @@ impl MemoryPanel {
.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("Component").underline());
ui.label(egui::RichText::new("Indices").underline());
ui.label(egui::RichText::new("Instances").underline());
ui.label(egui::RichText::new("Size").underline());
ui.end_row();

for (entity_path, stats) in latest_at {
if !show_empty && stats.is_empty() {
continue;
}
for (cache_key, stats) in latest_at {
let &CachedComponentStats {
total_indices,
total_instances,
total_size_bytes,
} = stats;

let res = ui.label(entity_path.to_string());
entity_stats_ui(ui, res, stats);
ui.label(cache_key.entity_path.to_string());
ui.label(cache_key.component_name.to_string());
ui.label(re_format::format_uint(total_indices));
ui.label(re_format::format_uint(total_instances));
ui.label(re_format::format_bytes(total_size_bytes as _));
ui.end_row();
}
});
});
}

if show_empty || !latest_at.is_empty() {
let range = range
.iter()
.filter(|(_, (_, stats))| stats.total_indices > 0)
.collect_vec();

if !range.is_empty() {
ui.separator();
ui.strong("Range");
egui::ScrollArea::vertical()
Expand All @@ -381,75 +366,36 @@ impl MemoryPanel {
.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 && 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,
hover_response: egui::Response,
entity_stats: &CachedEntityStats,
) {
let CachedEntityStats {
total_size_bytes,
total_rows,
per_component,
} = entity_stats;

if let Some(per_component) = per_component.as_ref() {
hover_response.on_hover_ui_at_pointer(|ui| {
egui::Grid::new("component cache stats grid")
.num_columns(3)
.show(ui, |ui| {
ui.label(egui::RichText::new("Component").underline());
ui.label(egui::RichText::new("Rows").underline());
ui.label(egui::RichText::new("Indices").underline());
ui.label(egui::RichText::new("Instances").underline());
ui.label(egui::RichText::new("Size").underline());
ui.label(egui::RichText::new("Time range").underline());
ui.end_row();

for (component_name, stats) in per_component {
for (cache_key, (time_range, stats)) in range {
let &CachedComponentStats {
total_rows,
total_indices,
total_instances,
total_size_bytes,
} = stats;

ui.label(component_name.to_string());
ui.label(re_format::format_uint(total_rows));
ui.label(cache_key.entity_path.to_string());
ui.label(cache_key.component_name.to_string());
ui.label(re_format::format_uint(total_indices));
ui.label(re_format::format_uint(total_instances));
ui.label(re_format::format_bytes(total_size_bytes as _));
ui.label(format!(
"{}({})",
cache_key.timeline.name(),
time_range.map_or("<static>".to_owned(), |time_range| {
cache_key.timeline.format_time_range_utc(&time_range)
})
));
ui.end_row();
}
});
});
}

ui.label(re_format::format_uint(*total_rows));
ui.label(re_format::format_bytes(*total_size_bytes as _));
}
}

Expand Down
2 changes: 2 additions & 0 deletions crates/re_viewer_context/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ re_entity_db = { workspace = true, features = ["serde"] }
re_log_types.workspace = true
re_log.workspace = true
re_query_cache.workspace = true
re_query_cache2.workspace = true
re_query.workspace = true
re_query2.workspace = true
re_renderer.workspace = true
re_smart_channel.workspace = true
re_string_interner.workspace = true
Expand Down
3 changes: 3 additions & 0 deletions crates/re_viewer_context/src/space_view/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ pub enum SpaceViewSystemExecutionError {
#[error(transparent)]
QueryError(#[from] re_query::QueryError),

#[error(transparent)]
QueryError2(#[from] re_query2::QueryError),

#[error(transparent)]
DeserializationError(#[from] re_types::DeserializationError),

Expand Down
6 changes: 3 additions & 3 deletions crates/re_viewer_context/src/store_hub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use re_data_store::StoreGeneration;
use re_data_store::{DataStoreConfig, DataStoreStats};
use re_entity_db::{EntityDb, StoreBundle};
use re_log_types::{ApplicationId, StoreId, StoreKind};
use re_query_cache::CachesStats;
use re_query_cache2::CachesStats;

use crate::StoreContext;

Expand Down Expand Up @@ -687,7 +687,7 @@ impl StoreHub {
//
// TODO(jleibs): We probably want stats for all recordings, not just
// the active recording.
pub fn stats(&self, detailed_cache_stats: bool) -> StoreHubStats {
pub fn stats(&self) -> StoreHubStats {
re_tracing::profile_function!();

// If we have an app-id, then use it to look up the blueprint.
Expand Down Expand Up @@ -715,7 +715,7 @@ impl StoreHub {
.unwrap_or_default();

let recording_cached_stats = recording
.map(|entity_db| entity_db.query_caches().stats(detailed_cache_stats))
.map(|entity_db| entity_db.query_caches2().stats())
.unwrap_or_default();

let recording_config = recording
Expand Down

0 comments on commit 55df6d5

Please sign in to comment.