use itertools::Itertools;
use crate::arrival::ArrivalBound;
use crate::demand::{self, RequestBound};
use crate::time::{Duration, Offset, Service};
use crate::{fixed_point, supply, wcet};
pub struct Task<'a, AB: ArrivalBound + ?Sized> {
pub wcet: wcet::Scalar,
pub arrivals: &'a AB,
pub deadline: Duration,
}
impl<'a, AB: ArrivalBound + ?Sized> Task<'a, AB> {
fn rbf(&self) -> impl RequestBound + '_ {
demand::RBF::new(self.arrivals, self.wcet)
}
}
pub type TaskUnderAnalysis<'a, T> = Task<'a, T>;
pub type InterferingTask<'a, T> = Task<'a, T>;
#[allow(non_snake_case)]
pub fn dedicated_uniproc_rta<AB1, AB2>(
tua: &TaskUnderAnalysis<AB1>,
other_tasks: &[InterferingTask<AB2>],
limit: Duration,
) -> fixed_point::SearchResult
where
AB1: ArrivalBound + ?Sized,
AB2: ArrivalBound + ?Sized,
{
let proc = supply::Dedicated::new();
let task_under_analysis = tua.rbf();
let rbfs: Vec<_> = other_tasks.iter().map(Task::rbf).collect();
let L = fixed_point::search(&proc, limit, |L| {
let interference_bound: Service = rbfs.iter().map(|rbf| rbf.service_needed(L)).sum();
interference_bound + task_under_analysis.service_needed(L)
})?;
let rtct = Service::epsilon();
let rem_cost = tua.wcet.wcet - rtct;
let rta = |A: Offset| {
let blocking_bound = other_tasks
.iter()
.filter(|ot| {
ot.deadline > tua.deadline + A.since_time_zero()
&& ot.rbf().service_needed(Duration::epsilon()) > Service::none()
})
.map(|ot| ot.wcet.wcet.saturating_sub(Service::epsilon()))
.max()
.unwrap_or_else(Service::none);
let rhs = |AF: Duration| {
let self_interference = task_under_analysis.service_needed(A.closed_since_time_zero());
let tua_demand = self_interference - rem_cost;
let bound_on_total_hep_workload: Service = other_tasks
.iter()
.map(|ot| {
ot.rbf().service_needed(std::cmp::min(
AF,
(A.closed_since_time_zero() + tua.deadline).saturating_sub(ot.deadline),
))
})
.sum();
blocking_bound + tua_demand + bound_on_total_hep_workload
};
let AF = fixed_point::search(&proc, limit, rhs)?;
let F = AF.saturating_sub(A.since_time_zero());
Ok(F + Duration::from(rem_cost))
};
let max_offset = Offset::from_time_zero(L);
let search_space_tua =
demand::step_offsets(&task_under_analysis).take_while(|A| *A < max_offset);
let search_space = other_tasks
.iter()
.zip(rbfs.iter())
.map(|(ot, rbf)| {
demand::step_offsets(rbf)
.map(move |delta| {
Offset::from_time_zero(
(delta + ot.deadline)
.since_time_zero()
.saturating_sub(tua.deadline),
)
})
.take_while(|A| *A < max_offset)
})
.kmerge()
.merge(search_space_tua)
.dedup();
fixed_point::max_response_time(search_space.map(rta))
}