re_memory/
memory_limit.rs1use saturating_cast::SaturatingCast as _;
2
3#[derive(Copy, Clone, Debug, PartialEq, Eq)]
11pub struct MemoryLimit {
12 pub max_bytes: Option<i64>,
18}
19
20impl MemoryLimit {
21 pub const UNLIMITED: Self = Self { max_bytes: None };
23
24 pub fn from_bytes(max_bytes: u64) -> Self {
26 Self {
27 max_bytes: Some(max_bytes.saturating_cast()),
28 }
29 }
30
31 pub fn from_fraction_of_total(fraction: f32) -> Self {
33 let total_memory = crate::total_ram_in_bytes();
34 if let Some(total_memory) = total_memory {
35 let max_bytes = (fraction as f64 * total_memory as f64).round();
36
37 re_log::debug!(
38 "Setting memory limit to {}, which is {}% of total available memory ({}).",
39 re_format::format_bytes(max_bytes),
40 100.0 * fraction,
41 re_format::format_bytes(total_memory as _),
42 );
43
44 Self {
45 max_bytes: Some(max_bytes as _),
46 }
47 } else {
48 re_log::info!("Couldn't determine total available memory. Setting no memory limit.");
49 Self { max_bytes: None }
50 }
51 }
52
53 pub fn parse(limit: &str) -> Result<Self, String> {
55 if let Some(percentage) = limit.strip_suffix('%') {
56 let percentage = percentage
57 .parse::<f32>()
58 .map_err(|_err| format!("expected e.g. '50%', got {limit:?}"))?;
59 let fraction = percentage / 100.0;
60 Ok(Self::from_fraction_of_total(fraction))
61 } else {
62 re_format::parse_bytes(limit)
63 .map(|max_bytes| Self {
64 max_bytes: Some(max_bytes),
65 })
66 .ok_or_else(|| format!("expected e.g. '16GB', got {limit:?}"))
67 }
68 }
69
70 #[inline]
71 pub fn is_limited(&self) -> bool {
72 self.max_bytes.is_some()
73 }
74
75 #[inline]
76 pub fn is_unlimited(&self) -> bool {
77 self.max_bytes.is_none()
78 }
79
80 pub fn is_exceeded_by(&self, mem_use: &crate::MemoryUse) -> Option<f32> {
82 let max_bytes = self.max_bytes?;
83
84 if let Some(counted_use) = mem_use.counted {
85 if max_bytes < counted_use {
86 return Some((counted_use - max_bytes) as f32 / counted_use as f32);
87 }
88 } else if let Some(resident_use) = mem_use.resident {
89 re_log::warn_once!(
90 "Using resident memory use (RSS) for memory limiting, because a memory tracker was not available."
91 );
92 if max_bytes < resident_use {
93 return Some((resident_use - max_bytes) as f32 / resident_use as f32);
94 }
95 }
96
97 None
98 }
99}
100
101impl std::str::FromStr for MemoryLimit {
102 type Err = String;
103
104 fn from_str(s: &str) -> Result<Self, Self::Err> {
105 Self::parse(s)
106 }
107}