use crate::api::{HostBudget, HostMemory};
pub const STALL_ENTER: u32 = 500;
pub const STALL_LEAVE: u32 = 100;
const MARGIN_MIN: u64 = 2 << 30;
const MARGIN_SHARE: u64 = 16;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Remembered {
pub short: bool,
pub stalled: bool,
}
pub fn margin(total: u64, short: bool) -> u64 {
let margin = MARGIN_MIN.max(total / MARGIN_SHARE);
if short {
margin.saturating_add(margin / 2)
} else {
margin
}
}
pub fn stalls(memory: &HostMemory, before: bool) -> bool {
let full = memory.full.map_or(0, |full| full.avg10);
let stalling = full >= STALL_ENTER || (before && full >= STALL_LEAVE);
stalling && memory.available < margin(memory.total, false).saturating_mul(2)
}
pub fn limit(memory: &HostMemory, short: bool) -> u64 {
memory
.slice
.saturating_add(memory.available)
.saturating_sub(margin(memory.total, short))
}
pub fn budget(memory: HostMemory, reserved: u64, remembered: Remembered) -> HostBudget {
let stalled = stalls(&memory, remembered.stalled);
let limit = limit(&memory, remembered.short || stalled);
HostBudget {
memory,
limit,
spare: u64::try_from(left(limit, reserved, stalled)).unwrap_or(0),
stalled,
}
}
pub fn left(limit: u64, reserved: u64, stalled: bool) -> i64 {
if stalled {
return 0;
}
let bytes = |bytes: u64| i64::try_from(bytes).unwrap_or(i64::MAX);
bytes(limit).saturating_sub(bytes(reserved))
}