From 5214b8f6cc9a6560f198d2726fac3572d24ec001 Mon Sep 17 00:00:00 2001 From: Burak Gurbuz Date: Fri, 25 Oct 2024 11:19:42 -0700 Subject: [PATCH] update and improve cgroup memory aggregation Summary: Refactor cgroup memory aggregation logic - Updated `aggr_top_level_val` to manually aggregate specific fields. - Ensured local event metrics are excluded from aggregation. - Added unit test to verify correct aggregation behavior and exclusion of local events. Reviewed By: lnyng Differential Revision: D64915570 fbshipit-source-id: 3747aec1a5efb9d95f1bba877add1705ed901fdf --- below/model/src/cgroup.rs | 111 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 3 deletions(-) diff --git a/below/model/src/cgroup.rs b/below/model/src/cgroup.rs index a4a81feb..526affae 100644 --- a/below/model/src/cgroup.rs +++ b/below/model/src/cgroup.rs @@ -266,9 +266,42 @@ impl CgroupModel { } pub fn aggr_top_level_val(mut self) -> Self { - self.data.memory = self.children.iter().fold(Default::default(), |acc, model| { - opt_add(acc, model.data.memory.clone()) - }); + if let Some(memory) = &self.data.memory { + // If root model has the value, return it directly + if memory.total.is_some() { + return self; + } + } + // Manually aggregate specified fields from children + let mut aggregated_memory = CgroupMemoryModel::default(); + for child in &self.children { + if let Some(child_memory) = &child.data.memory { + aggregated_memory.total = opt_add(aggregated_memory.total, child_memory.total); + aggregated_memory.swap = opt_add(aggregated_memory.swap, child_memory.swap); + aggregated_memory.events_low = + opt_add(aggregated_memory.events_low, child_memory.events_low); + aggregated_memory.events_high = + opt_add(aggregated_memory.events_high, child_memory.events_high); + aggregated_memory.events_max = + opt_add(aggregated_memory.events_max, child_memory.events_max); + aggregated_memory.events_oom = + opt_add(aggregated_memory.events_oom, child_memory.events_oom); + aggregated_memory.events_oom_kill = opt_add( + aggregated_memory.events_oom_kill, + child_memory.events_oom_kill, + ); + } + } + // Assign aggregated values to root memory model + if let Some(memory) = &mut self.data.memory { + memory.total = aggregated_memory.total; + memory.swap = aggregated_memory.swap; + memory.events_low = aggregated_memory.events_low; + memory.events_high = aggregated_memory.events_high; + memory.events_max = aggregated_memory.events_max; + memory.events_oom = aggregated_memory.events_oom; + memory.events_oom_kill = aggregated_memory.events_oom_kill; + } self } @@ -997,4 +1030,76 @@ mod tests { Some(Field::F64(42.0)) ); } + + #[test] + fn test_aggr_top_level_val() { + /* + Summary: This test verifies the aggregation of top-level values in a CgroupModel, executed in the aggr_top_level_val() function. + The test creates two child cgroup models with memory values, then uses them to create a root cgroup model. + The root cgroup model is aggregated using the aggr_top_level_val() function. During aggregation, local events should not be aggregated. + The test checks that the total memory is aggregated correctly and confirms that local events are not aggregated. + */ + // Create two children cgroup models with memory values + let child1 = CgroupModel { + data: SingleCgroupModel { + name: "child1".to_string(), + memory: Some(CgroupMemoryModel { + total: Some(100), + swap: Some(50), + events_low: Some(1), + events_high: Some(2), + events_max: Some(3), + events_oom: Some(4), + events_oom_kill: Some(5), + events_local_low: Some(10), + events_local_high: Some(20), + ..Default::default() + }), + ..Default::default() + }, + ..Default::default() + }; + let child2 = CgroupModel { + data: SingleCgroupModel { + name: "child2".to_string(), + memory: Some(CgroupMemoryModel { + total: Some(200), + swap: Some(30), + events_low: Some(1), + events_high: Some(2), + events_max: Some(3), + events_oom: Some(4), + events_oom_kill: Some(5), + events_local_low: Some(10), + events_local_high: Some(20), + ..Default::default() + }), + ..Default::default() + }, + ..Default::default() + }; + // Create root cgroup model without pre-existing memory values + let mut root = CgroupModel { + data: SingleCgroupModel { + name: "root".to_string(), + memory: Some(CgroupMemoryModel::default()), + ..Default::default() + }, + children: vec![child1, child2].into_iter().collect(), + ..Default::default() + }; + // Aggregate top-level values + root = root.aggr_top_level_val(); + // Check that the total memory is aggregated correctly + assert_eq!(root.data.memory.as_ref().unwrap().total, Some(300)); + assert_eq!(root.data.memory.as_ref().unwrap().swap, Some(80)); + assert_eq!(root.data.memory.as_ref().unwrap().events_low, Some(2)); + assert_eq!(root.data.memory.as_ref().unwrap().events_high, Some(4)); + assert_eq!(root.data.memory.as_ref().unwrap().events_max, Some(6)); + assert_eq!(root.data.memory.as_ref().unwrap().events_oom, Some(8)); + assert_eq!(root.data.memory.as_ref().unwrap().events_oom_kill, Some(10)); + // Confirm local events are not aggregated + assert_eq!(root.data.memory.as_ref().unwrap().events_local_low, None); + assert_eq!(root.data.memory.as_ref().unwrap().events_local_high, None); + } }