diff options
author | Bjoern Brandenburg <bbb@mpi-sws.org> | 2014-09-17 11:25:50 -0400 |
---|---|---|
committer | Namhoon Kim <namhoonk@cs.unc.edu> | 2014-11-03 21:59:45 -0500 |
commit | f460d28c594341d8e8f78cfe92e6e0d42b2f5616 (patch) | |
tree | 0b3b3b5bdb77e7586103943afe0fc880cb7fc48c | |
parent | 33ad22dfbddcff613fd530f3721cd3e941f4614c (diff) |
Reservations: fix time-tracking of table-driven reservations
Keep track of the current slot and major cycle explicitly to avoid
ambiguity when the budget charging is delayed into the next major
cycle due to a late interrupt or other sources of delay.
-rw-r--r-- | include/litmus/polling_reservations.h | 5 | ||||
-rw-r--r-- | litmus/polling_reservations.c | 53 | ||||
-rw-r--r-- | litmus/reservation.c | 2 |
3 files changed, 46 insertions, 14 deletions
diff --git a/include/litmus/polling_reservations.h b/include/litmus/polling_reservations.h index fa221817ad30..66c9b1e31f20 100644 --- a/include/litmus/polling_reservations.h +++ b/include/litmus/polling_reservations.h | |||
@@ -24,7 +24,10 @@ struct table_driven_reservation { | |||
24 | unsigned int next_interval; | 24 | unsigned int next_interval; |
25 | unsigned int num_intervals; | 25 | unsigned int num_intervals; |
26 | struct lt_interval *intervals; | 26 | struct lt_interval *intervals; |
27 | struct lt_interval *cur_interval; | 27 | |
28 | /* info about current scheduling slot */ | ||
29 | struct lt_interval cur_interval; | ||
30 | lt_t major_cycle_start; | ||
28 | }; | 31 | }; |
29 | 32 | ||
30 | void table_driven_reservation_init(struct table_driven_reservation *tdres, | 33 | void table_driven_reservation_init(struct table_driven_reservation *tdres, |
diff --git a/litmus/polling_reservations.c b/litmus/polling_reservations.c index 2c481b46ba39..86a32068a3a8 100644 --- a/litmus/polling_reservations.c +++ b/litmus/polling_reservations.c | |||
@@ -318,7 +318,8 @@ static void td_client_arrives( | |||
318 | switch (res->state) { | 318 | switch (res->state) { |
319 | case RESERVATION_INACTIVE: | 319 | case RESERVATION_INACTIVE: |
320 | /* Figure out first replenishment time. */ | 320 | /* Figure out first replenishment time. */ |
321 | res->next_replenishment = td_next_major_cycle_start(tdres); | 321 | tdres->major_cycle_start = td_next_major_cycle_start(tdres); |
322 | res->next_replenishment = tdres->major_cycle_start; | ||
322 | res->next_replenishment += tdres->intervals[0].start; | 323 | res->next_replenishment += tdres->intervals[0].start; |
323 | tdres->next_interval = 0; | 324 | tdres->next_interval = 0; |
324 | 325 | ||
@@ -368,11 +369,12 @@ static void td_client_departs( | |||
368 | static lt_t td_time_remaining_until_end(struct table_driven_reservation *tdres) | 369 | static lt_t td_time_remaining_until_end(struct table_driven_reservation *tdres) |
369 | { | 370 | { |
370 | lt_t now = tdres->res.env->current_time; | 371 | lt_t now = tdres->res.env->current_time; |
371 | lt_t end = td_cur_major_cycle_start(tdres) + tdres->cur_interval->end; | 372 | lt_t end = tdres->cur_interval.end; |
372 | TRACE("td_remaining(%u): start=%llu now=%llu end=%llu\n", | 373 | TRACE("td_remaining(%u): start=%llu now=%llu end=%llu state=%d\n", |
373 | tdres->res.id, | 374 | tdres->res.id, |
374 | td_cur_major_cycle_start(tdres) + tdres->cur_interval->start, | 375 | tdres->cur_interval.start, |
375 | now, end); | 376 | now, end, |
377 | tdres->res.state); | ||
376 | if (now >= end) | 378 | if (now >= end) |
377 | return 0; | 379 | return 0; |
378 | else | 380 | else |
@@ -385,20 +387,36 @@ static void td_replenish( | |||
385 | struct table_driven_reservation *tdres = | 387 | struct table_driven_reservation *tdres = |
386 | container_of(res, struct table_driven_reservation, res); | 388 | container_of(res, struct table_driven_reservation, res); |
387 | 389 | ||
388 | /* replenish budget */ | 390 | TRACE("td_replenish(%u): expected_replenishment=%llu\n", res->id, |
389 | tdres->cur_interval = tdres->intervals + tdres->next_interval; | 391 | res->next_replenishment); |
392 | |||
393 | /* figure out current interval */ | ||
394 | tdres->cur_interval.start = tdres->major_cycle_start + | ||
395 | tdres->intervals[tdres->next_interval].start; | ||
396 | tdres->cur_interval.end = tdres->major_cycle_start + | ||
397 | tdres->intervals[tdres->next_interval].end; | ||
398 | TRACE("major_cycle_start=%llu => [%llu, %llu]\n", | ||
399 | tdres->major_cycle_start, | ||
400 | tdres->cur_interval.start, | ||
401 | tdres->cur_interval.end); | ||
402 | |||
403 | /* reset budget */ | ||
390 | res->cur_budget = td_time_remaining_until_end(tdres); | 404 | res->cur_budget = td_time_remaining_until_end(tdres); |
391 | res->budget_consumed = 0; | 405 | res->budget_consumed = 0; |
392 | TRACE("td_replenish(%u): %s budget=%llu\n", res->id, | 406 | TRACE("td_replenish(%u): %s budget=%llu\n", res->id, |
393 | res->cur_budget ? "" : "WARNING", res->cur_budget); | 407 | res->cur_budget ? "" : "WARNING", res->cur_budget); |
394 | 408 | ||
409 | /* prepare next slot */ | ||
395 | tdres->next_interval = (tdres->next_interval + 1) % tdres->num_intervals; | 410 | tdres->next_interval = (tdres->next_interval + 1) % tdres->num_intervals; |
396 | if (tdres->next_interval) | 411 | if (!tdres->next_interval) |
397 | res->next_replenishment = td_cur_major_cycle_start(tdres); | ||
398 | else | ||
399 | /* wrap to next major cycle */ | 412 | /* wrap to next major cycle */ |
400 | res->next_replenishment = td_next_major_cycle_start(tdres); | 413 | tdres->major_cycle_start += tdres->major_cycle; |
414 | |||
415 | /* determine next time this reservation becomes eligible to execute */ | ||
416 | res->next_replenishment = tdres->major_cycle_start; | ||
401 | res->next_replenishment += tdres->intervals[tdres->next_interval].start; | 417 | res->next_replenishment += tdres->intervals[tdres->next_interval].start; |
418 | TRACE("td_replenish(%u): next_replenishment=%llu\n", res->id, | ||
419 | res->next_replenishment); | ||
402 | 420 | ||
403 | 421 | ||
404 | switch (res->state) { | 422 | switch (res->state) { |
@@ -433,6 +451,9 @@ static void td_drain_budget( | |||
433 | /* Table-driven scheduling: instead of tracking the budget, we compute | 451 | /* Table-driven scheduling: instead of tracking the budget, we compute |
434 | * how much time is left in this allocation interval. */ | 452 | * how much time is left in this allocation interval. */ |
435 | 453 | ||
454 | /* sanity check: we should never try to drain from future slots */ | ||
455 | BUG_ON(tdres->cur_interval.start > res->env->current_time); | ||
456 | |||
436 | switch (res->state) { | 457 | switch (res->state) { |
437 | case RESERVATION_DEPLETED: | 458 | case RESERVATION_DEPLETED: |
438 | case RESERVATION_INACTIVE: | 459 | case RESERVATION_INACTIVE: |
@@ -447,7 +468,12 @@ static void td_drain_budget( | |||
447 | if (!res->cur_budget) { | 468 | if (!res->cur_budget) { |
448 | res->env->change_state(res->env, res, | 469 | res->env->change_state(res->env, res, |
449 | RESERVATION_DEPLETED); | 470 | RESERVATION_DEPLETED); |
450 | } /* else: stay in current state */ | 471 | } else { |
472 | /* sanity check budget calculation */ | ||
473 | BUG_ON(res->env->current_time >= tdres->cur_interval.end); | ||
474 | BUG_ON(res->env->current_time < tdres->cur_interval.start); | ||
475 | } | ||
476 | |||
451 | break; | 477 | break; |
452 | } | 478 | } |
453 | } | 479 | } |
@@ -515,7 +541,8 @@ void table_driven_reservation_init( | |||
515 | reservation_init(&tdres->res); | 541 | reservation_init(&tdres->res); |
516 | tdres->major_cycle = major_cycle; | 542 | tdres->major_cycle = major_cycle; |
517 | tdres->intervals = intervals; | 543 | tdres->intervals = intervals; |
518 | tdres->cur_interval = intervals; | 544 | tdres->cur_interval.start = 0; |
545 | tdres->cur_interval.end = 0; | ||
519 | tdres->num_intervals = num_intervals; | 546 | tdres->num_intervals = num_intervals; |
520 | tdres->res.ops = &td_ops; | 547 | tdres->res.ops = &td_ops; |
521 | } | 548 | } |
diff --git a/litmus/reservation.c b/litmus/reservation.c index 447fc5b1be23..f79689823be7 100644 --- a/litmus/reservation.c +++ b/litmus/reservation.c | |||
@@ -206,6 +206,7 @@ static void sup_charge_budget( | |||
206 | /* stop at the first ACTIVE reservation */ | 206 | /* stop at the first ACTIVE reservation */ |
207 | break; | 207 | break; |
208 | } | 208 | } |
209 | TRACE("finished charging budgets\n"); | ||
209 | } | 210 | } |
210 | 211 | ||
211 | static void sup_replenish_budgets(struct sup_reservation_environment* sup_env) | 212 | static void sup_replenish_budgets(struct sup_reservation_environment* sup_env) |
@@ -222,6 +223,7 @@ static void sup_replenish_budgets(struct sup_reservation_environment* sup_env) | |||
222 | break; | 223 | break; |
223 | } | 224 | } |
224 | } | 225 | } |
226 | TRACE("finished replenishing budgets\n"); | ||
225 | 227 | ||
226 | /* request a scheduler update at the next replenishment instant */ | 228 | /* request a scheduler update at the next replenishment instant */ |
227 | res = list_first_entry_or_null(&sup_env->depleted_reservations, | 229 | res = list_first_entry_or_null(&sup_env->depleted_reservations, |