response_time_analysis/ros2/
rr.rs1use crate::fixed_point;
2use crate::supply::SupplyBound;
3use crate::time::{Duration, Service};
4
5use crate::arrival::ArrivalBound;
6use crate::wcet::JobCostModel;
7
8const EPSILON: Duration = Duration::epsilon();
9const EPSILON_SERVICE: Service = Service::in_interval(EPSILON);
10
11pub type PolledCallbackPriority = i32;
17
18pub fn is_higher_callback_priority_than(
22 a: PolledCallbackPriority,
23 b: PolledCallbackPriority,
24) -> bool {
25 a < b
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum CallbackType {
31 Timer,
33 EventSource,
35 PolledUnknownPrio,
37 Polled(PolledCallbackPriority),
39}
40
41impl CallbackType {
42 pub fn is_pp(&self) -> bool {
43 matches!(
44 self,
45 CallbackType::PolledUnknownPrio | CallbackType::Polled(_)
46 )
47 }
48}
49
50pub struct Callback<'a, 'b, AB: ArrivalBound + ?Sized, CM: JobCostModel + ?Sized> {
59 response_time_bound: Duration,
60 arrival_bound: &'a AB,
61 cost_model: &'b CM,
62 kind: CallbackType,
63}
64
65impl<'a, 'b, AB: ArrivalBound + ?Sized, CM: JobCostModel + ?Sized> Callback<'a, 'b, AB, CM> {
66 pub fn new(
73 response_time_bound: Duration,
74 arrival_bound: &'a AB,
75 cost_model: &'b CM,
76 kind: CallbackType,
77 ) -> Callback<'a, 'b, AB, CM> {
78 Callback {
79 response_time_bound,
80 arrival_bound,
81 cost_model,
82 kind,
83 }
84 }
85
86 fn direct_rbf(
88 &self,
89 interfered_with: &CallbackType,
90 delta: Duration,
91 num_polling_points: usize,
92 ) -> Service {
93 let effective_interval = (delta + self.response_time_bound).saturating_sub(EPSILON);
94 let arrived = self.arrival_bound.number_arrivals(effective_interval);
95 let n = match self.kind {
96 CallbackType::Timer | CallbackType::EventSource => arrived,
97 CallbackType::PolledUnknownPrio => arrived.min(num_polling_points + 1),
98 CallbackType::Polled(inf_prio) => match *interfered_with {
99 CallbackType::Polled(ref_prio) => arrived.min(
100 num_polling_points
101 + is_higher_callback_priority_than(inf_prio, ref_prio) as usize,
102 ),
103 _ => arrived.min(num_polling_points + 1),
104 },
105 };
106 self.cost_model.cost_of_jobs(n)
107 }
108
109 fn max_self_interfering_instances(&self, delta: Duration) -> usize {
111 let effective_interval = (delta + self.response_time_bound).saturating_sub(EPSILON);
112 self.arrival_bound
113 .number_arrivals(effective_interval)
114 .saturating_sub(1)
115 }
116
117 fn self_interference_rbf(&self, delta: Duration) -> Service {
119 self.cost_model
120 .cost_of_jobs(self.max_self_interfering_instances(delta))
121 }
122
123 fn marginal_execution_cost(&self, delta: Duration) -> Service {
125 let n = self.max_self_interfering_instances(delta);
126 self.cost_model.cost_of_jobs(n + 1) - self.cost_model.cost_of_jobs(n)
127 }
128
129 fn polling_point_bound(&self) -> usize {
132 self.arrival_bound.number_arrivals(self.response_time_bound)
133 }
134
135 fn subchain_polling_point_bound(subchain: &[&Callback<AB, CM>]) -> usize {
139 subchain.iter().map(|cb| cb.polling_point_bound()).sum()
140 }
141}
142
143#[allow(non_snake_case)]
158pub fn rta_subchain<SBF, AB, CM>(
159 supply: &SBF,
160 workload: &[Callback<AB, CM>],
161 subchain: &[&Callback<AB, CM>],
162 limit: Duration,
163) -> fixed_point::SearchResult
164where
165 SBF: SupplyBound + ?Sized,
166 AB: ArrivalBound + ?Sized,
167 CM: JobCostModel + ?Sized,
168{
169 let eoc = subchain.last().expect("subchain must not be empty");
171
172 debug_assert!(
175 subchain
176 .iter()
177 .all(|sc_cb| workload.iter().any(|wl_cb| std::ptr::eq(*sc_cb, wl_cb))),
178 "subchain not wholly part of workload"
179 );
180
181 let max_num_polling_points = Callback::subchain_polling_point_bound(subchain);
185
186 let rhs_S_star = |s_star: Duration| {
187 let di = workload
188 .iter()
189 .map(|cb| {
190 if std::ptr::eq(*eoc, cb) {
191 Service::none()
194 } else {
195 cb.direct_rbf(&eoc.kind, s_star, max_num_polling_points)
196 }
197 })
198 .sum();
199 let si = eoc.self_interference_rbf(s_star);
200 EPSILON_SERVICE + di + si
201 };
202
203 let S_star = fixed_point::search(supply, limit, rhs_S_star)?;
204
205 let supply_star = supply.provided_service(S_star);
208 let omega = eoc.marginal_execution_cost(S_star);
209 let rhs_R_star = supply_star.saturating_sub(EPSILON_SERVICE) + omega;
210
211 Ok(supply.service_time(rhs_R_star))
213}