use std::collections::BTreeMap;
use crate::ctprof::{
CgroupCpuStats, CgroupMemoryStats, CgroupPidsStats, Psi, PsiHalf, PsiResource,
};
pub(super) fn merge_cgroup_cpu(agg: &mut CgroupCpuStats, src: &CgroupCpuStats) {
agg.usage_usec = agg.usage_usec.saturating_add(src.usage_usec);
agg.nr_throttled = agg.nr_throttled.saturating_add(src.nr_throttled);
agg.throttled_usec = agg.throttled_usec.saturating_add(src.throttled_usec);
agg.max_quota_us = merge_max_option(agg.max_quota_us, src.max_quota_us);
agg.max_period_us = agg.max_period_us.max(src.max_period_us);
agg.weight = merge_max_option(agg.weight, src.weight);
agg.weight_nice = match (agg.weight_nice, src.weight_nice) {
(Some(a), Some(b)) => Some(a.max(b)),
(Some(_), None) | (None, Some(_)) | (None, None) => None,
};
}
pub(super) fn merge_cgroup_memory(agg: &mut CgroupMemoryStats, src: &CgroupMemoryStats) {
agg.current = agg.current.max(src.current);
agg.max = merge_max_option(agg.max, src.max);
agg.high = merge_max_option(agg.high, src.high);
agg.low = merge_min_option(agg.low, src.low);
agg.min = merge_min_option(agg.min, src.min);
merge_memory_stat(&mut agg.stat, &src.stat);
merge_kv_counters(&mut agg.events, &src.events);
}
const MEMORY_STAT_GAUGE_KEYS: &[&str] = &[
"anon",
"file",
"kernel",
"kernel_stack",
"pagetables",
"sec_pagetables",
"percpu",
"sock",
"vmalloc",
"shmem",
"zswap",
"zswapped",
"file_mapped",
"file_dirty",
"file_writeback",
"swapcached",
"anon_thp",
"file_thp",
"shmem_thp",
"inactive_anon",
"active_anon",
"inactive_file",
"active_file",
"unevictable",
"slab_reclaimable",
"slab_unreclaimable",
"slab",
"hugetlb",
];
pub(super) fn merge_memory_stat(agg: &mut BTreeMap<String, u64>, src: &BTreeMap<String, u64>) {
for (key, value) in src {
let is_gauge = MEMORY_STAT_GAUGE_KEYS.contains(&key.as_str());
agg.entry(key.clone())
.and_modify(|v| {
*v = if is_gauge {
(*v).max(*value)
} else {
v.saturating_add(*value)
};
})
.or_insert(*value);
}
}
pub(super) fn merge_cgroup_pids(agg: &mut CgroupPidsStats, src: &CgroupPidsStats) {
agg.current = match (agg.current, src.current) {
(Some(a), Some(b)) => Some(a.saturating_add(b)),
(Some(v), None) | (None, Some(v)) => Some(v),
(None, None) => None,
};
agg.max = merge_max_option(agg.max, src.max);
}
pub(super) fn merge_max_option(a: Option<u64>, b: Option<u64>) -> Option<u64> {
match (a, b) {
(Some(a), Some(b)) => Some(a.max(b)),
(Some(_), None) | (None, Some(_)) => None,
(None, None) => None,
}
}
pub(super) fn merge_min_option(a: Option<u64>, b: Option<u64>) -> Option<u64> {
match (a, b) {
(Some(a), Some(b)) => Some(a.min(b)),
(Some(_), None) | (None, Some(_)) => None,
(None, None) => None,
}
}
pub(super) fn merge_kv_counters(agg: &mut BTreeMap<String, u64>, src: &BTreeMap<String, u64>) {
for (key, value) in src {
agg.entry(key.clone())
.and_modify(|v| *v = v.saturating_add(*value))
.or_insert(*value);
}
}
pub(super) fn merge_psi(a: Psi, b: Psi) -> Psi {
Psi {
cpu: merge_psi_resource(a.cpu, b.cpu),
memory: merge_psi_resource(a.memory, b.memory),
io: merge_psi_resource(a.io, b.io),
irq: merge_psi_resource(a.irq, b.irq),
}
}
fn merge_psi_resource(a: PsiResource, b: PsiResource) -> PsiResource {
PsiResource {
some: merge_psi_half(a.some, b.some),
full: merge_psi_half(a.full, b.full),
}
}
fn merge_psi_half(a: PsiHalf, b: PsiHalf) -> PsiHalf {
PsiHalf {
avg10: a.avg10.max(b.avg10),
avg60: a.avg60.max(b.avg60),
avg300: a.avg300.max(b.avg300),
total_usec: a.total_usec.saturating_add(b.total_usec),
}
}