Skip to content

Commit

Permalink
implement support for detailed statistics
Browse files Browse the repository at this point in the history
  • Loading branch information
teh-cmc committed Jan 10, 2024
1 parent 314164a commit 15964d3
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 19 deletions.
50 changes: 45 additions & 5 deletions crates/re_query_cache/src/cache_stats.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,25 @@
use std::collections::BTreeMap;
use std::{collections::BTreeMap, sync::atomic::AtomicBool};

use re_log_types::EntityPath;
use re_types_core::ComponentName;

use crate::Caches;

// ---

/// If `true`, enables the much-more-costly-to-compute per-component stats.
static ENABLE_DETAILED_STATS: AtomicBool = AtomicBool::new(false);

#[inline]
pub fn detailed_stats() -> bool {
ENABLE_DETAILED_STATS.load(std::sync::atomic::Ordering::Relaxed)
}

#[inline]
pub fn set_detailed_stats(b: bool) {
ENABLE_DETAILED_STATS.store(b, std::sync::atomic::Ordering::Relaxed);
}

/// Stats for all primary caches.
///
/// Fetch them via [`Caches::stats`].
Expand All @@ -27,12 +41,24 @@ impl CachesStats {
/// Stats for a cached entity.
#[derive(Debug, Clone)]
pub struct CachedEntityStats {
pub total_times: u64,
pub total_size_bytes: u64,
pub num_cached_timestamps: u64,

/// Only if [`detailed_stats`] returns `true` (see [`set_detailed_stats`]).
pub per_component: Option<BTreeMap<ComponentName, CachedComponentStats>>,
}

/// Stats for a cached component.
#[derive(Default, Debug, Clone)]
pub struct CachedComponentStats {
pub total_times: u64,
pub total_values: u64,
}

impl Caches {
/// Computes the stats for all primary caches.
///
/// `per_component` toggles per-component stats.
pub fn stats() -> CachesStats {
re_tracing::profile_function!();

Expand All @@ -44,19 +70,33 @@ impl Caches {
.map(|(key, caches_per_arch)| {
(key.entity_path.clone(), {
let mut total_size_bytes = 0u64;
let mut num_cached_timestamps = 0u64;
let mut total_times = 0u64;
let mut per_component = detailed_stats().then(BTreeMap::default);

for latest_at_cache in
caches_per_arch.latest_at_per_archetype.read().values()
{
let latest_at_cache = latest_at_cache.read();
total_size_bytes += latest_at_cache.total_size_bytes;
num_cached_timestamps = latest_at_cache.per_data_time.len() as _;
total_times = latest_at_cache.per_data_time.len() as _;

if let Some(per_component) = per_component.as_mut() {
for bucket in latest_at_cache.per_data_time.values() {
for (component_name, data) in &bucket.read().components {
let stats: &mut CachedComponentStats =
per_component.entry(*component_name).or_default();
stats.total_times += data.dyn_num_entries() as u64;
stats.total_values += data.dyn_num_values() as u64;
}
}
}
}

CachedEntityStats {
total_size_bytes,
num_cached_timestamps,
total_times,

per_component,
}
})
})
Expand Down
22 changes: 22 additions & 0 deletions crates/re_query_cache/src/flat_vec_deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,18 @@ pub trait ErasedFlatVecDeque: std::any::Any {

fn into_any(self: Box<Self>) -> Box<dyn std::any::Any>;

/// Dynamically dispatches to [`FlatVecDeque::num_entries`].
///
/// This is prefixed with `dyn_` to avoid method dispatch ambiguities that are very hard to
/// avoid even with explicit syntax and that silently lead to infinite recursions.
fn dyn_num_entries(&self) -> usize;

/// Dynamically dispatches to [`FlatVecDeque::num_values`].
///
/// This is prefixed with `dyn_` to avoid method dispatch ambiguities that are very hard to
/// avoid even with explicit syntax and that silently lead to infinite recursions.
fn dyn_num_values(&self) -> usize;

/// Dynamically dispatches to [`FlatVecDeque::remove`].
///
/// This is prefixed with `dyn_` to avoid method dispatch ambiguities that are very hard to
Expand Down Expand Up @@ -51,6 +63,16 @@ impl<T: 'static> ErasedFlatVecDeque for FlatVecDeque<T> {
self
}

#[inline]
fn dyn_num_entries(&self) -> usize {
self.num_entries()
}

#[inline]
fn dyn_num_values(&self) -> usize {
self.num_values()
}

#[inline]
fn dyn_remove(&mut self, at: usize) {
FlatVecDeque::<T>::remove(self, at);
Expand Down
4 changes: 3 additions & 1 deletion crates/re_query_cache/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ mod flat_vec_deque;
mod query;

pub use self::cache::{AnyQuery, Caches};
pub use self::cache_stats::{CachedEntityStats, CachesStats};
pub use self::cache_stats::{
detailed_stats, set_detailed_stats, CachedComponentStats, CachedEntityStats, CachesStats,
};
pub use self::flat_vec_deque::{ErasedFlatVecDeque, FlatVecDeque};
pub use self::query::{
query_archetype_pov1, query_archetype_with_history_pov1, MaybeCachedComponentData,
Expand Down
61 changes: 48 additions & 13 deletions crates/re_viewer/src/ui/memory_panel.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use re_data_store::{DataStoreConfig, DataStoreRowStats, DataStoreStats};
use re_format::{format_bytes, format_number};
use re_log_types::EntityPath;
use re_memory::{util::sec_since_start, MemoryHistory, MemoryLimit, MemoryUse};
use re_query_cache::{CachedEntityStats, CachesStats};
use re_query_cache::{CachedComponentStats, CachedEntityStats, CachesStats};
use re_renderer::WgpuResourcePoolStatistics;

use crate::{env_vars::RERUN_TRACK_ALLOCATIONS, store_hub::StoreHubStats};
Expand Down Expand Up @@ -106,7 +107,7 @@ impl MemoryPanel {

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

ui.separator();
Expand Down Expand Up @@ -309,35 +310,69 @@ impl MemoryPanel {
});
}

fn caches_stats(ui: &mut egui::Ui, caches_stats: &CachesStats) {
fn caches_stats(ui: &mut egui::Ui, re_ui: &re_ui::ReUi, caches_stats: &CachesStats) {
let mut detailed_stats = re_query_cache::detailed_stats();
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.");
re_query_cache::set_detailed_stats(detailed_stats);

egui::Grid::new("cache stats grid")
.num_columns(3)
.show(ui, |ui| {
let CachesStats { latest_at } = caches_stats;

ui.label(egui::RichText::new("Stats").italics());
ui.label("Entity");
ui.label("Entries").on_hover_text(
"How many timestamps distinct data timestamps have been cached?",
);
ui.label("Size");
ui.end_row();

fn label_entity_stats(ui: &mut egui::Ui, cache_stats: &CachedEntityStats) {
let &CachedEntityStats {
fn label_entity_stats(
ui: &mut egui::Ui,
cache_stats: &CachedEntityStats,
entity_path: &EntityPath,
) {
let CachedEntityStats {
total_size_bytes,
num_cached_timestamps,
total_times,
per_component,
} = cache_stats;

ui.label(re_format::format_number(num_cached_timestamps as _));
ui.label(re_format::format_bytes(total_size_bytes as _));
let res = ui.label(entity_path.to_string());
if let Some(per_component) = per_component.as_ref() {
res.on_hover_ui_at_pointer(|ui| {
egui::Grid::new("component cache stats grid")
.num_columns(3)
.show(ui, |ui| {
ui.label("Component");
ui.label("Entries");
ui.label("Count");
ui.end_row();

for (component_name, stats) in per_component {
let &CachedComponentStats {
total_times,
total_values,
} = stats;

ui.label(component_name.to_string());
ui.label(re_format::format_number(total_times as _));
ui.label(re_format::format_number(total_values as _));
ui.end_row();
}
});
});
}

ui.label(re_format::format_number(*total_times as _));
ui.label(re_format::format_bytes(*total_size_bytes as _));
ui.end_row();
}

for (entity_path, stats) in latest_at {
ui.label(entity_path.to_string());
ui.label("");
label_entity_stats(ui, stats);
ui.end_row();
label_entity_stats(ui, stats, entity_path);
}
});
}
Expand Down

0 comments on commit 15964d3

Please sign in to comment.