aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/reservation.c
diff options
context:
space:
mode:
authorNamhoon Kim <namhoonk@cs.unc.edu>2015-01-28 09:26:59 -0500
committerNamhoon Kim <namhoonk@cs.unc.edu>2015-01-28 09:26:59 -0500
commit5ba38eb6290a0c1767932c03b15edb0627ffd6b2 (patch)
tree8b1221cf821755ff7de26bf3fe375596e26d64d4 /litmus/reservation.c
parentca538aafd7cebfd09a47af0a628647620a6bba35 (diff)
Diffstat (limited to 'litmus/reservation.c')
-rw-r--r--litmus/reservation.c356
1 files changed, 352 insertions, 4 deletions
diff --git a/litmus/reservation.c b/litmus/reservation.c
index 16b3a4818e1e..e30892c72f4a 100644
--- a/litmus/reservation.c
+++ b/litmus/reservation.c
@@ -1,4 +1,5 @@
1#include <linux/sched.h> 1#include <linux/sched.h>
2#include <linux/slab.h>
2 3
3#include <litmus/litmus.h> 4#include <litmus/litmus.h>
4#include <litmus/reservation.h> 5#include <litmus/reservation.h>
@@ -48,7 +49,7 @@ static void sup_scheduler_update_at(
48 struct sup_reservation_environment* sup_env, 49 struct sup_reservation_environment* sup_env,
49 lt_t when) 50 lt_t when)
50{ 51{
51 TRACE("SCHEDULER_UPDATE_AT update: %llu > when %llu\n", sup_env->next_scheduler_update, when); 52 //TRACE("SCHEDULER_UPDATE_AT update: %llu > when %llu\n", sup_env->next_scheduler_update, when);
52 if (sup_env->next_scheduler_update > when) 53 if (sup_env->next_scheduler_update > when)
53 sup_env->next_scheduler_update = when; 54 sup_env->next_scheduler_update = when;
54} 55}
@@ -252,7 +253,7 @@ void sup_update_time(
252 /* If the time didn't advance, there is nothing to do. 253 /* If the time didn't advance, there is nothing to do.
253 * This check makes it safe to call sup_advance_time() potentially 254 * This check makes it safe to call sup_advance_time() potentially
254 * multiple times (e.g., via different code paths. */ 255 * multiple times (e.g., via different code paths. */
255 TRACE("(sup_update_time) now: %llu, current_time: %llu\n", now, sup_env->env.current_time); 256 //TRACE("(sup_update_time) now: %llu, current_time: %llu\n", now, sup_env->env.current_time);
256 if (unlikely(now <= sup_env->env.current_time)) 257 if (unlikely(now <= sup_env->env.current_time))
257 return; 258 return;
258 259
@@ -264,11 +265,11 @@ void sup_update_time(
264 sup_env->next_scheduler_update = SUP_NO_SCHEDULER_UPDATE; 265 sup_env->next_scheduler_update = SUP_NO_SCHEDULER_UPDATE;
265 266
266 /* deplete budgets by passage of time */ 267 /* deplete budgets by passage of time */
267 TRACE("CHARGE###\n"); 268 //TRACE("CHARGE###\n");
268 sup_charge_budget(sup_env, delta); 269 sup_charge_budget(sup_env, delta);
269 270
270 /* check if any budgets where replenished */ 271 /* check if any budgets where replenished */
271 TRACE("REPLENISH###\n"); 272 //TRACE("REPLENISH###\n");
272 sup_replenish_budgets(sup_env); 273 sup_replenish_budgets(sup_env);
273} 274}
274 275
@@ -325,3 +326,350 @@ void sup_init(struct sup_reservation_environment* sup_env)
325 326
326 sup_env->next_scheduler_update = SUP_NO_SCHEDULER_UPDATE; 327 sup_env->next_scheduler_update = SUP_NO_SCHEDULER_UPDATE;
327} 328}
329
330struct reservation* gmp_find_by_id(struct gmp_reservation_environment* gmp_env,
331 unsigned int id)
332{
333 struct reservation *res;
334
335 list_for_each_entry(res, &gmp_env->active_reservations, list) {
336 if (res->id == id)
337 return res;
338 }
339 list_for_each_entry(res, &gmp_env->inactive_reservations, list) {
340 if (res->id == id)
341 return res;
342 }
343 list_for_each_entry(res, &gmp_env->depleted_reservations, list) {
344 if (res->id == id)
345 return res;
346 }
347
348 return NULL;
349}
350
351/*
352struct next_timer_event* gmp_find_event_by_id(struct gmp_reservation_environment* gmp_env,
353 unsigned int id)
354{
355 struct next_timer_event *event;
356
357 list_for_each_entry(event, &gmp_env->next_events, list) {
358 if (event->id == id)
359 return event;
360 }
361
362 return NULL;
363}
364*/
365
366struct next_timer_event* gmp_find_event_by_time(struct gmp_reservation_environment* gmp_env,
367 lt_t when)
368{
369 struct next_timer_event *event;
370
371 list_for_each_entry(event, &gmp_env->next_events, list) {
372 if (event->next_update == when)
373 return event;
374 }
375
376 return NULL;
377}
378
379/*
380static void gmp_scheduler_update_at(
381 struct gmp_reservation_environment* gmp_env, unsigned int id,
382 event_type_t type, lt_t when)
383{
384 struct next_timer_event *nevent, *queued;
385 struct list_head *pos;
386 int found = 0;
387
388 nevent = gmp_find_event_by_id(gmp_env, id);
389
390 if (!nevent) {
391 nevent = kzalloc(sizeof(*nevent), GFP_KERNEL);
392 nevent->next_update = when;
393 nevent->id = id;
394 nevent->timer_armed_on = NO_CPU;
395 nevent->type = type;
396
397 list_for_each(pos, &gmp_env->next_events) {
398 queued = list_entry(pos, struct next_timer_event, list);
399 if (queued->next_update > nevent->next_update) {
400 list_add(&nevent->list, pos->prev);
401 found = 1;
402 TRACE("NEXT_EVENT ADDED after %llu\n", queued->next_update);
403 break;
404 }
405 }
406
407 if (!found) {
408 list_add_tail(&nevent->list, &gmp_env->next_events);
409 TRACE("NEXT_EVENT ADDED at [0]\n");
410 }
411 } else {
412 TRACE("EVENT FOUND at %llu T(%d), NEW EVENT %llu T(%d)\n", nevent->next_update, nevent->type, when, type);
413 }
414}
415*/
416#define TIMER_RESOLUTION 100000L
417
418static void gmp_scheduler_update_at(
419 struct gmp_reservation_environment* gmp_env,
420 lt_t when)
421{
422 struct next_timer_event *nevent, *queued;
423 struct list_head *pos;
424 int found = 0;
425
426 //when = div64_u64(when, TIMER_RESOLUTION);
427 //when *= TIMER_RESOLUTION;
428
429 nevent = gmp_find_event_by_time(gmp_env, when);
430
431 if (!nevent) {
432 nevent = kzalloc(sizeof(*nevent), GFP_KERNEL);
433 nevent->next_update = when;
434 nevent->timer_armed_on = NO_CPU;
435
436 list_for_each(pos, &gmp_env->next_events) {
437 queued = list_entry(pos, struct next_timer_event, list);
438 if (queued->next_update > nevent->next_update) {
439 list_add(&nevent->list, pos->prev);
440 found = 1;
441 TRACE("NEXT_EVENT at %llu ADDED before %llu\n", nevent->next_update, queued->next_update);
442 break;
443 }
444 }
445
446 if (!found) {
447 list_add_tail(&nevent->list, &gmp_env->next_events);
448 TRACE("NEXT_EVENT ADDED at %llu ADDED at HEAD\n", nevent->next_update);
449 }
450 } else {
451 ; //TRACE("EVENT FOUND at %llu, NEW EVENT %llu\n", nevent->next_update, when);
452 }
453}
454
455void gmp_scheduler_update_after(
456 struct gmp_reservation_environment* gmp_env, lt_t timeout)
457{
458 gmp_scheduler_update_at(gmp_env, gmp_env->env.current_time + timeout);
459}
460
461static void gmp_queue_depleted(
462 struct gmp_reservation_environment* gmp_env,
463 struct reservation *res)
464{
465 struct list_head *pos;
466 struct reservation *queued;
467 int found = 0;
468
469 list_for_each(pos, &gmp_env->depleted_reservations) {
470 queued = list_entry(pos, struct reservation, list);
471 if (queued->next_replenishment > res->next_replenishment) {
472 list_add(&res->list, pos->prev);
473 found = 1;
474 }
475 }
476
477 if (!found)
478 list_add_tail(&res->list, &gmp_env->depleted_reservations);
479
480 gmp_scheduler_update_at(gmp_env, res->next_replenishment);
481}
482
483static void gmp_queue_active(
484 struct gmp_reservation_environment* gmp_env,
485 struct reservation *res)
486{
487 struct list_head *pos;
488 struct reservation *queued;
489 int check_preempt = 1, found = 0;
490
491 list_for_each(pos, &gmp_env->active_reservations) {
492 queued = list_entry(pos, struct reservation, list);
493 if (queued->priority > res->priority) {
494 list_add(&res->list, pos->prev);
495 found = 1;
496 break;
497 } else if (queued->scheduled_on == NO_CPU)
498 check_preempt = 0;
499 }
500
501 if (!found)
502 list_add_tail(&res->list, &gmp_env->active_reservations);
503
504 /* check for possible preemption */
505 if (res->state == RESERVATION_ACTIVE && !check_preempt)
506 gmp_env->schedule_now = true;
507
508 gmp_scheduler_update_after(gmp_env, res->cur_budget);
509}
510
511static void gmp_queue_reservation(
512 struct gmp_reservation_environment* gmp_env,
513 struct reservation *res)
514{
515 switch (res->state) {
516 case RESERVATION_INACTIVE:
517 list_add(&res->list, &gmp_env->inactive_reservations);
518 break;
519
520 case RESERVATION_DEPLETED:
521 gmp_queue_depleted(gmp_env, res);
522 break;
523
524 case RESERVATION_ACTIVE_IDLE:
525 case RESERVATION_ACTIVE:
526 gmp_queue_active(gmp_env, res);
527 break;
528 }
529}
530
531void gmp_add_new_reservation(
532 struct gmp_reservation_environment* gmp_env,
533 struct reservation* new_res)
534{
535 new_res->env = &gmp_env->env;
536 gmp_queue_reservation(gmp_env, new_res);
537}
538
539static void gmp_charge_budget(
540 struct gmp_reservation_environment* gmp_env,
541 lt_t delta)
542{
543 struct list_head *pos, *next;
544 struct reservation *res;
545
546 list_for_each_safe(pos, next, &gmp_env->active_reservations) {
547 int drained = 0;
548 /* charge all ACTIVE_IDLE up to the first ACTIVE reservation */
549 res = list_entry(pos, struct reservation, list);
550 if (res->state == RESERVATION_ACTIVE) {
551 TRACE("gmp_charge_budget ACTIVE R%u drain %llu\n", res->id, delta);
552 if (res->scheduled_on != NO_CPU && res->blocked_by_ghost == 0) {
553 TRACE("DRAIN !!\n");
554 drained = 1;
555 res->ops->drain_budget(res, delta);
556 }
557 } else {
558 //BUG_ON(res->state != RESERVATION_ACTIVE_IDLE);
559 if (res->state != RESERVATION_ACTIVE_IDLE)
560 TRACE("BUG!!!!!!!!!!!! gmp_charge_budget()\n");
561 TRACE("gmp_charge_budget INACTIVE R%u drain %llu\n", res->id, delta);
562 //if (res->is_ghost == 1) {
563 TRACE("DRAIN !!\n");
564 drained = 1;
565 res->ops->drain_budget(res, delta);
566 //}
567 }
568 if ((res->state == RESERVATION_ACTIVE ||
569 res->state == RESERVATION_ACTIVE_IDLE) && (drained == 1))
570 {
571 /* make sure scheduler is invoked when this reservation expires
572 * its remaining budget */
573 TRACE("requesting gmp_scheduler update for reservation %u in %llu nanoseconds\n",
574 res->id, res->cur_budget);
575 gmp_scheduler_update_after(gmp_env, res->cur_budget);
576 }
577 //if (encountered_active == 2)
578 /* stop at the first ACTIVE reservation */
579 // break;
580 }
581 //TRACE("finished charging budgets\n");
582}
583
584static void gmp_replenish_budgets(struct gmp_reservation_environment* gmp_env)
585{
586 struct list_head *pos, *next;
587 struct reservation *res;
588
589 list_for_each_safe(pos, next, &gmp_env->depleted_reservations) {
590 res = list_entry(pos, struct reservation, list);
591 if (res->next_replenishment <= gmp_env->env.current_time) {
592 res->ops->replenish(res);
593 } else {
594 /* list is ordered by increasing depletion times */
595 break;
596 }
597 }
598 //TRACE("finished replenishing budgets\n");
599
600 /* request a scheduler update at the next replenishment instant */
601 res = list_first_entry_or_null(&gmp_env->depleted_reservations,
602 struct reservation, list);
603 if (res)
604 gmp_scheduler_update_at(gmp_env, res->next_replenishment);
605}
606
607/* return schedule_now */
608bool gmp_update_time(
609 struct gmp_reservation_environment* gmp_env,
610 lt_t now)
611{
612 lt_t delta;
613
614 if (!gmp_env) {
615 TRACE("BUG****************************************\n");
616 return false;
617 }
618 /* If the time didn't advance, there is nothing to do.
619 * This check makes it safe to call sup_advance_time() potentially
620 * multiple times (e.g., via different code paths. */
621 //TRACE("(sup_update_time) now: %llu, current_time: %llu\n", now, sup_env->env.current_time);
622 if (unlikely(now <= gmp_env->env.current_time))
623 return gmp_env->schedule_now;
624
625 delta = now - gmp_env->env.current_time;
626 gmp_env->env.current_time = now;
627
628
629 /* deplete budgets by passage of time */
630 //TRACE("CHARGE###\n");
631 gmp_charge_budget(gmp_env, delta);
632
633 /* check if any budgets where replenished */
634 //TRACE("REPLENISH###\n");
635 gmp_replenish_budgets(gmp_env);
636
637 return gmp_env->schedule_now;
638}
639
640static void gmp_res_change_state(
641 struct reservation_environment* env,
642 struct reservation *res,
643 reservation_state_t new_state)
644{
645 struct gmp_reservation_environment* gmp_env;
646
647 gmp_env = container_of(env, struct gmp_reservation_environment, env);
648
649 TRACE("GMP reservation R%d state %d->%d at %llu\n",
650 res->id, res->state, new_state, env->current_time);
651
652 list_del(&res->list);
653 /* check if we need to reschedule because we lost an active reservation */
654 if (res->state == RESERVATION_ACTIVE && !gmp_env->will_schedule)
655 gmp_env->schedule_now = true;
656 res->state = new_state;
657 gmp_queue_reservation(gmp_env, res);
658}
659
660void gmp_init(struct gmp_reservation_environment* gmp_env)
661{
662 memset(gmp_env, sizeof(*gmp_env), 0);
663
664 INIT_LIST_HEAD(&gmp_env->active_reservations);
665 INIT_LIST_HEAD(&gmp_env->depleted_reservations);
666 INIT_LIST_HEAD(&gmp_env->inactive_reservations);
667 INIT_LIST_HEAD(&gmp_env->next_events);
668
669 gmp_env->env.change_state = gmp_res_change_state;
670
671 gmp_env->schedule_now = false;
672 gmp_env->will_schedule = false;
673
674 raw_spin_lock_init(&gmp_env->lock);
675} \ No newline at end of file