diff options
author | Namhoon Kim <namhoonk@cs.unc.edu> | 2015-01-28 09:26:59 -0500 |
---|---|---|
committer | Namhoon Kim <namhoonk@cs.unc.edu> | 2015-01-28 09:26:59 -0500 |
commit | 5ba38eb6290a0c1767932c03b15edb0627ffd6b2 (patch) | |
tree | 8b1221cf821755ff7de26bf3fe375596e26d64d4 /litmus/reservation.c | |
parent | ca538aafd7cebfd09a47af0a628647620a6bba35 (diff) |
LV cwip-mc2-ver2
Diffstat (limited to 'litmus/reservation.c')
-rw-r--r-- | litmus/reservation.c | 356 |
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 | |||
330 | struct 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 | /* | ||
352 | struct 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 | |||
366 | struct 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 | /* | ||
380 | static 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 | |||
418 | static 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 | |||
455 | void 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 | |||
461 | static 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 | |||
483 | static 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 | |||
511 | static 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 | |||
531 | void 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 | |||
539 | static 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 | |||
584 | static 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 */ | ||
608 | bool 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 | |||
640 | static 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 | |||
660 | void 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 | ||