Library prosa.classic.model.schedule.uni.jitter.busy_interval

Require Import prosa.classic.util.all.
Require Import prosa.classic.model.arrival.basic.task prosa.classic.model.arrival.basic.job
               prosa.classic.model.arrival.basic.arrival_sequence
               prosa.classic.model.priority prosa.classic.model.arrival.basic.task_arrival.
Require Import prosa.classic.model.schedule.uni.service prosa.classic.model.schedule.uni.workload.
Require Import prosa.classic.model.schedule.uni.jitter.schedule prosa.classic.model.schedule.uni.jitter.platform.
From mathcomp Require Import ssreflect ssrbool eqtype ssrnat seq fintype bigop.

(* In this file, we provide definitions and lemmas about busy intervals
   and their relation with response times. *)

Module BusyInterval.

  Import Job UniprocessorScheduleWithJitter Priority Platform
         Service Workload TaskArrival.

  (* In this section, we define the notion of a busy interval. *)
  Section Defs.

    Context {Task: eqType}.
    Context {Job: eqType}.
    Variable job_arrival: Job time.
    Variable job_cost: Job time.
    Variable job_jitter: Job time.
    Variable job_task: Job Task.

    (* Consider any arrival sequence with consistent arrival times... *)
    Variable arr_seq: arrival_sequence Job.
    Hypothesis H_arrival_times_are_consistent: arrival_times_are_consistent job_arrival arr_seq.

    (* ...and any uniprocessor schedule of these jobs. *)
    Variable sched: schedule Job.
    Hypothesis H_jobs_come_from_arrival_sequence:
      jobs_come_from_arrival_sequence sched arr_seq.

    (* Consider any JLFP policy. *)
    Variable higher_eq_priority: JLFP_policy Job.

    (* Let j be any job to be analyzed. *)
    Variable j: Job.
    Hypothesis H_from_arrival_sequence: arrives_in arr_seq j.

    (* For simplicity, let's define some local names. *)
    Let job_pending_at := pending job_arrival job_cost job_jitter sched.
    Let job_scheduled_at := scheduled_at sched.
    Let job_completed_by := completed_by job_cost sched.
    Let actual_job_arrival := actual_arrival job_arrival job_jitter.
    Let actual_job_arrival_between := actual_arrival_between job_arrival job_jitter.

    (* We say that t is a quiet time for j iff every higher-priority job that
       has an actual arrival time (with jitter) before t has completed by that time. *)

    Definition quiet_time (t: time) :=
       j_hp,
        arrives_in arr_seq j_hp
        higher_eq_priority j_hp j
        actual_arrival_before job_arrival job_jitter j_hp t
        job_completed_by j_hp t.

    (* Based on the definition of quiet time, we say that interval
       t1, t_busy) is a (potentially unbounded) busy-interval prefix iff the interval starts with a quiet time and remains non-quiet. *)

    Definition busy_interval_prefix (t1 t_busy: time) :=
      t1 < t_busy
      quiet_time t1
      ( t, t1 < t < t_busy ¬ quiet_time t).

    (* Next, we say that an interval t1, t2) is a busy interval iff [t1, t2) is a busy-interval prefix and t2 is a quiet time. *)
    Definition busy_interval (t1 t2: time) :=
      busy_interval_prefix t1 t2
      quiet_time t2.

    (* Now we prove some lemmas about busy intervals. *)
    Section Lemmas.

      (* Recall the list of jobs with actual arrival time (including jitter) in the
         interval t1, t2). *)

      Let actual_arrivals t1 t2 := actual_arrivals_between job_arrival job_jitter arr_seq t1 t2.

      (* We begin by proving basic lemmas about the arrival and
         completion of jobs that are pending during a busy interval. *)

      Section BasicLemmas.

        (* Assume that the priority relation is reflexive. *)
        Hypothesis H_priority_is_reflexive: JLFP_is_reflexive higher_eq_priority.

        (* Consider any busy interval t1, t2)... *)
        Variable t1 t2: time.
        Hypothesis H_busy_interval: busy_interval t1 t2.

        (* ...and assume that job j is pending during this busy interval. *)
        Variable t: time.
        Hypothesis H_during_interval: t1 t < t2.
        Hypothesis H_job_is_pending: job_pending_at j t.

        (* First, we prove that job j completes by the end of the busy interval. *)
        Section CompletesDuringBusyInterval.

          Lemma job_completes_within_busy_interval:
            job_completed_by j t2.

        End CompletesDuringBusyInterval.

        (* Next, we prove that the actual arrival of job j cannot have occurred before the busy interval. *)
        Section ArrivesDuringBusyInterval.

          (* Assume that jobs do not execute after completion. *)
          Hypothesis H_completed_jobs_dont_execute:
            completed_jobs_dont_execute job_cost sched.

          (* Then, we prove that job j's actual arrival (with jitter) occurs no earlier than t1. *)
          Lemma job_arrives_within_busy_interval:
            t1 actual_job_arrival j.

        End ArrivesDuringBusyInterval.

      End BasicLemmas.

      (* In this section, we prove that during a busy interval there
         always exists a pending job. *)

      Section ExistsPendingJob.

        (* Assume that jobs do not execute after completion. *)
        Hypothesis H_completed_jobs_dont_execute:
          completed_jobs_dont_execute job_cost sched.

        (* Let t1, t2 be any interval where time t1 is quiet and
           time t2 is not quiet. *)

        Variable t1 t2: time.
        Hypothesis H_interval: t1 t2.
        Hypothesis H_quiet: quiet_time t1.
        Hypothesis H_not_quiet: ¬ quiet_time t2.

      (* Then, we prove that there exists a job pending at time t2
         that has higher or equal priority (with respect ot tsk). *)

        Lemma not_quiet_implies_exists_pending_job:
           j_hp,
            arrives_in arr_seq j_hp
            actual_job_arrival_between j_hp t1 t2
            higher_eq_priority j_hp j
            ¬ job_completed_by j_hp t2.

      End ExistsPendingJob.

      (* In this section, we prove that during a busy interval the
         processor is never idle. *)

      Section ProcessorAlwaysBusy.

        (* Assume that the schedule is work-conserving and that jobs do
           not execute before the jitter has passed nor after completion. *)

        Hypothesis H_work_conserving: work_conserving job_arrival job_cost job_jitter arr_seq sched.
        Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.
        Hypothesis H_jobs_execute_after_jitter:
          jobs_execute_after_jitter job_arrival job_jitter sched.

        (* Consider any interval t1, t2 such that t1 < t2 and t1 is the only quiet time. *)
        Variable t1 t2: time.
        Hypothesis H_strictly_larger: t1 < t2.
        Hypothesis H_quiet: quiet_time t1.
        Hypothesis H_not_quiet: t, t1 < t t2 ¬ quiet_time t.

        (* We prove that at every time t in t1, t2, the processor is not idle. *)
        Lemma not_quiet_implies_not_idle:
           t,
            t1 t t2
            ¬ is_idle sched t.

        (* In fact, we can infer a stronger property. *)
        Section OnlyHigherOrEqualPriority.

          (* If the JLFP policy is transitive and is respected by the schedule, ...*)
          Hypothesis H_priority_is_transitive: JLFP_is_transitive higher_eq_priority.
          Hypothesis H_respects_policy:
            respects_JLFP_policy job_arrival job_cost job_jitter arr_seq sched higher_eq_priority.

          (* ... then the processor is always busy with a job of higher or equal priority
             and actual arrival time in the interval. *)

          Lemma not_quiet_implies_exists_scheduled_hp_job:
             t,
              t1 t < t2
               j_hp,
                actual_job_arrival_between j_hp t1 t2
                higher_eq_priority j_hp j
                job_scheduled_at j_hp t.

        End OnlyHigherOrEqualPriority.

      End ProcessorAlwaysBusy.

      (* In this section, we show that the length of any busy interval
         is bounded, as long as there is enough supply to accomodate
         the workload of tasks with higher or equal priority. *)

      Section BoundingBusyInterval.

        (* Assume that there are no duplicate job arrivals... *)
        Hypothesis H_arrival_sequence_is_a_set:
          arrival_sequence_is_a_set arr_seq.

        (* ...and that jobs do not execute before the jitter has passed nor after completion. *)
        Hypothesis H_jobs_execute_after_jitter:
          jobs_execute_after_jitter job_arrival job_jitter sched.
        Hypothesis H_completed_jobs_dont_execute: completed_jobs_dont_execute job_cost sched.

        (* Also assume a work-conserving FP schedule, ... *)
        Hypothesis H_work_conserving: work_conserving job_arrival job_cost job_jitter arr_seq sched.
        Hypothesis H_respects_policy:
          respects_JLFP_policy job_arrival job_cost job_jitter arr_seq sched higher_eq_priority.

        (* ...in which the priority relation is reflexive and transitive. *)
        Hypothesis H_priority_is_reflexive: JLFP_is_reflexive higher_eq_priority.
        Hypothesis H_priority_is_transitive: JLFP_is_transitive higher_eq_priority.

        (* Next, we recall the notion of workload of all jobs with actual arrival time
           in a given interval t1, t2) that have higher-or-equal priority than the job j being analyzed. *)

        Let actual_hp_workload t1 t2 :=
          workload_of_higher_or_equal_priority_jobs job_cost (actual_arrivals t1 t2)
                                                    higher_eq_priority j.

        (* With regard to the jobs with higher-or-equal priority that have actual
           arrival time in a given interval t1, t2), we also recall the service received by these jobs in the same interval [t1, t2). *)

        Let actual_hp_service t1 t2 :=
          service_of_higher_or_equal_priority_jobs sched (actual_arrivals t1 t2)
                                                   higher_eq_priority j t1 t2.

        (* Now we begin the proof. First, we show that the busy interval is bounded. *)
        Section BoundingBusyInterval.

          (* Suppose that job j is pending at time t_busy. *)
          Variable t_busy: time.
          Hypothesis H_j_is_pending: job_pending_at j t_busy.

          (* First, we show that there must exist a busy interval prefix. *)
          Section LowerBound.

            (* Since job j is pending, there exists a (potentially unbounded)
               busy interval that starts prior to the actual arrival time of j. *)

            Lemma exists_busy_interval_prefix:
               t1,
                busy_interval_prefix t1 t_busy.+1
                t1 actual_job_arrival j t_busy.

          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 that starts at time t1 <= actual_job_arrival j. *)
            Variable t1: time.
            Hypothesis H_is_busy_prefix: busy_interval_prefix t1 t_busy.+1.
            Hypothesis H_busy_prefix_contains_arrival: actual_job_arrival j t1.

            (* Next, assume that for some delta > 0, the requested workload
               at time (t1 + delta) is bounded by delta (i.e., the supply). *)

            Variable delta: time.
            Hypothesis H_delta_positive: delta > 0.
            Hypothesis H_workload_is_bounded: actual_hp_workload t1 (t1 + delta) delta.

            (* If there exists a quiet time by time (t1 + delta), 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 + delta]. *)
              Hypothesis H_no_quiet_time:
                 t, t1 < t t1 + delta ¬ quiet_time t.

              (* Since the interval is always non-quiet, the processor is always busy
                 with tasks of higher-or-equal priority, i.e., the service done by
                 jobs with actual arrival time in t1, t1 + delta) equals delta. *)

              Lemma busy_interval_has_uninterrupted_service:
                actual_hp_service t1 (t1 + delta) = delta.

              (* Moreover, the fact that the interval is not quiet also implies
                 that there's more workload requested than service received. *)

              Lemma busy_interval_too_much_workload:
                actual_hp_workload t1 (t1 + delta) > actual_hp_service t1 (t1 + delta).

              (* Using the two lemmas above, we infer that the workload is larger than the
                 interval length. However, this contradicts the assumption H_workload_is_bounded. *)

              Corollary busy_interval_workload_larger_than_interval:
                actual_hp_workload t1 (t1 + delta) > delta.

            End CannotBeBusyForSoLong.

            (* Since the interval cannot remain busy for so long, we prove that
               the busy interval finishes at some point t2 <= t1 + delta. *)

            Lemma busy_interval_is_bounded:
               t2,
                t2 t1 + delta
                busy_interval t1 t2.

          End UpperBound.

        End BoundingBusyInterval.

        (* In this section, we show that from a workload bound we can infer
           the existence of a busy interval. *)

        Section BusyIntervalFromWorkloadBound.

          (* Assume that for some delta > 0, the requested workload at
             time (t1 + delta) is bounded by delta (i.e., the supply). *)

          Variable delta: time.
          Hypothesis H_delta_positive: delta > 0.
          Hypothesis H_workload_is_bounded:
             t, actual_hp_workload t (t + delta) delta.

          (* Next, we assume that job j has positive cost, from which we can
             infer that there always is a time in which j is pending. *)

          Hypothesis H_positive_cost: job_cost j > 0.

          (* Therefore there must exists a busy interval t1, t2) that contains the actual arrival time of job j. *)
          Corollary exists_busy_interval:
             t1 t2,
              t1 actual_job_arrival j < t2
              t2 t1 + delta
              busy_interval t1 t2.

          End BusyIntervalFromWorkloadBound.

        (* If we know that the workload is bounded, we can also use the
           busy interval to infer a response-time bound. *)

        Section ResponseTimeBoundFromBusyInterval.

          (* Assume that for some delta > 0, the requested workload
             at time (t1 + delta) is bounded by delta (i.e., the supply). *)

          Variable delta: time.
          Hypothesis H_delta_positive: delta > 0.
          Hypothesis H_workload_is_bounded:
             t,
              actual_hp_workload t (t + delta) delta.

          (* Then, job j must complete by (actual_job_arrival j + delta). *)
          Lemma busy_interval_bounds_response_time:
            job_completed_by j (actual_job_arrival j + delta).

        End ResponseTimeBoundFromBusyInterval.

      End BoundingBusyInterval.

    End Lemmas.

  End Defs.

End BusyInterval.