use super::backdrop::Backdrop;
use super::ops::{CgroupDef, HoldSpec, Op, Step, execute_scenario, execute_steps};
use super::{CgroupGroup, Ctx, collect_all, dfl_wl, setup_cgroups};
use crate::assert::AssertResult;
use crate::workload::*;
use anyhow::Result;
use std::collections::BTreeSet;
use std::thread;
use std::time::{Duration, Instant};
pub fn custom_nested_cgroup_steady(ctx: &Ctx) -> Result<AssertResult> {
let steps = vec![
Step::with_defs(
vec![
CgroupDef::named("cg_0/sub_a"),
CgroupDef::named("cg_0/sub_b"),
CgroupDef::named("cg_1/sub_b"),
CgroupDef::named("cg_1/sub_a/deep"),
],
HoldSpec::Fixed(Duration::from_secs(2) + ctx.duration),
)
.set_ops(vec![
Op::add_cgroup("cg_0"),
Op::add_cgroup("cg_1"),
Op::add_cgroup("cg_1/sub_a"),
]),
];
execute_steps(ctx, steps)
}
pub fn custom_nested_cgroup_task_move(ctx: &Ctx) -> Result<AssertResult> {
let backdrop = Backdrop::new()
.with_cgroup(CgroupDef::named("cg_0/sub"))
.with_ops(vec![
Op::add_cgroup("cg_0"),
Op::add_cgroup("cg_1"),
Op::add_cgroup("cg_1/sub"),
]);
let steps = vec![
Step::new(
vec![],
HoldSpec::Fixed(Duration::from_secs(2) + ctx.duration / 4),
),
Step::new(
vec![Op::move_all_tasks("cg_0/sub", "cg_0")],
HoldSpec::Frac(0.25),
),
Step::new(
vec![Op::move_all_tasks("cg_0", "cg_1/sub")],
HoldSpec::Frac(0.25),
),
Step::new(
vec![Op::move_all_tasks("cg_1/sub", "cg_1")],
HoldSpec::Frac(0.25),
),
];
execute_scenario(ctx, backdrop, steps)
}
pub fn custom_nested_cgroup_rapid_churn(ctx: &Ctx) -> Result<AssertResult> {
let (handles, mut guard) = setup_cgroups(ctx, 2, &dfl_wl(ctx))?;
let deadline = Instant::now() + ctx.duration;
let mut i = 0usize;
const MAX_EPHEMERAL_NAMES: usize = 100;
while Instant::now() < deadline {
let path = format!("cg_0/churn_{}", i % MAX_EPHEMERAL_NAMES);
guard.add_cgroup_no_cpuset(&path)?;
if i.is_multiple_of(3) {
let deep = format!("{path}/deep");
guard.add_cgroup_no_cpuset(&deep)?;
thread::sleep(Duration::from_millis(50));
if let Err(e) = ctx.cgroups.remove_cgroup(&deep) {
tracing::warn!(cgroup = %deep, err = %format!("{e:#}"), "nested churn: remove_cgroup(deep) failed; parent removal or guard Drop will reap");
}
}
thread::sleep(Duration::from_millis(50));
if let Err(e) = ctx.cgroups.remove_cgroup(&path) {
tracing::warn!(cgroup = %path, err = %format!("{e:#}"), "nested churn: remove_cgroup(path) failed; guard Drop will reap on scenario teardown");
}
i = i.wrapping_add(1);
}
Ok(collect_all(handles, &ctx.assert))
}
pub fn custom_nested_cgroup_cpuset(ctx: &Ctx) -> Result<AssertResult> {
let all = ctx.topo.all_cpus();
if all.len() < 4 {
return Ok(AssertResult::skip("need >=4 CPUs"));
}
let mid = all.len() / 2;
let set_a: BTreeSet<usize> = all[..mid].iter().copied().collect();
let mut _guard = CgroupGroup::new(ctx.cgroups);
_guard.add_cgroup("cg_0", &set_a)?;
thread::sleep(Duration::from_secs(2));
let sub_set: BTreeSet<usize> = all[..mid / 2].iter().copied().collect();
_guard.add_cgroup("cg_0/narrow", &sub_set)?;
let wl = WorkloadConfig {
num_workers: ctx.workers_per_cgroup,
..Default::default()
};
let mut h = WorkloadHandle::spawn(&wl)?;
ctx.cgroups
.move_tasks("cg_0/narrow", &h.worker_pids_for_cgroup_procs()?)?;
h.start();
thread::sleep(ctx.duration);
let reports = h.stop_and_collect();
let mut r = AssertResult::pass();
if ctx.assert.has_worker_checks() {
r.merge(ctx.assert.assert_cgroup(&reports, Some(&sub_set)));
}
Ok(r)
}
pub fn custom_nested_cgroup_imbalance(ctx: &Ctx) -> Result<AssertResult> {
let steps = vec![
Step::with_defs(
vec![
CgroupDef::named("cg_0/sub_a").workers(8),
CgroupDef::named("cg_1/sub_b")
.workers(2)
.work_type(WorkType::bursty(
Duration::from_millis(50),
Duration::from_millis(100),
)),
],
HoldSpec::Fixed(ctx.settle + ctx.duration),
)
.set_ops(vec![Op::add_cgroup("cg_0"), Op::add_cgroup("cg_1")]),
];
execute_steps(ctx, steps)
}
pub fn custom_nested_cgroup_no_ctrl(ctx: &Ctx) -> Result<AssertResult> {
let steps = vec![
Step::with_defs(
vec![
CgroupDef::named("cg_0/sub_a/deep"),
CgroupDef::named("cg_1/sub_b"),
],
HoldSpec::Fixed(ctx.settle + ctx.duration),
)
.set_ops(vec![
Op::add_cgroup("cg_0"),
Op::add_cgroup("cg_0/sub_a"),
Op::add_cgroup("cg_1"),
]),
];
execute_steps(ctx, steps)
}