ax_task/sched/system/task_system/scheduling/
balance.rs1use super::*;
4
5impl TaskSystem {
6 pub fn request_idle_pull(&self, mut cpu: Pin<&mut CpuLocal>) -> Result<bool, TaskError> {
12 self.ensure_owner_cpu_context(&cpu)?;
13 if task_runtime::in_hard_irq() {
14 return Ok(false);
15 }
16 self.ensure_owner_cpu_online(&cpu)?;
17 if !self.root_domain.has_idle_pull_source() {
18 cpu.as_mut().reset_idle_pull_scan();
19 return Ok(false);
20 }
21 if !cpu.idle_pull_eligible() || cpu.has_remote_work() {
22 cpu.as_mut().reset_idle_pull_scan();
23 return Ok(false);
24 }
25 let target_remote = Arc::clone(cpu.remote());
26 let reservation = match target_remote.begin_idle_pull() {
27 IdlePullReservation::Started(reservation) => reservation,
28 IdlePullReservation::AlreadyPending => return Ok(true),
29 IdlePullReservation::Busy => return Ok(false),
30 };
31 if !cpu.idle_pull_eligible() || cpu.has_remote_work() {
32 target_remote.cancel_idle_pull(reservation);
33 cpu.as_mut().reset_idle_pull_scan();
34 return Ok(false);
35 }
36 let target = cpu.owner();
37 let source = self
38 .root_domain
39 .find_idle_pull_source(target, cpu.idle_pull_visited());
40 let Some((source, class)) = source else {
41 target_remote.cancel_idle_pull(reservation);
42 cpu.as_mut().reset_idle_pull_scan();
43 return Ok(false);
44 };
45 cpu.as_mut().mark_idle_pull_source(source);
46 let Some(source_local) = self.cpu_remote(source) else {
47 target_remote.cancel_idle_pull(reservation);
48 cpu.request_scheduler_work();
49 return Ok(true);
50 };
51 let message = InboxMessage::balance_request(source, target, reservation, class);
52 let result = source_local.publish_owner_control(cpu.balance_request_node(), message);
53 match result {
54 PublishResult::Published => Ok(true),
55 PublishResult::AlreadyPending => {
56 target_remote.cancel_idle_pull(reservation);
57 cpu.request_scheduler_work();
58 Ok(true)
59 }
60 PublishResult::WrongKind => {
61 target_remote.cancel_idle_pull(reservation);
62 cpu.request_scheduler_work();
63 Ok(true)
64 }
65 }
66 }
67
68 pub(in crate::sched::system::task_system) fn request_fair_nohz_idle_pulls(&self) -> bool {
76 let mut requested = false;
77 for (index, target_remote) in self.cpu_remotes.iter().enumerate() {
78 let target = CpuId::new(index as u32);
79 if !self.root_domain.fair_nohz_idle_target(target)
80 || !target_remote.accepts_placement()
81 || !target_remote.is_scheduler_ready()
82 {
83 continue;
84 }
85 requested |= self.request_fair_nohz_idle_pull(target, target_remote);
86 }
87 requested
88 }
89
90 pub(super) fn request_fair_nohz_idle_pull(
91 &self,
92 target: CpuId,
93 target_remote: &CpuRemote,
94 ) -> bool {
95 let reservation = match target_remote.begin_idle_pull() {
96 IdlePullReservation::Started(reservation) => reservation,
97 IdlePullReservation::AlreadyPending => return true,
98 IdlePullReservation::Busy => return false,
99 };
100 if !self.root_domain.fair_nohz_idle_target(target)
101 || !target_remote.accepts_placement()
102 || !target_remote.is_scheduler_ready()
103 {
104 target_remote.cancel_idle_pull(reservation);
105 return false;
106 }
107 let Some(source) = self
108 .root_domain
109 .find_unvisited_fair_idle_pull_source(target)
110 else {
111 target_remote.cancel_idle_pull(reservation);
112 return false;
113 };
114 let Some(source_remote) = self.cpu_remote(source) else {
115 target_remote.cancel_idle_pull(reservation);
116 return false;
117 };
118 let message =
119 InboxMessage::balance_request(source, target, reservation, SchedulingClass::Fair);
120 match source_remote.publish_owner_control(target_remote.balance_request_node(), message) {
121 PublishResult::Published => true,
122 PublishResult::AlreadyPending | PublishResult::WrongKind => {
123 target_remote.cancel_idle_pull(reservation);
124 false
125 }
126 }
127 }
128
129 pub fn push_rt_deadline(&self, cpu: Pin<&mut CpuLocal>) -> Result<Option<ThreadId>, TaskError> {
134 self.ensure_owner_cpu_context(&cpu)?;
135 if task_runtime::in_hard_irq() {
136 return Ok(None);
137 }
138 self.ensure_owner_cpu_online(&cpu)?;
139 self.push_rt_deadline_from_root_domain(cpu, None)
140 }
141
142 pub(in crate::sched::system::task_system) fn push_rt_deadline_from_root_domain(
150 &self,
151 mut cpu: Pin<&mut CpuLocal>,
152 class: Option<SchedulingClass>,
153 ) -> Result<Option<ThreadId>, TaskError> {
154 if !class.map_or_else(
155 || self.root_domain.cpu_has_rt_deadline_overload(cpu.owner()),
156 |class| self.root_domain.cpu_has_overload(cpu.owner(), class),
157 ) {
158 return Ok(None);
159 }
160 let Some(selection) =
161 self.select_rt_deadline_balance_transfer(cpu.as_ref().get_ref(), class)
162 else {
163 return Ok(None);
164 };
165 let target = selection.target();
166 let outcome = self.commit_owner_balance_transfer(cpu.as_mut(), selection)?;
167 if outcome == BalanceTransferOutcome::Retry
168 && let Some(target_remote) = self.cpu_remote(target)
169 {
170 target_remote.kick_scheduler_work();
174 }
175 Ok(outcome.migrated())
176 }
177}