aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNamhoon Kim <namhoonk@cs.unc.edu>2016-04-30 19:46:44 -0400
committerNamhoon Kim <namhoonk@cs.unc.edu>2016-04-30 19:46:44 -0400
commitfc35ca6c9592d43b067a45c49f98cf4b5b361b87 (patch)
tree9a7d7d6eec9ea24bea317de137cc0431ff54cb8b
parentf0e07f0e5cba027377c57e1aa25101023640c62b (diff)
PGM supportwip-mc2-new
-rw-r--r--include/litmus/pgm.h12
-rw-r--r--include/litmus/rt_param.h15
-rw-r--r--include/litmus/sched_trace.h39
-rw-r--r--include/trace/events/litmus.h53
-rw-r--r--litmus/Makefile1
-rw-r--r--litmus/litmus.c22
-rw-r--r--litmus/pgm.c61
-rw-r--r--litmus/sched_mc2.c76
-rw-r--r--litmus/sched_task_trace.c23
9 files changed, 296 insertions, 6 deletions
diff --git a/include/litmus/pgm.h b/include/litmus/pgm.h
new file mode 100644
index 000000000000..5682a76b3acb
--- /dev/null
+++ b/include/litmus/pgm.h
@@ -0,0 +1,12 @@
1#ifndef _LITMUS_PGM_H_
2#define _LITMUS_PGM_H_
3
4#include <litmus/litmus.h>
5
6#define is_pgm_waiting(t) (tsk_rt(t)->ctrl_page && tsk_rt(t)->ctrl_page->pgm_waiting)
7#define is_pgm_sending(t) (tsk_rt(t)->ctrl_page && tsk_rt(t)->ctrl_page->pgm_sending)
8#define is_pgm_satisfied(t) (tsk_rt(t)->ctrl_page && tsk_rt(t)->ctrl_page->pgm_satisfied)
9
10int setup_pgm_release(struct task_struct* t);
11
12#endif
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h
index a3dde39753bd..fa0f5f4647bd 100644
--- a/include/litmus/rt_param.h
+++ b/include/litmus/rt_param.h
@@ -51,6 +51,14 @@ typedef enum {
51 TASK_EARLY 51 TASK_EARLY
52} release_policy_t; 52} release_policy_t;
53 53
54typedef enum {
55 PGM_NOT_A_NODE,
56 PGM_SRC,
57 PGM_SINK,
58 PGM_SRC_SINK,
59 PGM_INTERNAL
60} pgm_node_type_t;
61
54/* We use the common priority interpretation "lower index == higher priority", 62/* We use the common priority interpretation "lower index == higher priority",
55 * which is commonly used in fixed-priority schedulability analysis papers. 63 * which is commonly used in fixed-priority schedulability analysis papers.
56 * So, a numerically lower priority value implies higher scheduling priority, 64 * So, a numerically lower priority value implies higher scheduling priority,
@@ -122,6 +130,8 @@ struct rt_task {
122 task_class_t cls; 130 task_class_t cls;
123 budget_policy_t budget_policy; /* ignored by pfair */ 131 budget_policy_t budget_policy; /* ignored by pfair */
124 release_policy_t release_policy; 132 release_policy_t release_policy;
133 pgm_node_type_t pgm_type;
134 lt_t pgm_expected_etoe;
125}; 135};
126 136
127union np_flag { 137union np_flag {
@@ -162,6 +172,11 @@ struct control_page {
162 uint64_t irq_syscall_start; /* Snapshot of irq_count when the syscall 172 uint64_t irq_syscall_start; /* Snapshot of irq_count when the syscall
163 * started. */ 173 * started. */
164 174
175 /* Flags from userspace signifying PGM wait states. */
176 volatile uint32_t pgm_waiting; /* waiting for tokens */
177 volatile uint32_t pgm_sending; /* sending tokens */
178 volatile uint32_t pgm_satisfied; /* done waiting/sending */
179
165 /* to be extended */ 180 /* to be extended */
166}; 181};
167 182
diff --git a/include/litmus/sched_trace.h b/include/litmus/sched_trace.h
index 82bde8241298..d3f78a812ef3 100644
--- a/include/litmus/sched_trace.h
+++ b/include/litmus/sched_trace.h
@@ -80,6 +80,19 @@ struct st_sys_release_data {
80 u64 release; 80 u64 release;
81}; 81};
82 82
83struct st_pgm_param_data {
84 u32 node_type;
85 u16 graph_pid;
86 u16 unused;
87 u64 expected_graph_etoe;
88};
89
90struct st_pgm_release_data {
91 u64 release; /* PGM-adjusted release time */
92 u64 deadline; /* PGM-adjusted deadline */
93};
94
95
83#define DATA(x) struct st_ ## x ## _data x; 96#define DATA(x) struct st_ ## x ## _data x;
84 97
85typedef enum { 98typedef enum {
@@ -94,7 +107,9 @@ typedef enum {
94 ST_BLOCK, 107 ST_BLOCK,
95 ST_RESUME, 108 ST_RESUME,
96 ST_ACTION, 109 ST_ACTION,
97 ST_SYS_RELEASE 110 ST_SYS_RELEASE,
111 ST_PGM_PARAM,
112 ST_PGM_RELEASE
98} st_event_record_type_t; 113} st_event_record_type_t;
99 114
100struct st_event_record { 115struct st_event_record {
@@ -113,6 +128,8 @@ struct st_event_record {
113 DATA(resume); 128 DATA(resume);
114 DATA(action); 129 DATA(action);
115 DATA(sys_release); 130 DATA(sys_release);
131 DATA(pgm_param);
132 DATA(pgm_release);
116 } data; 133 } data;
117}; 134};
118 135
@@ -154,6 +171,10 @@ feather_callback void do_sched_trace_action(unsigned long id,
154 unsigned long action); 171 unsigned long action);
155feather_callback void do_sched_trace_sys_release(unsigned long id, 172feather_callback void do_sched_trace_sys_release(unsigned long id,
156 lt_t* start); 173 lt_t* start);
174feather_callback void do_sched_trace_pgm_param(unsigned long id,
175 struct task_struct* task);
176feather_callback void do_sched_trace_pgm_release(unsigned long id,
177 struct task_struct* task);
157 178
158#endif 179#endif
159 180
@@ -179,6 +200,8 @@ feather_callback void do_sched_trace_sys_release(unsigned long id,
179#define trace_litmus_task_block(t) 200#define trace_litmus_task_block(t)
180#define trace_litmus_task_resume(t) 201#define trace_litmus_task_resume(t)
181#define trace_litmus_sys_release(start) 202#define trace_litmus_sys_release(start)
203#define trace_litmus_pgm_param(t)
204#define trace_litmus_pgm_release(t)
182 205
183#endif 206#endif
184 207
@@ -252,6 +275,20 @@ feather_callback void do_sched_trace_sys_release(unsigned long id,
252 trace_litmus_sys_release(when); \ 275 trace_litmus_sys_release(when); \
253 } while (0) 276 } while (0)
254 277
278#define sched_trace_pgm_param(t) \
279 do { \
280 SCHED_TRACE(SCHED_TRACE_BASE_ID + 11, \
281 do_sched_trace_pgm_param, t); \
282 trace_litmus_pgm_param(t); \
283 } while (0)
284
285#define sched_trace_pgm_release(t) \
286 do { \
287 SCHED_TRACE(SCHED_TRACE_BASE_ID + 12, \
288 do_sched_trace_pgm_release, t); \
289 trace_litmus_pgm_release(t); \
290 } while (0)
291
255#define sched_trace_quantum_boundary() /* NOT IMPLEMENTED */ 292#define sched_trace_quantum_boundary() /* NOT IMPLEMENTED */
256 293
257#endif /* __KERNEL__ */ 294#endif /* __KERNEL__ */
diff --git a/include/trace/events/litmus.h b/include/trace/events/litmus.h
index 0fffcee02be0..02b4b54f718c 100644
--- a/include/trace/events/litmus.h
+++ b/include/trace/events/litmus.h
@@ -39,7 +39,7 @@ TRACE_EVENT(litmus_task_param,
39 __entry->partition = get_partition(t); 39 __entry->partition = get_partition(t);
40 ), 40 ),
41 41
42 TP_printk("period(%d, %Lu).\nwcet(%d, %Lu).\n", 42 TP_printk("period(%u, %Lu).\nwcet(%d, %Lu).\n",
43 __entry->pid, __entry->period, 43 __entry->pid, __entry->period,
44 __entry->pid, __entry->wcet) 44 __entry->pid, __entry->wcet)
45); 45);
@@ -225,6 +225,57 @@ TRACE_EVENT(litmus_sys_release,
225 TP_printk("SynRelease(%Lu) at %Lu\n", __entry->rel, __entry->when) 225 TP_printk("SynRelease(%Lu) at %Lu\n", __entry->rel, __entry->when)
226); 226);
227 227
228/* Tracing PGM node parameters */
229TRACE_EVENT(litmus_pgm_param,
230
231 TP_PROTO(struct task_struct *t),
232
233 TP_ARGS(t),
234
235 TP_STRUCT__entry(
236 __field( pid_t, pid )
237 __field( pgm_node_type_t, node_type )
238 __field( pid_t, graph_pid )
239 ),
240
241 TP_fast_assign(
242 __entry->pid = t ? t->pid : 0;
243 __entry->node_type = t ? t->rt_param.task_params.pgm_type : PGM_NOT_A_NODE;
244 __entry->graph_pid = t ? t->tgid : 0;
245 ),
246
247 TP_printk("pgm node (%u, node type = %d) in graph (%u)\n",
248 __entry->pid, __entry->node_type, __entry->graph_pid)
249);
250
251/*
252 * Tracing PGM-adjusted job release
253 */
254TRACE_EVENT(litmus_pgm_release,
255
256 TP_PROTO(struct task_struct *t),
257
258 TP_ARGS(t),
259
260 TP_STRUCT__entry(
261 __field( pid_t, pid )
262 __field( unsigned int, job )
263 __field( lt_t, release )
264 __field( lt_t, deadline )
265 ),
266
267 TP_fast_assign(
268 __entry->pid = t ? t->pid : 0;
269 __entry->job = t ? t->rt_param.job_params.job_no : 0;
270 __entry->release = get_release(t);
271 __entry->deadline = get_deadline(t);
272 ),
273
274 TP_printk("release(job(%u, %u)): %Lu\ndeadline(job(%u, %u)): %Lu\n",
275 __entry->pid, __entry->job, __entry->release,
276 __entry->pid, __entry->job, __entry->deadline)
277);
278
228#endif /* _SCHED_TASK_TRACEPOINT_H */ 279#endif /* _SCHED_TASK_TRACEPOINT_H */
229 280
230/* Must stay outside the protection */ 281/* Must stay outside the protection */
diff --git a/litmus/Makefile b/litmus/Makefile
index 3d0de72284f8..c19b6015b02e 100644
--- a/litmus/Makefile
+++ b/litmus/Makefile
@@ -40,3 +40,4 @@ obj-y += reservation.o polling_reservations.o
40 40
41obj-y += sched_pres.o 41obj-y += sched_pres.o
42obj-y += mc2_common.o sched_mc2.o 42obj-y += mc2_common.o sched_mc2.o
43obj-y += pgm.o
diff --git a/litmus/litmus.c b/litmus/litmus.c
index d72039067689..d2815f52876e 100644
--- a/litmus/litmus.c
+++ b/litmus/litmus.c
@@ -140,10 +140,16 @@ asmlinkage long sys_set_rt_task_param(pid_t pid, struct rt_task __user * param)
140 if (tp.relative_deadline == 0) 140 if (tp.relative_deadline == 0)
141 tp.relative_deadline = tp.period; 141 tp.relative_deadline = tp.period;
142 142
143 if (tp.exec_cost <= 0) 143 if (tp.exec_cost <= 0) {
144 printk(KERN_INFO "litmus: real-time task %d rejected "
145 "because declared job execution time <= 0.", pid);
144 goto out_unlock; 146 goto out_unlock;
145 if (tp.period <= 0) 147 }
148 if (tp.period <= 0) {
149 printk(KERN_INFO "litmus: real-time task %d rejected "
150 "because declared job period <= 0.", pid);
146 goto out_unlock; 151 goto out_unlock;
152 }
147 if (min(tp.relative_deadline, tp.period) < tp.exec_cost) /*density check*/ 153 if (min(tp.relative_deadline, tp.period) < tp.exec_cost) /*density check*/
148 { 154 {
149 printk(KERN_INFO "litmus: real-time task %d rejected " 155 printk(KERN_INFO "litmus: real-time task %d rejected "
@@ -169,6 +175,13 @@ asmlinkage long sys_set_rt_task_param(pid_t pid, struct rt_task __user * param)
169 goto out_unlock; 175 goto out_unlock;
170 } 176 }
171 177
178 if (tp.pgm_type < PGM_NOT_A_NODE || tp.pgm_type > PGM_INTERNAL) {
179 printk(KERN_INFO "litmus: real-time task %d rejected "
180 "because of unknown PGM node type specified (%d)\n",
181 pid, tp.pgm_type);
182 goto out_unlock;
183 }
184
172 target->rt_param.task_params = tp; 185 target->rt_param.task_params = tp;
173 186
174 retval = 0; 187 retval = 0;
@@ -549,6 +562,10 @@ long litmus_admit_task(struct task_struct* tsk)
549 if (get_rt_relative_deadline(tsk) == 0 || 562 if (get_rt_relative_deadline(tsk) == 0 ||
550 get_exec_cost(tsk) > 563 get_exec_cost(tsk) >
551 min(get_rt_relative_deadline(tsk), get_rt_period(tsk)) ) { 564 min(get_rt_relative_deadline(tsk), get_rt_period(tsk)) ) {
565 printk(KERN_INFO "litmus: invalid task parameters "
566 "(e = %lu, p = %lu, d = %lu)\n",
567 get_exec_cost(tsk), get_rt_period(tsk),
568 get_rt_relative_deadline(tsk));
552 TRACE_TASK(tsk, 569 TRACE_TASK(tsk,
553 "litmus admit: invalid task parameters " 570 "litmus admit: invalid task parameters "
554 "(e = %lu, p = %lu, d = %lu)\n", 571 "(e = %lu, p = %lu, d = %lu)\n",
@@ -580,6 +597,7 @@ long litmus_admit_task(struct task_struct* tsk)
580 if (!retval) { 597 if (!retval) {
581 sched_trace_task_name(tsk); 598 sched_trace_task_name(tsk);
582 sched_trace_task_param(tsk); 599 sched_trace_task_param(tsk);
600 sched_trace_pgm_param(tsk);
583 atomic_inc(&rt_task_count); 601 atomic_inc(&rt_task_count);
584 } 602 }
585 603
diff --git a/litmus/pgm.c b/litmus/pgm.c
new file mode 100644
index 000000000000..db3378ff803d
--- /dev/null
+++ b/litmus/pgm.c
@@ -0,0 +1,61 @@
1/* litmus/pgm.c - common pgm control code
2 */
3
4#include <linux/sched.h>
5#include <litmus/litmus.h>
6#include <litmus/pgm.h>
7#include <litmus/sched_trace.h>
8
9/* Only readjust release/deadline if difference is over a given threshold.
10 It's a weak method for accounting overheads. Ideally, we'd know the last
11 time t was woken up by its last predecessor, rather than having to look
12 at 'now'. Adjustment threshold currently set to 200us. */
13#define ADJUSTMENT_THRESH_NS (200*1000LL)
14
15int setup_pgm_release(struct task_struct* t)
16{
17 int shifted_release = 0;
18
19 /* approximate time last predecessor gave us tokens */
20 lt_t now = litmus_clock();
21
22 TRACE_TASK(t, "is starting a new PGM job: waiting:%d\n",
23 tsk_rt(t)->ctrl_page->pgm_waiting);
24
25 BUG_ON(!tsk_rt(t)->ctrl_page->pgm_waiting);
26
27 /* Adjust release time if we got the last tokens after release of this job.
28 This is possible since PGM jobs are early-released. Don't shift our
29 deadline if we got the tokens earlier than expected. */
30 if (now > tsk_rt(t)->job_params.release) {
31 long long diff_ns = now - tsk_rt(t)->job_params.release;
32 if (diff_ns > ADJUSTMENT_THRESH_NS) {
33 lt_t adj_deadline = now + get_rt_relative_deadline(t);
34
35 TRACE_TASK(t, "adjusting PGM release time from (r = %llu, d = %llu) "
36 "to (r = %llu, d = %llu)\n",
37 tsk_rt(t)->job_params.release, tsk_rt(t)->job_params.deadline,
38 now, adj_deadline);
39
40 tsk_rt(t)->job_params.release = now;
41 tsk_rt(t)->job_params.deadline = adj_deadline;
42 shifted_release = 1;
43 }
44 else {
45 TRACE_TASK(t, "adjustment falls below threshold. %lld < %lld\n",
46 diff_ns, ADJUSTMENT_THRESH_NS);
47 }
48 }
49 else {
50 TRACE_TASK(t, "got tokens early--no need to adjust release. "
51 "cur time = %llu, release time = %llu\n",
52 now, tsk_rt(t)->job_params.release);
53 }
54
55 /* possible that there can be multiple instances of pgm_release logged.
56 analysis tools should filter out all but the last pgm_release for
57 a given job release */
58 sched_trace_pgm_release(t);
59
60 return shifted_release;
61}
diff --git a/litmus/sched_mc2.c b/litmus/sched_mc2.c
index a310723dce24..9ed92d355d7a 100644
--- a/litmus/sched_mc2.c
+++ b/litmus/sched_mc2.c
@@ -25,6 +25,7 @@
25#include <litmus/mc2_common.h> 25#include <litmus/mc2_common.h>
26#include <litmus/reservation.h> 26#include <litmus/reservation.h>
27#include <litmus/polling_reservations.h> 27#include <litmus/polling_reservations.h>
28#include <litmus/pgm.h>
28 29
29#define BUDGET_ENFORCEMENT_AT_C 0 30#define BUDGET_ENFORCEMENT_AT_C 0
30 31
@@ -614,14 +615,82 @@ static struct task_struct* mc2_schedule(struct task_struct * prev)
614 /* next == NULL means "schedule background work". */ 615 /* next == NULL means "schedule background work". */
615 lt_t now; 616 lt_t now;
616 struct mc2_cpu_state *state = local_cpu_state(); 617 struct mc2_cpu_state *state = local_cpu_state();
618 int sleep, preempt, np, exists, blocks;
617 619
618 pre_schedule(prev, state->cpu); 620 pre_schedule(prev, state->cpu);
619 621
620 raw_spin_lock(&_global_env.lock); 622 raw_spin_lock(&_global_env.lock);
621 raw_spin_lock(&state->lock); 623 raw_spin_lock(&state->lock);
622 624
623 //BUG_ON(state->scheduled && state->scheduled != prev); 625 /* sanity check */
624 //BUG_ON(state->scheduled && !is_realtime(prev)); 626 BUG_ON(state->scheduled && state->scheduled != prev);
627 BUG_ON(state->scheduled && !is_realtime(prev));
628 BUG_ON(is_realtime(prev) && !state->scheduled);
629
630 /* (0) Determine state */
631 exists = state->scheduled != NULL;
632 blocks = exists && !is_running(state->scheduled);
633 sleep = exists && is_completed(state->scheduled);
634 np = exists && is_np(state->scheduled);
635 preempt = _lowest_prio_cpu.cpu_entries[state->cpu].will_schedule;
636
637 if (exists) {
638 if (is_pgm_sending(state->scheduled)) {
639 if (!is_pgm_satisfied(state->scheduled)) {
640 if (!is_priority_boosted(state->scheduled)) {
641 TRACE_TASK(state->scheduled, "is sending PGM tokens and needs boosting.\n");
642 BUG_ON(is_pgm_satisfied(state->scheduled));
643
644 /* We are either sending tokens or waiting for tokes.
645 If waiting: Boost priority so we'll be scheduled
646 immediately when needed tokens arrive.
647 If sending: Boost priority so no one (specifically, our
648 consumers) will preempt us while signalling the token
649 transmission.
650 */
651 tsk_rt(state->scheduled)->priority_boosted = 1;
652 tsk_rt(state->scheduled)->boost_start_time = litmus_clock();
653
654 if (likely(!blocks)) {
655 task_departs(state->scheduled, is_completed(prev));
656 task_arrives(state, state->scheduled);
657 /* we may regain the processor */
658 if (preempt) {
659 //preempt = resched_cpu[state->cpu];
660 litmus_reschedule_local();
661 if (!preempt) {
662 TRACE_TASK(state->scheduled, "blocked preemption by lazy boosting.\n");
663 }
664 }
665 }
666 }
667 }
668 else { /* sending is satisfied */
669 tsk_rt(state->scheduled)->ctrl_page->pgm_sending = 0;
670 tsk_rt(state->scheduled)->ctrl_page->pgm_satisfied = 0;
671
672 if (is_priority_boosted(state->scheduled)) {
673 TRACE_TASK(state->scheduled,
674 "is done sending PGM tokens must relinquish boosting.\n");
675 /* clear boosting */
676 tsk_rt(state->scheduled)->priority_boosted = 0;
677 if(likely(!blocks)) {
678 /* recheck priority */
679 task_departs(state->scheduled, is_completed(prev));
680 task_arrives(state, state->scheduled);
681 /* we may lose the processor */
682 if (!preempt) {
683 //preempt = resched_cpu[state->cpu];
684 litmus_reschedule_local();
685 if (preempt) {
686 TRACE_TASK(state->scheduled, "preempted by lazy unboosting.\n");
687 }
688 }
689 }
690 }
691 }
692 }
693 }
625 694
626 /* update time */ 695 /* update time */
627 state->sup_env.will_schedule = true; 696 state->sup_env.will_schedule = true;
@@ -701,6 +770,9 @@ static void resume_legacy_task_model_updates(struct task_struct *tsk)
701 sched_trace_task_release(tsk); 770 sched_trace_task_release(tsk);
702 } 771 }
703 } 772 }
773 //if (is_pgm_waiting(tsk)) {
774 // setup_pgm_release(tsk);
775 //}
704} 776}
705 777
706/* mc2_task_resume - Called when the state of tsk changes back to 778/* mc2_task_resume - Called when the state of tsk changes back to
diff --git a/litmus/sched_task_trace.c b/litmus/sched_task_trace.c
index 3a6756deb32f..784b18ecfd8b 100644
--- a/litmus/sched_task_trace.c
+++ b/litmus/sched_task_trace.c
@@ -238,3 +238,26 @@ feather_callback void do_sched_trace_action(unsigned long id,
238 put_record(rec); 238 put_record(rec);
239 } 239 }
240} 240}
241
242feather_callback void do_sched_trace_pgm_param(unsigned long id, unsigned long _task)
243{
244 struct task_struct *t = (struct task_struct*) _task;
245 struct st_event_record* rec = get_record(ST_PGM_PARAM, t);
246 if (rec) {
247 rec->data.pgm_param.node_type = tsk_rt(t)->task_params.pgm_type;
248 rec->data.pgm_param.graph_pid = t->tgid;
249 rec->data.pgm_param.expected_graph_etoe = tsk_rt(t)->task_params.pgm_expected_etoe;
250 put_record(rec);
251 }
252}
253
254feather_callback void do_sched_trace_pgm_release(unsigned long id, unsigned long _task)
255{
256 struct task_struct *t = (struct task_struct*) _task;
257 struct st_event_record* rec = get_record(ST_PGM_RELEASE, t);
258 if (rec) {
259 rec->data.pgm_release.release = get_release(t);
260 rec->data.pgm_release.deadline = get_deadline(t);
261 put_record(rec);
262 }
263}