diff options
| -rw-r--r-- | include/litmus/rt_param.h | 14 | ||||
| -rw-r--r-- | litmus/Makefile | 9 | ||||
| -rwxr-xr-x | litmus/sched_pfair.c | 785 |
3 files changed, 799 insertions, 9 deletions
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index a7dd67a81a..7bb568432e 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
| @@ -64,6 +64,8 @@ struct rt_job { | |||
| 64 | }; | 64 | }; |
| 65 | 65 | ||
| 66 | 66 | ||
| 67 | struct pfair_param; | ||
| 68 | |||
| 67 | /* RT task parameters for scheduling extensions | 69 | /* RT task parameters for scheduling extensions |
| 68 | * These parameters are inherited during clone and therefore must | 70 | * These parameters are inherited during clone and therefore must |
| 69 | * be explicitly set up before the task set is launched. | 71 | * be explicitly set up before the task set is launched. |
| @@ -108,15 +110,12 @@ struct rt_param { | |||
| 108 | * is currently scheduled. It is the responsibility of the | 110 | * is currently scheduled. It is the responsibility of the |
| 109 | * plugin to avoid race conditions. | 111 | * plugin to avoid race conditions. |
| 110 | * | 112 | * |
| 111 | * Used by GSN-EDF. | 113 | * This used by GSN-EDF and PFAIR. |
| 112 | */ | 114 | */ |
| 113 | volatile int scheduled_on; | 115 | volatile int scheduled_on; |
| 114 | 116 | ||
| 115 | /* Is the stack of the task currently in use? Currently, this | 117 | /* Is the stack of the task currently in use? This is updated by |
| 116 | * is the responsibility of the plugin to update this field. | 118 | * the LITMUS core. |
| 117 | * Maybe become part of the LITMUS core some day. | ||
| 118 | * | ||
| 119 | * Used by GSN-EDF. | ||
| 120 | * | 119 | * |
| 121 | * Be careful to avoid deadlocks! | 120 | * Be careful to avoid deadlocks! |
| 122 | */ | 121 | */ |
| @@ -130,6 +129,9 @@ struct rt_param { | |||
| 130 | */ | 129 | */ |
| 131 | volatile int linked_on; | 130 | volatile int linked_on; |
| 132 | 131 | ||
| 132 | /* PFAIR/PD^2 state. Allocated on demand. */ | ||
| 133 | struct pfair_param* pfair; | ||
| 134 | |||
| 133 | /* Fields saved before BE->RT transition. | 135 | /* Fields saved before BE->RT transition. |
| 134 | */ | 136 | */ |
| 135 | int old_policy; | 137 | int old_policy; |
diff --git a/litmus/Makefile b/litmus/Makefile index bfe393eb56..545203876a 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
| @@ -3,9 +3,12 @@ | |||
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-y = sched_plugin.o litmus.o sched_trace.o \ | 5 | obj-y = sched_plugin.o litmus.o sched_trace.o \ |
| 6 | edf_common.o jobs.o\ | 6 | edf_common.o jobs.o \ |
| 7 | sched_gsn_edf.o sched_psn_edf.o sched_cedf.o \ | ||
| 8 | rt_domain.o fdso.o sync.o \ | 7 | rt_domain.o fdso.o sync.o \ |
| 9 | fmlp.o srp.o norqlock.o | 8 | fmlp.o srp.o norqlock.o \ |
| 9 | sched_gsn_edf.o \ | ||
| 10 | sched_psn_edf.o \ | ||
| 11 | sched_cedf.o \ | ||
| 12 | sched_pfair.o | ||
| 10 | 13 | ||
| 11 | obj-$(CONFIG_FEATHER_TRACE) += trace.o ft_event.o | 14 | obj-$(CONFIG_FEATHER_TRACE) += trace.o ft_event.o |
diff --git a/litmus/sched_pfair.c b/litmus/sched_pfair.c new file mode 100755 index 0000000000..6f95688508 --- /dev/null +++ b/litmus/sched_pfair.c | |||
| @@ -0,0 +1,785 @@ | |||
| 1 | /* | ||
| 2 | * kernel/sched_pfair.c | ||
| 3 | * | ||
| 4 | * Implementation of the (global) Pfair scheduling algorithm. | ||
| 5 | * | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <asm/div64.h> | ||
| 9 | #include <linux/delay.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/spinlock.h> | ||
| 12 | #include <linux/percpu.h> | ||
| 13 | #include <linux/sched.h> | ||
| 14 | #include <linux/list.h> | ||
| 15 | |||
| 16 | #include <litmus/litmus.h> | ||
| 17 | #include <litmus/jobs.h> | ||
| 18 | #include <litmus/rt_domain.h> | ||
| 19 | #include <litmus/sched_plugin.h> | ||
| 20 | #include <litmus/sched_trace.h> | ||
| 21 | |||
| 22 | #include <litmus/heap.h> | ||
| 23 | |||
| 24 | /* Tick period is used to convert ns-specified execution | ||
| 25 | * costs and periods into tick-based equivalents. | ||
| 26 | */ | ||
| 27 | extern ktime_t tick_period; | ||
| 28 | |||
| 29 | /* make the unit explicit */ | ||
| 30 | typedef unsigned long quanta_t; | ||
| 31 | |||
| 32 | struct subtask { | ||
| 33 | /* measured in quanta relative to job release */ | ||
| 34 | quanta_t release; | ||
| 35 | quanta_t deadline; | ||
| 36 | quanta_t overlap; /* called "b bit" by PD^2 */ | ||
| 37 | quanta_t group_deadline; | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct pfair_param { | ||
| 41 | quanta_t quanta; /* number of subtasks */ | ||
| 42 | quanta_t cur; /* index of current subtask */ | ||
| 43 | |||
| 44 | quanta_t release; /* in quanta */ | ||
| 45 | quanta_t period; /* in quanta */ | ||
| 46 | |||
| 47 | quanta_t last_quantum; /* when scheduled last */ | ||
| 48 | int last_cpu; /* where scheduled last */ | ||
| 49 | |||
| 50 | unsigned int present; /* Can the task be scheduled? */ | ||
| 51 | |||
| 52 | struct subtask subtasks[0]; /* allocate together with pfair_param */ | ||
| 53 | }; | ||
| 54 | |||
| 55 | #define tsk_pfair(tsk) ((tsk)->rt_param.pfair) | ||
| 56 | |||
| 57 | struct pfair_state { | ||
| 58 | int cpu; | ||
| 59 | volatile quanta_t cur_tick; /* updated by the CPU that is advancing | ||
| 60 | * the time */ | ||
| 61 | volatile quanta_t local_tick; /* What tick is the local CPU currently | ||
| 62 | * executing? Updated only by the local | ||
| 63 | * CPU. In QEMU, this may lag behind the | ||
| 64 | * current tick. In a real system, with | ||
| 65 | * proper timers and aligned quanta, | ||
| 66 | * that should only be the | ||
| 67 | * case for a very short time after the | ||
| 68 | * time advanced. With staggered quanta, | ||
| 69 | * it will lag for the duration of the | ||
| 70 | * offset. | ||
| 71 | */ | ||
| 72 | |||
| 73 | struct task_struct* linked; /* the task that should be executing */ | ||
| 74 | struct task_struct* local; /* the local copy of linked */ | ||
| 75 | struct task_struct* scheduled; /* what is actually scheduled */ | ||
| 76 | |||
| 77 | unsigned long missed_quanta; | ||
| 78 | }; | ||
| 79 | |||
| 80 | /* Currently, we limit the maximum period of any task to 1000 quanta. | ||
| 81 | * The reason is that it makes the implementation easier since we do not | ||
| 82 | * need to reallocate the release wheel on task arrivals. | ||
| 83 | * In the future | ||
| 84 | */ | ||
| 85 | #define PFAIR_MAX_PERIOD 1000 | ||
| 86 | |||
| 87 | /* This is the release queue wheel. It is indexed by pfair_time % | ||
| 88 | * PFAIR_MAX_PERIOD. Each heap is ordered by PFAIR priority, so that it can be | ||
| 89 | * merged with the ready queue. | ||
| 90 | */ | ||
| 91 | static struct heap release_queue[PFAIR_MAX_PERIOD]; | ||
| 92 | |||
| 93 | DEFINE_PER_CPU(struct pfair_state, pfair_state); | ||
| 94 | struct pfair_state* pstate[NR_CPUS]; /* short cut */ | ||
| 95 | |||
| 96 | #define NO_CPU 0xffffffff | ||
| 97 | |||
| 98 | static quanta_t pfair_time = 0; /* the "official" PFAIR clock */ | ||
| 99 | static quanta_t merge_time = 0; /* Updated after the release queue has been | ||
| 100 | * merged. Used by drop_all_references(). | ||
| 101 | */ | ||
| 102 | |||
| 103 | static rt_domain_t pfair; | ||
| 104 | |||
| 105 | /* The pfair_lock is used to serialize all scheduling events. | ||
| 106 | */ | ||
| 107 | #define pfair_lock pfair.ready_lock | ||
| 108 | |||
| 109 | /* Enable for lots of trace info. | ||
| 110 | * #define PFAIR_DEBUG | ||
| 111 | */ | ||
| 112 | |||
| 113 | #ifdef PFAIR_DEBUG | ||
| 114 | #define PTRACE_TASK(t, f, args...) TRACE_TASK(t, f, # args) | ||
| 115 | #define PTRACE(f, args...) TRACE(f, # args) | ||
| 116 | #else | ||
| 117 | #define PTRACE_TASK(t, f, args...) | ||
| 118 | #define PTRACE(f, args...) | ||
| 119 | #endif | ||
| 120 | |||
| 121 | /* gcc will inline all of these accessor functions... */ | ||
| 122 | static struct subtask* cur_subtask(struct task_struct* t) | ||
| 123 | { | ||
| 124 | return tsk_pfair(t)->subtasks + tsk_pfair(t)->cur; | ||
| 125 | } | ||
| 126 | |||
| 127 | static quanta_t cur_deadline(struct task_struct* t) | ||
| 128 | { | ||
| 129 | return cur_subtask(t)->deadline + tsk_pfair(t)->release; | ||
| 130 | } | ||
| 131 | |||
| 132 | static quanta_t cur_release(struct task_struct* t) | ||
| 133 | { | ||
| 134 | #ifdef EARLY_RELEASE | ||
| 135 | /* only the release of the first subtask counts when we early | ||
| 136 | * release */ | ||
| 137 | return tsk_pfair(t)->release; | ||
| 138 | #else | ||
| 139 | return cur_subtask(t)->release + tsk_pfair(t)->release; | ||
| 140 | #endif | ||
| 141 | } | ||
| 142 | |||
| 143 | static quanta_t cur_sub_release(struct task_struct* t) | ||
| 144 | { | ||
| 145 | return cur_subtask(t)->release + tsk_pfair(t)->release; | ||
| 146 | } | ||
| 147 | |||
| 148 | static quanta_t cur_overlap(struct task_struct* t) | ||
| 149 | { | ||
| 150 | return cur_subtask(t)->overlap; | ||
| 151 | } | ||
| 152 | |||
| 153 | static quanta_t cur_group_deadline(struct task_struct* t) | ||
| 154 | { | ||
| 155 | quanta_t gdl = cur_subtask(t)->group_deadline; | ||
| 156 | if (gdl) | ||
| 157 | return gdl + tsk_pfair(t)->release; | ||
| 158 | else | ||
| 159 | return gdl; | ||
| 160 | } | ||
| 161 | |||
| 162 | e | ||
