kernel/scheduler: Properly handle thread masks not being set.

There was a missing case in reschedule(). Also fix a copy/paste
error in the power_saving logic.

This also slightly optimizes things by having an unset CPU mask
turn into a boolean and be processed separately, avoiding
loops and masks entirely in that case.

Have CPU masks be unset by default for new threads, while at it.

Change-Id: Ic5d000a72839448a2d025cfc99de1ed49c841852
Reviewed-on: https://review.haiku-os.org/c/haiku/+/7900
Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
Augustin Cavalier
2024-07-25 21:29:52 +00:00
committed by waddlesplash
parent 05c46731b8
commit 37df18e183
5 changed files with 47 additions and 48 deletions
+10 -14
View File
@@ -57,15 +57,13 @@ choose_core(const ThreadData* threadData)
int32 index = 0;
CPUSet mask = threadData->GetCPUMask();
if (mask.IsEmpty()) {
// ignore when empty
mask.SetAll();
}
const bool useMask = !mask.IsEmpty();
CoreEntry* core = NULL;
if (package != NULL) {
do {
core = package->GetIdleCore(index++);
} while (core != NULL && !core->CPUMask().Matches(mask));
} while (useMask && core != NULL && !core->CPUMask().Matches(mask));
}
if (core == NULL) {
ReadSpinLocker coreLocker(gCoreHeapsLock);
@@ -73,12 +71,12 @@ choose_core(const ThreadData* threadData)
// no idle cores, use least occupied core
do {
core = gCoreLoadHeap.PeekMinimum(index++);
} while (core != NULL && !core->CPUMask().Matches(mask));
} while (useMask && core != NULL && !core->CPUMask().Matches(mask));
if (core == NULL) {
index = 0;
do {
core = gCoreHighLoadHeap.PeekMinimum(index++);
} while (core != NULL && !core->CPUMask().Matches(mask));
} while (useMask && core != NULL && !core->CPUMask().Matches(mask));
}
}
@@ -98,23 +96,21 @@ rebalance(const ThreadData* threadData)
// Get the least loaded core.
ReadSpinLocker coreLocker(gCoreHeapsLock);
CPUSet mask = threadData->GetCPUMask();
if (mask.IsEmpty()) {
// ignore when empty
mask.SetAll();
}
const bool useMask = !mask.IsEmpty();
int32 index = 0;
CoreEntry* other;
do {
other = gCoreLoadHeap.PeekMinimum(index++);
if (other != NULL && other->CPUMask().IsEmpty())
if (other != NULL && (useMask && other->CPUMask().IsEmpty()))
panic("other->CPUMask().IsEmpty()\n");
} while (other != NULL && !other->CPUMask().Matches(mask));
} while (useMask && other != NULL && !other->CPUMask().Matches(mask));
if (other == NULL) {
index = 0;
do {
other = gCoreHighLoadHeap.PeekMinimum(index++);
} while (other != NULL && !other->CPUMask().Matches(mask));
} while (useMask && other != NULL && !other->CPUMask().Matches(mask));
}
coreLocker.Unlock();
ASSERT(other != NULL);
+11 -16
View File
@@ -89,14 +89,11 @@ choose_core(const ThreadData* threadData)
CoreEntry* core = NULL;
CPUSet mask = threadData->GetCPUMask();
if (mask.IsEmpty()) {
// ignore when empty
mask.SetAll();
}
const bool useMask = !mask.IsEmpty();
// try to pack all threads on one core
core = choose_small_task_core();
if (core != NULL && !core->CPUMask().Matches(mask))
if (core != NULL && (useMask && !core->CPUMask().Matches(mask)))
core = NULL;
if (core == NULL || core->GetLoad() + threadData->GetLoad() >= kHighLoad) {
@@ -106,12 +103,12 @@ choose_core(const ThreadData* threadData)
int32 index = 0;
do {
core = gCoreLoadHeap.PeekMinimum(index++);
} while (core != NULL && !core->CPUMask().Matches(mask));
} while (useMask && core != NULL && !core->CPUMask().Matches(mask));
if (core == NULL) {
coreLocker.Unlock();
core = choose_idle_core();
if (!core->CPUMask().Matches(mask))
if (useMask && !core->CPUMask().Matches(mask))
core = NULL;
if (core == NULL) {
@@ -119,7 +116,7 @@ choose_core(const ThreadData* threadData)
index = 0;
do {
core = gCoreHighLoadHeap.PeekMinimum(index++);
} while (core != NULL && !core->CPUMask().Matches(mask));
} while (useMask && core != NULL && !core->CPUMask().Matches(mask));
}
}
}
@@ -137,10 +134,8 @@ rebalance(const ThreadData* threadData)
ASSERT(!gSingleCore);
CPUSet mask = threadData->GetCPUMask();
if (mask.IsEmpty()) {
// ignore when empty
mask.SetAll();
}
const bool useMask = !mask.IsEmpty();
CoreEntry* core = threadData->Core();
int32 coreLoad = core->GetLoad();
@@ -151,7 +146,7 @@ rebalance(const ThreadData* threadData)
CoreEntry* smallTaskCore = choose_small_task_core();
if (threadLoad > coreLoad / 3 || smallTaskCore == NULL
|| !smallTaskCore->CPUMask().Matches(mask)) {
|| (useMask && !smallTaskCore->CPUMask().Matches(mask))) {
return core;
}
return coreLoad > kVeryHighLoad ? smallTaskCore : core;
@@ -165,12 +160,12 @@ rebalance(const ThreadData* threadData)
int32 index = 0;
do {
other = gCoreLoadHeap.PeekMaximum(index++);
} while (other != NULL && !core->CPUMask().Matches(mask));
} while (useMask && other != NULL && !other->CPUMask().Matches(mask));
if (other == NULL) {
index = 0;
do {
other = gCoreHighLoadHeap.PeekMinimum(index++);
} while (other != NULL && !core->CPUMask().Matches(mask));
} while (useMask && other != NULL && !other->CPUMask().Matches(mask));
}
coreLocker.Unlock();
ASSERT(other != NULL);
@@ -184,7 +179,7 @@ rebalance(const ThreadData* threadData)
return core;
CoreEntry* smallTaskCore = choose_small_task_core();
if (smallTaskCore == NULL || !smallTaskCore->CPUMask().Matches(mask))
if (smallTaskCore == NULL || (useMask && !smallTaskCore->CPUMask().Matches(mask)))
return core;
return smallTaskCore->GetLoad() + threadLoad < kHighLoad
? smallTaskCore : core;
+16 -5
View File
@@ -329,6 +329,9 @@ reschedule(int32 nextState)
Thread* oldThread = thread_get_current_thread();
ThreadData* oldThreadData = oldThread->scheduler_data;
CPUSet oldThreadMask;
bool useOldThreadMask, fetchedOldThreadMask = false;
oldThreadData->StopCPUTime();
SchedulerModeLocker modeLocker;
@@ -348,7 +351,11 @@ reschedule(int32 nextState)
case B_THREAD_READY:
enqueueOldThread = true;
if (!oldThreadData->IsIdle() && oldThreadData->GetCPUMask().GetBit(thisCPU)) {
oldThreadMask = oldThreadData->GetCPUMask();
useOldThreadMask = !oldThreadMask.IsEmpty();
fetchedOldThreadMask = true;
if (!oldThreadData->IsIdle() && (!useOldThreadMask || oldThreadMask.GetBit(thisCPU))) {
oldThreadData->Continues();
if (oldThreadData->HasQuantumEnded(oldThread->cpu->preempted,
oldThread->has_yielded)) {
@@ -394,15 +401,19 @@ reschedule(int32 nextState)
} else
nextThreadData = oldThreadData;
} else {
CPUSet mask = oldThreadData->GetCPUMask();
if (mask.IsEmpty())
mask.SetAll();
bool oldThreadShouldMigrate = !mask.GetBit(thisCPU);
if (!fetchedOldThreadMask) {
oldThreadMask = oldThreadData->GetCPUMask();
useOldThreadMask = !oldThreadMask.IsEmpty();
fetchedOldThreadMask = true;
}
bool oldThreadShouldMigrate = useOldThreadMask && !oldThreadMask.GetBit(thisCPU);
if (oldThreadShouldMigrate)
enqueueOldThread = false;
nextThreadData
= cpu->ChooseNextThread(enqueueOldThread ? oldThreadData : NULL,
putOldThreadAtBack);
if (oldThreadShouldMigrate) {
enqueue(oldThread, true);
// replace with the idle thread, if no other thread could be found
@@ -60,12 +60,11 @@ ThreadData::_ChooseCPU(CoreEntry* core, bool& rescheduleNeeded) const
int32 threadPriority = GetEffectivePriority();
CPUSet mask = GetCPUMask();
if (mask.IsEmpty())
mask.SetAll();
ASSERT(mask.Matches(core->CPUMask()));
const bool useMask = !mask.IsEmpty();
ASSERT(!useMask || mask.Matches(core->CPUMask()));
if (fThread->previous_cpu != NULL && !fThread->previous_cpu->disabled
&& mask.GetBit(fThread->previous_cpu->cpu_num)) {
&& (!useMask || mask.GetBit(fThread->previous_cpu->cpu_num))) {
CPUEntry* previousCPU
= CPUEntry::GetCPU(fThread->previous_cpu->cpu_num);
if (previousCPU->Core() == core) {
@@ -83,7 +82,7 @@ ThreadData::_ChooseCPU(CoreEntry* core, bool& rescheduleNeeded) const
CPUEntry* cpu;
do {
cpu = core->CPUHeap()->PeekRoot(index++);
} while (cpu != NULL && !mask.GetBit(cpu->ID()));
} while (useMask && cpu != NULL && !mask.GetBit(cpu->ID()));
ASSERT(cpu != NULL);
if (CPUPriorityHeap::GetKey(cpu) < threadPriority) {
@@ -166,9 +165,12 @@ ThreadData::ChooseCoreAndCPU(CoreEntry*& targetCore, CPUEntry*& targetCPU)
bool rescheduleNeeded = false;
if (targetCore != NULL && !targetCore->CPUMask().Matches(GetCPUMask()))
CPUSet mask = GetCPUMask();
const bool useMask = !mask.IsEmpty();
if (targetCore != NULL && (useMask && !targetCore->CPUMask().Matches(mask)))
targetCore = NULL;
if (targetCPU != NULL && !GetCPUMask().GetBit(targetCPU->ID()))
if (targetCPU != NULL && (useMask && !mask.GetBit(targetCPU->ID())))
targetCPU = NULL;
if (targetCore == NULL && targetCPU != NULL)
@@ -177,10 +179,7 @@ ThreadData::ChooseCoreAndCPU(CoreEntry*& targetCore, CPUEntry*& targetCPU)
targetCPU = _ChooseCPU(targetCore, rescheduleNeeded);
else if (targetCore == NULL && targetCPU == NULL) {
targetCore = _ChooseCore();
CPUSet mask = GetCPUMask();
if (mask.IsEmpty())
mask.SetAll();
ASSERT(mask.Matches(targetCore->CPUMask()));
ASSERT(!useMask || mask.Matches(targetCore->CPUMask()));
targetCPU = _ChooseCPU(targetCore, rescheduleNeeded);
}
-2
View File
@@ -204,7 +204,6 @@ Thread::Thread(const char* name, thread_id threadID, struct cpu_ent* cpu)
{
id = threadID >= 0 ? threadID : allocate_thread_id();
visible = false;
cpumask.SetAll();
// init locks
char lockName[32];
@@ -2755,7 +2754,6 @@ thread_init(kernel_args *args)
thread->team = team_get_kernel_team();
thread->priority = B_IDLE_PRIORITY;
thread->state = B_THREAD_RUNNING;
thread->cpumask.SetAll();
sprintf(name, "idle thread %" B_PRIu32 " kstack", i + 1);
thread->kernel_stack_area = find_area(name);