scheduler: Let ThreadData::ShouldRebalance() choose the actual core
Currently, ThreadData::ShouldRebalance() (and mode specific functions it calls) only decides whether to migrate thread to another core or not. However, in most cases it actually needs to find the best candidate for new core so it could as well return that information.
This commit is contained in:
@@ -72,18 +72,19 @@ choose_core(const ThreadData* /* threadData */)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static CoreEntry*
|
||||||
should_rebalance(const ThreadData* threadData)
|
rebalance(const ThreadData* threadData)
|
||||||
{
|
{
|
||||||
SCHEDULER_ENTER_FUNCTION();
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
|
||||||
int32 coreLoad = threadData->Core()->GetLoad();
|
CoreEntry* core = threadData->Core();
|
||||||
int32 threadLoad = threadData->GetLoad() / threadData->Core()->CPUCount();
|
int32 coreLoad = core->GetLoad();
|
||||||
|
int32 threadLoad = threadData->GetLoad() / core->CPUCount();
|
||||||
|
|
||||||
// If the thread produces more than 50% of the load, leave it here. In
|
// If the thread produces more than 50% of the load, leave it here. In
|
||||||
// such situation it is better to move other threads away.
|
// such situation it is better to move other threads away.
|
||||||
if (threadLoad >= coreLoad / 2)
|
if (threadLoad >= coreLoad / 2)
|
||||||
return false;
|
return core;
|
||||||
|
|
||||||
// Get the least loaded core.
|
// Get the least loaded core.
|
||||||
ReadSpinLocker coreLocker(gCoreHeapsLock);
|
ReadSpinLocker coreLocker(gCoreHeapsLock);
|
||||||
@@ -93,18 +94,18 @@ should_rebalance(const ThreadData* threadData)
|
|||||||
coreLocker.Unlock();
|
coreLocker.Unlock();
|
||||||
ASSERT(other != NULL);
|
ASSERT(other != NULL);
|
||||||
|
|
||||||
if (other == threadData->Core())
|
if (other == core)
|
||||||
return false;
|
return core;
|
||||||
|
|
||||||
// If there are idle cores give them some work unless that will cause
|
// If there are idle cores give them some work unless that will cause
|
||||||
// the current core to become idle.
|
// the current core to become idle.
|
||||||
int32 coreNewLoad = coreLoad - threadLoad;
|
int32 coreNewLoad = coreLoad - threadLoad;
|
||||||
if (other->GetLoad() == 0 && coreNewLoad != 0)
|
if (other->GetLoad() == 0 && coreNewLoad != 0)
|
||||||
return true;
|
return other;
|
||||||
|
|
||||||
// Attempt to keep load balanced.
|
// Attempt to keep load balanced.
|
||||||
int32 otherNewLoad = other->GetLoad() + threadLoad;
|
int32 otherNewLoad = other->GetLoad() + threadLoad;
|
||||||
return coreNewLoad - otherNewLoad >= kLoadDifference;
|
return coreNewLoad - otherNewLoad >= kLoadDifference ? other : core;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -168,7 +169,7 @@ scheduler_mode_operations gSchedulerLowLatencyMode = {
|
|||||||
set_cpu_enabled,
|
set_cpu_enabled,
|
||||||
has_cache_expired,
|
has_cache_expired,
|
||||||
choose_core,
|
choose_core,
|
||||||
should_rebalance,
|
rebalance,
|
||||||
rebalance_irqs,
|
rebalance_irqs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -114,8 +114,8 @@ choose_core(const ThreadData* threadData)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool
|
static CoreEntry*
|
||||||
should_rebalance(const ThreadData* threadData)
|
rebalance(const ThreadData* threadData)
|
||||||
{
|
{
|
||||||
SCHEDULER_ENTER_FUNCTION();
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
|
||||||
@@ -128,15 +128,15 @@ should_rebalance(const ThreadData* threadData)
|
|||||||
if (coreLoad > kHighLoad) {
|
if (coreLoad > kHighLoad) {
|
||||||
if (sSmallTaskCore == core) {
|
if (sSmallTaskCore == core) {
|
||||||
sSmallTaskCore = NULL;
|
sSmallTaskCore = NULL;
|
||||||
choose_small_task_core();
|
CoreEntry* smallTaskCore = choose_small_task_core();
|
||||||
|
|
||||||
if (threadLoad > coreLoad / 3)
|
if (threadLoad > coreLoad / 3)
|
||||||
return false;
|
return core;
|
||||||
return coreLoad > kVeryHighLoad;
|
return coreLoad > kVeryHighLoad ? smallTaskCore : core;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (threadLoad >= coreLoad / 2)
|
if (threadLoad >= coreLoad / 2)
|
||||||
return false;
|
return core;
|
||||||
|
|
||||||
ReadSpinLocker coreLocker(gCoreHeapsLock);
|
ReadSpinLocker coreLocker(gCoreHeapsLock);
|
||||||
CoreEntry* other = gCoreLoadHeap.PeekMaximum();
|
CoreEntry* other = gCoreLoadHeap.PeekMaximum();
|
||||||
@@ -147,17 +147,17 @@ should_rebalance(const ThreadData* threadData)
|
|||||||
|
|
||||||
int32 coreNewLoad = coreLoad - threadLoad;
|
int32 coreNewLoad = coreLoad - threadLoad;
|
||||||
int32 otherNewLoad = other->GetLoad() + threadLoad;
|
int32 otherNewLoad = other->GetLoad() + threadLoad;
|
||||||
return coreNewLoad - otherNewLoad >= kLoadDifference / 2;
|
return coreNewLoad - otherNewLoad >= kLoadDifference / 2 ? other : core;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coreLoad >= kMediumLoad)
|
if (coreLoad >= kMediumLoad)
|
||||||
return false;
|
return core;
|
||||||
|
|
||||||
CoreEntry* smallTaskCore = choose_small_task_core();
|
CoreEntry* smallTaskCore = choose_small_task_core();
|
||||||
if (smallTaskCore == NULL)
|
if (smallTaskCore == NULL)
|
||||||
return false;
|
return core;
|
||||||
return smallTaskCore != core
|
return smallTaskCore->GetLoad() + threadLoad < kHighLoad
|
||||||
&& smallTaskCore->GetLoad() + threadLoad < kHighLoad;
|
? smallTaskCore : core;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -249,7 +249,7 @@ scheduler_mode_operations gSchedulerPowerSavingMode = {
|
|||||||
set_cpu_enabled,
|
set_cpu_enabled,
|
||||||
has_cache_expired,
|
has_cache_expired,
|
||||||
choose_core,
|
choose_core,
|
||||||
should_rebalance,
|
rebalance,
|
||||||
rebalance_irqs,
|
rebalance_irqs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -111,9 +111,8 @@ enqueue(Thread* thread, bool newOne)
|
|||||||
} else if (gSingleCore)
|
} else if (gSingleCore)
|
||||||
targetCore = &gCoreEntries[0];
|
targetCore = &gCoreEntries[0];
|
||||||
else if (threadData->Core() != NULL
|
else if (threadData->Core() != NULL
|
||||||
&& (!newOne || !threadData->HasCacheExpired())
|
&& (!newOne || !threadData->HasCacheExpired())) {
|
||||||
&& !threadData->ShouldRebalance()) {
|
targetCore = threadData->Rebalance();
|
||||||
targetCore = threadData->Core();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool rescheduleNeeded = threadData->ChooseCoreAndCPU(targetCore, targetCPU);
|
bool rescheduleNeeded = threadData->ChooseCoreAndCPU(targetCore, targetCPU);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ struct scheduler_mode_operations {
|
|||||||
const Scheduler::ThreadData* threadData);
|
const Scheduler::ThreadData* threadData);
|
||||||
Scheduler::CoreEntry* (*choose_core)(
|
Scheduler::CoreEntry* (*choose_core)(
|
||||||
const Scheduler::ThreadData* threadData);
|
const Scheduler::ThreadData* threadData);
|
||||||
bool (*should_rebalance)(
|
Scheduler::CoreEntry* (*rebalance)(
|
||||||
const Scheduler::ThreadData* threadData);
|
const Scheduler::ThreadData* threadData);
|
||||||
void (*rebalance_irqs)(bool idle);
|
void (*rebalance_irqs)(bool idle);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ public:
|
|||||||
inline bool IsIdle() const;
|
inline bool IsIdle() const;
|
||||||
|
|
||||||
inline bool HasCacheExpired() const;
|
inline bool HasCacheExpired() const;
|
||||||
inline bool ShouldRebalance() const;
|
inline CoreEntry* Rebalance() const;
|
||||||
|
|
||||||
inline int32 GetEffectivePriority() const;
|
inline int32 GetEffectivePriority() const;
|
||||||
|
|
||||||
@@ -176,13 +176,13 @@ ThreadData::HasCacheExpired() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool
|
inline CoreEntry*
|
||||||
ThreadData::ShouldRebalance() const
|
ThreadData::Rebalance() const
|
||||||
{
|
{
|
||||||
SCHEDULER_ENTER_FUNCTION();
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
|
||||||
ASSERT(!gSingleCore);
|
ASSERT(!gSingleCore);
|
||||||
return gCurrentMode->should_rebalance(this);
|
return gCurrentMode->rebalance(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user