use super::Ctx;
use super::backdrop::Backdrop;
use super::ops::{CgroupDef, CpusetSpec, HoldSpec, Op, Step, execute_scenario, execute_steps};
use crate::assert::AssertResult;
use crate::workload::*;
use anyhow::Result;
use std::time::Duration;
pub fn custom_cgroup_add_load_imbalance(ctx: &Ctx) -> Result<AssertResult> {
let backdrop = Backdrop::new()
.with_cgroup(
CgroupDef::named("cg_0")
.workers(1)
.work_type(WorkType::YieldHeavy),
)
.with_cgroup(
CgroupDef::named("cg_1")
.workers(1)
.work_type(WorkType::YieldHeavy),
);
let steps = vec![
Step::new(vec![], HoldSpec::Fixed(ctx.settle + ctx.duration / 2)),
Step::with_defs(
vec![CgroupDef::named("cg_2").workers(16)],
HoldSpec::Frac(0.5),
),
];
execute_scenario(ctx, backdrop, steps)
}
pub fn custom_cgroup_imbalance_mixed_workload(ctx: &Ctx) -> Result<AssertResult> {
let steps = vec![Step::with_defs(
vec![
CgroupDef::named("cg_0").workers(8),
CgroupDef::named("cg_1")
.workers(ctx.workers_per_cgroup)
.work_type(WorkType::bursty(100, 50)),
CgroupDef::named("cg_2")
.workers(ctx.workers_per_cgroup)
.work_type(WorkType::IoSync),
],
HoldSpec::Fixed(ctx.settle + ctx.duration),
)];
execute_steps(ctx, steps)
}
pub fn custom_cgroup_load_oscillation(ctx: &Ctx) -> Result<AssertResult> {
let heavy_cg = |name: &'static str| CgroupDef::named(name).workers(ctx.workers_per_cgroup * 2);
let light_cg = |name: &'static str| {
CgroupDef::named(name)
.workers(1)
.work_type(WorkType::YieldHeavy)
};
let mut steps = vec![Step::with_defs(
vec![heavy_cg("cg_0"), light_cg("cg_1")],
HoldSpec::Fixed(ctx.settle + ctx.duration / 4),
)];
for i in 1..4 {
let defs = if i % 2 == 0 {
vec![heavy_cg("cg_0"), light_cg("cg_1")]
} else {
vec![light_cg("cg_0"), heavy_cg("cg_1")]
};
steps.push(Step::with_defs(defs, HoldSpec::Frac(0.25)));
}
execute_steps(ctx, steps)
}
pub fn custom_cgroup_4way_load_imbalance(ctx: &Ctx) -> Result<AssertResult> {
if ctx.topo.all_cpus().len() < 5 {
return Ok(AssertResult::skip("need >=5 CPUs for 4 cgroups"));
}
let steps = vec![Step::with_defs(
vec![
CgroupDef::named("cg_0").workers(16),
CgroupDef::named("cg_1")
.workers(1)
.work_type(WorkType::YieldHeavy),
CgroupDef::named("cg_2").workers(8),
CgroupDef::named("cg_3").workers(4),
],
HoldSpec::Fixed(ctx.settle + ctx.duration),
)];
execute_steps(ctx, steps)
}
pub fn custom_cgroup_cpuset_imbalance_combined(ctx: &Ctx) -> Result<AssertResult> {
let mid = ctx.topo.usable_cpus().len() / 2;
let steps = vec![Step::with_defs(
vec![
CgroupDef::named("cg_0")
.with_cpuset(CpusetSpec::disjoint(0, 2))
.workers(mid * 2),
CgroupDef::named("cg_1")
.with_cpuset(CpusetSpec::disjoint(1, 2))
.workers(2)
.work_type(WorkType::bursty(50, 150)),
],
HoldSpec::Fixed(ctx.settle + ctx.duration),
)];
execute_steps(ctx, steps)
}
pub fn custom_cgroup_cpuset_overlap_imbalance_combined(ctx: &Ctx) -> Result<AssertResult> {
let sets = ctx.topo.overlapping_cpusets(3, 0.5);
if sets.iter().any(|s| s.is_empty()) {
return Ok(AssertResult::skip("not enough CPUs"));
}
let steps = vec![Step::with_defs(
vec![
CgroupDef::named("cg_0")
.with_cpuset(CpusetSpec::Exact(sets[0].clone()))
.workers(12),
CgroupDef::named("cg_1")
.with_cpuset(CpusetSpec::Exact(sets[1].clone()))
.workers(2)
.work_type(WorkType::bursty(50, 100)),
CgroupDef::named("cg_2")
.with_cpuset(CpusetSpec::Exact(sets[2].clone()))
.workers(1)
.work_type(WorkType::YieldHeavy),
],
HoldSpec::Fixed(ctx.settle + ctx.duration),
)];
execute_steps(ctx, steps)
}
pub fn custom_cgroup_no_ctrl_task_migration(ctx: &Ctx) -> Result<AssertResult> {
let backdrop = Backdrop::new()
.with_cgroup(CgroupDef::named("cg_0").workers(ctx.workers_per_cgroup))
.with_cgroup(CgroupDef::named("cg_mobile").workers(ctx.workers_per_cgroup))
.with_op(Op::add_cgroup("cg_1"));
let mut steps = vec![Step::new(vec![], HoldSpec::Fixed(Duration::from_secs(2)))];
let mut move_steps: Vec<Step> = (0..9)
.map(|i| {
let (from, to) = if i % 2 == 0 {
("cg_mobile", "cg_1")
} else {
("cg_1", "cg_mobile")
};
Step::new(vec![Op::move_all_tasks(from, to)], HoldSpec::Frac(0.1))
})
.collect();
steps.append(&mut move_steps);
steps.push(Step::new(vec![], HoldSpec::Frac(0.1)));
execute_scenario(ctx, backdrop, steps)
}
pub fn custom_cgroup_no_ctrl_imbalance(ctx: &Ctx) -> Result<AssertResult> {
let backdrop = Backdrop::new()
.with_cgroup(CgroupDef::named("cg_heavy").workers(6))
.with_cgroup(CgroupDef::named("cg_mobile").workers(2))
.with_cgroup(
CgroupDef::named("cg_light")
.workers(2)
.work_type(WorkType::bursty(50, 100)),
)
.with_op(Op::add_cgroup("cg_overflow"));
let mut steps = vec![Step::new(vec![], HoldSpec::Fixed(ctx.settle))];
let mut move_steps: Vec<Step> = (0..5)
.map(|i| {
let (from, to) = if i % 2 == 0 {
("cg_mobile", "cg_overflow")
} else {
("cg_overflow", "cg_mobile")
};
Step::new(
vec![Op::move_all_tasks(from, to)],
HoldSpec::Frac(1.0 / 6.0),
)
})
.collect();
steps.append(&mut move_steps);
steps.push(Step::new(vec![], HoldSpec::Frac(1.0 / 6.0)));
execute_scenario(ctx, backdrop, steps)
}
pub fn custom_cgroup_no_ctrl_cpuset_change(ctx: &Ctx) -> Result<AssertResult> {
let backdrop = Backdrop::new()
.with_cgroup(CgroupDef::named("cg_0").with_cpuset(CpusetSpec::disjoint(0, 2)))
.with_cgroup(CgroupDef::named("cg_1").with_cpuset(CpusetSpec::disjoint(1, 2)));
let steps = vec![
Step::new(vec![], HoldSpec::Fixed(ctx.settle + ctx.duration / 2)),
Step::new(
vec![Op::clear_cpuset("cg_0"), Op::clear_cpuset("cg_1")],
HoldSpec::Frac(0.5),
),
];
execute_scenario(ctx, backdrop, steps)
}
pub fn custom_cgroup_no_ctrl_load_imbalance(ctx: &Ctx) -> Result<AssertResult> {
let steps = vec![Step::with_defs(
vec![
CgroupDef::named("cg_0").workers(16),
CgroupDef::named("cg_1")
.workers(1)
.work_type(WorkType::YieldHeavy),
],
HoldSpec::Fixed(ctx.settle + ctx.duration),
)];
execute_steps(ctx, steps)
}
pub fn custom_cgroup_io_compute_imbalance(ctx: &Ctx) -> Result<AssertResult> {
let steps = vec![Step::with_defs(
vec![
CgroupDef::named("cg_0")
.workers(ctx.workers_per_cgroup)
.work_type(WorkType::IoSync),
CgroupDef::named("cg_1").workers(ctx.topo.total_cpus()),
],
HoldSpec::Fixed(ctx.settle + ctx.duration),
)];
execute_steps(ctx, steps)
}