ax_task/sched/system/task_system/scheduling/
accounting.rs1use super::*;
4
5impl TaskSystem {
6 pub fn charge_current(
8 &self,
9 cpu: Pin<&mut CpuLocal>,
10 runtime_ns: u64,
11 reclaimed_ns: u64,
12 ) -> Result<ChargeOutcome, TaskError> {
13 self.ensure_owner_cpu_context(&cpu)?;
14 if !cpu.is_online() {
15 return Err(TaskError::CpuOffline(cpu.owner().as_u32()));
16 }
17 let remote = unsafe { cpu.as_ref().get_ref().remote_for_owner() };
21 let mut transaction = OwnerRqTxn::begin(self, remote);
22 if transaction.current().is_none() {
23 transaction.commit();
24 return Err(TaskError::NoRunnableThread);
25 }
26 let charge = transaction.charge_current(runtime_ns, reclaimed_ns);
27 transaction.commit();
28 Ok(ChargeOutcome {
29 slice_expired: charge.slice_expired,
30 deadline_overrun: charge.deadline_overrun,
31 })
32 }
33
34 pub fn charge_current_until(
37 &self,
38 cpu: Pin<&mut CpuLocal>,
39 reclaimed_ns: u64,
40 ) -> Result<ChargeOutcome, TaskError> {
41 self.charge_current_until_with_clock(cpu, reclaimed_ns)
42 .map(|(charge, _clock, _thread, _rq_observation)| charge)
43 }
44
45 pub(crate) fn charge_current_until_with_clock(
46 &self,
47 cpu: Pin<&mut CpuLocal>,
48 reclaimed_ns: u64,
49 ) -> Result<
50 (
51 ChargeOutcome,
52 RunQueueClockSnapshot,
53 ThreadId,
54 SchedulerDeadlineRqObservation,
55 ),
56 TaskError,
57 > {
58 self.ensure_owner_cpu_context(&cpu)?;
59 if !cpu.is_online() {
60 return Err(TaskError::CpuOffline(cpu.owner().as_u32()));
61 }
62 let remote = unsafe { cpu.as_ref().get_ref().remote_for_owner() };
66 let mut transaction = OwnerRqTxn::begin(self, remote);
67 let clock = transaction.clock();
68 let Some(thread) = transaction.current_thread() else {
69 transaction.commit();
70 return Err(TaskError::NoRunnableThread);
71 };
72 let charge = transaction.settle_current(reclaimed_ns);
73 let rq_observation = transaction.scheduler_deadline_rq_observation(cpu.as_ref().get_ref());
74 transaction.commit();
75 Ok((
76 ChargeOutcome {
77 slice_expired: charge.slice_expired,
78 deadline_overrun: charge.deadline_overrun,
79 },
80 clock,
81 thread,
82 rq_observation,
83 ))
84 }
85
86 pub(crate) fn task_tick_current_until_with_clock(
87 &self,
88 cpu: Pin<&mut CpuLocal>,
89 reclaimed_ns: u64,
90 tick_ns: u64,
91 ) -> Result<
92 (
93 ChargeOutcome,
94 RunQueueClockSnapshot,
95 ThreadId,
96 SchedulerDeadlineRqObservation,
97 ),
98 TaskError,
99 > {
100 self.ensure_owner_cpu_context(&cpu)?;
101 if !cpu.is_online() {
102 return Err(TaskError::CpuOffline(cpu.owner().as_u32()));
103 }
104 let remote = unsafe { cpu.as_ref().get_ref().remote_for_owner() };
108 let mut transaction = OwnerRqTxn::begin(self, remote);
109 let clock = transaction.clock();
110 let Some(thread) = transaction.current_thread() else {
111 transaction.commit();
112 return Err(TaskError::NoRunnableThread);
113 };
114 let charge = transaction.task_tick_current_until(reclaimed_ns, tick_ns);
115 sample_current_realtime_tick(&transaction, tick_ns);
116 let rq_observation = transaction.scheduler_deadline_rq_observation(cpu.as_ref().get_ref());
117 transaction.commit();
118 Ok((
119 ChargeOutcome {
120 slice_expired: charge.slice_expired,
121 deadline_overrun: charge.deadline_overrun,
122 },
123 clock,
124 thread,
125 rq_observation,
126 ))
127 }
128
129 pub(crate) fn clock_event_current_until_with_clock(
130 &self,
131 cpu: Pin<&mut CpuLocal>,
132 reclaimed_ns: u64,
133 ) -> Result<
134 (
135 ChargeOutcome,
136 RunQueueClockSnapshot,
137 ThreadId,
138 SchedulerDeadlineRqObservation,
139 ),
140 TaskError,
141 > {
142 self.ensure_owner_cpu_context(&cpu)?;
143 if !cpu.is_online() {
144 return Err(TaskError::CpuOffline(cpu.owner().as_u32()));
145 }
146 let remote = unsafe { cpu.as_ref().get_ref().remote_for_owner() };
149 let mut transaction = OwnerRqTxn::begin(self, remote);
150 let clock = transaction.clock();
151 let Some(thread) = transaction.current_thread() else {
152 transaction.commit();
153 return Err(TaskError::NoRunnableThread);
154 };
155 let charge = transaction.clock_event_current_until(reclaimed_ns);
156 let rq_observation = transaction.scheduler_deadline_rq_observation(cpu.as_ref().get_ref());
157 transaction.commit();
158 Ok((
159 ChargeOutcome {
160 slice_expired: charge.slice_expired,
161 deadline_overrun: charge.deadline_overrun,
162 },
163 clock,
164 thread,
165 rq_observation,
166 ))
167 }
168
169 pub(crate) fn task_tick_and_clock_event_current_until_with_clock(
170 &self,
171 cpu: Pin<&mut CpuLocal>,
172 reclaimed_ns: u64,
173 tick_ns: u64,
174 ) -> Result<
175 (
176 ChargeOutcome,
177 RunQueueClockSnapshot,
178 ThreadId,
179 SchedulerDeadlineRqObservation,
180 ),
181 TaskError,
182 > {
183 self.ensure_owner_cpu_context(&cpu)?;
184 if !cpu.is_online() {
185 return Err(TaskError::CpuOffline(cpu.owner().as_u32()));
186 }
187 let remote = unsafe { cpu.as_ref().get_ref().remote_for_owner() };
190 let mut transaction = OwnerRqTxn::begin(self, remote);
191 let clock = transaction.clock();
192 let Some(thread) = transaction.current_thread() else {
193 transaction.commit();
194 return Err(TaskError::NoRunnableThread);
195 };
196 let charge = transaction.task_tick_and_clock_event_current_until(reclaimed_ns, tick_ns);
197 sample_current_realtime_tick(&transaction, tick_ns);
198 let rq_observation = transaction.scheduler_deadline_rq_observation(cpu.as_ref().get_ref());
199 transaction.commit();
200 Ok((
201 ChargeOutcome {
202 slice_expired: charge.slice_expired,
203 deadline_overrun: charge.deadline_overrun,
204 },
205 clock,
206 thread,
207 rq_observation,
208 ))
209 }
210
211 pub fn rt_run_queue_may_run(&self, cpu: Pin<&mut CpuLocal>) -> Result<bool, TaskError> {
213 self.ensure_owner_cpu_context(&cpu)?;
214 self.ensure_owner_cpu_online(&cpu)?;
215 let run_queue = cpu
216 .remote()
217 .lock_run_queue(RunQueueGuardSource::RtAccounting);
218 Ok(!run_queue.rt_is_throttled() || run_queue.has_exempt_rt())
219 }
220}
221
222fn sample_current_realtime_tick(transaction: &OwnerRqTxn<'_>, tick_ns: u64) {
223 if transaction.current().is_some_and(|current| {
224 matches!(
225 current.schedule_policy_ref(),
226 SchedulePolicy::Fifo { .. } | SchedulePolicy::RoundRobin { .. }
227 )
228 }) && let Some(core) = transaction.current_core_ref()
229 {
230 core.sample_realtime_tick(transaction.clock().wall().as_nanos(), tick_ns);
231 }
232}