use super::workspace_index::WorkspaceIndex;
use std::fmt;
#[derive(Clone, Debug, Default)]
pub struct MemorySnapshot {
pub file_count: usize,
pub symbol_count: usize,
pub files_bytes: usize,
pub symbols_bytes: usize,
pub global_refs_bytes: usize,
pub document_store_bytes: usize,
}
impl MemorySnapshot {
pub fn capture(index: &WorkspaceIndex) -> Self {
index.memory_snapshot()
}
pub fn total_estimated_bytes(&self) -> usize {
self.files_bytes + self.symbols_bytes + self.global_refs_bytes + self.document_store_bytes
}
pub fn bytes_per_symbol(&self) -> usize {
if self.symbol_count == 0 {
return 0;
}
self.total_estimated_bytes() / self.symbol_count
}
pub fn bytes_per_file(&self) -> usize {
if self.file_count == 0 {
return 0;
}
self.total_estimated_bytes() / self.file_count
}
pub fn to_report_string(&self) -> String {
let total = self.total_estimated_bytes();
format!(
"MemorySnapshot {{ files: {} ({} B), symbols map: {} ({} B), \
global_refs: {} B, doc_store: {} B, total: {} B, \
{} symbols, {} B/symbol }}",
self.file_count,
self.files_bytes,
self.symbol_count,
self.symbols_bytes,
self.global_refs_bytes,
self.document_store_bytes,
total,
self.symbol_count,
self.bytes_per_symbol(),
)
}
}
impl fmt::Display for MemorySnapshot {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.to_report_string())
}
}
#[derive(Debug, Default)]
pub struct ScaleReport {
checkpoints: Vec<(usize, MemorySnapshot)>,
}
impl ScaleReport {
pub fn new() -> Self {
Self { checkpoints: Vec::new() }
}
pub fn add_checkpoint(&mut self, file_count: usize, snap: MemorySnapshot) {
self.checkpoints.push((file_count, snap));
}
pub fn checkpoints(&self) -> &[(usize, MemorySnapshot)] {
&self.checkpoints
}
pub fn scaling_factor(&self) -> Option<f64> {
if self.checkpoints.len() < 2 {
return None;
}
let first = self.checkpoints.first()?;
let last = self.checkpoints.last()?;
let mem_first = first.1.total_estimated_bytes();
let mem_last = last.1.total_estimated_bytes();
let file_first = first.0;
let file_last = last.0;
if mem_first == 0 || file_first == 0 || file_last == 0 {
return None;
}
let expected_linear = mem_first as f64 * (file_last as f64 / file_first as f64);
Some(mem_last as f64 / expected_linear)
}
}
impl fmt::Display for ScaleReport {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(
f,
"{:<10} {:>12} {:>12} {:>12} {:>14}",
"files", "total_B", "symbols", "B/sym", "B/file"
)?;
writeln!(f, "{}", "-".repeat(64))?;
for (file_count, snap) in &self.checkpoints {
writeln!(
f,
"{:<10} {:>12} {:>12} {:>12} {:>14}",
file_count,
snap.total_estimated_bytes(),
snap.symbol_count,
snap.bytes_per_symbol(),
snap.bytes_per_file(),
)?;
}
if let Some(factor) = self.scaling_factor() {
writeln!(f, "\nScaling factor vs linear: {:.2}x", factor)?;
}
Ok(())
}
}