aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/polling_reservations.c
diff options
context:
space:
mode:
authorNamhoon Kim <namhoonk@cs.unc.edu>2016-03-23 08:20:51 -0400
committerNamhoon Kim <namhoonk@cs.unc.edu>2016-03-23 08:20:51 -0400
commitff210e0441b743890ad85c7335e41894b34a1431 (patch)
tree21027c2433f5ca9a26731b3af72fa6eb620df369 /litmus/polling_reservations.c
parent2e23e3f0cc7c3249b510e94b5b3ec92577b67e81 (diff)
MC2 scheduler and partition modules
Diffstat (limited to 'litmus/polling_reservations.c')
-rw-r--r--litmus/polling_reservations.c564
1 files changed, 564 insertions, 0 deletions
diff --git a/litmus/polling_reservations.c b/litmus/polling_reservations.c
new file mode 100644
index 000000000000..4a2fee575127
--- /dev/null
+++ b/litmus/polling_reservations.c
@@ -0,0 +1,564 @@
1#include <linux/sched.h>
2
3#include <litmus/litmus.h>
4#include <litmus/reservation.h>
5#include <litmus/polling_reservations.h>
6
7
8static void periodic_polling_client_arrives(
9 struct reservation* res,
10 struct reservation_client *client
11)
12{
13 struct polling_reservation *pres =
14 container_of(res, struct polling_reservation, res);
15 lt_t instances, tmp;
16
17 list_add_tail(&client->list, &res->clients);
18
19 switch (res->state) {
20 case RESERVATION_INACTIVE:
21 /* Figure out next replenishment time. */
22 if (res->env->time_zero == 0) {
23 tmp = res->env->current_time - res->env->time_zero;
24 instances = div64_u64(tmp, pres->period);
25 res->next_replenishment =
26 (instances + 1) * pres->period + pres->offset;
27 }
28 else {
29 tmp = res->env->current_time - res->env->time_zero;
30 instances = div64_u64(tmp, pres->period);
31 res->next_replenishment = res->env->time_zero + instances * pres->period;
32 }
33
34 TRACE("ENV_TIME_ZERO %llu\n", res->env->time_zero);
35 TRACE("pol-res: R%d activate tmp=%llu instances=%llu period=%llu nextrp=%llu cur=%llu\n",
36 res->id, tmp, instances, pres->period, res->next_replenishment,
37 res->env->current_time);
38
39 res->env->change_state(res->env, res,
40 RESERVATION_DEPLETED);
41 break;
42
43 case RESERVATION_ACTIVE:
44 case RESERVATION_DEPLETED:
45 /* do nothing */
46 break;
47
48 case RESERVATION_ACTIVE_IDLE:
49 res->blocked_by_ghost = 0;
50 res->env->change_state(res->env, res,
51 RESERVATION_ACTIVE);
52 break;
53 }
54}
55
56
57static void periodic_polling_client_departs(
58 struct reservation *res,
59 struct reservation_client *client,
60 int did_signal_job_completion
61)
62{
63 list_del(&client->list);
64
65 switch (res->state) {
66 case RESERVATION_INACTIVE:
67 case RESERVATION_ACTIVE_IDLE:
68 BUG(); /* INACTIVE or IDLE <=> no client */
69 break;
70
71 case RESERVATION_ACTIVE:
72 if (list_empty(&res->clients)) {
73 res->env->change_state(res->env, res,
74// RESERVATION_ACTIVE_IDLE);
75 res->cur_budget ?
76 RESERVATION_ACTIVE_IDLE :
77 RESERVATION_DEPLETED);
78// did_signal_job_completion ?
79// RESERVATION_DEPLETED :
80// RESERVATION_ACTIVE_IDLE);
81 } /* else: nothing to do, more clients ready */
82 break;
83
84 case RESERVATION_DEPLETED:
85 /* do nothing */
86 break;
87 }
88}
89
90static void periodic_polling_on_replenishment(
91 struct reservation *res
92)
93{
94 struct polling_reservation *pres =
95 container_of(res, struct polling_reservation, res);
96
97 /* replenish budget */
98 res->cur_budget = pres->max_budget;
99 res->next_replenishment += pres->period;
100 res->budget_consumed = 0;
101
102 TRACE("polling_replenish(%u): next_replenishment=%llu\n", res->id, res->next_replenishment);
103 switch (res->state) {
104 case RESERVATION_DEPLETED:
105 case RESERVATION_INACTIVE:
106 case RESERVATION_ACTIVE_IDLE:
107 if (list_empty(&res->clients))
108 /* no clients => poll again later */
109 res->env->change_state(res->env, res,
110 RESERVATION_INACTIVE);
111 else
112 /* we have clients & budget => ACTIVE */
113 res->env->change_state(res->env, res,
114 RESERVATION_ACTIVE);
115 break;
116
117 case RESERVATION_ACTIVE:
118 /* Replenished while active => tardy? In any case,
119 * go ahead and stay active. */
120 break;
121 }
122}
123
124static void periodic_polling_on_replenishment_edf(
125 struct reservation *res
126)
127{
128 struct polling_reservation *pres =
129 container_of(res, struct polling_reservation, res);
130
131 /* update current priority */
132 res->priority = res->next_replenishment + pres->deadline;
133
134 /* do common updates */
135 periodic_polling_on_replenishment(res);
136}
137
138static void common_drain_budget(
139 struct reservation *res,
140 lt_t how_much)
141{
142 if (how_much >= res->cur_budget)
143 res->cur_budget = 0;
144 else
145 res->cur_budget -= how_much;
146
147 res->budget_consumed += how_much;
148 res->budget_consumed_total += how_much;
149
150 switch (res->state) {
151 case RESERVATION_DEPLETED:
152 case RESERVATION_INACTIVE:
153 //BUG();
154 TRACE("!!!!!!!!!!!!!!!STATE ERROR R%d STATE(%d)\n", res->id, res->state);
155 break;
156
157 case RESERVATION_ACTIVE_IDLE:
158 case RESERVATION_ACTIVE:
159 if (!res->cur_budget) {
160 res->env->change_state(res->env, res,
161 RESERVATION_DEPLETED);
162 } /* else: stay in current state */
163 break;
164 }
165}
166
167static struct reservation_ops periodic_polling_ops_fp = {
168 .dispatch_client = default_dispatch_client,
169 .client_arrives = periodic_polling_client_arrives,
170 .client_departs = periodic_polling_client_departs,
171 .replenish = periodic_polling_on_replenishment,
172 .drain_budget = common_drain_budget,
173};
174
175static struct reservation_ops periodic_polling_ops_edf = {
176 .dispatch_client = default_dispatch_client,
177 .client_arrives = periodic_polling_client_arrives,
178 .client_departs = periodic_polling_client_departs,
179 .replenish = periodic_polling_on_replenishment_edf,
180 .drain_budget = common_drain_budget,
181};
182
183
184
185
186static void sporadic_polling_client_arrives_fp(
187 struct reservation* res,
188 struct reservation_client *client
189)
190{
191 struct polling_reservation *pres =
192 container_of(res, struct polling_reservation, res);
193
194 list_add_tail(&client->list, &res->clients);
195
196 switch (res->state) {
197 case RESERVATION_INACTIVE:
198 /* Replenish now. */
199 res->cur_budget = pres->max_budget;
200 res->next_replenishment =
201 res->env->current_time + pres->period;
202
203 res->env->change_state(res->env, res,
204 RESERVATION_ACTIVE);
205 break;
206
207 case RESERVATION_ACTIVE:
208 case RESERVATION_DEPLETED:
209 /* do nothing */
210 break;
211
212 case RESERVATION_ACTIVE_IDLE:
213 res->env->change_state(res->env, res,
214 RESERVATION_ACTIVE);
215 break;
216 }
217}
218
219static void sporadic_polling_client_arrives_edf(
220 struct reservation* res,
221 struct reservation_client *client
222)
223{
224 struct polling_reservation *pres =
225 container_of(res, struct polling_reservation, res);
226
227 list_add_tail(&client->list, &res->clients);
228
229 switch (res->state) {
230 case RESERVATION_INACTIVE:
231 /* Replenish now. */
232 res->cur_budget = pres->max_budget;
233 res->next_replenishment =
234 res->env->current_time + pres->period;
235 res->priority =
236 res->env->current_time + pres->deadline;
237
238 res->env->change_state(res->env, res,
239 RESERVATION_ACTIVE);
240 break;
241
242 case RESERVATION_ACTIVE:
243 case RESERVATION_DEPLETED:
244 /* do nothing */
245 break;
246
247 case RESERVATION_ACTIVE_IDLE:
248 res->env->change_state(res->env, res,
249 RESERVATION_ACTIVE);
250 break;
251 }
252}
253
254static struct reservation_ops sporadic_polling_ops_fp = {
255 .dispatch_client = default_dispatch_client,
256 .client_arrives = sporadic_polling_client_arrives_fp,
257 .client_departs = periodic_polling_client_departs,
258 .replenish = periodic_polling_on_replenishment,
259 .drain_budget = common_drain_budget,
260};
261
262static struct reservation_ops sporadic_polling_ops_edf = {
263 .dispatch_client = default_dispatch_client,
264 .client_arrives = sporadic_polling_client_arrives_edf,
265 .client_departs = periodic_polling_client_departs,
266 .replenish = periodic_polling_on_replenishment_edf,
267 .drain_budget = common_drain_budget,
268};
269
270void polling_reservation_init(
271 struct polling_reservation *pres,
272 int use_edf_prio,
273 int use_periodic_polling,
274 lt_t budget, lt_t period, lt_t deadline, lt_t offset
275)
276{
277 if (!deadline)
278 deadline = period;
279 BUG_ON(budget > period);
280 BUG_ON(budget > deadline);
281 BUG_ON(offset >= period);
282
283 reservation_init(&pres->res);
284 pres->max_budget = budget;
285 pres->period = period;
286 pres->deadline = deadline;
287 pres->offset = offset;
288 TRACE_TASK(current, "polling_reservation_init: periodic %d, use_edf %d\n", use_periodic_polling, use_edf_prio);
289 if (use_periodic_polling) {
290 if (use_edf_prio)
291 pres->res.ops = &periodic_polling_ops_edf;
292 else
293 pres->res.ops = &periodic_polling_ops_fp;
294 } else {
295 if (use_edf_prio)
296 pres->res.ops = &sporadic_polling_ops_edf;
297 else
298 pres->res.ops = &sporadic_polling_ops_fp;
299 }
300}
301
302
303static lt_t td_cur_major_cycle_start(struct table_driven_reservation *tdres)
304{
305 lt_t x, tmp;
306
307 tmp = tdres->res.env->current_time - tdres->res.env->time_zero;
308 x = div64_u64(tmp, tdres->major_cycle);
309 x *= tdres->major_cycle;
310 return x;
311}
312
313
314static lt_t td_next_major_cycle_start(struct table_driven_reservation *tdres)
315{
316 lt_t x, tmp;
317
318 tmp = tdres->res.env->current_time - tdres->res.env->time_zero;
319 x = div64_u64(tmp, tdres->major_cycle) + 1;
320 x *= tdres->major_cycle;
321 return x;
322}
323
324static void td_client_arrives(
325 struct reservation* res,
326 struct reservation_client *client
327)
328{
329 struct table_driven_reservation *tdres =
330 container_of(res, struct table_driven_reservation, res);
331
332 list_add_tail(&client->list, &res->clients);
333
334 switch (res->state) {
335 case RESERVATION_INACTIVE:
336 /* Figure out first replenishment time. */
337 tdres->major_cycle_start = td_next_major_cycle_start(tdres);
338 res->next_replenishment = tdres->major_cycle_start;
339 res->next_replenishment += tdres->intervals[0].start;
340 tdres->next_interval = 0;
341
342 res->env->change_state(res->env, res,
343 RESERVATION_DEPLETED);
344 break;
345
346 case RESERVATION_ACTIVE:
347 case RESERVATION_DEPLETED:
348 /* do nothing */
349 break;
350
351 case RESERVATION_ACTIVE_IDLE:
352 res->env->change_state(res->env, res,
353 RESERVATION_ACTIVE);
354 break;
355 }
356}
357
358static void td_client_departs(
359 struct reservation *res,
360 struct reservation_client *client,
361 int did_signal_job_completion
362)
363{
364 list_del(&client->list);
365
366 switch (res->state) {
367 case RESERVATION_INACTIVE:
368 case RESERVATION_ACTIVE_IDLE:
369 //BUG(); /* INACTIVE or IDLE <=> no client */
370 break;
371
372 case RESERVATION_ACTIVE:
373 if (list_empty(&res->clients)) {
374 res->env->change_state(res->env, res,
375 RESERVATION_ACTIVE_IDLE);
376 } /* else: nothing to do, more clients ready */
377 break;
378
379 case RESERVATION_DEPLETED:
380 /* do nothing */
381 break;
382 }
383}
384
385static lt_t td_time_remaining_until_end(struct table_driven_reservation *tdres)
386{
387 lt_t now = tdres->res.env->current_time;
388 lt_t end = tdres->cur_interval.end;
389 //TRACE("td_remaining(%u): start=%llu now=%llu end=%llu state=%d\n", tdres->res.id, tdres->cur_interval.start, now, end, tdres->res.state);
390 if (now >= end)
391 return 0;
392 else
393 return end - now;
394}
395
396static void td_replenish(
397 struct reservation *res)
398{
399 struct table_driven_reservation *tdres =
400 container_of(res, struct table_driven_reservation, res);
401
402 //TRACE("td_replenish(%u): expected_replenishment=%llu\n", res->id, res->next_replenishment);
403
404 /* figure out current interval */
405 tdres->cur_interval.start = tdres->major_cycle_start +
406 tdres->intervals[tdres->next_interval].start;
407 tdres->cur_interval.end = tdres->major_cycle_start +
408 tdres->intervals[tdres->next_interval].end;
409/* TRACE("major_cycle_start=%llu => [%llu, %llu]\n",
410 tdres->major_cycle_start,
411 tdres->cur_interval.start,
412 tdres->cur_interval.end);
413*/
414 /* reset budget */
415 res->cur_budget = td_time_remaining_until_end(tdres);
416 res->budget_consumed = 0;
417 //TRACE("td_replenish(%u): %s budget=%llu\n", res->id, res->cur_budget ? "" : "WARNING", res->cur_budget);
418
419 /* prepare next slot */
420 tdres->next_interval = (tdres->next_interval + 1) % tdres->num_intervals;
421 if (!tdres->next_interval)
422 /* wrap to next major cycle */
423 tdres->major_cycle_start += tdres->major_cycle;
424
425 /* determine next time this reservation becomes eligible to execute */
426 res->next_replenishment = tdres->major_cycle_start;
427 res->next_replenishment += tdres->intervals[tdres->next_interval].start;
428 //TRACE("td_replenish(%u): next_replenishment=%llu\n", res->id, res->next_replenishment);
429
430
431 switch (res->state) {
432 case RESERVATION_DEPLETED:
433 case RESERVATION_ACTIVE:
434 case RESERVATION_ACTIVE_IDLE:
435 if (list_empty(&res->clients))
436 res->env->change_state(res->env, res,
437 RESERVATION_ACTIVE_IDLE);
438 else
439 /* we have clients & budget => ACTIVE */
440 res->env->change_state(res->env, res,
441 RESERVATION_ACTIVE);
442 break;
443
444 case RESERVATION_INACTIVE:
445 BUG();
446 break;
447 }
448}
449
450static void td_drain_budget(
451 struct reservation *res,
452 lt_t how_much)
453{
454 struct table_driven_reservation *tdres =
455 container_of(res, struct table_driven_reservation, res);
456
457 res->budget_consumed += how_much;
458 res->budget_consumed_total += how_much;
459
460 /* Table-driven scheduling: instead of tracking the budget, we compute
461 * how much time is left in this allocation interval. */
462
463 /* sanity check: we should never try to drain from future slots */
464 //TRACE("TD_DRAIN STATE(%d) [%llu,%llu] %llu ?\n", res->state, tdres->cur_interval.start, tdres->cur_interval.end, res->env->current_time);
465 //BUG_ON(tdres->cur_interval.start > res->env->current_time);
466 if (tdres->cur_interval.start > res->env->current_time)
467 TRACE("TD_DRAIN BUG!!!!!!!!!!\n");
468
469 switch (res->state) {
470 case RESERVATION_DEPLETED:
471 case RESERVATION_INACTIVE:
472 //BUG();
473 TRACE("TD_DRAIN!!!!!!!!! RES_STATE = %d\n", res->state);
474 break;
475
476 case RESERVATION_ACTIVE_IDLE:
477 case RESERVATION_ACTIVE:
478 res->cur_budget = td_time_remaining_until_end(tdres);
479 //TRACE("td_drain_budget(%u): drained to budget=%llu\n", res->id, res->cur_budget);
480 if (!res->cur_budget) {
481 res->env->change_state(res->env, res,
482 RESERVATION_DEPLETED);
483 } else {
484 /* sanity check budget calculation */
485 //BUG_ON(res->env->current_time >= tdres->cur_interval.end);
486 //BUG_ON(res->env->current_time < tdres->cur_interval.start);
487 if (res->env->current_time >= tdres->cur_interval.end)
488 printk(KERN_ALERT "TD_DRAIN_BUDGET WARNING1\n");
489 if (res->env->current_time < tdres->cur_interval.start)
490 printk(KERN_ALERT "TD_DRAIN_BUDGET WARNING2\n");
491 }
492
493 break;
494 }
495}
496
497static struct task_struct* td_dispatch_client(
498 struct reservation *res,
499 lt_t *for_at_most)
500{
501 struct task_struct *t;
502 struct table_driven_reservation *tdres =
503 container_of(res, struct table_driven_reservation, res);
504
505 /* usual logic for selecting a client */
506 t = default_dispatch_client(res, for_at_most);
507
508 TRACE_TASK(t, "td_dispatch_client(%u): selected, budget=%llu\n",
509 res->id, res->cur_budget);
510
511 /* check how much budget we have left in this time slot */
512 res->cur_budget = td_time_remaining_until_end(tdres);
513
514 TRACE_TASK(t, "td_dispatch_client(%u): updated to budget=%llu next=%d\n",
515 res->id, res->cur_budget, tdres->next_interval);
516
517 if (unlikely(!res->cur_budget)) {
518 /* Unlikely case: if we ran out of budget, the user configured
519 * a broken scheduling table (overlapping table slots).
520 * Not much we can do about this, but we can't dispatch a job
521 * now without causing overload. So let's register this reservation
522 * as depleted and wait for the next allocation. */
523 TRACE("td_dispatch_client(%u): budget unexpectedly depleted "
524 "(check scheduling table for unintended overlap)\n",
525 res->id);
526 res->env->change_state(res->env, res,
527 RESERVATION_DEPLETED);
528 return NULL;
529 } else
530 return t;
531}
532
533static struct reservation_ops td_ops = {
534 .dispatch_client = td_dispatch_client,
535 .client_arrives = td_client_arrives,
536 .client_departs = td_client_departs,
537 .replenish = td_replenish,
538 .drain_budget = td_drain_budget,
539};
540
541void table_driven_reservation_init(
542 struct table_driven_reservation *tdres,
543 lt_t major_cycle,
544 struct lt_interval *intervals,
545 unsigned int num_intervals)
546{
547 unsigned int i;
548
549 /* sanity checking */
550 BUG_ON(!num_intervals);
551 for (i = 0; i < num_intervals; i++)
552 BUG_ON(intervals[i].end <= intervals[i].start);
553 for (i = 0; i + 1 < num_intervals; i++)
554 BUG_ON(intervals[i + 1].start <= intervals[i].end);
555 BUG_ON(intervals[num_intervals - 1].end > major_cycle);
556
557 reservation_init(&tdres->res);
558 tdres->major_cycle = major_cycle;
559 tdres->intervals = intervals;
560 tdres->cur_interval.start = 0;
561 tdres->cur_interval.end = 0;
562 tdres->num_intervals = num_intervals;
563 tdres->res.ops = &td_ops;
564}