1use super::Ctx;
4use super::backdrop::Backdrop;
5use super::ops::{CgroupDef, CpusetSpec, HoldSpec, Op, Step, execute_scenario, execute_steps};
6use crate::assert::AssertResult;
7use crate::workload::*;
8use anyhow::Result;
9use std::time::Duration;
10
11pub fn custom_cgroup_add_load_imbalance(ctx: &Ctx) -> Result<AssertResult> {
18 let backdrop = Backdrop::new()
19 .push_cgroup(
20 CgroupDef::named("cg_0")
21 .workers(1)
22 .work_type(WorkType::YieldHeavy),
23 )
24 .push_cgroup(
25 CgroupDef::named("cg_1")
26 .workers(1)
27 .work_type(WorkType::YieldHeavy),
28 );
29 let steps = vec![
30 Step::new(vec![], ctx.settled_hold(0.5)),
32 Step::with_defs(
34 vec![CgroupDef::named("cg_2").workers(16)],
35 HoldSpec::frac(0.5),
36 ),
37 ];
38
39 execute_scenario(ctx, backdrop, steps)
40}
41
42pub fn custom_cgroup_imbalance_mixed_workload(ctx: &Ctx) -> Result<AssertResult> {
44 let steps = vec![Step::with_defs(
45 vec![
46 CgroupDef::named("cg_0").workers(8),
47 ctx.cgroup_def("cg_1").work_type(WorkType::bursty(
48 Duration::from_millis(100),
49 Duration::from_millis(50),
50 )),
51 ctx.cgroup_def("cg_2").work_type(WorkType::IoSyncWrite),
52 ],
53 ctx.settled_hold(1.0),
54 )];
55
56 execute_steps(ctx, steps)
57}
58
59pub fn custom_cgroup_load_oscillation(ctx: &Ctx) -> Result<AssertResult> {
70 let heavy_cg = |name: &'static str| CgroupDef::named(name).workers(ctx.workers_per_cgroup * 2);
71 let light_cg = |name: &'static str| {
72 CgroupDef::named(name)
73 .workers(1)
74 .work_type(WorkType::YieldHeavy)
75 };
76
77 let mut steps = vec![Step::with_defs(
78 vec![heavy_cg("cg_0"), light_cg("cg_1")],
79 ctx.settled_hold(0.25),
80 )];
81
82 for i in 1..4 {
83 let defs = if i % 2 == 0 {
84 vec![heavy_cg("cg_0"), light_cg("cg_1")]
85 } else {
86 vec![light_cg("cg_0"), heavy_cg("cg_1")]
87 };
88 steps.push(Step::with_defs(defs, HoldSpec::frac(0.25)));
89 }
90
91 execute_steps(ctx, steps)
92}
93
94pub fn custom_cgroup_4way_load_imbalance(ctx: &Ctx) -> Result<AssertResult> {
96 if ctx.topo.all_cpus().len() < 5 {
97 return Ok(AssertResult::skip("need >=5 CPUs for 4 cgroups"));
98 }
99
100 let steps = vec![Step::with_defs(
101 vec![
102 CgroupDef::named("cg_0").workers(16),
103 CgroupDef::named("cg_1")
104 .workers(1)
105 .work_type(WorkType::YieldHeavy),
106 CgroupDef::named("cg_2").workers(8),
107 CgroupDef::named("cg_3").workers(4),
108 ],
109 ctx.settled_hold(1.0),
110 )];
111
112 execute_steps(ctx, steps)
113}
114
115pub fn custom_cgroup_cpuset_imbalance_combined(ctx: &Ctx) -> Result<AssertResult> {
117 let mid = ctx.topo.usable_cpus().len() / 2;
118
119 let steps = vec![Step::with_defs(
120 vec![
121 CgroupDef::named("cg_0")
122 .cpuset(CpusetSpec::disjoint(0, 2))
123 .workers(mid * 2),
124 CgroupDef::named("cg_1")
125 .cpuset(CpusetSpec::disjoint(1, 2))
126 .workers(2)
127 .work_type(WorkType::bursty(
128 Duration::from_millis(50),
129 Duration::from_millis(150),
130 )),
131 ],
132 ctx.settled_hold(1.0),
133 )];
134
135 execute_steps(ctx, steps)
136}
137
138pub fn custom_cgroup_cpuset_overlap_imbalance_combined(ctx: &Ctx) -> Result<AssertResult> {
140 let sets = ctx.topo.overlapping_cpusets(3, 0.5);
141 if sets.iter().any(|s| s.is_empty()) {
142 return Ok(AssertResult::skip("not enough CPUs"));
143 }
144
145 let steps = vec![Step::with_defs(
146 vec![
147 CgroupDef::named("cg_0")
148 .cpuset(CpusetSpec::Exact(sets[0].clone()))
149 .workers(12),
150 CgroupDef::named("cg_1")
151 .cpuset(CpusetSpec::Exact(sets[1].clone()))
152 .workers(2)
153 .work_type(WorkType::bursty(
154 Duration::from_millis(50),
155 Duration::from_millis(100),
156 )),
157 CgroupDef::named("cg_2")
158 .cpuset(CpusetSpec::Exact(sets[2].clone()))
159 .workers(1)
160 .work_type(WorkType::YieldHeavy),
161 ],
162 ctx.settled_hold(1.0),
163 )];
164
165 execute_steps(ctx, steps)
166}
167
168pub fn custom_cgroup_no_ctrl_task_migration(ctx: &Ctx) -> Result<AssertResult> {
180 let backdrop = Backdrop::new()
184 .push_cgroup(ctx.cgroup_def("cg_0"))
185 .push_cgroup(ctx.cgroup_def("cg_mobile"))
186 .push_op(Op::add_cgroup("cg_1"));
187
188 let mut steps = vec![Step::new(vec![], HoldSpec::fixed(Duration::from_secs(2)))];
191
192 let mut move_steps: Vec<Step> = (0..9)
194 .map(|i| {
195 let (from, to) = if i % 2 == 0 {
196 ("cg_mobile", "cg_1")
197 } else {
198 ("cg_1", "cg_mobile")
199 };
200 Step::new(vec![Op::move_all_tasks(from, to)], HoldSpec::frac(0.1))
201 })
202 .collect();
203 steps.append(&mut move_steps);
204 steps.push(Step::new(vec![], HoldSpec::frac(0.1)));
206
207 execute_scenario(ctx, backdrop, steps)
208}
209
210pub fn custom_cgroup_no_ctrl_imbalance(ctx: &Ctx) -> Result<AssertResult> {
220 let backdrop = Backdrop::new()
227 .push_cgroup(CgroupDef::named("cg_heavy").workers(6))
228 .push_cgroup(CgroupDef::named("cg_mobile").workers(2))
229 .push_cgroup(
230 CgroupDef::named("cg_light")
231 .workers(2)
232 .work_type(WorkType::bursty(
233 Duration::from_millis(50),
234 Duration::from_millis(100),
235 )),
236 )
237 .push_op(Op::add_cgroup("cg_overflow"));
238
239 let mut steps = vec![Step::new(vec![], HoldSpec::fixed(ctx.settle))];
240
241 let mut move_steps: Vec<Step> = (0..5)
242 .map(|i| {
243 let (from, to) = if i % 2 == 0 {
244 ("cg_mobile", "cg_overflow")
245 } else {
246 ("cg_overflow", "cg_mobile")
247 };
248 Step::new(
249 vec![Op::move_all_tasks(from, to)],
250 HoldSpec::frac(1.0 / 6.0),
251 )
252 })
253 .collect();
254 steps.append(&mut move_steps);
255 steps.push(Step::new(vec![], HoldSpec::frac(1.0 / 6.0)));
256
257 execute_scenario(ctx, backdrop, steps)
258}
259
260pub fn custom_cgroup_no_ctrl_cpuset_change(ctx: &Ctx) -> Result<AssertResult> {
268 let backdrop = Backdrop::new()
269 .push_cgroup(CgroupDef::named("cg_0").cpuset(CpusetSpec::disjoint(0, 2)))
270 .push_cgroup(CgroupDef::named("cg_1").cpuset(CpusetSpec::disjoint(1, 2)));
271
272 let steps = vec![
273 Step::new(vec![], ctx.settled_hold(0.5)),
275 Step::new(
277 vec![Op::clear_cpuset("cg_0"), Op::clear_cpuset("cg_1")],
278 HoldSpec::frac(0.5),
279 ),
280 ];
281
282 execute_scenario(ctx, backdrop, steps)
283}
284
285pub fn custom_cgroup_no_ctrl_load_imbalance(ctx: &Ctx) -> Result<AssertResult> {
287 let steps = vec![Step::with_defs(
288 vec![
289 CgroupDef::named("cg_0").workers(16),
290 CgroupDef::named("cg_1")
291 .workers(1)
292 .work_type(WorkType::YieldHeavy),
293 ],
294 ctx.settled_hold(1.0),
295 )];
296
297 execute_steps(ctx, steps)
298}
299
300pub fn custom_cgroup_io_compute_imbalance(ctx: &Ctx) -> Result<AssertResult> {
302 let steps = vec![Step::with_defs(
303 vec![
304 ctx.cgroup_def("cg_0").work_type(WorkType::IoSyncWrite),
305 CgroupDef::named("cg_1").workers(ctx.topo.total_cpus()),
306 ],
307 ctx.settled_hold(1.0),
308 )];
309
310 execute_steps(ctx, steps)
311}