Skip to content

Commit

Permalink
Add CgroupMemoryNumaModel
Browse files Browse the repository at this point in the history
Summary:
This diff adds the CgroupMemoryNumaModel which calculates memory usage
and workingset events.

Reviewed By: lnyng

Differential Revision: D40867411

fbshipit-source-id: 9e7455cb74c2f07dadf54209ef1f4777d0cbdaf8
  • Loading branch information
Dan Schatzberg authored and facebook-github-bot committed Nov 4, 2022
1 parent 89fe991 commit 4bbb68d
Show file tree
Hide file tree
Showing 3 changed files with 223 additions and 1 deletion.
135 changes: 135 additions & 0 deletions below/model/src/cgroup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ pub struct SingleCgroupModel {
pub pressure: Option<CgroupPressureModel>,
#[queriable(subquery)]
pub cgroup_stat: Option<CgroupStatModel>,
#[queriable(subquery)]
#[queriable(preferred_name = mem_numa)]
pub memory_numa_stat: Option<BTreeMap<u32, CgroupMemoryNumaModel>>,
}

/// A model that represents a cgroup subtree. Each instance is a node that uses
Expand Down Expand Up @@ -225,6 +228,24 @@ impl CgroupModel {

let cgroup_stat = sample.cgroup_stat.as_ref().map(CgroupStatModel::new);

let memory_numa_stat = {
sample.memory_numa_stat.as_ref().map(|end_numa_nodes| {
let begin_numa_nodes = last_if_inode_matches.and_then(|(s, d)| {
s.memory_numa_stat
.as_ref()
.map(|numa_nodes| (numa_nodes, d))
});
end_numa_nodes
.iter()
.map(|(node_id, stat)| {
let begin_numa_stat = begin_numa_nodes
.and_then(|(nodes, d)| nodes.get(node_id).map(|stat| (stat, d)));
(*node_id, CgroupMemoryNumaModel::new(stat, begin_numa_stat))
})
.collect()
})
};

// recursively calculate view of children
// `children` is optional, but we treat it the same as an empty map
let empty = BTreeMap::new();
Expand Down Expand Up @@ -262,6 +283,7 @@ impl CgroupModel {
pressure,
depth,
cgroup_stat,
memory_numa_stat,
},
children,
count: nr_descendants + 1,
Expand Down Expand Up @@ -653,6 +675,119 @@ impl CgroupPressureModel {
}
}
}
#[derive(
Clone,
Debug,
Default,
PartialEq,
Serialize,
Deserialize,
below_derive::Queriable
)]
pub struct CgroupMemoryNumaModel {
pub total: Option<u64>,
pub anon: Option<u64>,
pub file: Option<u64>,
pub kernel_stack: Option<u64>,
pub pagetables: Option<u64>,
pub shmem: Option<u64>,
pub file_mapped: Option<u64>,
pub file_dirty: Option<u64>,
pub file_writeback: Option<u64>,
pub swapcached: Option<u64>,
pub anon_thp: Option<u64>,
pub file_thp: Option<u64>,
pub shmem_thp: Option<u64>,
pub inactive_anon: Option<u64>,
pub active_anon: Option<u64>,
pub inactive_file: Option<u64>,
pub active_file: Option<u64>,
pub unevictable: Option<u64>,
pub slab_reclaimable: Option<u64>,
pub slab_unreclaimable: Option<u64>,
pub workingset_refault_anon: Option<f64>,
pub workingset_refault_file: Option<f64>,
pub workingset_activate_anon: Option<f64>,
pub workingset_activate_file: Option<f64>,
pub workingset_restore_anon: Option<f64>,
pub workingset_restore_file: Option<f64>,
pub workingset_nodereclaim: Option<f64>,
}

impl CgroupMemoryNumaModel {
pub fn new(
begin: &cgroupfs::MemoryNumaStat,
last: Option<(&cgroupfs::MemoryNumaStat, Duration)>,
) -> CgroupMemoryNumaModel {
let mut model = CgroupMemoryNumaModel {
total: None,
anon: begin.anon,
file: begin.file,
kernel_stack: begin.kernel_stack,
pagetables: begin.pagetables,
shmem: begin.shmem,
file_mapped: begin.file_mapped,
file_dirty: begin.file_dirty,
file_writeback: begin.file_writeback,
swapcached: begin.swapcached,
anon_thp: begin.anon_thp,
file_thp: begin.file_thp,
shmem_thp: begin.shmem_thp,
inactive_anon: begin.inactive_anon,
active_anon: begin.active_anon,
inactive_file: begin.inactive_file,
active_file: begin.active_file,
unevictable: begin.unevictable,
slab_reclaimable: begin.slab_reclaimable,
slab_unreclaimable: begin.slab_unreclaimable,
..Default::default()
};
if let (Some(anon), Some(file), Some(kernel_stack), Some(pagetables)) =
(model.anon, model.file, model.kernel_stack, model.pagetables)
{
model.total = Some(anon + file + kernel_stack + pagetables);
}

if let Some((l, delta)) = last {
model.workingset_refault_anon = count_per_sec!(
begin.workingset_refault_anon,
l.workingset_refault_anon,
delta
);
model.workingset_refault_file = count_per_sec!(
begin.workingset_refault_file,
l.workingset_refault_file,
delta
);
model.workingset_activate_anon = count_per_sec!(
begin.workingset_activate_anon,
l.workingset_activate_anon,
delta
);
model.workingset_activate_file = count_per_sec!(
begin.workingset_activate_file,
l.workingset_activate_file,
delta
);
model.workingset_restore_anon = count_per_sec!(
begin.workingset_restore_anon,
l.workingset_restore_anon,
delta
);
model.workingset_restore_file = count_per_sec!(
begin.workingset_restore_file,
l.workingset_restore_file,
delta
);
model.workingset_nodereclaim = count_per_sec!(
begin.workingset_nodereclaim,
l.workingset_nodereclaim,
delta
);
}
model
}
}

#[cfg(test)]
mod tests {
Expand Down
29 changes: 28 additions & 1 deletion below/model/src/common_field_ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
///
/// This list also servers as documentation for available field ids that could
/// be used in other below crates. A test ensures that this list is up-to-date.
pub const COMMON_MODEL_FIELD_IDS: [&str; 315] = [
pub const COMMON_MODEL_FIELD_IDS: [&str; 342] = [
"system.hostname",
"system.kernel_version",
"system.os_release",
Expand Down Expand Up @@ -207,6 +207,33 @@ pub const COMMON_MODEL_FIELD_IDS: [&str; 315] = [
"cgroup.[path:/<cgroup_path>/.]pressure.memory_full_pct",
"cgroup.[path:/<cgroup_path>/.]cgroup_stat.nr_descendants",
"cgroup.[path:/<cgroup_path>/.]cgroup_stat.nr_dying_descendants",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.total",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.anon",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.file",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.kernel_stack",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.pagetables",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.shmem",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.file_mapped",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.file_dirty",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.file_writeback",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.swapcached",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.anon_thp",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.file_thp",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.shmem_thp",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.inactive_anon",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.active_anon",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.inactive_file",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.active_file",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.unevictable",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.slab_reclaimable",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.slab_unreclaimable",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_refault_anon",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_refault_file",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_activate_anon",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_activate_file",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_restore_anon",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_restore_file",
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_nodereclaim",
"process.processes.<key>.pid",
"process.processes.<key>.ppid",
"process.processes.<key>.comm",
Expand Down
60 changes: 60 additions & 0 deletions below/render/src/default_configs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ impl HasRenderConfig for model::SingleCgroupModel {
Mem(field_id) => model::CgroupMemoryModel::get_render_config_builder(field_id),
Pressure(field_id) => model::CgroupPressureModel::get_render_config_builder(field_id),
CgroupStat(field_id) => model::CgroupStatModel::get_render_config_builder(field_id),
MemNuma(field_id) => {
model::CgroupMemoryNumaModel::get_render_config_builder(&field_id.subquery_id)
}
}
}
}
Expand Down Expand Up @@ -603,3 +606,60 @@ impl HasRenderConfig for model::CgroupStatModel {
}
}
}

impl HasRenderConfig for model::CgroupMemoryNumaModel {
fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
use model::CgroupMemoryNumaModelFieldId::*;
let rc = RenderConfigBuilder::new();
match field_id {
Total => rc.title("Total").format(ReadableSize),
Anon => rc.title("Anon").format(ReadableSize),
File => rc.title("File").format(ReadableSize),
KernelStack => rc.title("KernelStack").format(ReadableSize),
Pagetables => rc.title("Pagetables").format(ReadableSize),
Shmem => rc.title("Shmem").format(ReadableSize),
FileMapped => rc.title("FileMapped").format(ReadableSize),
FileDirty => rc.title("FileDirty").format(ReadableSize),
FileWriteback => rc.title("FileWriteback").format(ReadableSize),
Swapcached => rc.title("Swapcached").format(ReadableSize),
AnonThp => rc.title("AnonThp").format(ReadableSize),
FileThp => rc.title("FileThp").format(ReadableSize),
ShmemThp => rc.title("ShmemThp").format(ReadableSize),
InactiveAnon => rc.title("InactiveAnon").format(ReadableSize),
ActiveAnon => rc.title("ActiveAnon").format(ReadableSize),
InactiveFile => rc.title("InactiveFile").format(ReadableSize),
ActiveFile => rc.title("ActiveFile").format(ReadableSize),
Unevictable => rc.title("Unevictable").format(ReadableSize),
SlabReclaimable => rc.title("SlabReclaimable").format(ReadableSize),
SlabUnreclaimable => rc.title("SlabUnreclaimable").format(ReadableSize),
WorkingsetRefaultAnon => rc
.title("Workingset Refaults Anon")
.suffix("/s")
.format(Precision(1)),
WorkingsetRefaultFile => rc
.title("Workingset Refaults File")
.suffix("/s")
.format(Precision(1)),
WorkingsetActivateAnon => rc
.title("Workingset Activates Anon")
.suffix("/s")
.format(Precision(1)),
WorkingsetActivateFile => rc
.title("Workingset Activates File")
.suffix("/s")
.format(Precision(1)),
WorkingsetRestoreAnon => rc
.title("Workingset Restores Anon")
.suffix("/s")
.format(Precision(1)),
WorkingsetRestoreFile => rc
.title("Workingset Restores File")
.suffix("/s")
.format(Precision(1)),
WorkingsetNodereclaim => rc
.title("Workingset Nodereclaims")
.suffix("/s")
.format(Precision(1)),
}
}
}

0 comments on commit 4bbb68d

Please sign in to comment.