From fee8009184189f5aa56d759f3f9974313013fbbc Mon Sep 17 00:00:00 2001 From: Pawel Dziepak Date: Wed, 9 Oct 2013 20:13:47 +0200 Subject: [PATCH] kernel: Add another penalty for CPU bound threads Each thread has its minimal priority that depends on the static priority. However, it is still able to starve threads with even lower priority (e.g. CPU bound threads with lower static priority). To prevent this another penalty is introduced. When the minimal priority is reached penalty (count mod minimal_priority) is added, where count is the number of time slices since the thread reached its minimal priority. This prevents starvation of lower priorirt threads (since all CPU bound threads may have their priority temporaily reduced to 1) but preserves relation between static priorities - when there are two CPU bound threads the one with higher static priority would get more CPU time. --- headers/private/kernel/kscheduler.h | 2 +- .../kernel/scheduler/scheduler_simple.cpp | 46 +++++++++++++++++-- src/system/kernel/thread.cpp | 2 +- 3 files changed, 43 insertions(+), 7 deletions(-) diff --git a/headers/private/kernel/kscheduler.h b/headers/private/kernel/kscheduler.h index 18fd30cca3..2c399b1b50 100644 --- a/headers/private/kernel/kscheduler.h +++ b/headers/private/kernel/kscheduler.h @@ -70,7 +70,7 @@ struct scheduler_ops { /*! Dumps scheduler specific thread information. */ - void (*dump_thread_data)(struct scheduler_thread_data* scheduler_data); + void (*dump_thread_data)(Thread* thread); }; extern struct scheduler_ops* gScheduler; diff --git a/src/system/kernel/scheduler/scheduler_simple.cpp b/src/system/kernel/scheduler/scheduler_simple.cpp index b428863cdb..01cbb21121 100644 --- a/src/system/kernel/scheduler/scheduler_simple.cpp +++ b/src/system/kernel/scheduler/scheduler_simple.cpp @@ -55,6 +55,7 @@ struct scheduler_thread_data { void Init(); int32 priority_penalty; + int32 additional_penalty; int32 forced_yield_count; bool lost_cpu; @@ -72,6 +73,7 @@ void scheduler_thread_data::Init() { priority_penalty = 0; + additional_penalty = 0; forced_yield_count = 0; time_left = 0; @@ -84,6 +86,28 @@ scheduler_thread_data::Init() } +static inline int +simple_get_minimal_priority(Thread* thread) +{ + return min_c(thread->priority, 25) / 5; +} + + +static inline int32 +simple_get_thread_penalty(Thread* thread) +{ + int32 penalty = thread->scheduler_data->priority_penalty; + + const int kMinimalPriority = simple_get_minimal_priority(thread); + if (kMinimalPriority > 0) { + penalty + += thread->scheduler_data->additional_penalty % kMinimalPriority; + } + + return penalty; + +} + static inline void dump_queue(SimpleRunQueue::ConstIterator& iterator) { @@ -95,7 +119,7 @@ dump_queue(SimpleRunQueue::ConstIterator& iterator) Thread* thread = iterator.Next(); kprintf("%p %-7" B_PRId32 " %-8" B_PRId32 " %-8" B_PRId32 " %s\n", thread, thread->id, thread->priority, - thread->scheduler_data->priority_penalty, thread->name); + simple_get_thread_penalty(thread), thread->name); } } } @@ -118,10 +142,21 @@ dump_run_queue(int argc, char** argv) static void -simple_dump_thread_data(scheduler_thread_data* schedulerThreadData) +simple_dump_thread_data(Thread* thread) { + scheduler_thread_data* schedulerThreadData = thread->scheduler_data; + kprintf("\tpriority_penalty:\t%" B_PRId32 "\n", schedulerThreadData->priority_penalty); + + int32 additionalPenalty = 0; + const int kMinimalPriority = simple_get_minimal_priority(thread); + if (kMinimalPriority > 0) { + additionalPenalty + = schedulerThreadData->additional_penalty % kMinimalPriority; + } + kprintf("\tadditional_penalty:\t%" B_PRId32 " (%" B_PRId32 ")\n", + additionalPenalty, schedulerThreadData->additional_penalty); kprintf("\tforced_yield_count:\t%" B_PRId32 "\n", schedulerThreadData->forced_yield_count); kprintf("\tstolen_time:\t\t%" B_PRId64 "\n", @@ -138,7 +173,7 @@ simple_get_effective_priority(Thread* thread) return thread->priority; int32 effectivePriority = thread->priority; - effectivePriority -= thread->scheduler_data->priority_penalty; + effectivePriority -= simple_get_thread_penalty(thread); ASSERT(effectivePriority < B_FIRST_REAL_TIME_PRIORITY); ASSERT(effectivePriority >= B_LOWEST_ACTIVE_PRIORITY); @@ -183,11 +218,11 @@ simple_increase_penalty(Thread* thread) int32 oldPenalty = schedulerThreadData->priority_penalty++; ASSERT(thread->priority - oldPenalty >= B_LOWEST_ACTIVE_PRIORITY); - const int kMinimalPriority - = min_c(thread->priority, 25) / 5; + const int kMinimalPriority = simple_get_minimal_priority(thread); if (thread->priority - oldPenalty <= kMinimalPriority) { schedulerThreadData->priority_penalty = oldPenalty; schedulerThreadData->forced_yield_count++; + schedulerThreadData->additional_penalty++; } } @@ -200,6 +235,7 @@ simple_cancel_penalty(Thread* thread) if (schedulerThreadData->priority_penalty != 0) TRACE("cancelling thread %ld penalty\n", thread->id); schedulerThreadData->priority_penalty = 0; + schedulerThreadData->additional_penalty = 0; schedulerThreadData->forced_yield_count = 0; } diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 66972e70bf..c069f2c800 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -1788,7 +1788,7 @@ _dump_thread_info(Thread *thread, bool shortInfo) arch_thread_dump_info(&thread->arch_info); if (gScheduler->dump_thread_data != NULL) { kprintf("scheduler data:\n"); - gScheduler->dump_thread_data(thread->scheduler_data); + gScheduler->dump_thread_data(thread); } }