diff --git a/analysis/abstract/busy_interval.v b/analysis/abstract/busy_interval.v index 34192af4c7f311e4bf46355847bc4d4fd3121d5c..8743a4a027902e0cbc6d2843cc4b43d745bdbb7e 100644 --- a/analysis/abstract/busy_interval.v +++ b/analysis/abstract/busy_interval.v @@ -1,7 +1,5 @@ -Require Export prosa.analysis.definitions.job_properties. -Require Export prosa.analysis.facts.behavior.all. -Require Export prosa.analysis.abstract.definitions. Require Export prosa.analysis.abstract.iw_auxiliary. +Require Export prosa.analysis.facts.model.workload. (** * Lemmas About Abstract Busy Intervals *) @@ -48,7 +46,55 @@ Section LemmasAboutAbstractBusyInterval. Hypothesis H_from_arrival_sequence : arrives_in arr_seq j. Hypothesis H_job_cost_positive : job_cost_positive j. - (** Consider a busy interval <<[t1, t2)>> of job [j]. *) + (** We first prove that any interval <<[t1, t2)>> is either a busy + interval of job [j] or not. *) + Lemma busy_interval_prefix_case : + forall t1 t2, + busy_interval_prefix sched j t1 t2 \/ ~ busy_interval_prefix sched j t1 t2. + Proof. + move=> t1 t2. + have [JA|NAT] := boolP (t1 <= job_arrival j < t2); last first. + { by right; move => PREF; move: NAT => /negP NQT; apply: NQT; apply PREF. } + have [QT1|NQT] := boolP (quiet_time sched j t1); last first. + { by right; move => PREF; move: NQT => /negP NQT; apply: NQT; apply PREF. } + have [AQT|NQT] := boolP (all (fun t => ~~ quiet_time sched j t) (index_iota t1.+1 t2)); last first. + { right; move=> PREF; move: NQT => /negP NQT; apply: NQT. + apply/allP => t IO; apply/negP. + by apply PREF; move: IO; rewrite mem_index_iota. + } + left; split; [by done | split] => //. + move => t NEQ; apply/negP; move: AQT => /allP AQT; apply: AQT. + by rewrite mem_index_iota. + Qed. + + (** Consider two intervals <<[t1, t2)>> ⊆ <<[t1, t2')>>, where + <<[t1, t2)>> is a busy-interval prefix and <<[t1, t2')>> is not + a busy-interval prefix. Then there exists [t2''] such that + <<[t1, t2'')>> is a busy interval. *) + Lemma terminating_busy_prefix_is_busy_interval : + forall t1 t2 t2', + t2 <= t2' -> + busy_interval_prefix sched j t1 t2 -> + ~ busy_interval_prefix sched j t1 t2' -> + exists t2'', busy_interval sched j t1 t2''. + Proof. + move=> t1 t2 t2' LE BUSY NBUSY. + interval_to_duration t2 t2' δ. + induction δ as [ | δ IHδ]. + { by exfalso; apply: NBUSY; rewrite addn0. } + have [BUSY'|NBUSY'] := busy_interval_prefix_case t1 (t2 + δ); last by apply IHδ in NBUSY'. + clear IHδ. + exists (t2 + δ); split => //. + apply negbNE; apply/negP => FF. + apply:NBUSY; split; first by move: BUSY => []; lia. + split; first by move: BUSY => []; lia. + move => t; rewrite addnS ltnS [_ <= t2 + δ]leq_eqVlt. + move => /andP [LT1 /orP [/eqP WDFW | VB]]. + - by subst; apply/negP. + - by apply BUSY'; lia. + Qed. + + (** Next, consider a busy interval <<[t1, t2)>> of job [j]. *) Variable t1 t2 : instant. Hypothesis H_busy_interval : busy_interval sched j t1 t2. @@ -158,6 +204,339 @@ Section LemmasAboutAbstractBusyInterval. End LemmasAboutAbstractBusyInterval. +(** In the following section, we derive a sufficient condition for the + existence of abstract busy intervals for unit-service + processors. *) +Section AbstractBusyIntervalExists. + + (** Consider any type of tasks ... *) + Context {Task : TaskType}. + Context `{TaskCost Task}. + + (** ... and any type of jobs associated with these tasks. *) + Context {Job : JobType}. + Context `{JobTask Job Task}. + Context `{JobArrival Job}. + Context `{JobCost Job}. + + (** Consider any kind of of unit-service processor model. *) + Context {PState : ProcessorState Job}. + Hypothesis H_unit_service_proc_model : unit_service_proc_model PState. + + (** Assume we are provided with abstract functions for interference + and interfering workload ... *) + Context `{Interference Job}. + Context `{InterferingWorkload Job}. + + (** ... that do not allow speculative execution. *) + Hypothesis H_no_speculative_exec : no_speculative_execution. + + (** Consider any arrival sequence with consistent, non-duplicate arrivals. *) + Variable arr_seq : arrival_sequence Job. + Hypothesis H_arrival_times_are_consistent : consistent_arrival_times arr_seq. + Hypothesis H_arrival_sequence_is_a_set : arrival_sequence_uniq arr_seq. + + (** Consider an arbitrary task [tsk]. *) + Variable tsk : Task. + + (** Next, consider any work-conserving (in the abstract sense) + schedule of this arrival sequence ... *) + Variable sched : schedule PState. + Hypothesis H_work_conserving : work_conserving arr_seq sched. + + (** ... where jobs do not execute before their arrival or after completion. *) + Hypothesis H_jobs_must_arrive_to_execute : jobs_must_arrive_to_execute sched. + Hypothesis H_completed_jobs_dont_execute : completed_jobs_dont_execute sched. + + (** Consider an arbitrary job [j] from task [tsk] with positive cost. *) + Variable j : Job. + Hypothesis H_from_arrival_sequence : arrives_in arr_seq j. + Hypothesis H_job_task : job_of_task tsk j. + Hypothesis H_job_cost_positive : job_cost_positive j. + + (** In this section, we prove a fact that allows one to extend an + inequality between cumulative interference and interfering + workload from a busy-interval prefix <<[t1, t)>> to the whole + timeline <<[0, t)>>. *) + Section CumulativeIntIntWorkExtension. + + (** Consider any busy-interval prefix of job [j]. *) + Variable t1 t_busy : instant. + Hypothesis H_is_busy_prefix : busy_interval_prefix sched j t1 t_busy.+1. + + (** We assume that, for some positive [δ], the cumulative + interfering workload within interval <<[t1, t1 + δ)>> is + bounded by cumulative interference in the same interval. *) + Variable δ : duration. + Hypothesis H_iw_bounded : + cumulative_interfering_workload j t1 (t1 + δ) <= cumulative_interference j t1 (t1 + δ). + + (** Then the cumulative interfering workload within interval <<[0, + t1 + δ)>> is bounded by the cumulative interference in the + same interval. *) + Local Lemma cumul_iw_bounded_by_cumul_i : + cumulative_interfering_workload j 0 (t1 + δ) <= cumulative_interference j 0 (t1 + δ). + Proof. + move: (H_iw_bounded) => LE. + rewrite /definitions.cumulative_interference + /definitions.cumulative_interfering_workload + /cumul_cond_interference. + rewrite (@big_cat_nat _ _ _ t1) //=; last by lia. + rewrite [in X in _ <= X](@big_cat_nat _ _ _ t1) //=; last by lia. + move: H_is_busy_prefix => [_ [/andP [/eqP DD KK ] ADD]]. + rewrite /cumulative_interfering_workload in LE; rewrite (leqRW LE); clear LE. + rewrite leq_add2r. + rewrite /cumulative_interfering_workload in DD. + by rewrite -DD; clear DD. + Qed. + + End CumulativeIntIntWorkExtension. + + (** In the following section, we show that the busy interval is + bounded. More specifically, we show that the length of any + abstract busy interval is bounded, as long as there is enough + supply to accommodate the interfering workload. *) + Section BoundingBusyInterval. + + (** For simplicity, let us define some local names. *) + Let quiet_time t := quiet_time sched j t. + Let busy_interval_prefix := busy_interval_prefix sched j. + Let busy_interval := busy_interval sched j. + + (** Suppose that job [j] is pending at time [t_busy]. *) + Variable t_busy : instant. + Hypothesis H_j_is_pending : pending sched j t_busy. + + (** First, we show that there must exist a busy interval prefix. *) + Section LowerBound. + + (** Since job [j] is pending at time [t_busy], there is a + (potentially unbounded) busy interval that starts no later + than with the arrival of [j]. *) + Lemma exists_busy_interval_prefix : + exists t1, + busy_interval_prefix t1 t_busy.+1 /\ + t1 <= job_arrival j <= t_busy. + Proof. + rename H_j_is_pending into PEND. + destruct ([exists t:'I_t_busy.+1, quiet_time t]) eqn:EX. + { set (last0 := \max_(t < t_busy.+1 | quiet_time t) t). + move: EX => /existsP [t EX]. + have PRED: quiet_time last0 by apply (bigmax_pred t_busy.+1 (quiet_time) t). + move: PRED => QUIET. + exists last0. + have JARRIN: last0 <= job_arrival j <= t_busy. + { move: PEND => /andP [ARR NCOM]. + apply/andP; split => //. move: QUIET => /andP [_ PE]. + move: PE; rewrite negb_and -leqNgt => /orP [ | /negPn COMPL] => //; exfalso. + apply completion_monotonic with (t' := t_busy) in COMPL. + - by move: NCOM => /negP. + - by rewrite -ltnS; eapply bigmax_ltn_ord. + } + repeat split; auto 2; try apply QUIET => //=. + move => t0 /andP [GTlast LTbusy] QUIET0. + move_neq_down GTlast. + by eapply (@leq_bigmax_cond + _ (fun (x: 'I_t_busy.+1) => quiet_time x) + (fun x => x) (Ordinal LTbusy)). + } + { apply negbT in EX; rewrite negb_exists in EX; move: EX => /forallP ALL. + exists 0; split; last by apply/andP; split; last by move: PEND => /andP [ARR _]. + repeat split. + - apply/andP; split => //; rewrite ltnS. + by move: PEND => /andP PEND; apply PEND. + - apply/andP; split; + first by rewrite /cumulative_interference /cumul_cond_interference /cumulative_interfering_workload !big_geq. + by apply not_pending_earlier_and_at_0. + - move => t /andP [GE LT] QUIET. + move: (ALL (Ordinal LT)) => /negP ALL'. + by apply ALL'. + } + Qed. + + End LowerBound. + + (** Next we prove that, if there is a point where the requested + workload is upper-bounded by the supply, then the busy + interval eventually ends. *) + Section UpperBound. + + (** Consider any busy interval prefix of job [j]. *) + Variable t1 : instant. + Hypothesis H_is_busy_prefix : busy_interval_prefix t1 t_busy.+1. + + (** We assume that for some positive [δ], the cumulative + interfering workload within interval <<[t1, t1 + δ)>> is + bounded by [δ]. *) + Variable δ : duration. + Hypothesis H_δ_positive : δ > 0. + Hypothesis H_workload_is_bounded : + workload_of_job arr_seq j t1 (t1 + δ) + + cumulative_interfering_workload j t1 (t1 + δ) <= δ. + + (** If there is a quiet time by time [t1 + δ], it trivially + follows that the busy interval is bounded. Thus, let's + consider first the harder case where there is no quiet time, + which turns out to be impossible. *) + Section CannotBeBusyForSoLong. + + (** Assume that there is no quiet time in the interval <<(t1, t1 + δ]>>. *) + Hypothesis H_no_quiet_time : forall t, t1 < t <= t1 + δ -> ~ quiet_time t. + + (** We prove that the sum of cumulative service and cumulative + interference in the interval <<[t, t + δ)>> is equal to + [δ]. *) + + (** Since the interval is always non-quiet, the processor is + always busy processing job [j] and the job's interference + and, hence, the sum of service of [j] and its cumulative + interference within the interval <<[t1, t1 + δ)>> is + greater than or equal to [δ]. *) + Lemma busy_interval_has_uninterrupted_service : + δ <= service_during sched j t1 (t1 + δ) + cumulative_interference j t1 (t1 + δ). + Proof. + clear H_δ_positive H_workload_is_bounded H_j_is_pending. + rewrite /service_during /cumulative_interference /cumul_cond_interference /cond_interference /service_at. + rewrite -big_split //= -{1}(sum_of_ones t1 δ). + rewrite big_nat [in X in _ <= X]big_nat. + apply leq_sum => x /andP[Lo Hi]. + destruct (leqP (t1 + δ) (t_busy.+1)) as [LE|LT]. + { move: (H_work_conserving j t1 t_busy.+1 x) => Workj. + feed_n 4 Workj; try done. + { by apply/andP; split; eapply leq_trans; eauto. } + destruct interference. + - by lia. + - by rewrite //= addn0; apply Workj. + } + { move: (H_work_conserving j t1 (t1 + δ) x) => Workj. + feed_n 4 Workj; try done. + - move: H_is_busy_prefix => [/andP [A1 A2] [QT NQT]]; split; [ | split]. + + by apply/andP; split => //; rewrite (leqRW A2) -(leqRW LT). + + by apply QT. + + move => t /andP [A3 A4]; apply H_no_quiet_time. + by apply/andP; split; lia. + - by apply/andP; split; eapply leq_trans; eauto 2. + - destruct interference. + + by lia. + + by rewrite //= addn0; apply Workj. + } + Qed. + + (** However, since the total workload is bounded (see + [H_workload_is_bounded]), the sum of [j]'s cost and its + interfering workload within the interval <<[t1, t1 + δ)>> + is bounded by [j]'s service and its interference within + the same time interval. *) + Lemma busy_interval_too_much_workload : + job_cost j + cumulative_interfering_workload j t1 (t1 + δ) <= + service_during sched j t1 (t1 + δ) + cumulative_interference j t1 (t1 + δ). + Proof. + replace (job_cost j) with (workload_of_job arr_seq j t1 (t1 + δ)); + first by rewrite (leqRW H_workload_is_bounded) + -(leqRW busy_interval_has_uninterrupted_service). + move: (H_is_busy_prefix) => [/andP [NEQ1 _] _]. + erewrite workload_of_job_eq_job_arrival => //=. + rewrite NEQ1 Bool.andb_true_l. + have -> : job_arrival j < t1 + δ; last by done. + move_neq_up GE. + apply (H_no_quiet_time (t1 + δ)). + { by apply/andP; split; [rewrite -addn1 leq_add2l | done]. } + apply/andP; split. + - move: (H_workload_is_bounded); rewrite workload_of_job_eq_job_arrival //=. + rewrite NEQ1 Bool.andb_true_l [_ < _ + _]leqNgt ltnS GE //= add0n => LE. + rewrite eqn_leq; apply/andP; split. + + by apply H_no_speculative_exec. + + apply (cumul_iw_bounded_by_cumul_i _ t_busy) => //=; rewrite (leqRW LE). + eapply leq_trans; first apply busy_interval_has_uninterrupted_service. + by have -> : service_during sched j t1 (t1 + δ) = 0 + by rewrite cumulative_service_before_job_arrival_zero. + - by rewrite /pending_earlier_and_at negb_and; + apply/orP; left; rewrite -ltnNge ltnS. + Qed. + + (** The latter two lemmas imply that [t1 + δ] is a quiet time ... *) + Lemma t1δ_is_quiet : quiet_time (t1 + δ). + Proof. + have LW := busy_interval_too_much_workload. + have NEQ: forall a b c d, a >= c -> b >= d -> a + b <= c + d -> a = c /\ b = d by lia. + apply NEQ in LW; first destruct LW as [EQ1 EQ2]. + - apply/andP; split. + + rewrite eqn_leq; apply/andP; split. + * by apply H_no_speculative_exec. + * by apply (cumul_iw_bounded_by_cumul_i _ t_busy) => //=; rewrite EQ2. + + rewrite negb_and Bool.negb_involutive; apply/orP; right. + rewrite /completed_by EQ1. + by erewrite <-(service_cat); [apply leq_addl | ]; lia. + - eapply leq_trans; last by apply service_at_most_cost => //=. + by erewrite <-(service_cat); [apply leq_addl | ]; lia. + - move: H_is_busy_prefix => [_ [/andP [/eqP D _] _]]. + rewrite -(leq_add2l (definitions.cumulative_interference j 0 t1)) {2}D. + rewrite -(big_cat_nat) //=; last by lia. + by rewrite -(big_cat_nat) //=; last by lia. + Qed. + + (** ... which is a contradiction with the initial + assumption. *) + Lemma t1δ_is_quiet_contra : False. + Proof. + eapply H_no_quiet_time; last by apply t1δ_is_quiet. + apply/andP; split; last by done. + by rewrite -addn1 leq_add2l. + Qed. + + End CannotBeBusyForSoLong. + + (** Since the interval cannot remain busy for so long, we prove + that the busy interval finishes at some point [t2 <= t1 + + δ]. *) + Lemma busy_interval_is_bounded : + exists t2, + t_busy < t2 + /\ t2 <= t1 + δ + /\ busy_interval t1 t2. + Proof. + move: H_is_busy_prefix => [NEQ [QT NQT]]. + destruct ([exists t2:'I_(t1 + δ).+1, (t2 > t1) && quiet_time t2]) eqn:EX. + { have EX': exists (t2 : instant), ((t1 < t2 <= t1 + δ) && quiet_time t2). + { move: EX => /existsP [t2 /andP [LE QUIET]]. + exists t2; apply/andP; split => //; + by apply/andP; split; last (rewrite -ltnS; apply ltn_ord). } + move: (ex_minnP EX') => [t2 /andP [/andP [GT LE] QUIET] MIN]; clear EX EX'. + exists t2; split; [ | split; [ |split; [split; [ | split] | ] ]]; try done. + { move_neq_up NEQ2. + move: (H_is_busy_prefix) => [_ [_ NQ]]; apply:(NQ t2) => //. + by apply/andP; split => //. + } + { move: NEQ => /andP [IN1 IN2]. + apply/andP; split => //. + apply leq_ltn_trans with t_busy; eauto 2. + rewrite ltnNge; apply/negP; intros CONTR. + apply NQT with t2 => //. + by apply/andP; split; last rewrite ltnS. + } + { move => t /andP [GT1 LT2] BUG. + feed (MIN t); first (apply/andP; split) => //. + { by apply/andP; split; last apply leq_trans with (n := t2); eauto using ltnW. } + { by lia. } + } + } + { apply negbT in EX; rewrite negb_exists in EX; move: EX => /forallP ALL'. + have ALL: forall t, t1 < t <= t1 + δ -> ~ quiet_time t. + { move => t /andP [GTt LEt] QUIET; rewrite -ltnS in LEt. + specialize (ALL' (Ordinal LEt)); rewrite negb_and /= GTt orFb in ALL'. + by move: ALL' => /negP ALL'; apply ALL'; clear ALL'. + } + by clear ALL'; exfalso; eapply t1δ_is_quiet_contra. + } + Qed. + + End UpperBound. + + End BoundingBusyInterval. + +End AbstractBusyIntervalExists. + + (** We add some facts into the "Hint Database" basic_rt_facts, so Coq will be able to apply them automatically where needed. *) Global Hint Resolve diff --git a/analysis/facts/behavior/completion.v b/analysis/facts/behavior/completion.v index cfd82b9dad04b9f22573c638f4ae2c0e341e48ad..e766711b388064a70c3361ad77a8f68779c5e18d 100644 --- a/analysis/facts/behavior/completion.v +++ b/analysis/facts/behavior/completion.v @@ -150,6 +150,14 @@ Section CompletionFacts. completed_by sched j t -> ~~ scheduled_at sched j t. Proof. move=> ? /negPn; exact/contra/scheduled_implies_not_completed. Qed. + (** Job [j] cannot be pending before and at time [0]. *) + Remark not_pending_earlier_and_at_0 : + ~~ pending_earlier_and_at sched j 0. + Proof. + rewrite /pending_earlier_and_at negb_and; apply/orP; left. + by rewrite /arrived_before -ltnNge. + Qed. + End CompletionFacts. (** In this section, we establish some facts that are really about service,