rendy_memory/
utilization.rs

1use {
2    colorful::{core::color_string::CString, Color, Colorful as _},
3    gfx_hal::memory::Properties,
4};
5
6/// Memory utilization stats.
7#[derive(Clone, Copy, Debug)]
8pub struct MemoryUtilization {
9    /// Total number of bytes allocated.
10    pub used: u64,
11    /// Effective number bytes allocated.
12    pub effective: u64,
13}
14
15/// Memory utilization of one heap.
16#[derive(Clone, Copy, Debug)]
17pub struct MemoryHeapUtilization {
18    /// Utilization.
19    pub utilization: MemoryUtilization,
20
21    /// Memory heap size.
22    pub size: u64,
23}
24
25/// Memory utilization of one type.
26#[derive(Clone, Copy, Debug)]
27pub struct MemoryTypeUtilization {
28    /// Utilization.
29    pub utilization: MemoryUtilization,
30
31    /// Memory type info.
32    pub properties: Properties,
33
34    /// Index of heap this memory type uses.
35    pub heap_index: usize,
36}
37
38/// Total memory utilization.
39#[derive(Clone, Debug)]
40pub struct TotalMemoryUtilization {
41    /// Utilization by types.
42    pub types: Vec<MemoryTypeUtilization>,
43
44    /// Utilization by heaps.
45    pub heaps: Vec<MemoryHeapUtilization>,
46}
47
48impl std::fmt::Display for TotalMemoryUtilization {
49    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
50        const MB: u64 = 1024 * 1024;
51
52        writeln!(fmt, "!!! Memory utilization !!!")?;
53        for (index, heap) in self.heaps.iter().enumerate() {
54            let size = heap.size;
55            let MemoryUtilization { used, effective } = heap.utilization;
56            let usage_basis_points = used * 10000 / size;
57            let fill = if usage_basis_points > 10000 {
58                // Shouldn't happen, but just in case.
59                50
60            } else {
61                (usage_basis_points / 200) as usize
62            };
63            let effective_basis_points = if used > 0 {
64                effective * 10000 / used
65            } else {
66                10000
67            };
68
69            let line = ("|".repeat(fill) + &(" ".repeat(50 - fill)))
70                .gradient_with_color(Color::Green, Color::Red);
71            writeln!(
72                fmt,
73                "Heap {}:\n{:6} / {:<6} or{} {{ effective:{} }} [{}]",
74                format!("{}", index).magenta(),
75                format!("{}MB", used / MB),
76                format!("{}MB", size / MB),
77                format_basis_points(usage_basis_points),
78                format_basis_points_inverted(effective_basis_points),
79                line
80            )?;
81
82            for ty in self.types.iter().filter(|ty| ty.heap_index == index) {
83                let properties = ty.properties;
84                let MemoryUtilization { used, effective } = ty.utilization;
85                let usage_basis_points = used * 10000 / size;
86                let effective_basis_points = if used > 0 {
87                    effective * 10000 / used
88                } else {
89                    0
90                };
91
92                writeln!(
93                    fmt,
94                    "         {:>6} or{} {{ effective:{} }} | {:?}",
95                    format!("{}MB", used / MB),
96                    format_basis_points(usage_basis_points),
97                    format_basis_points_inverted(effective_basis_points),
98                    properties,
99                )?;
100            }
101        }
102
103        Ok(())
104    }
105}
106
107fn format_basis_points(basis_points: u64) -> CString {
108    debug_assert!(basis_points <= 10000);
109    let s = format!("{:>3}.{:02}%", basis_points / 100, basis_points % 100);
110    if basis_points > 7500 {
111        s.red()
112    } else if basis_points > 5000 {
113        s.yellow()
114    } else if basis_points > 2500 {
115        s.green()
116    } else if basis_points > 100 {
117        s.blue()
118    } else {
119        s.white()
120    }
121}
122
123fn format_basis_points_inverted(basis_points: u64) -> CString {
124    debug_assert!(basis_points <= 10000);
125    let s = format!("{:>3}.{:02}%", basis_points / 100, basis_points % 100);
126    if basis_points > 9900 {
127        s.white()
128    } else if basis_points > 7500 {
129        s.blue()
130    } else if basis_points > 5000 {
131        s.green()
132    } else if basis_points > 2500 {
133        s.yellow()
134    } else {
135        s.red()
136    }
137}