scheduler_affine: Try not to get overloaded by small tasks

This commit is contained in:
Pawel Dziepak
2013-10-23 21:32:27 +02:00
parent 2df11d8a80
commit 453bf75027
@@ -50,8 +50,8 @@ const bigtime_t kMaxThreadQuantum = 10000;
const bigtime_t kCacheExpire = 100000; const bigtime_t kCacheExpire = 100000;
static bigtime_t sDisableSmallTaskPacking; static int sDisableSmallTaskPacking;
static int32 sSmallTaskCore = -1; static int32 sSmallTaskCore;
static scheduler_mode sSchedulerMode; static scheduler_mode sSchedulerMode;
@@ -512,9 +512,6 @@ affine_update_thread_heaps(int32 core)
if (newKey > thread_max_threads()) { if (newKey > thread_max_threads()) {
if (oldKey <= thread_max_threads()) { if (oldKey <= thread_max_threads()) {
if (sSmallTaskCore == entry->fCoreID)
sSmallTaskCore = -1;
sCoreThreadHeap->ModifyKey(entry, -1); sCoreThreadHeap->ModifyKey(entry, -1);
ASSERT(sCoreThreadHeap->PeekMinimum() == entry); ASSERT(sCoreThreadHeap->PeekMinimum() == entry);
sCoreThreadHeap->RemoveMinimum(); sCoreThreadHeap->RemoveMinimum();
@@ -535,6 +532,18 @@ affine_update_thread_heaps(int32 core)
} }
static inline void
affine_disable_small_task_packing(void)
{
ASSERT(sDisableSmallTaskPacking == 0);
ASSERT(sSmallTaskCore == sCPUToCore[smp_get_current_cpu()]);
ASSERT(sAssignedThreads > 0);
sDisableSmallTaskPacking = sAssignedThreads * 64;
sSmallTaskCore = -1;
}
static inline void static inline void
affine_increase_penalty(Thread* thread) affine_increase_penalty(Thread* thread)
{ {
@@ -549,16 +558,26 @@ affine_increase_penalty(Thread* thread)
int32 oldPenalty = schedulerThreadData->priority_penalty++; int32 oldPenalty = schedulerThreadData->priority_penalty++;
ASSERT(thread->priority - oldPenalty >= B_LOWEST_ACTIVE_PRIORITY); ASSERT(thread->priority - oldPenalty >= B_LOWEST_ACTIVE_PRIORITY);
const int kMinimalPriority = affine_get_minimal_priority(thread); const int kMinimalPriority = affine_get_minimal_priority(thread);
if (thread->priority - oldPenalty <= kMinimalPriority) { if (thread->priority - oldPenalty <= kMinimalPriority) {
int32 core = schedulerThreadData->previous_core; int32 core = schedulerThreadData->previous_core;
ASSERT(core >= 0); ASSERT(core >= 0);
if (schedulerThreadData->additional_penalty == 0) {
int32 additionalPenalty = schedulerThreadData->additional_penalty;
if (additionalPenalty == 0) {
sCPUBoundThreads++; sCPUBoundThreads++;
sCoreEntries[core].fCPUBoundThreads++; sCoreEntries[core].fCPUBoundThreads++;
affine_update_thread_heaps(core); affine_update_thread_heaps(core);
} }
const int kSmallTaskThreshold = 50;
if (additionalPenalty > kSmallTaskThreshold) {
if (sSmallTaskCore == core)
affine_disable_small_task_packing();
}
schedulerThreadData->priority_penalty = oldPenalty; schedulerThreadData->priority_penalty = oldPenalty;
schedulerThreadData->additional_penalty++; schedulerThreadData->additional_penalty++;
} }
@@ -573,8 +592,22 @@ affine_cancel_penalty(Thread* thread)
if (schedulerThreadData->priority_penalty != 0) if (schedulerThreadData->priority_penalty != 0)
TRACE("cancelling thread %ld penalty\n", thread->id); TRACE("cancelling thread %ld penalty\n", thread->id);
schedulerThreadData->priority_penalty = 0; switch (sSchedulerMode) {
schedulerThreadData->additional_penalty = 0; case SCHEDULER_MODE_PERFORMANCE:
schedulerThreadData->additional_penalty = 0;
schedulerThreadData->priority_penalty = 0;
break;
case SCHEDULER_MODE_POWER_SAVING:
if (schedulerThreadData->additional_penalty != 0)
schedulerThreadData->additional_penalty /= 2;
else if (schedulerThreadData->priority_penalty != 0)
schedulerThreadData->priority_penalty--;
break;
default:
break;
}
} }
@@ -688,15 +721,26 @@ affine_choose_core_performance(Thread* thread)
} }
static inline bool
affine_is_task_small(Thread* thread)
{
int32 priority = affine_get_effective_priority(thread);
int32 penalty = thread->scheduler_data->priority_penalty;
return penalty == 0 || priority >= B_DISPLAY_PRIORITY;
}
static int32 static int32
affine_choose_core_power_saving(Thread* thread) affine_choose_core_power_saving(Thread* thread)
{ {
CoreEntry* entry; CoreEntry* entry;
int32 priority = affine_get_effective_priority(thread); int32 priority = affine_get_effective_priority(thread);
int32 penalty = thread->scheduler_data->priority_penalty;
if (!sDisableSmallTaskPacking && penalty == 0 if (sDisableSmallTaskPacking > 0)
sDisableSmallTaskPacking--;
if (!sDisableSmallTaskPacking && affine_is_task_small(thread)
&& sCoreThreadHeap->PeekMaximum() != NULL) { && sCoreThreadHeap->PeekMaximum() != NULL) {
// try to pack all threads on one core // try to pack all threads on one core
if (sSmallTaskCore < 0) if (sSmallTaskCore < 0)
@@ -772,15 +816,27 @@ affine_should_rebalance(Thread* thread)
} }
} }
int32 threadsAboveAverage = coreEntry->fThreads - averageThread;
// All cores try to give us small tasks, check whether we have enough.
const int kSmallTaskCountThreshold = 5;
if (sDisableSmallTaskPacking == 0 && sSmallTaskCore == coreEntry->fCoreID) {
if (threadsAboveAverage > kSmallTaskCountThreshold) {
if (!affine_is_task_small(thread))
return true;
} else if (threadsAboveAverage > 2 * kSmallTaskCountThreshold) {
affine_disable_small_task_packing();
}
}
// Try our luck at small task packing. // Try our luck at small task packing.
int32 penalty = schedulerThreadData->priority_penalty; if (sDisableSmallTaskPacking == 0 && affine_is_task_small(thread))
if (!sDisableSmallTaskPacking && penalty == 0)
return sSmallTaskCore != coreEntry->fCoreID; return sSmallTaskCore != coreEntry->fCoreID;
// No cpu bound threads - the situation is quite good. Make sure it // No cpu bound threads - the situation is quite good. Make sure it
// won't get much worse... // won't get much worse...
const int32 kBalanceThreshold = 3; const int32 kBalanceThreshold = 3;
return coreEntry->fThreads - averageThread > kBalanceThreshold; return threadsAboveAverage > kBalanceThreshold;
} }
@@ -1340,12 +1396,14 @@ affine_set_operation_mode(scheduler_mode mode)
sSchedulerMode = mode; sSchedulerMode = mode;
switch (mode) { switch (mode) {
case SCHEDULER_MODE_PERFORMANCE: case SCHEDULER_MODE_PERFORMANCE:
sDisableSmallTaskPacking = true; sDisableSmallTaskPacking = -1;
sSmallTaskCore = -1;
sChooseCore = affine_choose_core_performance; sChooseCore = affine_choose_core_performance;
break; break;
case SCHEDULER_MODE_POWER_SAVING: case SCHEDULER_MODE_POWER_SAVING:
sDisableSmallTaskPacking = false; sDisableSmallTaskPacking = 0;
sSmallTaskCore = -1;
sChooseCore = affine_choose_core_power_saving; sChooseCore = affine_choose_core_power_saving;
break; break;
@@ -1481,8 +1539,7 @@ scheduler_affine_init()
sCoreEntries = new CoreEntry[coreCount]; sCoreEntries = new CoreEntry[coreCount];
if (sCoreEntries == NULL) if (sCoreEntries == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
ArrayDeleter<CoreEntry> coreEntriesDeleter( ArrayDeleter<CoreEntry> coreEntriesDeleter(sCoreEntries);
sCoreEntries);
sCorePriorityHeap = new AffineCorePriorityHeap(coreCount); sCorePriorityHeap = new AffineCorePriorityHeap(coreCount);
if (sCorePriorityHeap == NULL) if (sCorePriorityHeap == NULL)