diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-04-25 23:37:58 -0400 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2012-04-25 23:37:58 -0400 |
commit | a030ea79736cd5aa4aef9800f7ce689fbcab5970 (patch) | |
tree | 773e79899eaf3c97a1055c68ce2a335e0bd971f1 | |
parent | 8b936011abd09adcfab5dea0b6fdc7a0c2e5fcce (diff) |
sched_color: group locks guarantee timestamp order, have better state checks
-rw-r--r-- | include/litmus/color.h | 3 | ||||
-rw-r--r-- | include/litmus/dgl.h | 14 | ||||
-rw-r--r-- | include/litmus/rt_param.h | 4 | ||||
-rw-r--r-- | litmus/dgl.c | 91 | ||||
-rw-r--r-- | litmus/sched_color.c | 26 |
5 files changed, 102 insertions, 36 deletions
diff --git a/include/litmus/color.h b/include/litmus/color.h index fb109c4f5b14..8f66bf50d5b7 100644 --- a/include/litmus/color.h +++ b/include/litmus/color.h | |||
@@ -1,6 +1,9 @@ | |||
1 | #ifndef LITMUS_COLOR_H | 1 | #ifndef LITMUS_COLOR_H |
2 | #define LITMUS_COLOR_H | 2 | #define LITMUS_COLOR_H |
3 | 3 | ||
4 | #define NUM_COLORS 10 | ||
5 | #define NUM_WAYS 5 | ||
6 | |||
4 | int color_server_params(int cpu, unsigned long *wcet, unsigned long *period); | 7 | int color_server_params(int cpu, unsigned long *wcet, unsigned long *period); |
5 | 8 | ||
6 | #endif | 9 | #endif |
diff --git a/include/litmus/dgl.h b/include/litmus/dgl.h index 989f6c7d5e8e..2bf61d4a7547 100644 --- a/include/litmus/dgl.h +++ b/include/litmus/dgl.h | |||
@@ -1,12 +1,15 @@ | |||
1 | #ifndef __DGL_H_ | 1 | #ifndef __DGL_H_ |
2 | #define __DGL_H_ | 2 | #define __DGL_H_ |
3 | 3 | ||
4 | #include <litmus/color.h> | ||
4 | #include <linux/list.h> | 5 | #include <linux/list.h> |
5 | 6 | ||
6 | #define NUM_REPLICAS 4 | 7 | #define WP(num, word) (num / word + (num % word != 0)) |
7 | #define NUM_RESOURCES 4 | 8 | |
9 | #define NUM_REPLICAS NUM_WAYS | ||
10 | #define NUM_RESOURCES NUM_COLORS | ||
8 | #define MASK_SIZE (sizeof(unsigned long) * 8) | 11 | #define MASK_SIZE (sizeof(unsigned long) * 8) |
9 | #define MASK_WORDS (NUM_RESOURCES/MASK_SIZE + (NUM_RESOURCES%MASK_SIZE != 0)) | 12 | #define MASK_WORDS WP(NUM_RESOURCES, MASK_SIZE) |
10 | 13 | ||
11 | /* | 14 | /* |
12 | * A request for @replica amount of a single resource. | 15 | * A request for @replica amount of a single resource. |
@@ -24,6 +27,7 @@ struct dgl_group_req { | |||
24 | unsigned long requested[MASK_WORDS]; | 27 | unsigned long requested[MASK_WORDS]; |
25 | unsigned long waiting[MASK_WORDS]; | 28 | unsigned long waiting[MASK_WORDS]; |
26 | struct dgl_req requests[NUM_RESOURCES]; | 29 | struct dgl_req requests[NUM_RESOURCES]; |
30 | unsigned long long ts; | ||
27 | }; | 31 | }; |
28 | 32 | ||
29 | /* | 33 | /* |
@@ -40,6 +44,10 @@ struct dgl_resource { | |||
40 | struct dgl { | 44 | struct dgl { |
41 | struct dgl_resource resources[NUM_RESOURCES]; | 45 | struct dgl_resource resources[NUM_RESOURCES]; |
42 | struct dgl_group_req* acquired[NR_CPUS]; | 46 | struct dgl_group_req* acquired[NR_CPUS]; |
47 | |||
48 | char requests; | ||
49 | char running; | ||
50 | unsigned long long ts; | ||
43 | }; | 51 | }; |
44 | 52 | ||
45 | void dgl_init(struct dgl *dgl); | 53 | void dgl_init(struct dgl *dgl); |
diff --git a/include/litmus/rt_param.h b/include/litmus/rt_param.h index e56aab006cc1..2eec39c7678c 100644 --- a/include/litmus/rt_param.h +++ b/include/litmus/rt_param.h | |||
@@ -5,7 +5,7 @@ | |||
5 | #ifndef _LINUX_RT_PARAM_H_ | 5 | #ifndef _LINUX_RT_PARAM_H_ |
6 | #define _LINUX_RT_PARAM_H_ | 6 | #define _LINUX_RT_PARAM_H_ |
7 | 7 | ||
8 | #include <litmus/dgl.h> | 8 | #include <litmus/color.h> |
9 | 9 | ||
10 | /* Litmus time type. */ | 10 | /* Litmus time type. */ |
11 | typedef unsigned long long lt_t; | 11 | typedef unsigned long long lt_t; |
@@ -68,7 +68,7 @@ struct control_page { | |||
68 | /* locking overhead tracing: time stamp prior to system call */ | 68 | /* locking overhead tracing: time stamp prior to system call */ |
69 | uint64_t ts_syscall_start; /* Feather-Trace cycles */ | 69 | uint64_t ts_syscall_start; /* Feather-Trace cycles */ |
70 | 70 | ||
71 | int requests[NUM_RESOURCES]; | 71 | int requests[NUM_COLORS]; |
72 | }; | 72 | }; |
73 | 73 | ||
74 | /* don't export internal data structures to user space (liblitmus) */ | 74 | /* don't export internal data structures to user space (liblitmus) */ |
diff --git a/litmus/dgl.c b/litmus/dgl.c index 9749597aa769..e09d57cc2672 100644 --- a/litmus/dgl.c +++ b/litmus/dgl.c | |||
@@ -27,27 +27,48 @@ static inline void mask_idx(int resource, int *word, int *bit) | |||
27 | *bit = resource % MASK_SIZE; | 27 | *bit = resource % MASK_SIZE; |
28 | } | 28 | } |
29 | 29 | ||
30 | |||
31 | static void print_waiting(struct dgl *dgl, struct dgl_resource *resource) | ||
32 | { | ||
33 | struct dgl_req *pos; | ||
34 | struct dgl_group_req *greq; | ||
35 | int rid = resource_id(dgl, resource); | ||
36 | unsigned long long last = 0; | ||
37 | |||
38 | TRACE("List for rid %d\n", resource_id(dgl, resource)); | ||
39 | list_for_each_entry(pos, &resource->waiting, list) { | ||
40 | greq = req_group(pos, rid); | ||
41 | TRACE(" 0x%p with timestamp %llu\n", greq, greq->ts); | ||
42 | BUG_ON(greq->ts < last); | ||
43 | last = greq->ts; | ||
44 | } | ||
45 | } | ||
46 | |||
30 | void dgl_init(struct dgl *dgl) | 47 | void dgl_init(struct dgl *dgl) |
31 | { | 48 | { |
32 | int i; | 49 | int i; |
33 | struct dgl_resource *resource; | 50 | struct dgl_resource *resource; |
34 | 51 | ||
35 | for (i = 0; i < NR_CPUS; i++) | 52 | for (i = 0; i < NR_CPUS; ++i) |
36 | dgl->acquired[i] = NULL; | 53 | dgl->acquired[i] = NULL; |
37 | 54 | ||
38 | for (i = 0; i < NUM_RESOURCES; i++) { | 55 | for (i = 0; i < NUM_RESOURCES; ++i) { |
39 | resource = &dgl->resources[i]; | 56 | resource = &dgl->resources[i]; |
40 | 57 | ||
41 | INIT_LIST_HEAD(&resource->waiting); | 58 | INIT_LIST_HEAD(&resource->waiting); |
42 | resource->free_replicas = NUM_REPLICAS; | 59 | resource->free_replicas = NUM_REPLICAS; |
43 | } | 60 | } |
61 | |||
62 | dgl->requests = 0; | ||
63 | dgl->running = 0; | ||
64 | dgl->ts = 0; | ||
44 | } | 65 | } |
45 | 66 | ||
46 | void dgl_group_req_init(struct dgl_group_req *greq) | 67 | void dgl_group_req_init(struct dgl_group_req *greq) |
47 | { | 68 | { |
48 | int i; | 69 | int i; |
49 | greq->cpu = NO_CPU; | 70 | greq->cpu = NO_CPU; |
50 | for (i = 0; i < MASK_WORDS; i++) { | 71 | for (i = 0; i < MASK_WORDS; ++i) { |
51 | greq->requested[i] = 0; | 72 | greq->requested[i] = 0; |
52 | greq->waiting[i] = 0; | 73 | greq->waiting[i] = 0; |
53 | } | 74 | } |
@@ -64,9 +85,6 @@ void set_req(struct dgl_group_req *greq, int resource, int replicas) | |||
64 | BUG_ON(replicas > NUM_REPLICAS); | 85 | BUG_ON(replicas > NUM_REPLICAS); |
65 | 86 | ||
66 | mask_idx(resource, &word, &bit); | 87 | mask_idx(resource, &word, &bit); |
67 | TRACE("0x%p will request resource %d, word %d, bit %d\n", | ||
68 | greq, resource, word, bit); | ||
69 | |||
70 | __set_bit(bit, &greq->requested[word]); | 88 | __set_bit(bit, &greq->requested[word]); |
71 | 89 | ||
72 | req = &greq->requests[resource]; | 90 | req = &greq->requests[resource]; |
@@ -82,25 +100,31 @@ void set_req(struct dgl_group_req *greq, int resource, int replicas) | |||
82 | static unsigned long try_acquire(struct dgl *dgl, struct dgl_resource *resource, | 100 | static unsigned long try_acquire(struct dgl *dgl, struct dgl_resource *resource, |
83 | struct dgl_req *req) | 101 | struct dgl_req *req) |
84 | { | 102 | { |
85 | int word, bit, rid; | 103 | int word, bit, rid, head, empty, room; |
86 | unsigned long waiting; | 104 | unsigned long waiting; |
87 | struct dgl_group_req *greq; | 105 | struct dgl_group_req *greq; |
88 | 106 | ||
89 | if (resource->free_replicas < req->replicas) { | 107 | rid = resource_id(dgl, resource); |
90 | TRACE("0x%p cannot acquire %d replicas, only %d free\n", | 108 | greq = req_group(req, rid); |
91 | greq, req->replicas, resource->free_replicas); | 109 | |
110 | head = resource->waiting.next == &req->list; | ||
111 | empty = list_empty(&resource->waiting); | ||
112 | room = resource->free_replicas >= req->replicas; | ||
113 | |||
114 | if (! (room && (head || empty)) ) { | ||
115 | TRACE("0x%p cannot acquire %d replicas, %d free\n", | ||
116 | greq, req->replicas, resource->free_replicas, | ||
117 | room, head, empty); | ||
92 | return 0; | 118 | return 0; |
93 | } | 119 | } |
94 | 120 | ||
95 | resource->free_replicas -= req->replicas; | 121 | resource->free_replicas -= req->replicas; |
122 | BUG_ON(resource->free_replicas > NUM_REPLICAS); | ||
96 | 123 | ||
97 | rid = resource_id(dgl, resource); | 124 | TRACE("0x%p acquired %d replicas of rid %d\n", |
98 | greq = req_group(req, rid); | 125 | greq, req->replicas, rid); |
99 | mask_idx(rid, &word, &bit); | ||
100 | |||
101 | TRACE("0x%p acquired rid %d, word %d, bit %d\n", | ||
102 | greq, rid, word, bit); | ||
103 | 126 | ||
127 | mask_idx(rid, &word, &bit); | ||
104 | clear_bit(bit, &greq->waiting[word]); | 128 | clear_bit(bit, &greq->waiting[word]); |
105 | 129 | ||
106 | waiting = 0; | 130 | waiting = 0; |
@@ -115,6 +139,7 @@ static unsigned long try_acquire(struct dgl *dgl, struct dgl_resource *resource, | |||
115 | BUG_ON(dgl->acquired[greq->cpu]); | 139 | BUG_ON(dgl->acquired[greq->cpu]); |
116 | dgl->acquired[greq->cpu] = greq; | 140 | dgl->acquired[greq->cpu] = greq; |
117 | litmus_reschedule(greq->cpu); | 141 | litmus_reschedule(greq->cpu); |
142 | dgl->running++; | ||
118 | } | 143 | } |
119 | 144 | ||
120 | return 1; | 145 | return 1; |
@@ -130,10 +155,13 @@ void add_group_req(struct dgl *dgl, struct dgl_group_req *greq, int cpu) | |||
130 | struct dgl_resource *resource; | 155 | struct dgl_resource *resource; |
131 | 156 | ||
132 | greq->cpu = cpu; | 157 | greq->cpu = cpu; |
158 | greq->ts = dgl->ts++; | ||
133 | 159 | ||
134 | TRACE("0x%p group request added for CPU %d\n", greq, cpu); | 160 | TRACE("0x%p group request added for CPU %d\n", greq, cpu); |
135 | BUG_ON(dgl->acquired[cpu] == greq); | 161 | BUG_ON(dgl->acquired[cpu] == greq); |
136 | 162 | ||
163 | ++dgl->requests; | ||
164 | |||
137 | for_each_resource(greq->requested, w, b, i) { | 165 | for_each_resource(greq->requested, w, b, i) { |
138 | __set_bit(b, &greq->waiting[w]); | 166 | __set_bit(b, &greq->waiting[w]); |
139 | } | 167 | } |
@@ -146,10 +174,19 @@ void add_group_req(struct dgl *dgl, struct dgl_group_req *greq, int cpu) | |||
146 | all_succ &= succ; | 174 | all_succ &= succ; |
147 | 175 | ||
148 | if (!succ) { | 176 | if (!succ) { |
149 | TRACE("0x%p waiting on resource %d\n", greq, i); | 177 | TRACE("0x%p waiting on rid %d\n", greq, i); |
150 | list_add_tail(&req->list, &resource->waiting); | 178 | list_add_tail(&req->list, &resource->waiting); |
151 | } | 179 | } |
152 | } | 180 | } |
181 | |||
182 | /* Grant empty requests */ | ||
183 | if (all_succ && !dgl->acquired[cpu]) { | ||
184 | TRACE("0x%p empty group request acquired cpu %d\n", greq, cpu); | ||
185 | dgl->acquired[cpu] = greq; | ||
186 | ++dgl->running; | ||
187 | } | ||
188 | |||
189 | BUG_ON(dgl->requests && !dgl->running); | ||
153 | } | 190 | } |
154 | 191 | ||
155 | /** | 192 | /** |
@@ -165,9 +202,12 @@ void remove_group_req(struct dgl *dgl, struct dgl_group_req *greq) | |||
165 | 202 | ||
166 | TRACE("0x%p removing group request for CPU %d\n", greq, greq->cpu); | 203 | TRACE("0x%p removing group request for CPU %d\n", greq, greq->cpu); |
167 | 204 | ||
205 | --dgl->requests; | ||
206 | |||
168 | if (dgl->acquired[greq->cpu] == greq) { | 207 | if (dgl->acquired[greq->cpu] == greq) { |
169 | TRACE("0x%p no longer acquired on CPU %d\n", greq, greq->cpu); | 208 | TRACE("0x%p no longer acquired on CPU %d\n", greq, greq->cpu); |
170 | dgl->acquired[greq->cpu] = NULL; | 209 | dgl->acquired[greq->cpu] = NULL; |
210 | --dgl->running; | ||
171 | } | 211 | } |
172 | 212 | ||
173 | for_each_resource(greq->requested, w, b, i) { | 213 | for_each_resource(greq->requested, w, b, i) { |
@@ -178,20 +218,31 @@ void remove_group_req(struct dgl *dgl, struct dgl_group_req *greq) | |||
178 | /* Waiting on resource */ | 218 | /* Waiting on resource */ |
179 | clear_bit(b, &greq->waiting[w]); | 219 | clear_bit(b, &greq->waiting[w]); |
180 | list_del_init(&req->list); | 220 | list_del_init(&req->list); |
181 | TRACE("0x%p quit waiting for resource %d\n", greq, i); | 221 | TRACE("Quitting 0x%p from rid %d\n", |
222 | req, i); | ||
182 | } else { | 223 | } else { |
183 | /* Have resource */ | 224 | /* Have resource */ |
184 | resource->free_replicas += req->replicas; | 225 | resource->free_replicas += req->replicas; |
185 | TRACE("0x%p releasing resource %d\n", greq, i); | 226 | BUG_ON(resource->free_replicas > NUM_REPLICAS); |
227 | TRACE("0x%p releasing %d of %d replicas, rid %d\n", | ||
228 | greq, req->replicas, resource->free_replicas, i); | ||
186 | 229 | ||
187 | if (!list_empty(&resource->waiting)) { | 230 | if (!list_empty(&resource->waiting)) { |
188 | /* Give it to the next guy */ | 231 | /* Give it to the next guy */ |
189 | next = list_first_entry(&resource->waiting, | 232 | next = list_first_entry(&resource->waiting, |
190 | struct dgl_req, | 233 | struct dgl_req, |
191 | list); | 234 | list); |
192 | if (try_acquire(dgl, resource, next)) | 235 | |
236 | BUG_ON(req_group(next, i)->ts < greq->ts); | ||
237 | |||
238 | if (try_acquire(dgl, resource, next)) { | ||
193 | list_del_init(&next->list); | 239 | list_del_init(&next->list); |
240 | print_waiting(dgl, resource); | ||
241 | |||
242 | } | ||
194 | } | 243 | } |
195 | } | 244 | } |
196 | } | 245 | } |
246 | |||
247 | BUG_ON(dgl->requests && !dgl->running); | ||
197 | } | 248 | } |
diff --git a/litmus/sched_color.c b/litmus/sched_color.c index 61a28da1ef6c..d5408c645644 100644 --- a/litmus/sched_color.c +++ b/litmus/sched_color.c | |||
@@ -459,7 +459,8 @@ static struct task_struct* color_schedule(struct task_struct *prev) | |||
459 | } else { | 459 | } else { |
460 | TRACE_TASK(next, "Does not have lock, 0x%p does\n", | 460 | TRACE_TASK(next, "Does not have lock, 0x%p does\n", |
461 | group_lock.acquired[entry->server.cpu]); | 461 | group_lock.acquired[entry->server.cpu]); |
462 | sched_trace_task_block(next, 1); | 462 | if (next != prev) |
463 | sched_trace_task_block(next, 1); | ||
463 | next = NULL; | 464 | next = NULL; |
464 | server_running = 0; | 465 | server_running = 0; |
465 | } | 466 | } |
@@ -509,20 +510,16 @@ static void color_task_new(struct task_struct *t, int on_rq, int running) | |||
509 | req = kmalloc(sizeof(*req), GFP_ATOMIC); | 510 | req = kmalloc(sizeof(*req), GFP_ATOMIC); |
510 | dgl_group_req_init(req); | 511 | dgl_group_req_init(req); |
511 | for (i = 0; i < NUM_RESOURCES; i++) { | 512 | for (i = 0; i < NUM_RESOURCES; i++) { |
512 | /* /\* Testing *\/ */ | 513 | replicas = get_control_page(t)->requests[i]; |
513 | /* set_req(req, i, 2); */ | 514 | if (replicas) |
514 | /* /\* Real *\/ */ | 515 | set_req(req, i, replicas); |
515 | /* replicas = get_control_page(t)->requests[i]; */ | ||
516 | /* if (replicas) { */ | ||
517 | /* set_req(req, i, replicas); */ | ||
518 | /* } */ | ||
519 | } | 516 | } |
520 | tsk_rt(t)->req = req; | 517 | tsk_rt(t)->req = req; |
521 | 518 | ||
522 | /* Join system */ | 519 | /* Join system */ |
523 | raw_spin_lock(lock); | 520 | raw_spin_lock(lock); |
524 | if (running) { | 521 | if (running) { |
525 | TRACE_TASK(t, "Already scheduled on %d\n", entry->cpu); | 522 | TRACE_TASK(t, "Already scheduled on %d\n", entry->server.cpu); |
526 | BUG_ON(entry->scheduled); | 523 | BUG_ON(entry->scheduled); |
527 | entry->scheduled = t; | 524 | entry->scheduled = t; |
528 | tsk_rt(t)->scheduled_on = entry->server.cpu; | 525 | tsk_rt(t)->scheduled_on = entry->server.cpu; |
@@ -630,7 +627,12 @@ static void color_task_exit(struct task_struct * t) | |||
630 | */ | 627 | */ |
631 | static long color_admit_task(struct task_struct* t) | 628 | static long color_admit_task(struct task_struct* t) |
632 | { | 629 | { |
633 | return is_be(t) || task_cpu(t) == get_partition(t) ? 0 : -EINVAL; | 630 | int ret = is_be(t) || task_cpu(t) == get_partition(t) ? 0 : -EINVAL; |
631 | if (!ret) { | ||
632 | printk(KERN_WARNING "Task failed to migrate to CPU %d\n", | ||
633 | get_partition(t)); | ||
634 | } | ||
635 | return ret; | ||
634 | } | 636 | } |
635 | 637 | ||
636 | /* | 638 | /* |
@@ -668,10 +670,12 @@ static long color_activate_plugin(void) | |||
668 | 670 | ||
669 | /* Make runnable */ | 671 | /* Make runnable */ |
670 | release_at(server_task, now); | 672 | release_at(server_task, now); |
671 | requeue(&entry->edf_domain, server_task); | ||
672 | entry->fifo_server.start_time = 0; | 673 | entry->fifo_server.start_time = 0; |
673 | entry->scheduled = NULL; | 674 | entry->scheduled = NULL; |
674 | 675 | ||
676 | if (!is_queued(server_task)) | ||
677 | requeue(&entry->edf_domain, server_task); | ||
678 | |||
675 | TRACE_TASK(server_task, "Created server with wcet: %llu, " | 679 | TRACE_TASK(server_task, "Created server with wcet: %llu, " |
676 | "period: %llu\n", tp.exec_cost, tp.period); | 680 | "period: %llu\n", tp.exec_cost, tp.period); |
677 | 681 | ||