diff --git a/implementation/definitions/generic_scheduler.v b/implementation/definitions/generic_scheduler.v new file mode 100644 index 0000000000000000000000000000000000000000..7270f996bc4203e97b3814d4ac1d8a55dae3dfa7 --- /dev/null +++ b/implementation/definitions/generic_scheduler.v @@ -0,0 +1,55 @@ +Require Export prosa.analysis.transform.swap. + +(** * Generic Reference Scheduler *) + +(** In this file, we provide a generic procedure that produces a schedule by + making a decision on what to schedule at each point in time. *) + +(** To begin with, we define the notion of a pointwise scheduling policy that + makes a decision at a given time [t] based on given prefix up to time + [t.-1]. *) +Section PointwisePolicy. + (** Consider any type of jobs and type of schedule. *) + Context {Job : JobType}. + Variable PState : Type. + + (** A pointwise scheduling policy is a function that, given a schedule prefix + that is valid up to time [t - 1], decides what to schedule at time + [t]. *) + Definition PointwisePolicy := schedule PState -> instant -> PState. +End PointwisePolicy. + +Section GenericSchedule. + (** Consider any type of jobs and type of schedule. *) + Context {Job : JobType} {PState : Type}. + Context `{ProcessorState Job PState}. + + (** Suppose we are given a policy function that, given a schedule prefix that + is valid up to time [t - 1], decides what to schedule at time [t]. *) + Variable policy : PointwisePolicy PState. + + (** Let [idle_state] denote the processor state that indicates that the + entire system is idle. *) + Variable idle_state : PState. + + (** We construct the schedule step by step starting from an "empty" schedule + that is idle at all times as a base case. *) + Definition empty_schedule: schedule PState := fun _ => idle_state. + + (** Next, we define a function that computes a schedule prefix up to a given + time horizon [h]. *) + Fixpoint schedule_up_to (h : instant) := + let + prefix := if h is h'.+1 then schedule_up_to h' else empty_schedule + in + replace_at prefix h (policy prefix h). + + (** Finally, we define the generic schedule as follows: for a + given point in time [t], we compute the finite prefix up to and including + [t], namely [schedule_up_to t], and then return the job scheduled at time + [t] in that prefix. *) + Definition generic_schedule (t : instant) : PState := + schedule_up_to t t. + +End GenericSchedule. + diff --git a/implementation/definitions/ideal_uni_scheduler.v b/implementation/definitions/ideal_uni_scheduler.v new file mode 100644 index 0000000000000000000000000000000000000000..d87919807d2a93a4e5853f63915c2a8bd76b530a --- /dev/null +++ b/implementation/definitions/ideal_uni_scheduler.v @@ -0,0 +1,105 @@ +Require Export prosa.implementation.definitions.generic_scheduler. + +Require Export prosa.model.preemption.parameter. +Require Export prosa.model.schedule.priority_driven. +Require Export prosa.analysis.facts.readiness.backlogged. +Require Export prosa.analysis.transform.swap. + +(** * Ideal Uniprocessor Reference Scheduler *) + +(** In this file, we provide a generic priority-aware scheduler that produces + an ideal uniprocessor schedule for a given arrival sequence. The scheduler + respects nonpreemptive sections and arbitrary readiness models. *) + +(** The following definitions assume ideal uniprocessor schedules. *) +Require prosa.model.processor.ideal. + +Section UniprocessorScheduler. + + (** Consider any type of jobs with costs and arrival times, ... *) + Context {Job : JobType} {JC : JobCost Job} {JA : JobArrival Job}. + + (** .. in the context of an ideal uniprocessor model. *) + Let PState := ideal.processor_state Job. + Let idle_state : PState := None. + + (** Suppose we are given a consistent arrival sequence of such jobs ... *) + Variable arr_seq : arrival_sequence Job. + Hypothesis H_consistent_arrival_times: consistent_arrival_times arr_seq. + + (** ... and a non-clairvoyant readiness model. *) + Context {RM: JobReady Job (ideal.processor_state Job)}. + Hypothesis H_nonclairvoyant_job_readiness: nonclairvoyant_readiness RM. + + (** ** Preemption-Aware Scheduler *) + + (** First, we define the notion of a generic uniprocessor scheduler that is + cognizant of non-preemptive sections, ... *) + + (** ... so consider any preemption model. *) + Context `{JobPreemptable Job}. + + Section NonPreemptiveSectionAware. + + (** Suppose we are given a scheduling policy that applies when jobs are + preemptive: given a set of jobs ready at time [t], select which to run + (if any) at time [t]. *) + Variable choose_job : instant -> seq Job -> option Job. + + (** The next job is then chosen either by [policy] (if the current job is + preemptive or the processor is idle) or a non-preemptively executing job + continues to execute. *) + Section JobAllocation. + + (** Consider a finite schedule prefix ... *) + Variable sched_prefix : schedule (ideal.processor_state Job). + + (** ... that is valid up to time [t - 1]. *) + Variable t : instant. + + (** We define a predicate that tests whether the job scheduled at the + previous instant (if [t > 0]) is nonpreemptive (and hence needs to be + continued to be scheduled). *) + Definition prev_job_nonpreemptive : bool := + match t with + | 0 => false + | S t' => if sched_prefix t' is Some j then + ~~job_preemptable j (service sched_prefix j t) + else + false + end. + + (** Based on the [prev_job_nonpreemptive] predicate, either the previous + job continues to be scheduled or the given policy chooses what to run + instead. *) + Definition allocation_at : option Job := + if prev_job_nonpreemptive then + sched_prefix t.-1 + else + choose_job t (jobs_backlogged_at arr_seq sched_prefix t). + End JobAllocation. + + (* A preemption-policy-aware ideal uniprocessor schedule is then produced + when using [allocation_at] as the policy for the generic scheduler. *) + Definition np_uni_schedule : schedule PState := generic_schedule allocation_at idle_state. + + End NonPreemptiveSectionAware. + + (** ** Priority-Aware Scheduler *) + + (** Building on the preemption-model aware scheduler, we next define a simple priority-aware scheduler. *) + Section PriorityAware. + + (** Given any JLDP priority policy... *) + Context `{JLDP_policy Job}. + + (** ...always choose the highest-priority job when making a scheduling decision... *) + Definition choose_highest_prio_job t jobs := supremum (hep_job_at t) jobs. + + (** ... to obtain a priority- and preemption-model-aware ideal uniprocessor + schedule. *) + Definition uni_schedule : schedule PState := np_uni_schedule choose_highest_prio_job. + End PriorityAware. + +End UniprocessorScheduler. + diff --git a/implementation/definitions/scheduler.v b/implementation/definitions/scheduler.v deleted file mode 100644 index 10b33292dbca53a060c0d5483fbb1fd7333ab0b0..0000000000000000000000000000000000000000 --- a/implementation/definitions/scheduler.v +++ /dev/null @@ -1,61 +0,0 @@ -Require Export prosa.behavior.all. -Require Export prosa.model.priority.classes. -Require Export prosa.util.supremum. -Require Export prosa.model.preemption.parameter. -Require Export prosa.model.schedule.work_conserving. -Require Export prosa.model.schedule.priority_driven. -Require Export prosa.model.processor.ideal. - -Section UniprocessorSchedule. - - Context {Job : JobType}. - Context `{JobCost Job}. - Context `{JobArrival Job}. - Context `{JobPreemptable Job}. - Context `{JLDP_policy Job}. - Context {Task : eqType}. - Context `{JobReady Job (ideal.processor_state Job)}. - - Variable arr_seq : arrival_sequence Job. - - Section JobAllocation. - - Variable sched_prefix : schedule (ideal.processor_state Job). - - Definition prev_job_nonpreemptive (t : instant) : bool:= - match t with - | 0 => false - | S t' => if sched_prefix t' is Some j then - ~~job_preemptable j (service sched_prefix j t) - else - false - end. - - (** Given an arrival sequence, a prefix schedule [[0, t-1]], computes - which job has to be scheduled at [t] **) - Definition allocation_at (t : instant): option Job := - if prev_job_nonpreemptive t then - sched_prefix t.-1 - else - supremum (hep_job_at t) (jobs_backlogged_at arr_seq sched_prefix t). - - End JobAllocation. - - Definition empty_schedule: schedule (ideal.processor_state Job) := fun _ => None. - - (** Given an arrival sequence, computes a schedule up to time [h] **) - Fixpoint schedule_up_to (h : instant) : schedule (ideal.processor_state Job) := - let - prefix := if h is S h' then schedule_up_to h' else empty_schedule - in - fun t => - if t == h then - allocation_at prefix t - else - prefix t. - - Definition uni_schedule (t : instant) : ideal.processor_state Job := - schedule_up_to t t. - -End UniprocessorSchedule. - diff --git a/implementation/facts/generic_schedule.v b/implementation/facts/generic_schedule.v new file mode 100644 index 0000000000000000000000000000000000000000..14207570894b28d4f244d72a7b337d79bac95e5c --- /dev/null +++ b/implementation/facts/generic_schedule.v @@ -0,0 +1,87 @@ +From mathcomp Require Export ssreflect ssrnat ssrbool eqtype fintype bigop. +Require Export prosa.implementation.definitions.generic_scheduler. +Require Export prosa.analysis.facts.transform.replace_at. + +(** * Properties of the Generic Reference Scheduler *) + +(** This file establishes some facts about the generic reference scheduler that + constructs a schedule via pointwise scheduling decisions based on a given + policy and the preceding prefix. *) + +Section GenericScheduleProperties. + (** For any type of jobs and type of schedule, ... *) + Context {Job : JobType} {PState : Type}. + Context `{ProcessorState Job PState}. + + (** ... any scheduling policy, and ... *) + Variable policy : PointwisePolicy PState. + + (** ... any notion of idleness. *) + Variable idle_state : PState. + + (** For notational convenience, we define [prefix t] to denote the finite + prefix considered when scheduling a job at time [t]. *) + Let prefix t := if t is t'.+1 then schedule_up_to policy idle_state t' else empty_schedule idle_state. + + (** To begin with, we establish two simple rewriting lemmas for unrolling + [schedule_up_to]. First, we observe that the allocation is indeed + determined by the policy based on the preceding prefix. *) + Lemma schedule_up_to_def: + forall t, + schedule_up_to policy idle_state t t = policy (prefix t) t. + Proof. by elim=> [|n IH]; rewrite [LHS]/schedule_up_to -/(schedule_up_to _) /replace_at; apply ifT. Qed. + + (** Second, we note how to replace [schedule_up_to] in the general case with + its definition. *) + Lemma schedule_up_to_unfold: + forall h t, + schedule_up_to policy idle_state h t = replace_at (prefix h) h (policy (prefix h) h) t. + Proof. by move=> h t; rewrite [LHS]/schedule_up_to /prefix; elim: h. Qed. + + (** Next, we observe that we can increase a prefix's horizon by one + time unit without changing any allocations in the prefix. *) + Lemma schedule_up_to_widen: + forall h t, + t <= h -> + schedule_up_to policy idle_state h t = schedule_up_to policy idle_state h.+1 t. + Proof. + move=> h t RANGE. + rewrite [RHS]schedule_up_to_unfold rest_of_schedule_invariant // => EQ. + now move: RANGE; rewrite EQ ltnn. + Qed. + + (** After the horizon of a prefix, the schedule is still "empty", meaning + that all instants are idle. *) + Lemma schedule_up_to_empty: + forall h t, + h < t -> + schedule_up_to policy idle_state h t = idle_state. + Proof. + move=> h t. + elim: h => [LT|h IH LT]. + { rewrite /schedule_up_to rest_of_schedule_invariant // => ZERO. + now subst. } + { rewrite /schedule_up_to rest_of_schedule_invariant -/(schedule_up_to _ h t); + first by apply IH => //; apply ltn_trans with (n := h.+1). + move=> EQ. move: LT. + now rewrite EQ ltnn. } + Qed. + + (** A crucial fact is that a prefix up to horizon [h1] is identical to a + prefix up to a later horizon [h2] at times up to [h1]. *) + Lemma schedule_up_to_prefix_inclusion: + forall h1 h2, + h1 <= h2 -> + forall t, + t <= h1 -> + schedule_up_to policy idle_state h1 t = schedule_up_to policy idle_state h2 t. + Proof. + move=> h1 h2 LEQ t BEFORE. + elim: h2 LEQ BEFORE; first by rewrite leqn0 => /eqP ->. + move=> t' IH. + rewrite leq_eqVlt ltnS => /orP [/eqP <-|LEQ] // t_H1. + rewrite IH // schedule_up_to_widen //. + now apply (leq_trans t_H1). + Qed. + +End GenericScheduleProperties. diff --git a/implementation/facts/ideal_uni/preemption_aware.v b/implementation/facts/ideal_uni/preemption_aware.v new file mode 100644 index 0000000000000000000000000000000000000000..4a7160f9bf052ed5fc4be4f5ca64dbc4095aa6fe --- /dev/null +++ b/implementation/facts/ideal_uni/preemption_aware.v @@ -0,0 +1,215 @@ +Require Export prosa.implementation.facts.generic_schedule. +Require Export prosa.implementation.definitions.ideal_uni_scheduler. +Require Export prosa.analysis.facts.model.ideal_schedule. + +(** * Properties of the Preemption-Aware Ideal Uniprocessor Scheduler *) + +(** This file establishes facts about the reference model of a + preemption-model-aware ideal uniprocessor scheduler. *) + +(** The following results assume ideal uniprocessor schedules. *) +Require Import prosa.model.processor.ideal. + +Section NPUniprocessorScheduler. + + (** Consider any type of jobs with costs and arrival times, ... *) + Context {Job : JobType} {JC : JobCost Job} {JA : JobArrival Job}. + + (** ... in the context of an ideal uniprocessor model. *) + Let PState := ideal.processor_state Job. + Let idle_state : PState := None. + + (** Suppose we are given a consistent arrival sequence of such jobs, ... *) + Variable arr_seq : arrival_sequence Job. + Hypothesis H_consistent_arrival_times: consistent_arrival_times arr_seq. + + (** ... a non-clairvoyant readiness model, ... *) + Context {RM: JobReady Job (ideal.processor_state Job)}. + Hypothesis H_nonclairvoyant_job_readiness: nonclairvoyant_readiness RM. + + (** ... and a preemption model. *) + Context `{JobPreemptable Job}. + + (** For any given job selection policy ... *) + Variable choose_job : instant -> seq Job -> option Job. + + (** ... consider the schedule produced by the preemption-aware scheduler for + the policy induced by [choose_job]. *) + Let schedule := np_uni_schedule arr_seq choose_job. + Let policy := allocation_at arr_seq choose_job. + + (** To begin with, we establish that the preemption-aware scheduler does not + induce non-work-conserving behavior. *) + Section WorkConservation. + + (** If [choose_job] does not voluntarily idle the processor, ... *) + Hypothesis H_non_idling: + forall t s, + choose_job t s = idle_state <-> s = [::]. + + (** ... then we can establish work-conservation. *) + + (** First, we observe that [allocation_at] yields [idle_state] only if there are + no backlogged jobs. *) + Lemma allocation_at_idle: + forall sched t, + allocation_at arr_seq choose_job sched t = idle_state -> + jobs_backlogged_at arr_seq sched t = [::]. + Proof. + move=> sched t. + elim: t => [|t _]; first by apply H_non_idling. + rewrite /allocation_at /prev_job_nonpreemptive. + elim: (sched t) => [j'|]; last by apply H_non_idling. + rewrite if_neg. + elim: (job_preemptable j' (service sched j' t.+1)); first by apply H_non_idling. + now discriminate. + Qed. + + (** As a stepping stone, we observe that the generated schedule is idle at + a time [t] only if there are no backlogged jobs. *) + Lemma idle_schedule_no_backlogged_jobs: + forall t, + is_idle schedule t -> + jobs_backlogged_at arr_seq schedule t = [::]. + Proof. + move=> t. + rewrite /is_idle /schedule /np_uni_schedule /generic_schedule => /eqP. + move=> NONE. move: (NONE). + rewrite schedule_up_to_def => IDLE. + apply allocation_at_idle in IDLE. + rewrite -IDLE. + apply backlogged_jobs_prefix_invariance with (h := t.+1) => //. + rewrite /identical_prefix => x. + rewrite ltnS leq_eqVlt => /orP [/eqP ->|LT]; last first. + { elim: t LT IDLE NONE => // => h IH LT_x IDLE NONE. + now apply schedule_up_to_prefix_inclusion. } + { elim: t IDLE NONE => [IDLE _| t' _ _ ->]; last by rewrite schedule_up_to_empty. + rewrite /schedule_up_to replace_at_def. + rewrite /allocation_at /prev_job_nonpreemptive IDLE H_non_idling //. } + Qed. + + (** From the preceding fact, we conclude that the generated schedule is + indeed work-conserving. *) + Theorem np_schedule_work_conserving: + work_conserving arr_seq schedule. + Proof. + move=> j t ARRIVES BACKLOGGED. + move: (@ideal_proc_model_sched_case_analysis Job schedule t) => [IDLE|SCHED]; last by exact. + exfalso. + have NON_EMPTY: j \in jobs_backlogged_at arr_seq schedule t by apply mem_backlogged_jobs => //. + clear BACKLOGGED. + move: (idle_schedule_no_backlogged_jobs t IDLE) => EMPTY. + now rewrite EMPTY in NON_EMPTY. + Qed. + + End WorkConservation. + + (** The next result establishes that the generated preemption-model-aware + schedule is structurally valid, meaning all jobs stem from the arrival + sequence and only ready jobs are scheduled. *) + Section Validity. + + (** Any reasonable job selection policy will not create jobs "out of thin + air," i.e., if a job is selected, it was among those given to choose + from. *) + Hypothesis H_chooses_from_set: + forall t s j, choose_job t s = Some j -> j \in s. + + (** For the schedule to be valid, we require the notion of readiness to be + consistent with the preemption model: a non-preemptive job remains + ready until (at least) the end of its current non-preemptive + section. *) + Hypothesis H_valid_preemption_behavior: + valid_nonpreemptive_readiness RM. + + (** Under this natural assumption, the generated schedule is valid. *) + Theorem np_schedule_valid: + valid_schedule schedule arr_seq. + Proof. + rewrite /valid_schedule; split; move=> j t; rewrite scheduled_at_def /schedule /np_uni_schedule /generic_schedule. + { elim: t => [/eqP | t' IH /eqP]. + - rewrite schedule_up_to_def /allocation_at /prev_job_nonpreemptive => IN. + move: (H_chooses_from_set _ _ _ IN). + now apply backlogged_job_arrives_in. + - rewrite schedule_up_to_def /allocation_at. + case: (prev_job_nonpreemptive (schedule_up_to _ _ t') t'.+1) => [|IN]; + first by rewrite -pred_Sn => SCHED; apply IH; apply /eqP. + move: (H_chooses_from_set _ _ _ IN). + now apply backlogged_job_arrives_in. } + { elim: t => [/eqP |t' IH /eqP]. + - rewrite schedule_up_to_def /allocation_at /prev_job_nonpreemptive => IN. + move: (H_chooses_from_set _ _ _ IN). + rewrite mem_filter /backlogged => /andP [/andP [READY _] _]. + now rewrite -(H_nonclairvoyant_job_readiness (empty_schedule idle_state) schedule j 0). + - rewrite schedule_up_to_def /allocation_at /prev_job_nonpreemptive. + have JOB: choose_job t'.+1 (jobs_backlogged_at arr_seq (schedule_up_to policy idle_state t') t'.+1) + = Some j + -> job_ready schedule j t'.+1. + { move=> IN. + move: (H_chooses_from_set _ _ _ IN). + rewrite mem_filter /backlogged => /andP [/andP [READY _] _]. + rewrite -(H_nonclairvoyant_job_readiness (schedule_up_to policy idle_state t') schedule j t'.+1) //. + rewrite /identical_prefix /schedule /np_uni_schedule /generic_schedule => t'' LT. + now rewrite (schedule_up_to_prefix_inclusion _ _ t'' t') //. } + case: (schedule_up_to _ _ t' t') => [j' | IN]; last by apply JOB. + destruct (~~ job_preemptable j' _) eqn:NP => [EQ|IN]; last by apply JOB. + apply H_valid_preemption_behavior. + injection EQ => <-. + move: NP. + have <-: (service (schedule_up_to policy idle_state t') j' t'.+1 + = service (fun t : instant => schedule_up_to policy idle_state t t) j' t'.+1) => //. + rewrite /service. + apply equal_prefix_implies_same_service_during => t /andP [_ BOUND]. + now rewrite (schedule_up_to_prefix_inclusion _ _ t t'). } + Qed. + + End Validity. + + (** Next, we observe that the resulting schedule is consistent with the + definition of "preemption times". *) + Section PreemptionTimes. + + (** For notational convenience, recall the definition of a prefix of the + schedule based on which the next decision is made. *) + Let prefix t := if t is t'.+1 then schedule_up_to policy idle_state t' else empty_schedule idle_state. + + (** First, we observe that non-preemptive jobs remain scheduled as long as + they are non-preemptive. *) + Lemma np_job_remains_scheduled: + forall t, + prev_job_nonpreemptive (prefix t) t -> + schedule_up_to policy idle_state t t = schedule_up_to policy idle_state t t.-1. + Proof. + elim => [|t _] // NP. + rewrite schedule_up_to_def /allocation_at /policy /allocation_at. + rewrite ifT // -pred_Sn. + now rewrite schedule_up_to_widen. + Qed. + + (** From this, we conclude that the predicate used to determine whether the + previously scheduled job is nonpreemptive in the computation of + [np_uni_schedule] is consistent with the existing notion of a + [preemption_time]. *) + Lemma np_consistent: + forall t, + prev_job_nonpreemptive (prefix t) t -> + ~~ preemption_time schedule t. + Proof. + elim => [|t _]; first by rewrite /prev_job_nonpreemptive. + rewrite /schedule /np_uni_schedule /generic_schedule /preemption_time schedule_up_to_def /prefix /allocation_at => NP. + rewrite ifT //. + rewrite -pred_Sn. + move: NP. rewrite /prev_job_nonpreemptive. + elim: (schedule_up_to policy idle_state t t) => // j. + have <-: service (schedule_up_to policy idle_state t) j t.+1 + = service (fun t0 : instant => schedule_up_to policy idle_state t0 t0) j t.+1 => //. + rewrite /service. + apply equal_prefix_implies_same_service_during => t' /andP [_ BOUND]. + now rewrite (schedule_up_to_prefix_inclusion _ _ t' t). + Qed. + + End PreemptionTimes. + +End NPUniprocessorScheduler. + + diff --git a/implementation/facts/ideal_uni/prio_aware.v b/implementation/facts/ideal_uni/prio_aware.v new file mode 100644 index 0000000000000000000000000000000000000000..b1df2e0ee708238b5495b490b2a813a71bedbe74 --- /dev/null +++ b/implementation/facts/ideal_uni/prio_aware.v @@ -0,0 +1,122 @@ +Require Export prosa.implementation.facts.ideal_uni.preemption_aware. + +(** * Ideal Uniprocessor Scheduler Properties *) + +(** This file establishes facts about the reference model of a priority- and + preemption-model-aware ideal uniprocessor scheduler. *) + +(** The following results assume ideal uniprocessor schedules. *) +Require Import prosa.model.processor.ideal. + +Section PrioAwareUniprocessorScheduler. + + (** Consider any type of jobs with costs and arrival times, ... *) + Context {Job : JobType} {JC : JobCost Job} {JA : JobArrival Job}. + + (** ... in the context of an ideal uniprocessor model. *) + Let PState := ideal.processor_state Job. + Let idle_state : PState := None. + + (** Suppose we are given a consistent arrival sequence of such jobs, ... *) + Variable arr_seq : arrival_sequence Job. + Hypothesis H_consistent_arrival_times: consistent_arrival_times arr_seq. + + (** ... a non-clairvoyant readiness model, ... *) + Context {RM: JobReady Job (ideal.processor_state Job)}. + Hypothesis H_nonclairvoyant_job_readiness: nonclairvoyant_readiness RM. + + (** ... a preemption model that is consistent with the readiness model, ... *) + Context `{JobPreemptable Job}. + Hypothesis H_valid_preemption_behavior: + valid_nonpreemptive_readiness RM. + + (** ... and reflexive, total, and transitive JLDP priority policy. *) + Context `{JLDP_policy Job}. + Hypothesis H_reflexive_priorities: reflexive_priorities. + Hypothesis H_total: total_priorities. + Hypothesis H_transitive: transitive_priorities. + + (** Consider the schedule generated by the preemption-policy- and + priority-aware ideal uniprocessor scheduler. *) + Let schedule := uni_schedule arr_seq. + + (** First, we note that the priority-aware job selection policy obviously + maintains work-conservation. *) + Corollary uni_schedule_work_conserving: + work_conserving arr_seq schedule. + Proof. + apply np_schedule_work_conserving => //. + move=> t jobs. + rewrite /choose_highest_prio_job; split. + - by apply supremum_none. + - by move=> ->. + Qed. + + (** Second, we similarly note that schedule validity is also maintained. *) + Corollary uni_schedule_valid: + valid_schedule schedule arr_seq. + Proof. + apply np_schedule_valid => //. + move=> t jobs j. + now apply supremum_in. + Qed. + + (** Now we proceed to the main property of the priority-aware scheduler: in + the following section we establish that [uni_schedule arr_seq] is + compliant with the given priority policy whenever jobs are + preemptable. *) + Section Priority. + + (** For notational convenience, recall the definitions of the job-selection + policy and a prefix of the schedule based on which the next decision is + made. *) + Let policy := allocation_at arr_seq choose_highest_prio_job. + Let prefix t := if t is t'.+1 then schedule_up_to policy idle_state t' else empty_schedule idle_state. + + (** To start, we observe that, at preemption times, the scheduled job is a + supremum w.r.t. to the priority order and the set of backlogged + jobs. *) + Lemma scheduled_job_is_supremum: + forall j t, + scheduled_at schedule j t -> + preemption_time schedule t -> + supremum (hep_job_at t) (jobs_backlogged_at arr_seq (prefix t) t) = Some j. + Proof. + move=> j t SCHED PREEMPT. + have NOT_NP: ~~ prev_job_nonpreemptive (prefix t) t. + { apply contraL with (b := preemption_time (uni_schedule arr_seq) t) => //. + now apply np_consistent. } + move: SCHED. + rewrite scheduled_at_def => /eqP. + rewrite {1}/schedule/uni_schedule/np_uni_schedule/generic_schedule schedule_up_to_def /allocation_at -/(prefix t). + rewrite ifF //. + now apply negbTE. + Qed. + + (** From the preceding facts, we conclude that [uni_schedule arr_seq] + respects the priority policy at preemption times. *) + Theorem schedule_respects_policy : + respects_policy_at_preemption_point arr_seq schedule. + Proof. + move=> j1 j2 t ARRIVES PREEMPT BACK_j1 SCHED_j2. + case: (boolP (scheduled_at (uni_schedule arr_seq) j1 t)) => [SCHED_j1|NOT_SCHED_j1]. + { have <-: j1 = j2 by apply (ideal_proc_model_is_a_uniprocessor_model j1 j2 (uni_schedule arr_seq) t). + now apply H_reflexive_priorities. } + { move: BACK_j1. + have ->: backlogged (uni_schedule arr_seq) j1 t = backlogged (prefix t) j1 t. + { apply backlogged_prefix_invariance' with (h := t) => //. + rewrite /identical_prefix /uni_schedule /prefix => t' LT. + induction t => //. + rewrite /np_uni_schedule /generic_schedule (schedule_up_to_prefix_inclusion _ _ t' t) //. + rewrite /prefix scheduled_at_def. + induction t => //. + now rewrite schedule_up_to_empty. } + move=> BACK_j1. + move: (scheduled_job_is_supremum j2 t SCHED_j2 PREEMPT) => SUPREMUM. + apply supremum_spec with (s := jobs_backlogged_at arr_seq (prefix t) t) => //. + now apply mem_backlogged_jobs. } + Qed. + + End Priority. + +End PrioAwareUniprocessorScheduler. diff --git a/scripts/wordlist.pws b/scripts/wordlist.pws index bdf248d267e16ddd49ccc37dd8dc591792dceebc..e74cc4d344fae1f9acf5484e299935b8ed552896 100644 --- a/scripts/wordlist.pws +++ b/scripts/wordlist.pws @@ -50,3 +50,4 @@ TODO mathcomp hyperperiod pointwise +notational