tinymist_analysis/
stats.rs

1//! Tinymist Analysis Statistics
2
3use std::sync::atomic::{AtomicUsize, Ordering};
4
5/// Statistics about the allocation
6
7#[derive(Debug, Default)]
8pub struct AllocStats {
9    /// The number of allocated objects.
10    pub allocated: AtomicUsize,
11    /// The number of dropped objects.
12    pub dropped: AtomicUsize,
13}
14
15impl AllocStats {
16    /// increment the statistics.
17    pub fn increment(&self) {
18        self.allocated.fetch_add(1, Ordering::Relaxed);
19    }
20
21    /// decrement the statistics.
22    pub fn decrement(&self) {
23        self.dropped.fetch_add(1, Ordering::Relaxed);
24    }
25
26    /// Report the statistics of the allocation.
27    pub fn report() -> String {
28        let maps = crate::adt::interner::MAPS.lock().clone();
29        let mut data = Vec::new();
30        for (name, sz, map) in maps {
31            let allocated = map.allocated.load(std::sync::atomic::Ordering::Relaxed);
32            let dropped = map.dropped.load(std::sync::atomic::Ordering::Relaxed);
33            let alive = allocated.saturating_sub(dropped);
34            data.push((name, sz * alive, allocated, dropped, alive));
35        }
36
37        // sort by total
38        data.sort_by(|x, y| y.4.cmp(&x.4));
39
40        // format to html
41
42        let mut html = String::new();
43        html.push_str(r#"<div>
44<style>
45table.alloc-stats { width: 100%; border-collapse: collapse; }
46table.alloc-stats th, table.alloc-stats td { border: 1px solid black; padding: 8px; text-align: center; }
47table.alloc-stats th.name-column, table.alloc-stats td.name-column { text-align: left; }
48table.alloc-stats tr:nth-child(odd) { background-color: rgba(242, 242, 242, 0.8); }
49@media (prefers-color-scheme: dark) {
50    table.alloc-stats tr:nth-child(odd) { background-color: rgba(50, 50, 50, 0.8); }
51}
52</style>
53<table class="alloc-stats"><tr><th class="name-column">Name</th><th>Alive</th><th>Allocated</th><th>Dropped</th><th>Size</th></tr>"#);
54
55        for (name, sz, allocated, dropped, alive) in data {
56            html.push_str("<tr>");
57            html.push_str(&format!(r#"<td class="name-column">{name}</td>"#));
58            html.push_str(&format!("<td>{alive}</td>"));
59            html.push_str(&format!("<td>{allocated}</td>"));
60            html.push_str(&format!("<td>{dropped}</td>"));
61            html.push_str(&format!("<td>{}</td>", human_size(sz)));
62            html.push_str("</tr>");
63        }
64        html.push_str("</table>");
65        html.push_str("</div>");
66
67        html
68    }
69}
70
71fn human_size(size: usize) -> String {
72    let units = ["B", "KB", "MB", "GB", "TB"];
73    let mut unit = 0;
74    let mut size = size as f64;
75    while size >= 768.0 && unit < units.len() {
76        size /= 1024.0;
77        unit += 1;
78    }
79    format!("{:.2} {}", size, units[unit])
80}