From 52db350b405153d1bc5cbc619060d4fc360b230e Mon Sep 17 00:00:00 2001 From: David Vernet Date: Wed, 21 Jun 2023 11:05:24 -0500 Subject: [PATCH] atropos: Use Instant instead of SystemTime Atropos currently uses the std::time::SystemTime object to time when load balance steps, etc should occur. As described in [0], SystemTime::duration_since() can throw an error if the @earlier field is in fact later than self. This can occur randomly even with correct code, as according to the docs: > This function may fail because measurements taken earlier are not > guaranteed to always be before later measurements (due to anomalies > such as the system clock being adjusted either forwards or backwards). [0]: https://doc.rust-lang.org/std/time/struct.SystemTime.html#method.duration_since The solution is to instead use std::time::Instant, which is monotonic as described in [1]. [1]: https://doc.rust-lang.org/std/time/struct.Instant.html#method.duration_since Without this patch, atropos will error out after ~1 minute of running rcutorture. With the patch, it is able to run (seemingly) indefinitely. Signed-off-by: David Vernet --- tools/sched_ext/atropos/src/main.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/sched_ext/atropos/src/main.rs b/tools/sched_ext/atropos/src/main.rs index 1ee8f11f8dd260..6d8ea6f4ef3c00 100644 --- a/tools/sched_ext/atropos/src/main.rs +++ b/tools/sched_ext/atropos/src/main.rs @@ -17,7 +17,7 @@ use std::sync::atomic::AtomicBool; use std::sync::atomic::Ordering; use std::sync::Arc; use std::time::Duration; -use std::time::SystemTime; +use std::time::Instant; use anyhow::anyhow; use anyhow::bail; @@ -844,7 +844,7 @@ struct Scheduler<'a> { top: Arc, - prev_at: SystemTime, + prev_at: Instant, prev_total_cpu: MyCpuStat, task_loads: BTreeMap, @@ -928,7 +928,7 @@ impl<'a> Scheduler<'a> { top: top.clone(), - prev_at: SystemTime::now(), + prev_at: Instant::now(), prev_total_cpu, task_loads: BTreeMap::new(), @@ -1060,7 +1060,7 @@ impl<'a> Scheduler<'a> { } fn lb_step(&mut self) -> Result<()> { - let started_at = std::time::SystemTime::now(); + let started_at = Instant::now(); let bpf_stats = self.read_bpf_stats()?; let cpu_busy = self.get_cpu_busy()?; @@ -1073,7 +1073,7 @@ impl<'a> Scheduler<'a> { &mut self.nr_lb_data_errors, ); - lb.read_task_loads(started_at.duration_since(self.prev_at)?)?; + lb.read_task_loads(started_at.duration_since(self.prev_at))?; lb.calculate_dom_load_balance()?; if self.balance_load { @@ -1087,7 +1087,7 @@ impl<'a> Scheduler<'a> { self.report( &bpf_stats, cpu_busy, - std::time::SystemTime::now().duration_since(started_at)?, + Instant::now().duration_since(started_at), load_avg, &dom_loads, &imbal, @@ -1121,12 +1121,12 @@ impl<'a> Scheduler<'a> { } fn run(&mut self, shutdown: Arc) -> Result<()> { - let now = std::time::SystemTime::now(); + let now = Instant::now(); let mut next_tune_at = now + self.tune_interval; let mut next_sched_at = now + self.sched_interval; while !shutdown.load(Ordering::Relaxed) && self.read_bpf_exit_type() == 0 { - let now = std::time::SystemTime::now(); + let now = Instant::now(); if now >= next_tune_at { self.tuner.step(&mut self.skel)?; @@ -1147,7 +1147,7 @@ impl<'a> Scheduler<'a> { std::thread::sleep( next_sched_at .min(next_tune_at) - .duration_since(std::time::SystemTime::now())?, + .duration_since(Instant::now()), ); }