Skip to content

Commit 37ff5bc

Browse files
committed
monitor: adjust for critical runners in compute_runner_changes()
1 parent a1edefe commit 37ff5bc

File tree

1 file changed

+104
-29
lines changed

1 file changed

+104
-29
lines changed

monitor/src/policy.rs

Lines changed: 104 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -217,9 +217,31 @@ impl Policy {
217217
result.unregister_and_destroy_runner_ids.push(id);
218218
}
219219

220-
let profile_wanted_counts = self
220+
// Adjust for critical runners, regardless of whether they fit the new policy.
221+
let mut scenario = self
222+
.profiles()
223+
.map(|(key, profile)| {
224+
(
225+
key.to_owned(),
226+
self.target_runner_count(profile)
227+
.max(self.critical_runner_count(profile)),
228+
)
229+
})
230+
.collect::<BTreeMap<_, _>>();
231+
let mut profile_target_counts = self
221232
.profiles()
222-
.map(|(key, profile)| (key, self.wanted_runner_count(profile)));
233+
.map(|(key, profile)| (key.to_owned(), self.target_runner_count(profile)))
234+
.collect::<BTreeMap<_, _>>();
235+
let mut profile_wanted_counts = self
236+
.profiles()
237+
.map(|(key, profile)| (key.to_owned(), self.wanted_runner_count(profile)))
238+
.collect::<BTreeMap<_, _>>();
239+
self.adjust_runner_counts_for_resource_limits(
240+
&mut scenario,
241+
&mut profile_target_counts,
242+
&mut profile_wanted_counts,
243+
);
244+
223245
for (profile_key, wanted_count) in profile_wanted_counts {
224246
result
225247
.create_counts_by_profile_key
@@ -622,13 +644,41 @@ impl Policy {
622644
*count += *extra_count;
623645
}
624646
}
625-
626-
// Starting with the ideal scenario, try to adjust the scenario until it validates.
627647
let mut adjusted_override_counts = profile_override_counts;
628-
'validate: while self
629-
.validate_resource_requirements(dbg!(&scenario))
630-
.is_err()
631-
{
648+
self.adjust_runner_counts_for_resource_limits(
649+
&mut scenario,
650+
&mut adjusted_override_counts,
651+
&mut profile_extra_counts,
652+
);
653+
654+
// Fail if the requested override had to be adjusted so far that it became meaningless.
655+
if profile_extra_counts.values().sum::<usize>() == 0 {
656+
bail!("Requested override had to be adjusted so far that it became meaningless");
657+
}
658+
659+
self.current_override = Some(Override {
660+
profile_override_counts: adjusted_override_counts,
661+
profile_target_counts: scenario,
662+
actual_runner_ids_by_profile_key: BTreeMap::default(),
663+
});
664+
665+
Ok(self
666+
.current_override
667+
.as_ref()
668+
.expect("Guaranteed by assignment"))
669+
}
670+
671+
/// - `scenario` is the proposed ideal scenario, including `adjusted_counts` and critical runners
672+
/// - `adjusted_counts` are the proposed runner counts after we create `extra_counts`
673+
/// - `extra_counts` are the proposed create counts that will achieve `adjusted_counts`
674+
fn adjust_runner_counts_for_resource_limits(
675+
&self,
676+
scenario: &mut BTreeMap<String, usize>,
677+
adjusted_counts: &mut BTreeMap<String, usize>,
678+
profile_extra_counts: &mut BTreeMap<String, usize>,
679+
) {
680+
// Starting with the given scenario, try to adjust the scenario until it validates.
681+
'validate: while self.validate_resource_requirements(&scenario).is_err() {
632682
// Try profiles in descending count order, to avoid starving niche runners.
633683
let candidate_profile_keys = scenario
634684
.clone()
@@ -639,7 +689,7 @@ impl Policy {
639689
.collect::<Vec<_>>();
640690
// First try decrementing a profile that was not requested.
641691
for profile_key in candidate_profile_keys.iter() {
642-
if !adjusted_override_counts.contains_key(profile_key) {
692+
if !adjusted_counts.contains_key(profile_key) {
643693
let profile = self
644694
.profile(profile_key)
645695
.expect("Guaranteed by initialiser");
@@ -655,7 +705,7 @@ impl Policy {
655705
}
656706
// If none of those profiles could be decremented, try decrementing a profile that was requested.
657707
for profile_key in candidate_profile_keys.iter() {
658-
if adjusted_override_counts.contains_key(profile_key) {
708+
if adjusted_counts.contains_key(profile_key) {
659709
let profile = self
660710
.profile(profile_key)
661711
.expect("Guaranteed by initialiser");
@@ -664,8 +714,7 @@ impl Policy {
664714
.expect("Guaranteed by candidate_profile_keys");
665715
// Only try decrementing profiles that have non-critical runners to spare.
666716
if *count > self.critical_runner_count(profile) {
667-
if let Some(override_count) = adjusted_override_counts.get_mut(profile_key)
668-
{
717+
if let Some(override_count) = adjusted_counts.get_mut(profile_key) {
669718
let extra_count = profile_extra_counts
670719
.get_mut(profile_key)
671720
.expect("Guaranteed by initialiser");
@@ -683,23 +732,7 @@ impl Policy {
683732
break;
684733
}
685734

686-
// Fail if the requested override had to be adjusted so far that it became meaningless.
687-
if profile_extra_counts.values().sum::<usize>() == 0 {
688-
bail!("Requested override had to be adjusted so far that it became meaningless");
689-
}
690-
691-
info!(adjusted_override_counts = ?adjusted_override_counts, extra_counts = ?profile_extra_counts, ?scenario, "Found solution for override request");
692-
693-
self.current_override = Some(Override {
694-
profile_override_counts: adjusted_override_counts,
695-
profile_target_counts: scenario,
696-
actual_runner_ids_by_profile_key: BTreeMap::default(),
697-
});
698-
699-
Ok(self
700-
.current_override
701-
.as_ref()
702-
.expect("Guaranteed by assignment"))
735+
info!(?scenario, adjusted_counts = ?adjusted_counts, extra_counts = ?profile_extra_counts, "Best possible proposal");
703736
}
704737

705738
pub fn cancel_override(&mut self) -> eyre::Result<Option<Override>> {
@@ -1388,6 +1421,48 @@ mod test {
13881421
Ok(())
13891422
}
13901423

1424+
#[test]
1425+
fn test_compute_runner_changes_dynamic() -> eyre::Result<()> {
1426+
let mut policy = Policy::new(
1427+
[
1428+
("linux".to_owned(), profile("linux", 5, 8, "0B")),
1429+
("windows".to_owned(), profile("windows", 4, 8, "0B")),
1430+
("macos".to_owned(), profile("macos", 3, 8, "0B")),
1431+
("wpt".to_owned(), profile("wpt", 0, 24, "0B")),
1432+
]
1433+
.into(),
1434+
)?;
1435+
let fresh = system_time_minus_seconds(0);
1436+
set_base_image_mtime_for_test("/var/lib/libvirt/images/base/linux/base.img@", fresh);
1437+
set_base_image_mtime_for_test("/var/lib/libvirt/images/base/macos/base.img@", fresh);
1438+
set_base_image_mtime_for_test("/var/lib/libvirt/images/base/windows/base.img@", fresh);
1439+
set_base_image_mtime_for_test("/var/lib/libvirt/images/base/wpt/base.img@", fresh);
1440+
policy.set_base_image_snapshot("linux", "")?;
1441+
policy.set_base_image_snapshot("macos", "")?;
1442+
policy.set_base_image_snapshot("windows", "")?;
1443+
policy.set_base_image_snapshot("wpt", "")?;
1444+
1445+
// Proposed create counts should be adjusted for critical runners, regardless of whether
1446+
// those runners fit the current policy.
1447+
let fake_runners = vec![FakeRunner::busy("wpt"), FakeRunner::reserved("wpt")];
1448+
policy.set_runners(runners(fake_runners.clone()));
1449+
assert_eq!(
1450+
policy.compute_runner_changes()?,
1451+
RunnerChanges {
1452+
unregister_and_destroy_runner_ids: vec![],
1453+
create_counts_by_profile_key: [
1454+
("linux".to_owned(), 2),
1455+
("windows".to_owned(), 2),
1456+
("macos".to_owned(), 2),
1457+
("wpt".to_owned(), 0),
1458+
]
1459+
.into(),
1460+
},
1461+
);
1462+
1463+
Ok(())
1464+
}
1465+
13911466
#[test]
13921467
fn test_try_override() -> eyre::Result<()> {
13931468
let mut policy = Policy::new(

0 commit comments

Comments
 (0)