From f9804cf1b5d1ec452fc592eb05e47104ae949c9d Mon Sep 17 00:00:00 2001
From: Sergei Bozhko <sbozhko@mpi-sws.org>
Date: Fri, 25 Sep 2020 13:08:21 +0200
Subject: [PATCH] EDF ensures the `sequential_tasks` property

---
 analysis/facts/edf.v | 120 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 119 insertions(+), 1 deletion(-)

diff --git a/analysis/facts/edf.v b/analysis/facts/edf.v
index 7969e812e..95d1d7c38 100644
--- a/analysis/facts/edf.v
+++ b/analysis/facts/edf.v
@@ -30,5 +30,123 @@ Section PropertiesOfEDF.
 End PropertiesOfEDF.
 
 (** We add the above lemma into a "Hint Database" basic_facts, so Coq
-    will be able to apply them automatically. *)
+    will be able to apply it automatically. *)
 Global Hint Resolve EDF_respects_sequential_tasks : basic_facts.
+
+
+Require Export prosa.model.task.sequentiality.
+Require Export prosa.analysis.facts.busy_interval.priority_inversion.
+
+(** In this section, we prove that EDF priority policy 
+    implies that tasks are sequential. *)
+Section SequentialEDF.  
+
+  (** Consider any type of tasks ... *)
+  Context {Task : TaskType}.
+  Context `{TaskCost Task}.
+  Context `{TaskDeadline Task}.
+
+  (** ... with a bound on the maximum non-preemptive segment length.
+      The bound is needed to ensure that, at any instant, it always 
+      exists a subsequent preemption time in which the scheduler can, 
+      if needed, switch to another higher-priority job. *)
+  Context `{TaskMaxNonpreemptiveSegment Task}.
+  
+  (** Further, consider any type of jobs associated with these tasks. *)
+  Context {Job : JobType}.
+  Context `{JobTask Job Task}.
+  Context `{Arrival : JobArrival Job}.
+  Context `{Cost : JobCost Job}.
+
+  (** Consider any arrival sequence. *)
+  Variable arr_seq : arrival_sequence Job.
+  
+  (** Next, consider any ideal uni-processor schedule of this arrival sequence, ... *)
+  Variable sched : schedule (ideal.processor_state Job).
+  
+  (** ... allow for any work-bearing notion of job readiness, ... *)
+  Context `{@JobReady Job (ideal.processor_state Job) _ Cost Arrival}.
+  Hypothesis H_job_ready : work_bearing_readiness arr_seq sched.
+
+  (** ... and assume that the schedule is valid. *)
+  Hypothesis H_sched_valid : valid_schedule sched arr_seq.
+  
+  (** In addition, we assume the existence of a function mapping jobs
+      to their preemption points ... *)
+  Context `{JobPreemptable Job}.
+
+  (** ... and assume that it defines a valid preemption model with
+      bounded non-preemptive segments. *)
+  Hypothesis H_valid_model_with_bounded_nonpreemptive_segments:
+    valid_model_with_bounded_nonpreemptive_segments arr_seq sched.
+
+  (** Next, we assume that the schedule respects the policy defined by
+     the [job_preemptable] function (i.e., jobs have bounded
+     non-preemptive segments). *)
+  Hypothesis H_respects_policy : respects_policy_at_preemption_point arr_seq sched.
+  
+  (** We say that a job [j1] always has higher priority than job [j2]
+      if, at any time [t], the priority of job [j1] is strictly higher than
+      priority of job [j2]. 
+      
+      NB: this definition and the following lemma are general facts about 
+      priority policies on uniprocessors that depend on neither EDF nor the ideal uniprocessor assumption. Generalizing to any priority policy and processor
+      model left to future work.
+      (https://gitlab.mpi-sws.org/RT-PROOFS/rt-proofs/-/issues/78). *)
+  Definition always_higher_priority j1 j2 :=
+    forall t, hep_job_at t j1 j2 && ~~ hep_job_at t j2 j1.
+  
+  (** First, we show that, given two jobs [j1] and [j2], if job [j1]
+      arrives earlier than job [j2] and [j1] always has higher
+      priority than [j2], then [j2] is scheduled only after [j1] is
+      completed. *) 
+  Lemma early_hep_job_is_scheduled: 
+    forall j1 j2,
+      arrives_in arr_seq j1 -> 
+      job_arrival j1 < job_arrival j2 -> 
+      always_higher_priority j1 j2 ->
+      forall t,
+        scheduled_at sched j2 t ->
+        completed_by sched j1 t.
+  Proof.
+    move=> j1 j2 ARR LE AHP t SCHED; apply/negPn/negP; intros NCOMPL.
+    move: H_sched_valid => [COARR MBR].
+    have ARR_EXEC := jobs_must_arrive_to_be_ready sched MBR. 
+    edestruct scheduling_of_any_segment_starts_with_preemption_time
+      as [pt [LET [PT ALL_SCHED]]]; try eauto 2.
+    move: LET => /andP [LE1 LE2].
+    specialize (ALL_SCHED pt); feed ALL_SCHED; first by apply/andP; split.
+    have PEND1: pending sched j1 pt.
+    { apply/andP; split.
+      - by rewrite /has_arrived; ssrlia.
+      - by move: NCOMPL; apply contra, completion_monotonic.
+    }
+    apply H_job_ready in PEND1 => //; destruct PEND1 as [j3 [ARR3 [READY3 HEP3]]].
+    move: (AHP pt) => /andP[HEP /negP NHEP]; eapply NHEP.
+    eapply EDF_is_transitive; last by apply HEP3.
+    eapply H_respects_policy; eauto 2.
+    apply/andP; split; first by done.
+    apply/negP; intros SCHED2.
+    have EQ := ideal_proc_model_is_a_uniprocessor_model _ _ _ pt SCHED2 ALL_SCHED.
+    subst j2; rename j3 into j.
+    by specialize (AHP 0); destruct AHP; auto.
+  Qed.
+
+  (** Clearly, under the EDF priority policy, jobs satisfy the conditions
+     described by the lemma above; hence EDF implies sequential tasks. *)
+  Lemma EDF_implies_sequential_tasks:
+    sequential_tasks arr_seq sched.
+  Proof.
+    intros ? ? ? ARR1 ARR2 SAME LT.
+    apply early_hep_job_is_scheduled => //.
+    - clear t; intros ?.
+      move: SAME => /eqP SAME.
+      apply /andP.
+      rewrite /hep_job_at /JLFP_to_JLDP /hep_job /edf.EDF /job_deadline
+              /absolute_deadline.job_deadline_from_task_deadline SAME.
+      split.
+      + by rewrite leq_add2r ltnW.
+      + by rewrite -ltnNge ltn_add2r. 
+  Qed.
+
+End SequentialEDF.
-- 
GitLab