response_time_analysis/fixed_priority/floating_nonpreemptive.rs
1//! RTA for FP scheduling with floating non-preemptive sections (**FP-NPS**)
2
3use crate::demand::{self, RequestBound};
4use crate::time::{Duration, Offset, Service};
5use crate::{fixed_point, supply};
6
7/// The information about the task under analysis required to perform
8/// the analysis.
9/// Create one struct of this type to represent the task under analysis.
10pub struct TaskUnderAnalysis<'a, RBF: RequestBound + ?Sized> {
11 /// The RBF upper-bounding the task's demand.
12 pub rbf: &'a RBF,
13
14 /// The `blocking_bound` must be a bound on the maximum priority
15 /// inversion caused by tasks of lower priority, which corresponds
16 /// to the maximum non-preemptive segment of any lower-priority
17 /// task.
18 pub blocking_bound: Service,
19}
20
21/// Try to find a response-time bound for a task under fixed-priority
22/// scheduling with floating non-preemptive regions on a dedicated
23/// uniprocessor.
24///
25/// The analysis assumes that all tasks are independent and that each
26/// is characterized by an arbitrary arrival curve and a WCET bound.
27/// The set of higher-or-equal-priority tasks is represented by
28/// `interfering_tasks`; the task under analysis is given by
29/// `tua`.
30///
31/// If no fixed point is found below the divergence limit given by
32/// `limit`, the function returns a
33/// [SearchFailure][fixed_point::SearchFailure] instead.
34///
35/// This analysis is an implementation of the corresponding verified
36/// instantiation of [the abstract RTA of Bozhko and Brandenburg
37/// (ECRTS 2020)](https://drops.dagstuhl.de/opus/volltexte/2020/12385/pdf/LIPIcs-ECRTS-2020-22.pdf).
38/// See also [the Coq-verified instantiation](http://prosa.mpi-sws.org/branches/master/pretty/prosa.results.fixed_priority.rta.floating_nonpreemptive.html).
39#[allow(non_snake_case)]
40pub fn dedicated_uniproc_rta<RBF, InterferingRBF>(
41 tua: &TaskUnderAnalysis<RBF>,
42 interfering_tasks: &[InterferingRBF],
43 limit: Duration,
44) -> fixed_point::SearchResult
45where
46 InterferingRBF: RequestBound,
47 RBF: RequestBound + ?Sized,
48{
49 // This analysis is specific to dedicated uniprocessors.
50 let proc = supply::Dedicated::new();
51
52 // First, bound the maximum possible busy-window length.
53 let L = fixed_point::search(&proc, limit, |L| {
54 let interference_bound: Service = interfering_tasks
55 .iter()
56 .map(|rbf| rbf.service_needed(L))
57 .sum();
58
59 tua.blocking_bound + interference_bound + tua.rbf.service_needed(L)
60 })?;
61
62 // In the model with floating non-preemptive regions, there is no
63 // static information about the placement of preemption points in
64 // all jobs, i.e., it is impossible to predict when exactly a job
65 // will be preemptable. Thus, the only safe run-to-completion
66 // threshold is the task's WCET. The remaining cost after the
67 // run-to-completion threshold has been reached is then zero, so
68 // omitted here. See also:
69 // http://prosa.mpi-sws.org/branches/master/pretty/prosa.model.task.
70 // preemption.floating_nonpreemptive.html
71
72 // Second, define the RTA for a given offset A.
73 let rta = |A: Offset| {
74 // Define the RHS of the equation in theorem 31 of the aRTA paper,
75 // where AF = A + F.
76 let rhs = |AF: Duration| {
77 // demand of the task under analysis
78 let tua_demand = tua.rbf.service_needed(A.closed_since_time_zero());
79
80 // demand of all interfering tasks
81 let interfering_demand = interfering_tasks
82 .iter()
83 .map(|rbf| rbf.service_needed(AF))
84 .sum();
85
86 // considering `blocking_bound` to account for priority inversion
87 tua.blocking_bound + tua_demand + interfering_demand
88 };
89
90 // Find the solution A+F that is the least fixed point.
91 let AF = fixed_point::search(&proc, limit, rhs)?;
92 // Extract the corresponding bound.
93 let F = AF - A.since_time_zero();
94 Ok(F)
95 };
96
97 // Third, define the search space. The search space is given by
98 // A=0 and each step below L of the task under analysis's RBF.
99 // The case of A=0 is not handled explicitly since `step_offsets()`
100 // necessarily yields it.
101 let max_offset = Offset::from_time_zero(L);
102 let search_space = demand::step_offsets(tua.rbf).take_while(|A| *A < max_offset);
103
104 // Apply the offset-specific RTA to each offset in the search space and
105 // return the maximum response-time bound.
106 fixed_point::max_response_time(search_space.map(rta))
107}