hw: preserve slack time, favor activated jobs

In the scheduler's implementation preserve the consumed slack-time
over periods of activation/deactivation, but instead of appending
activated jobs to the end of the slack queue, insert it as new head.
Thereby, the extreme discrimination of threads with short execution
times and frequent blocking behaviour against long running computations
gets avoided.

Fix genodelabs/genode#4796
This commit is contained in:
Stefan Kalkowski 2024-04-16 11:40:54 +02:00 committed by Christian Helmuth
parent 4e78e91bc2
commit aefbc47c56
3 changed files with 79 additions and 89 deletions

View File

@ -75,15 +75,13 @@ void Scheduler::_account_priotized(Context &c, unsigned const r)
void Scheduler::_account_slack(Context &c, unsigned const r)
{
if (_slack_list.head() != &c)
return;
if (r)
if (r) {
c._slack_time_left = r;
else {
c._slack_time_left = _slack_quota;
_slack_list.head_to_tail();
return;
}
c._slack_time_left = _slack_quota;
if (c.ready()) _slack_list.to_tail(&c._slack_le);
}
@ -129,8 +127,8 @@ void Scheduler::update(time_t time)
_last_time = time;
/* do not detract the quota of idle or removed context */
if (_current) {
unsigned const r = (_state != YIELD) ? _current_quantum - duration : 0;
if (_current && _current != &_idle) {
unsigned const r = (_state != YIELD) ? _current_quantum - duration : 0;
if (_current->_priotized_time_left) _account_priotized(*_current, r);
else _account_slack(*_current, r);
}
@ -155,30 +153,23 @@ void Scheduler::ready(Context &c)
c._ready = true;
bool out_of_date = false;
bool keep_current =
(_current->_priotized_time_left &&
!c._priotized_time_left) ||
(_current->_priotized_time_left &&
(_current->_priority > c._priority));
if (c._quota) {
_upl[c._priority].remove(&c._priotized_le);
if (c._priotized_time_left) {
if (c._priotized_time_left)
_rpl[c._priority].insert_head(&c._priotized_le);
if (_current && _current->_priotized_time_left) {
if (c._priority >= _current->_priority)
out_of_date = true;
} else out_of_date = true;
} else {
_rpl[c._priority].insert_tail(&c._priotized_le);;
}
else
_rpl[c._priority].insert_tail(&c._priotized_le);
}
c._slack_time_left = _slack_quota;
_slack_list.insert_tail(&c._slack_le);
_slack_list.insert_head(&c._slack_le);
if (!_current || _current == &_idle) out_of_date = true;
if (out_of_date && _state == UP_TO_DATE) _state = OUT_OF_DATE;
if (!keep_current && _state == UP_TO_DATE) _state = OUT_OF_DATE;
}
@ -225,6 +216,8 @@ void Scheduler::insert(Context &c)
{
assert(!c.ready());
c._slack_time_left = _slack_quota;
if (!c._quota)
return;

View File

@ -145,7 +145,6 @@ class Kernel::Scheduler
_last = le;
}
void to_tail(List_element * const le)
{
remove(le);
@ -157,9 +156,6 @@ class Kernel::Scheduler
remove(le);
insert_head(le);
}
void head_to_tail() {
to_tail(_list.first()); }
};
enum State { UP_TO_DATE, OUT_OF_DATE, YIELD };

View File

@ -452,7 +452,7 @@ Scheduler_test::Main::Main(Env &env)
_construct_context(6, __LINE__);
_scheduler.ready(_context(6));
_update_current_and_check(120, 700, 2, 100, __LINE__);
_update_current_and_check(120, 700, 6, 100, __LINE__);
_scheduler.ready(_context(4));
_update_current_and_check( 80, 780, 4, 90, __LINE__);
@ -460,10 +460,10 @@ Scheduler_test::Main::Main(Env &env)
_scheduler.unready(_context(4));
_scheduler.ready(_context(1));
_update_current_and_check( 50, 830, 1, 10, __LINE__);
_update_current_and_check( 50, 840, 1, 100, __LINE__);
_update_current_and_check( 50, 890, 1, 50, __LINE__);
_update_current_and_check(100, 940, 2, 20, __LINE__);
_update_current_and_check( 60, 960, 6, 40, __LINE__);
_update_current_and_check( 50, 840, 1, 50, __LINE__);
_update_current_and_check( 50, 890, 6, 20, __LINE__);
_update_current_and_check(100, 910, 2, 90, __LINE__);
_update_current_and_check( 60, 970, 2, 30, __LINE__);
_update_current_and_check( 60, 0, 3, 110, __LINE__);
@ -519,8 +519,8 @@ Scheduler_test::Main::Main(Env &env)
_update_current_and_check( 40, 810, 4, 100, __LINE__);
_scheduler.ready(_context(3));
_update_current_and_check( 30, 840, 4, 70, __LINE__);
_update_current_and_check( 80, 910, 1, 90, __LINE__);
_update_current_and_check( 30, 840, 3, 100, __LINE__);
_update_current_and_check( 70, 910, 3, 30, __LINE__);
_scheduler.ready(_context(7));
_scheduler.ready(_context(8));
@ -557,15 +557,16 @@ Scheduler_test::Main::Main(Env &env)
_scheduler.unready(_context(8));
_scheduler.yield();
_update_current_and_check( 40, 260, 1, 90, __LINE__);
_update_current_and_check( 40, 260, 2, 10, __LINE__);
_update_current_and_check( 40, 270, 1, 100, __LINE__);
_scheduler.unready(_context(1));
_update_current_and_check( 50, 310, 2, 100, __LINE__);
_update_current_and_check( 40, 310, 2, 100, __LINE__);
_update_current_and_check( 10, 320, 2, 90, __LINE__);
_set_context_ready_and_check(1, false, __LINE__);
_update_current_and_check(200, 410, 1, 100, __LINE__);
_update_current_and_check( 10, 420, 1, 90, __LINE__);
_set_context_ready_and_check(1, true, __LINE__);
_update_current_and_check(200, 410, 1, 60, __LINE__);
_update_current_and_check( 10, 420, 1, 50, __LINE__);
_scheduler.unready(_context(1));
_update_current_and_check( 10, 430, 2, 100, __LINE__);
@ -574,36 +575,36 @@ Scheduler_test::Main::Main(Env &env)
_update_current_and_check( 10, 440, 5, 120, __LINE__);
_scheduler.yield();
_update_current_and_check( 90, 530, 2, 90, __LINE__);
_update_current_and_check( 90, 530, 5, 100, __LINE__);
_scheduler.yield();
_update_current_and_check( 10, 540, 5, 100, __LINE__);
_update_current_and_check( 10, 540, 2, 90, __LINE__);
_set_context_ready_and_check(7, true, __LINE__);
_update_current_and_check( 10, 550, 7, 180, __LINE__);
_scheduler.yield();
_update_current_and_check( 10, 560, 5, 90, __LINE__);
_update_current_and_check( 10, 560, 7, 100, __LINE__);
_scheduler.yield();
_update_current_and_check( 10, 570, 2, 100, __LINE__);
_update_current_and_check( 10, 570, 2, 80, __LINE__);
_scheduler.yield();
_update_current_and_check( 10, 580, 7, 100, __LINE__);
_update_current_and_check( 10, 580, 5, 100, __LINE__);
_scheduler.unready(_context(5));
_update_current_and_check( 10, 590, 7, 90, __LINE__);
_update_current_and_check( 10, 590, 7, 100, __LINE__);
_scheduler.unready(_context(7));
_set_context_ready_and_check(5, true, __LINE__);
_update_current_and_check( 10, 600, 2, 100, __LINE__);
_update_current_and_check( 10, 600, 5, 90, __LINE__);
_set_context_ready_and_check(7, false, __LINE__);
_update_current_and_check(200, 700, 5, 100, __LINE__);
_set_context_ready_and_check(7, true, __LINE__);
_update_current_and_check(200, 690, 7, 90, __LINE__);
_scheduler.unready(_context(5));
_scheduler.unready(_context(7));
_update_current_and_check( 10, 710, 2, 100, __LINE__);
_update_current_and_check( 20, 710, 2, 100, __LINE__);
_scheduler.unready(_context(2));
_update_current_and_check( 10, 720, 0, 100, __LINE__);
@ -613,25 +614,25 @@ Scheduler_test::Main::Main(Env &env)
_set_context_ready_and_check(9, true, __LINE__);
_update_current_and_check( 10, 840, 9, 100, __LINE__);
_set_context_ready_and_check(6, false, __LINE__);
_update_current_and_check( 20, 860, 9, 80, __LINE__);
_set_context_ready_and_check(6, true, __LINE__);
_update_current_and_check( 20, 860, 6, 100, __LINE__);
_set_context_ready_and_check(8, false, __LINE__);
_update_current_and_check( 10, 870, 9, 70, __LINE__);
_set_context_ready_and_check(8, true, __LINE__);
_update_current_and_check( 10, 870, 8, 100, __LINE__);
_scheduler.yield();
_update_current_and_check( 10, 880, 6, 100, __LINE__);
_update_current_and_check( 10, 880, 6, 90, __LINE__);
_scheduler.yield();
_update_current_and_check( 10, 890, 8, 100, __LINE__);
_update_current_and_check( 10, 890, 9, 80, __LINE__);
_set_context_ready_and_check(7, false, __LINE__);
_set_context_ready_and_check(7, true, __LINE__);
_scheduler.yield();
_update_current_and_check( 20, 910, 9, 90, __LINE__);
_update_current_and_check( 20, 910, 7, 70, __LINE__);
_scheduler.unready(_context(8));
_scheduler.unready(_context(9));
_update_current_and_check( 10, 920, 6, 80, __LINE__);
_update_current_and_check( 10, 920, 7, 60, __LINE__);
_scheduler.unready(_context(6));
_scheduler.unready(_context(7));
@ -649,7 +650,7 @@ Scheduler_test::Main::Main(Env &env)
_update_current_and_check( 10, 970, 3, 30, __LINE__);
_scheduler.unready(_context(3));
_update_current_and_check( 10, 980, 1, 20, __LINE__);
_update_current_and_check( 10, 980, 5, 20, __LINE__);
_set_context_ready_and_check(3, true, __LINE__);
_update_current_and_check( 10, 990, 3, 10, __LINE__);
@ -684,9 +685,9 @@ Scheduler_test::Main::Main(Env &env)
_scheduler.unready(_context(5));
_update_current_and_check( 10, 200, 9, 30, __LINE__);
_set_context_ready_and_check(6, false, __LINE__);
_set_context_ready_and_check(6, true, __LINE__);
_construct_context(4, __LINE__);
_update_current_and_check( 10, 210, 9, 20, __LINE__);
_update_current_and_check( 10, 210, 6, 100, __LINE__);
_destroy_context(5, __LINE__);
_set_context_ready_and_check(4, true, __LINE__);
@ -695,7 +696,7 @@ Scheduler_test::Main::Main(Env &env)
_update_current_and_check( 10, 320, 4, 90, __LINE__);
_destroy_context(4, __LINE__);
_update_current_and_check(200, 410, 9, 10, __LINE__);
_update_current_and_check(200, 410, 6, 90, __LINE__);
_construct_context(5, __LINE__);
_scheduler.ready(_context(5));
@ -703,7 +704,7 @@ Scheduler_test::Main::Main(Env &env)
_construct_context(4, __LINE__);
_scheduler.yield();
_update_current_and_check( 10, 430, 6, 100, __LINE__);
_update_current_and_check( 10, 430, 5, 100, __LINE__);
_set_context_ready_and_check(4, true, __LINE__);
_scheduler.yield();
@ -711,14 +712,14 @@ Scheduler_test::Main::Main(Env &env)
_destroy_context(6, __LINE__);
_scheduler.yield();
_update_current_and_check( 20, 500, 5, 100, __LINE__);
_update_current_and_check( 20, 500, 4, 100, __LINE__);
_destroy_context(9, __LINE__);
_update_current_and_check(200, 600, 4, 100, __LINE__);
_update_current_and_check(200, 600, 5, 100, __LINE__);
_construct_context(7, __LINE__);
_construct_context(8, __LINE__);
_update_current_and_check(200, 700, 5, 100, __LINE__);
_update_current_and_check(200, 700, 4, 100, __LINE__);
_set_context_ready_and_check(1, true, __LINE__);
_set_context_ready_and_check(7, true, __LINE__);
@ -776,16 +777,16 @@ Scheduler_test::Main::Main(Env &env)
_scheduler.unready(_context(1));
_update_current_and_check(100, 270, 4, 90, __LINE__);
_update_current_and_check(100, 360, 4, 100, __LINE__);
_update_current_and_check(100, 360, 4, 90, __LINE__);
_scheduler.quota(_context(1), 110);
_update_current_and_check( 10, 370, 4, 90, __LINE__);
_update_current_and_check( 10, 370, 4, 80, __LINE__);
_scheduler.quota(_context(1), 120);
_update_current_and_check( 20, 390, 4, 70, __LINE__);
_update_current_and_check( 20, 390, 4, 60, __LINE__);
_scheduler.quota(_context(4), 210);
_update_current_and_check( 10, 400, 4, 60, __LINE__);
_update_current_and_check( 10, 400, 4, 50, __LINE__);
_scheduler.ready(_context(1));
_update_current_and_check( 10, 410, 1, 110, __LINE__);
@ -813,43 +814,43 @@ Scheduler_test::Main::Main(Env &env)
_scheduler.unready(_context(2));
_scheduler.quota(_context(4), 80);
_update_current_and_check( 70, 630, 8, 100, __LINE__);
_update_current_and_check( 50, 680, 8, 50, __LINE__);
_update_current_and_check( 70, 630, 8, 60, __LINE__);
_update_current_and_check( 50, 680, 8, 10, __LINE__);
_scheduler.unready(_context(8));
_update_current_and_check( 10, 690, 4, 50, __LINE__);
_update_current_and_check( 10, 690, 4, 40, __LINE__);
_construct_context(3, __LINE__);
_update_current_and_check( 30, 720, 4, 20, __LINE__);
_update_current_and_check( 30, 720, 4, 10, __LINE__);
_scheduler.quota(_context(3), 210);
_scheduler.yield();
_scheduler.unready(_context(4));
_update_current_and_check( 20, 740, 5, 90, __LINE__);
_update_current_and_check( 20, 730, 9, 100, __LINE__);
_scheduler.unready(_context(9));
_set_context_ready_and_check(4, false, __LINE__);
_update_current_and_check( 50, 790, 5, 40, __LINE__);
_set_context_ready_and_check(4, true, __LINE__);
_update_current_and_check( 60, 790, 4, 100, __LINE__);
_set_context_ready_and_check(2, true, __LINE__);
_update_current_and_check( 40, 830, 2, 50, __LINE__);
_update_current_and_check( 60, 880, 2, 100, __LINE__);
_update_current_and_check( 10, 890, 2, 90, __LINE__);
_update_current_and_check( 60, 880, 2, 90, __LINE__);
_update_current_and_check( 10, 890, 2, 80, __LINE__);
_scheduler.yield();
_set_context_ready_and_check(9, true, __LINE__);
_update_current_and_check( 60, 950, 6, 50, __LINE__);
_update_current_and_check( 60, 950, 9, 40, __LINE__);
_scheduler.unready(_context(6));
_update_current_and_check( 20, 970, 1, 30, __LINE__);
_update_current_and_check( 20, 970, 9, 20, __LINE__);
_scheduler.yield();
_scheduler.ready(_context(8));
_update_current_and_check( 10, 980, 4, 20, __LINE__);
_update_current_and_check( 10, 980, 8, 20, __LINE__);
_scheduler.unready(_context(8));
_scheduler.yield();
_update_current_and_check( 10, 990, 5, 10, __LINE__);
_update_current_and_check( 10, 990, 4, 10, __LINE__);
_scheduler.yield();
_update_current_and_check( 20, 0, 9, 40, __LINE__);
@ -896,9 +897,9 @@ Scheduler_test::Main::Main(Env &env)
_destroy_context(3, __LINE__);
_update_current_and_check( 90, 840, 9, 40, __LINE__);
_update_current_and_check( 60, 880, 2, 100, __LINE__);
_update_current_and_check(120, 980, 1, 20, __LINE__);
_update_current_and_check( 80, 0, 9, 40, __LINE__);
_update_current_and_check( 60, 880, 5, 20, __LINE__);
_update_current_and_check(120, 900, 1, 100, __LINE__);
_update_current_and_check(100, 0, 9, 40, __LINE__);
_env.parent().exit(0);