use super::backdrop::Backdrop;
use super::ops::{CgroupDef, CpusetSpec, HoldSpec, Step, execute_scenario};
use super::{Ctx, collect_all, dfl_wl, setup_cgroups};
use crate::assert::AssertResult;
use crate::workload::*;
use anyhow::Result;
use std::thread;
use std::time::{Duration, Instant};
pub fn custom_cgroup_add_midrun(ctx: &Ctx) -> Result<AssertResult> {
let max_new = ctx.topo.total_cpus().saturating_sub(3).min(2);
if max_new == 0 {
return Ok(AssertResult::skip("need >=4 CPUs"));
}
let extra_names: &[&str] = &["cg_2", "cg_3"];
let phase2_setup: Vec<CgroupDef> = extra_names[..max_new]
.iter()
.map(|&name| CgroupDef::named(name))
.collect();
let backdrop = Backdrop::new()
.with_cgroup(CgroupDef::named("cg_0"))
.with_cgroup(CgroupDef::named("cg_1"));
let steps = vec![
Step::new(vec![], HoldSpec::Fixed(ctx.settle + ctx.duration / 2)),
Step::with_defs(phase2_setup, HoldSpec::Frac(0.5)),
];
execute_scenario(ctx, backdrop, steps)
}
pub fn custom_cgroup_remove_midrun(ctx: &Ctx) -> Result<AssertResult> {
let n = 4.min(ctx.topo.total_cpus().saturating_sub(1));
if n < 2 {
return Ok(AssertResult::skip("need >=3 CPUs"));
}
let half = n / 2;
let cgroup_names: &[&str] = &["cg_0", "cg_1", "cg_2", "cg_3"];
let mut backdrop = Backdrop::new();
for &name in &cgroup_names[..half] {
backdrop = backdrop.with_cgroup(CgroupDef::named(name));
}
let step0_defs: Vec<CgroupDef> = cgroup_names[half..n]
.iter()
.map(|&name| CgroupDef::named(name))
.collect();
let steps = vec![
Step::with_defs(step0_defs, HoldSpec::Fixed(ctx.settle + ctx.duration / 2)),
Step::new(vec![], HoldSpec::Frac(0.5)),
];
execute_scenario(ctx, backdrop, steps)
}
pub fn custom_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 n = format!("ephemeral_{}", i % MAX_EPHEMERAL_NAMES);
guard.add_cgroup_no_cpuset(&n)?;
thread::sleep(Duration::from_millis(100));
if let Err(e) = ctx.cgroups.remove_cgroup(&n) {
tracing::warn!(cgroup = %n, err = %format!("{e:#}"), "rapid churn: remove_cgroup failed; guard Drop will reap on scenario teardown");
}
i = i.wrapping_add(1);
}
Ok(collect_all(handles, &ctx.assert))
}
pub fn custom_cgroup_cpuset_add_remove(ctx: &Ctx) -> Result<AssertResult> {
if ctx.topo.all_cpus().len() < 4 {
return Ok(AssertResult::skip("need >=4 CPUs"));
}
let backdrop = Backdrop::new().with_cgroups([
CgroupDef::named("cg_0").with_cpuset(CpusetSpec::disjoint(0, 3)),
CgroupDef::named("cg_1").with_cpuset(CpusetSpec::disjoint(1, 3)),
]);
let steps = vec![
Step::new(vec![], HoldSpec::Fixed(ctx.settle + ctx.duration / 3)),
Step::with_defs(
vec![CgroupDef::named("cg_2").with_cpuset(CpusetSpec::disjoint(2, 3))],
HoldSpec::Frac(1.0 / 3.0),
),
Step::new(vec![], HoldSpec::Frac(1.0 / 3.0)),
];
execute_scenario(ctx, backdrop, steps)
}
pub fn custom_cgroup_add_during_imbalance(ctx: &Ctx) -> Result<AssertResult> {
let backdrop = Backdrop::new().with_cgroups([
CgroupDef::named("cg_0").workers(8),
CgroupDef::named("cg_1")
.workers(2)
.work_type(WorkType::bursty(
Duration::from_millis(50),
Duration::from_millis(100),
)),
]);
let steps = vec![
Step::new(vec![], HoldSpec::Fixed(ctx.settle + ctx.duration / 2)),
Step::with_defs(
vec![CgroupDef::named("cg_2").workers(4)],
HoldSpec::Frac(0.5),
),
];
execute_scenario(ctx, backdrop, steps)
}