aboutsummaryrefslogtreecommitdiff
path: root/rendy-memory/src/utilization.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rendy-memory/src/utilization.rs')
-rw-r--r--rendy-memory/src/utilization.rs137
1 files changed, 137 insertions, 0 deletions
diff --git a/rendy-memory/src/utilization.rs b/rendy-memory/src/utilization.rs
new file mode 100644
index 0000000..723c429
--- /dev/null
+++ b/rendy-memory/src/utilization.rs
@@ -0,0 +1,137 @@
+use {
+ colorful::{core::color_string::CString, Color, Colorful as _},
+ gfx_hal::memory::Properties,
+};
+
+/// Memory utilization stats.
+#[derive(Clone, Copy, Debug)]
+pub struct MemoryUtilization {
+ /// Total number of bytes allocated.
+ pub used: u64,
+ /// Effective number bytes allocated.
+ pub effective: u64,
+}
+
+/// Memory utilization of one heap.
+#[derive(Clone, Copy, Debug)]
+pub struct MemoryHeapUtilization {
+ /// Utilization.
+ pub utilization: MemoryUtilization,
+
+ /// Memory heap size.
+ pub size: u64,
+}
+
+/// Memory utilization of one type.
+#[derive(Clone, Copy, Debug)]
+pub struct MemoryTypeUtilization {
+ /// Utilization.
+ pub utilization: MemoryUtilization,
+
+ /// Memory type info.
+ pub properties: Properties,
+
+ /// Index of heap this memory type uses.
+ pub heap_index: usize,
+}
+
+/// Total memory utilization.
+#[derive(Clone, Debug)]
+pub struct TotalMemoryUtilization {
+ /// Utilization by types.
+ pub types: Vec<MemoryTypeUtilization>,
+
+ /// Utilization by heaps.
+ pub heaps: Vec<MemoryHeapUtilization>,
+}
+
+impl std::fmt::Display for TotalMemoryUtilization {
+ fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ const MB: u64 = 1024 * 1024;
+
+ writeln!(fmt, "!!! Memory utilization !!!")?;
+ for (index, heap) in self.heaps.iter().enumerate() {
+ let size = heap.size;
+ let MemoryUtilization { used, effective } = heap.utilization;
+ let usage_basis_points = used * 10000 / size;
+ let fill = if usage_basis_points > 10000 {
+ // Shouldn't happen, but just in case.
+ 50
+ } else {
+ (usage_basis_points / 200) as usize
+ };
+ let effective_basis_points = if used > 0 {
+ effective * 10000 / used
+ } else {
+ 10000
+ };
+
+ let line = ("|".repeat(fill) + &(" ".repeat(50 - fill)))
+ .gradient_with_color(Color::Green, Color::Red);
+ writeln!(
+ fmt,
+ "Heap {}:\n{:6} / {:<6} or{} {{ effective:{} }} [{}]",
+ format!("{}", index).magenta(),
+ format!("{}MB", used / MB),
+ format!("{}MB", size / MB),
+ format_basis_points(usage_basis_points),
+ format_basis_points_inverted(effective_basis_points),
+ line
+ )?;
+
+ for ty in self.types.iter().filter(|ty| ty.heap_index == index) {
+ let properties = ty.properties;
+ let MemoryUtilization { used, effective } = ty.utilization;
+ let usage_basis_points = used * 10000 / size;
+ let effective_basis_points = if used > 0 {
+ effective * 10000 / used
+ } else {
+ 0
+ };
+
+ writeln!(
+ fmt,
+ " {:>6} or{} {{ effective:{} }} | {:?}",
+ format!("{}MB", used / MB),
+ format_basis_points(usage_basis_points),
+ format_basis_points_inverted(effective_basis_points),
+ properties,
+ )?;
+ }
+ }
+
+ Ok(())
+ }
+}
+
+fn format_basis_points(basis_points: u64) -> CString {
+ debug_assert!(basis_points <= 10000);
+ let s = format!("{:>3}.{:02}%", basis_points / 100, basis_points % 100);
+ if basis_points > 7500 {
+ s.red()
+ } else if basis_points > 5000 {
+ s.yellow()
+ } else if basis_points > 2500 {
+ s.green()
+ } else if basis_points > 100 {
+ s.blue()
+ } else {
+ s.white()
+ }
+}
+
+fn format_basis_points_inverted(basis_points: u64) -> CString {
+ debug_assert!(basis_points <= 10000);
+ let s = format!("{:>3}.{:02}%", basis_points / 100, basis_points % 100);
+ if basis_points > 9900 {
+ s.white()
+ } else if basis_points > 7500 {
+ s.blue()
+ } else if basis_points > 5000 {
+ s.green()
+ } else if basis_points > 2500 {
+ s.yellow()
+ } else {
+ s.red()
+ }
+}