///|
/// A visible cgroup layer. Missing controller files are distinct from `max`.
pub fn Layer::parse(
name : String,
cpu_max? : String,
memory_max? : String,
memory_high? : String,
memory_current? : String,
) -> Layer raise ParseError {
guard name.length() > 0 && name.length() <= 4096 else {
raise Invalid("invalid layer name")
}
let cpu = match cpu_max {
Some(text) => Some(parse_cpu_max(text))
None => None
}
let max = match memory_max {
Some(text) => Some(parse_limit(text))
None => None
}
let high = match memory_high {
Some(text) => Some(parse_limit(text))
None => None
}
let current = match memory_current {
Some(text) => Some(parse_counter(text))
None => None
}
if (max is Some(Finite(_)) || high is Some(Finite(_))) && current is None {
raise Invalid("finite memory limit needs current usage")
}
{ name, cpu, memory_max: max, memory_high: high, memory_current: current, }
}
///|
fn remaining(limit : Int64, current : Int64) -> Int64 {
if current >= limit {
0L
} else {
limit - current
}
}
///|
/// Reduces visible layers, including ancestors' *own* current usage.
/// CPU result is a quota upper bound, not affinity-aware guaranteed capacity.
pub fn budget(layers : ArrayView[Layer]) -> Budget raise ParseError {
guard layers.length() > 0 && layers.length() <= 256 else {
raise Invalid("expected 1..256 hierarchy layers")
}
let mut quota : Double? = None
let mut hard : Int64? = None
let mut high : Int64? = None
let mut quota_source : String? = None
let mut hard_source : String? = None
let mut high_source : String? = None
let seen : Map[String, Bool] = Map([])
for layer in layers {
guard !seen.contains(layer.name) else {
raise Invalid("duplicate hierarchy layer")
}
seen[layer.name] = true
if layer.cpu is Some({ quota: Finite(q), period_us: p, }) {
let cores = q.to_double() / p.to_double()
if quota is None || (quota is Some(old) && cores < old) {
quota = Some(cores)
quota_source = Some(layer.name)
}
}
if layer.memory_max is Some(Finite(max)) &&
layer.memory_current is Some(current) {
let free = remaining(max, current)
if hard is None || (hard is Some(old) && free < old) {
hard = Some(free)
hard_source = Some(layer.name)
}
}
if layer.memory_high is Some(Finite(max)) &&
layer.memory_current is Some(current) {
let free = remaining(max, current)
if high is None || (high is Some(old) && free < old) {
high = Some(free)
high_source = Some(layer.name)
}
}
}
{
quota_cores: quota,
hard_headroom_bytes: hard,
high_headroom_bytes: high,
quota_source,
hard_source,
high_source,
}
}