Skip to content

Commit 4bbb68d

Browse files
Dan Schatzbergfacebook-github-bot
authored andcommitted
Add CgroupMemoryNumaModel
Summary: This diff adds the CgroupMemoryNumaModel which calculates memory usage and workingset events. Reviewed By: lnyng Differential Revision: D40867411 fbshipit-source-id: 9e7455cb74c2f07dadf54209ef1f4777d0cbdaf8
1 parent 89fe991 commit 4bbb68d

File tree

3 files changed

+223
-1
lines changed

3 files changed

+223
-1
lines changed

below/model/src/cgroup.rs

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ pub struct SingleCgroupModel {
3838
pub pressure: Option<CgroupPressureModel>,
3939
#[queriable(subquery)]
4040
pub cgroup_stat: Option<CgroupStatModel>,
41+
#[queriable(subquery)]
42+
#[queriable(preferred_name = mem_numa)]
43+
pub memory_numa_stat: Option<BTreeMap<u32, CgroupMemoryNumaModel>>,
4144
}
4245

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

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

231+
let memory_numa_stat = {
232+
sample.memory_numa_stat.as_ref().map(|end_numa_nodes| {
233+
let begin_numa_nodes = last_if_inode_matches.and_then(|(s, d)| {
234+
s.memory_numa_stat
235+
.as_ref()
236+
.map(|numa_nodes| (numa_nodes, d))
237+
});
238+
end_numa_nodes
239+
.iter()
240+
.map(|(node_id, stat)| {
241+
let begin_numa_stat = begin_numa_nodes
242+
.and_then(|(nodes, d)| nodes.get(node_id).map(|stat| (stat, d)));
243+
(*node_id, CgroupMemoryNumaModel::new(stat, begin_numa_stat))
244+
})
245+
.collect()
246+
})
247+
};
248+
228249
// recursively calculate view of children
229250
// `children` is optional, but we treat it the same as an empty map
230251
let empty = BTreeMap::new();
@@ -262,6 +283,7 @@ impl CgroupModel {
262283
pressure,
263284
depth,
264285
cgroup_stat,
286+
memory_numa_stat,
265287
},
266288
children,
267289
count: nr_descendants + 1,
@@ -653,6 +675,119 @@ impl CgroupPressureModel {
653675
}
654676
}
655677
}
678+
#[derive(
679+
Clone,
680+
Debug,
681+
Default,
682+
PartialEq,
683+
Serialize,
684+
Deserialize,
685+
below_derive::Queriable
686+
)]
687+
pub struct CgroupMemoryNumaModel {
688+
pub total: Option<u64>,
689+
pub anon: Option<u64>,
690+
pub file: Option<u64>,
691+
pub kernel_stack: Option<u64>,
692+
pub pagetables: Option<u64>,
693+
pub shmem: Option<u64>,
694+
pub file_mapped: Option<u64>,
695+
pub file_dirty: Option<u64>,
696+
pub file_writeback: Option<u64>,
697+
pub swapcached: Option<u64>,
698+
pub anon_thp: Option<u64>,
699+
pub file_thp: Option<u64>,
700+
pub shmem_thp: Option<u64>,
701+
pub inactive_anon: Option<u64>,
702+
pub active_anon: Option<u64>,
703+
pub inactive_file: Option<u64>,
704+
pub active_file: Option<u64>,
705+
pub unevictable: Option<u64>,
706+
pub slab_reclaimable: Option<u64>,
707+
pub slab_unreclaimable: Option<u64>,
708+
pub workingset_refault_anon: Option<f64>,
709+
pub workingset_refault_file: Option<f64>,
710+
pub workingset_activate_anon: Option<f64>,
711+
pub workingset_activate_file: Option<f64>,
712+
pub workingset_restore_anon: Option<f64>,
713+
pub workingset_restore_file: Option<f64>,
714+
pub workingset_nodereclaim: Option<f64>,
715+
}
716+
717+
impl CgroupMemoryNumaModel {
718+
pub fn new(
719+
begin: &cgroupfs::MemoryNumaStat,
720+
last: Option<(&cgroupfs::MemoryNumaStat, Duration)>,
721+
) -> CgroupMemoryNumaModel {
722+
let mut model = CgroupMemoryNumaModel {
723+
total: None,
724+
anon: begin.anon,
725+
file: begin.file,
726+
kernel_stack: begin.kernel_stack,
727+
pagetables: begin.pagetables,
728+
shmem: begin.shmem,
729+
file_mapped: begin.file_mapped,
730+
file_dirty: begin.file_dirty,
731+
file_writeback: begin.file_writeback,
732+
swapcached: begin.swapcached,
733+
anon_thp: begin.anon_thp,
734+
file_thp: begin.file_thp,
735+
shmem_thp: begin.shmem_thp,
736+
inactive_anon: begin.inactive_anon,
737+
active_anon: begin.active_anon,
738+
inactive_file: begin.inactive_file,
739+
active_file: begin.active_file,
740+
unevictable: begin.unevictable,
741+
slab_reclaimable: begin.slab_reclaimable,
742+
slab_unreclaimable: begin.slab_unreclaimable,
743+
..Default::default()
744+
};
745+
if let (Some(anon), Some(file), Some(kernel_stack), Some(pagetables)) =
746+
(model.anon, model.file, model.kernel_stack, model.pagetables)
747+
{
748+
model.total = Some(anon + file + kernel_stack + pagetables);
749+
}
750+
751+
if let Some((l, delta)) = last {
752+
model.workingset_refault_anon = count_per_sec!(
753+
begin.workingset_refault_anon,
754+
l.workingset_refault_anon,
755+
delta
756+
);
757+
model.workingset_refault_file = count_per_sec!(
758+
begin.workingset_refault_file,
759+
l.workingset_refault_file,
760+
delta
761+
);
762+
model.workingset_activate_anon = count_per_sec!(
763+
begin.workingset_activate_anon,
764+
l.workingset_activate_anon,
765+
delta
766+
);
767+
model.workingset_activate_file = count_per_sec!(
768+
begin.workingset_activate_file,
769+
l.workingset_activate_file,
770+
delta
771+
);
772+
model.workingset_restore_anon = count_per_sec!(
773+
begin.workingset_restore_anon,
774+
l.workingset_restore_anon,
775+
delta
776+
);
777+
model.workingset_restore_file = count_per_sec!(
778+
begin.workingset_restore_file,
779+
l.workingset_restore_file,
780+
delta
781+
);
782+
model.workingset_nodereclaim = count_per_sec!(
783+
begin.workingset_nodereclaim,
784+
l.workingset_nodereclaim,
785+
delta
786+
);
787+
}
788+
model
789+
}
790+
}
656791

657792
#[cfg(test)]
658793
mod tests {

below/model/src/common_field_ids.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
///
2424
/// This list also servers as documentation for available field ids that could
2525
/// be used in other below crates. A test ensures that this list is up-to-date.
26-
pub const COMMON_MODEL_FIELD_IDS: [&str; 315] = [
26+
pub const COMMON_MODEL_FIELD_IDS: [&str; 342] = [
2727
"system.hostname",
2828
"system.kernel_version",
2929
"system.os_release",
@@ -207,6 +207,33 @@ pub const COMMON_MODEL_FIELD_IDS: [&str; 315] = [
207207
"cgroup.[path:/<cgroup_path>/.]pressure.memory_full_pct",
208208
"cgroup.[path:/<cgroup_path>/.]cgroup_stat.nr_descendants",
209209
"cgroup.[path:/<cgroup_path>/.]cgroup_stat.nr_dying_descendants",
210+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.total",
211+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.anon",
212+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.file",
213+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.kernel_stack",
214+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.pagetables",
215+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.shmem",
216+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.file_mapped",
217+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.file_dirty",
218+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.file_writeback",
219+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.swapcached",
220+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.anon_thp",
221+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.file_thp",
222+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.shmem_thp",
223+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.inactive_anon",
224+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.active_anon",
225+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.inactive_file",
226+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.active_file",
227+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.unevictable",
228+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.slab_reclaimable",
229+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.slab_unreclaimable",
230+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_refault_anon",
231+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_refault_file",
232+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_activate_anon",
233+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_activate_file",
234+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_restore_anon",
235+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_restore_file",
236+
"cgroup.[path:/<cgroup_path>/.]mem_numa.<key>.workingset_nodereclaim",
210237
"process.processes.<key>.pid",
211238
"process.processes.<key>.ppid",
212239
"process.processes.<key>.comm",

below/render/src/default_configs.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ impl HasRenderConfig for model::SingleCgroupModel {
3636
Mem(field_id) => model::CgroupMemoryModel::get_render_config_builder(field_id),
3737
Pressure(field_id) => model::CgroupPressureModel::get_render_config_builder(field_id),
3838
CgroupStat(field_id) => model::CgroupStatModel::get_render_config_builder(field_id),
39+
MemNuma(field_id) => {
40+
model::CgroupMemoryNumaModel::get_render_config_builder(&field_id.subquery_id)
41+
}
3942
}
4043
}
4144
}
@@ -603,3 +606,60 @@ impl HasRenderConfig for model::CgroupStatModel {
603606
}
604607
}
605608
}
609+
610+
impl HasRenderConfig for model::CgroupMemoryNumaModel {
611+
fn get_render_config_builder(field_id: &Self::FieldId) -> RenderConfigBuilder {
612+
use model::CgroupMemoryNumaModelFieldId::*;
613+
let rc = RenderConfigBuilder::new();
614+
match field_id {
615+
Total => rc.title("Total").format(ReadableSize),
616+
Anon => rc.title("Anon").format(ReadableSize),
617+
File => rc.title("File").format(ReadableSize),
618+
KernelStack => rc.title("KernelStack").format(ReadableSize),
619+
Pagetables => rc.title("Pagetables").format(ReadableSize),
620+
Shmem => rc.title("Shmem").format(ReadableSize),
621+
FileMapped => rc.title("FileMapped").format(ReadableSize),
622+
FileDirty => rc.title("FileDirty").format(ReadableSize),
623+
FileWriteback => rc.title("FileWriteback").format(ReadableSize),
624+
Swapcached => rc.title("Swapcached").format(ReadableSize),
625+
AnonThp => rc.title("AnonThp").format(ReadableSize),
626+
FileThp => rc.title("FileThp").format(ReadableSize),
627+
ShmemThp => rc.title("ShmemThp").format(ReadableSize),
628+
InactiveAnon => rc.title("InactiveAnon").format(ReadableSize),
629+
ActiveAnon => rc.title("ActiveAnon").format(ReadableSize),
630+
InactiveFile => rc.title("InactiveFile").format(ReadableSize),
631+
ActiveFile => rc.title("ActiveFile").format(ReadableSize),
632+
Unevictable => rc.title("Unevictable").format(ReadableSize),
633+
SlabReclaimable => rc.title("SlabReclaimable").format(ReadableSize),
634+
SlabUnreclaimable => rc.title("SlabUnreclaimable").format(ReadableSize),
635+
WorkingsetRefaultAnon => rc
636+
.title("Workingset Refaults Anon")
637+
.suffix("/s")
638+
.format(Precision(1)),
639+
WorkingsetRefaultFile => rc
640+
.title("Workingset Refaults File")
641+
.suffix("/s")
642+
.format(Precision(1)),
643+
WorkingsetActivateAnon => rc
644+
.title("Workingset Activates Anon")
645+
.suffix("/s")
646+
.format(Precision(1)),
647+
WorkingsetActivateFile => rc
648+
.title("Workingset Activates File")
649+
.suffix("/s")
650+
.format(Precision(1)),
651+
WorkingsetRestoreAnon => rc
652+
.title("Workingset Restores Anon")
653+
.suffix("/s")
654+
.format(Precision(1)),
655+
WorkingsetRestoreFile => rc
656+
.title("Workingset Restores File")
657+
.suffix("/s")
658+
.format(Precision(1)),
659+
WorkingsetNodereclaim => rc
660+
.title("Workingset Nodereclaims")
661+
.suffix("/s")
662+
.format(Precision(1)),
663+
}
664+
}
665+
}

0 commit comments

Comments
 (0)