CPU selection in enqueue_in_run_queue():
* Moved the CPU selection conde into a separate function. * Re-added the support for disabling CPUs, which I accidentally removed. * Got rid of idle CPU tracking. We don't need it anymore -- we iterate through all CPUs and check the priority of the running thread. * Added a kind of round-robin component to the CPU selection loop, so that we pick CPUs more evenly. And indeed, the ProcessController display is less skewed, now. There doesn't seem to be a measurable performance gain, though. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34637 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
faf3d7997f
commit
e36d79e9dc
@ -38,7 +38,8 @@
|
||||
|
||||
// The run queue. Holds the threads ready to run ordered by priority.
|
||||
static struct thread *sRunQueue = NULL;
|
||||
static cpu_mask_t sIdleCPUs = 0;
|
||||
static int32 sCPUCount = 1;
|
||||
static int32 sNextCPUForSelection = 0;
|
||||
|
||||
|
||||
static int
|
||||
@ -75,6 +76,46 @@ dump_run_queue(int argc, char **argv)
|
||||
}
|
||||
|
||||
|
||||
static int32
|
||||
select_cpu(int32 currentCPU, struct thread* thread, int32& targetPriority)
|
||||
{
|
||||
if (thread->pinned_to_cpu > 0) {
|
||||
// the thread is pinned to a specific CPU
|
||||
int32 targetCPU = thread->previous_cpu->cpu_num;
|
||||
targetPriority = gCPU[targetCPU].running_thread->priority;
|
||||
return targetCPU;
|
||||
}
|
||||
|
||||
// Choose the CPU running the lowest priority thread. Favor the current CPU
|
||||
// as it doesn't require ICI to be notified.
|
||||
int32 targetCPU = currentCPU;
|
||||
targetPriority = B_IDLE_PRIORITY;
|
||||
if (gCPU[currentCPU].disabled)
|
||||
targetCPU = -1;
|
||||
else
|
||||
targetPriority = gCPU[currentCPU].running_thread->priority;
|
||||
|
||||
int32 cpu = sNextCPUForSelection;
|
||||
for (int32 i = 0; i < sCPUCount; i++, cpu++) {
|
||||
if (cpu >= sCPUCount)
|
||||
cpu = 0;
|
||||
|
||||
if (!gCPU[cpu].disabled) {
|
||||
int32 cpuPriority = gCPU[cpu].running_thread->priority;
|
||||
if (targetCPU < 0 || cpuPriority < targetPriority) {
|
||||
targetCPU = cpu;
|
||||
targetPriority = cpuPriority;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (++sNextCPUForSelection >= sCPUCount)
|
||||
sNextCPUForSelection = 0;
|
||||
|
||||
return targetCPU;
|
||||
}
|
||||
|
||||
|
||||
/*! Enqueues the thread into the run queue.
|
||||
Note: thread lock must be held when entering this function
|
||||
*/
|
||||
@ -113,60 +154,27 @@ enqueue_in_run_queue(struct thread *thread)
|
||||
|
||||
bool reschedule = false;
|
||||
if (thread->priority != B_IDLE_PRIORITY) {
|
||||
// Select a CPU for the thread to run on. It's not certain that the
|
||||
// thread will actually run on it, but we will notify the CPU to
|
||||
// preempt the thread it is currently running, if the new thread has
|
||||
// a higher priority.
|
||||
int32 currentCPU = smp_get_current_cpu();
|
||||
int32 targetCPU = currentCPU;
|
||||
int32 targetPriority = B_IDLE_PRIORITY;
|
||||
int32 targetPriority;
|
||||
int32 targetCPU = select_cpu(currentCPU, thread, targetPriority);
|
||||
|
||||
if (thread->pinned_to_cpu > 0) {
|
||||
// the thread is pinned to a specific CPU
|
||||
targetCPU = thread->previous_cpu->cpu_num;
|
||||
targetPriority = gCPU[targetCPU].running_thread->priority;
|
||||
} else if (sIdleCPUs != 0) {
|
||||
// The thread is not pinned to any CPU and there are idle CPUs
|
||||
// -- pick the first available one.
|
||||
if (!CHECK_BIT(sIdleCPUs, currentCPU)) {
|
||||
for (int32 i = 0; i < B_MAX_CPU_COUNT; i++) {
|
||||
if (CHECK_BIT(sIdleCPUs, i)) {
|
||||
targetCPU = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// No idle CPUs -- choose the CPU running the lowest priority
|
||||
// thread. Favor the current CPU as it doesn't require ICI to be
|
||||
// notified.
|
||||
targetPriority = gCPU[currentCPU].running_thread->priority;
|
||||
int32 cpuCount = smp_get_num_cpus();
|
||||
for (int32 i = 0; i < cpuCount; i++) {
|
||||
struct thread* runningThread = gCPU[i].running_thread;
|
||||
if (runningThread->priority < targetPriority) {
|
||||
targetPriority = runningThread->priority;
|
||||
targetCPU = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the (potential) target CPU, if appropriate.
|
||||
cpu_mask_t idleBit = 1 << targetCPU;
|
||||
if ((sIdleCPUs & idleBit) != 0) {
|
||||
// The target CPU is idle. Clear its idle bit to avoid it from
|
||||
// being picked by the next
|
||||
sIdleCPUs ^= idleBit;
|
||||
// If the target CPU runs a thread with a lower priority, tell it to
|
||||
// reschedule.
|
||||
if (thread->priority > targetPriority) {
|
||||
if (targetCPU == currentCPU) {
|
||||
reschedule = true;
|
||||
} else {
|
||||
smp_send_ici(targetCPU, SMP_MSG_RESCHEDULE_IF_IDLE, 0, 0,
|
||||
0, NULL, SMP_MSG_FLAG_ASYNC);
|
||||
}
|
||||
} else if (thread->priority > targetPriority) {
|
||||
// The target CPU is not idle, but runs a thread with a lower
|
||||
// priority. Tell it to reschedule.
|
||||
if (targetCPU == currentCPU) {
|
||||
reschedule = true;
|
||||
} else {
|
||||
smp_send_ici(targetCPU, SMP_MSG_RESCHEDULE, 0, 0, 0, NULL,
|
||||
SMP_MSG_FLAG_ASYNC);
|
||||
if (targetPriority == B_IDLE_PRIORITY) {
|
||||
smp_send_ici(targetCPU, SMP_MSG_RESCHEDULE_IF_IDLE, 0, 0,
|
||||
0, NULL, SMP_MSG_FLAG_ASYNC);
|
||||
} else {
|
||||
smp_send_ici(targetCPU, SMP_MSG_RESCHEDULE, 0, 0, 0, NULL,
|
||||
SMP_MSG_FLAG_ASYNC);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -407,13 +415,6 @@ reschedule(void)
|
||||
add_timer(quantumTimer, &reschedule_event, quantum,
|
||||
B_ONE_SHOT_RELATIVE_TIMER | B_TIMER_ACQUIRE_THREAD_LOCK);
|
||||
|
||||
// update the idle bit for this CPU in the CPU mask
|
||||
int32 cpuNum = smp_get_current_cpu();
|
||||
if (nextThread->priority == B_IDLE_PRIORITY)
|
||||
sIdleCPUs = SET_BIT(sIdleCPUs, cpuNum);
|
||||
else
|
||||
sIdleCPUs = CLEAR_BIT(sIdleCPUs, cpuNum);
|
||||
|
||||
if (nextThread != oldThread)
|
||||
context_switch(oldThread, nextThread);
|
||||
}
|
||||
@ -472,6 +473,8 @@ static scheduler_ops kSimpleSMPOps = {
|
||||
void
|
||||
scheduler_simple_smp_init()
|
||||
{
|
||||
sCPUCount = smp_get_num_cpus();
|
||||
|
||||
gScheduler = &kSimpleSMPOps;
|
||||
|
||||
add_debugger_command_etc("run_queue", &dump_run_queue,
|
||||
|
Loading…
Reference in New Issue
Block a user