scheduler: Try to pack IRQs in power saving mode
This commit is contained in:
@@ -124,19 +124,20 @@ rebalance_irqs(bool idle)
|
|||||||
CoreEntry* other = gCoreLoadHeap->PeekMinimum();
|
CoreEntry* other = gCoreLoadHeap->PeekMinimum();
|
||||||
if (other == NULL)
|
if (other == NULL)
|
||||||
other = gCoreHighLoadHeap->PeekMinimum();
|
other = gCoreHighLoadHeap->PeekMinimum();
|
||||||
|
|
||||||
|
int32 newCPU = gCPUPriorityHeaps[other->fCoreID].PeekMinimum()->fCPUNumber;
|
||||||
coreLocker.Unlock();
|
coreLocker.Unlock();
|
||||||
|
|
||||||
ASSERT(other != NULL);
|
ASSERT(other != NULL);
|
||||||
|
|
||||||
int32 thigCore = gCPUToCore[smp_get_current_cpu()];
|
int32 thisCore = gCPUToCore[smp_get_current_cpu()];
|
||||||
if (other->fCoreID == thigCore)
|
if (other->fCoreID == thisCore)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (other->fLoad + kLoadDifference >= gCoreEntries[thigCore].fLoad)
|
if (other->fLoad + kLoadDifference >= gCoreEntries[thisCore].fLoad)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
coreLocker.Lock();
|
assign_io_interrupt_to_cpu(chosen->irq, newCPU);
|
||||||
gCPUPriorityHeaps[other->fCoreID].PeekMinimum();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ has_cache_expired(Thread* thread)
|
|||||||
scheduler_thread_data* schedulerThreadData = thread->scheduler_data;
|
scheduler_thread_data* schedulerThreadData = thread->scheduler_data;
|
||||||
ASSERT(schedulerThreadData->previous_core >= 0);
|
ASSERT(schedulerThreadData->previous_core >= 0);
|
||||||
|
|
||||||
CoreEntry* coreEntry = &gCoreEntries[schedulerThreadData->previous_core];
|
|
||||||
return system_time() - schedulerThreadData->went_sleep > kCacheExpire;
|
return system_time() - schedulerThreadData->went_sleep > kCacheExpire;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,6 +148,76 @@ should_rebalance(Thread* thread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
pack_irqs(void)
|
||||||
|
{
|
||||||
|
cpu_ent* cpu = get_cpu_struct();
|
||||||
|
int32 core = gCPUToCore[cpu->cpu_num];
|
||||||
|
|
||||||
|
SpinLocker locker(cpu->irqs_lock);
|
||||||
|
while (sSmallTaskCore != core && list_get_first_item(&cpu->irqs) != NULL) {
|
||||||
|
irq_assignment* irq = (irq_assignment*)list_get_first_item(&cpu->irqs);
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
SpinLocker coreLocker(gCoreHeapsLock);
|
||||||
|
int32 newCPU
|
||||||
|
= gCPUPriorityHeaps[sSmallTaskCore].PeekMinimum()->fCPUNumber;
|
||||||
|
coreLocker.Unlock();
|
||||||
|
|
||||||
|
if (newCPU != cpu->cpu_num)
|
||||||
|
assign_io_interrupt_to_cpu(irq->irq, newCPU);
|
||||||
|
|
||||||
|
locker.Lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
rebalance_irqs(bool idle)
|
||||||
|
{
|
||||||
|
if (idle && !is_small_task_packing_enabled() && sSmallTaskCore != -1) {
|
||||||
|
pack_irqs();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idle)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cpu_ent* cpu = get_cpu_struct();
|
||||||
|
SpinLocker locker(cpu->irqs_lock);
|
||||||
|
|
||||||
|
irq_assignment* chosen = NULL;
|
||||||
|
irq_assignment* irq = (irq_assignment*)list_get_first_item(&cpu->irqs);
|
||||||
|
|
||||||
|
while (irq != NULL) {
|
||||||
|
if (chosen == NULL || chosen->load < irq->load)
|
||||||
|
chosen = irq;
|
||||||
|
irq = (irq_assignment*)list_get_next_item(&cpu->irqs, irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
if (chosen == NULL || chosen->load < kLowLoad)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SpinLocker coreLocker(gCoreHeapsLock);
|
||||||
|
CoreEntry* other = gCoreLoadHeap->PeekMinimum();
|
||||||
|
if (other == NULL)
|
||||||
|
return;
|
||||||
|
int32 newCPU = gCPUPriorityHeaps[other->fCoreID].PeekMinimum()->fCPUNumber;
|
||||||
|
coreLocker.Unlock();
|
||||||
|
|
||||||
|
int32 thisCore = gCPUToCore[smp_get_current_cpu()];
|
||||||
|
if (other->fCoreID == thisCore)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (other->fLoad + kLoadDifference >= gCoreEntries[thisCore].fLoad)
|
||||||
|
return;
|
||||||
|
|
||||||
|
assign_io_interrupt_to_cpu(chosen->irq, newCPU);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
scheduler_mode_operations gSchedulerPowerSavingMode = {
|
scheduler_mode_operations gSchedulerPowerSavingMode = {
|
||||||
"power saving",
|
"power saving",
|
||||||
|
|
||||||
@@ -158,7 +227,6 @@ scheduler_mode_operations gSchedulerPowerSavingMode = {
|
|||||||
has_cache_expired,
|
has_cache_expired,
|
||||||
choose_core,
|
choose_core,
|
||||||
should_rebalance,
|
should_rebalance,
|
||||||
NULL,
|
rebalance_irqs,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -994,14 +994,14 @@ compute_quantum(Thread* thread)
|
|||||||
|
|
||||||
|
|
||||||
static inline Thread*
|
static inline Thread*
|
||||||
choose_next_thread(int32 thigCPU, Thread* oldThread, bool putAtBack)
|
choose_next_thread(int32 thisCPU, Thread* oldThread, bool putAtBack)
|
||||||
{
|
{
|
||||||
int32 thigCore = gCPUToCore[thigCPU];
|
int32 thisCore = gCPUToCore[thisCPU];
|
||||||
|
|
||||||
SpinLocker runQueueLocker(gCoreEntries[thigCore].fLock);
|
SpinLocker runQueueLocker(gCoreEntries[thisCore].fLock);
|
||||||
|
|
||||||
Thread* sharedThread = gRunQueues[thigCore].PeekMaximum();
|
Thread* sharedThread = gRunQueues[thisCore].PeekMaximum();
|
||||||
Thread* pinnedThread = gPinnedRunQueues[thigCPU].PeekMaximum();
|
Thread* pinnedThread = gPinnedRunQueues[thisCPU].PeekMaximum();
|
||||||
|
|
||||||
ASSERT(sharedThread != NULL || pinnedThread != NULL || oldThread != NULL);
|
ASSERT(sharedThread != NULL || pinnedThread != NULL || oldThread != NULL);
|
||||||
|
|
||||||
@@ -1027,34 +1027,34 @@ choose_next_thread(int32 thigCPU, Thread* oldThread, bool putAtBack)
|
|||||||
ASSERT(sharedThread->scheduler_data->enqueued);
|
ASSERT(sharedThread->scheduler_data->enqueued);
|
||||||
sharedThread->scheduler_data->enqueued = false;
|
sharedThread->scheduler_data->enqueued = false;
|
||||||
|
|
||||||
gRunQueues[thigCore].Remove(sharedThread);
|
gRunQueues[thisCore].Remove(sharedThread);
|
||||||
return sharedThread;
|
return sharedThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT(pinnedThread->scheduler_data->enqueued);
|
ASSERT(pinnedThread->scheduler_data->enqueued);
|
||||||
pinnedThread->scheduler_data->enqueued = false;
|
pinnedThread->scheduler_data->enqueued = false;
|
||||||
|
|
||||||
gPinnedRunQueues[thigCPU].Remove(pinnedThread);
|
gPinnedRunQueues[thisCPU].Remove(pinnedThread);
|
||||||
return pinnedThread;
|
return pinnedThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
track_cpu_activity(Thread* oldThread, Thread* nextThread, int32 thigCore)
|
track_cpu_activity(Thread* oldThread, Thread* nextThread, int32 thisCore)
|
||||||
{
|
{
|
||||||
bigtime_t now = system_time();
|
bigtime_t now = system_time();
|
||||||
bigtime_t usedTime = now - oldThread->scheduler_data->quantum_start;
|
bigtime_t usedTime = now - oldThread->scheduler_data->quantum_start;
|
||||||
|
|
||||||
if (thread_is_idle_thread(oldThread) && usedTime >= kMinimalWaitTime) {
|
if (thread_is_idle_thread(oldThread) && usedTime >= kMinimalWaitTime) {
|
||||||
atomic_set64(&gCoreEntries[thigCore].fReachedBottom,
|
atomic_set64(&gCoreEntries[thisCore].fReachedBottom,
|
||||||
now - kMinimalWaitTime);
|
now - kMinimalWaitTime);
|
||||||
atomic_set64(&gCoreEntries[thigCore].fReachedIdle,
|
atomic_set64(&gCoreEntries[thisCore].fReachedIdle,
|
||||||
now - kMinimalWaitTime);
|
now - kMinimalWaitTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_effective_priority(oldThread) == B_LOWEST_ACTIVE_PRIORITY
|
if (get_effective_priority(oldThread) == B_LOWEST_ACTIVE_PRIORITY
|
||||||
&& usedTime >= kMinimalWaitTime) {
|
&& usedTime >= kMinimalWaitTime) {
|
||||||
atomic_set64(&gCoreEntries[thigCore].fReachedBottom,
|
atomic_set64(&gCoreEntries[thisCore].fReachedBottom,
|
||||||
now - kMinimalWaitTime);
|
now - kMinimalWaitTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1067,7 +1067,7 @@ track_cpu_activity(Thread* oldThread, Thread* nextThread, int32 thigCore)
|
|||||||
oldThread->scheduler_data->measure_active_time += active;
|
oldThread->scheduler_data->measure_active_time += active;
|
||||||
|
|
||||||
gCPUEntries[smp_get_current_cpu()].fMeasureActiveTime += active;
|
gCPUEntries[smp_get_current_cpu()].fMeasureActiveTime += active;
|
||||||
atomic_add64(&gCoreEntries[thigCore].fActiveTime, active);
|
atomic_add64(&gCoreEntries[thisCore].fActiveTime, active);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!gSingleCore)
|
if (!gSingleCore)
|
||||||
@@ -1078,16 +1078,16 @@ track_cpu_activity(Thread* oldThread, Thread* nextThread, int32 thigCore)
|
|||||||
|
|
||||||
if (thread_is_idle_thread(nextThread)) {
|
if (thread_is_idle_thread(nextThread)) {
|
||||||
if (!thread_is_idle_thread(oldThread))
|
if (!thread_is_idle_thread(oldThread))
|
||||||
atomic_set64(&gCoreEntries[thigCore].fStartedIdle, now);
|
atomic_set64(&gCoreEntries[thisCore].fStartedIdle, now);
|
||||||
if (oldPriority > B_LOWEST_ACTIVE_PRIORITY)
|
if (oldPriority > B_LOWEST_ACTIVE_PRIORITY)
|
||||||
atomic_set64(&gCoreEntries[thigCore].fStartedBottom, now);
|
atomic_set64(&gCoreEntries[thisCore].fStartedBottom, now);
|
||||||
} else if (nextPriority == B_LOWEST_ACTIVE_PRIORITY) {
|
} else if (nextPriority == B_LOWEST_ACTIVE_PRIORITY) {
|
||||||
atomic_set64(&gCoreEntries[thigCore].fStartedIdle, 0);
|
atomic_set64(&gCoreEntries[thisCore].fStartedIdle, 0);
|
||||||
if (oldPriority > B_LOWEST_ACTIVE_PRIORITY)
|
if (oldPriority > B_LOWEST_ACTIVE_PRIORITY)
|
||||||
atomic_set64(&gCoreEntries[thigCore].fStartedBottom, now);
|
atomic_set64(&gCoreEntries[thisCore].fStartedBottom, now);
|
||||||
} else {
|
} else {
|
||||||
atomic_set64(&gCoreEntries[thigCore].fStartedBottom, 0);
|
atomic_set64(&gCoreEntries[thisCore].fStartedBottom, 0);
|
||||||
atomic_set64(&gCoreEntries[thigCore].fStartedIdle, 0);
|
atomic_set64(&gCoreEntries[thisCore].fStartedIdle, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!thread_is_idle_thread(nextThread)) {
|
if (!thread_is_idle_thread(nextThread)) {
|
||||||
@@ -1098,10 +1098,10 @@ track_cpu_activity(Thread* oldThread, Thread* nextThread, int32 thigCore)
|
|||||||
|
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
update_cpu_performance(Thread* thread, int32 thigCore)
|
update_cpu_performance(Thread* thread, int32 thisCore)
|
||||||
{
|
{
|
||||||
int32 load = max_c(thread->scheduler_data->load,
|
int32 load = max_c(thread->scheduler_data->load,
|
||||||
gCoreEntries[thigCore].fLoad);
|
gCoreEntries[thisCore].fLoad);
|
||||||
load = min_c(max_c(load, 0), kMaxLoad);
|
load = min_c(max_c(load, 0), kMaxLoad);
|
||||||
|
|
||||||
if (load < kTargetLoad) {
|
if (load < kTargetLoad) {
|
||||||
@@ -1131,10 +1131,10 @@ _scheduler_reschedule(void)
|
|||||||
|
|
||||||
Thread* oldThread = thread_get_current_thread();
|
Thread* oldThread = thread_get_current_thread();
|
||||||
|
|
||||||
int32 thigCPU = smp_get_current_cpu();
|
int32 thisCPU = smp_get_current_cpu();
|
||||||
int32 thigCore = gCPUToCore[thigCPU];
|
int32 thisCore = gCPUToCore[thisCPU];
|
||||||
|
|
||||||
TRACE("reschedule(): cpu %ld, current thread = %ld\n", thigCPU,
|
TRACE("reschedule(): cpu %ld, current thread = %ld\n", thisCPU,
|
||||||
oldThread->id);
|
oldThread->id);
|
||||||
|
|
||||||
oldThread->state = oldThread->next_state;
|
oldThread->state = oldThread->next_state;
|
||||||
@@ -1185,7 +1185,7 @@ _scheduler_reschedule(void)
|
|||||||
|
|
||||||
// select thread with the biggest priority and enqueue back the old thread
|
// select thread with the biggest priority and enqueue back the old thread
|
||||||
Thread* nextThread
|
Thread* nextThread
|
||||||
= choose_next_thread(thigCPU, enqueueOldThread ? oldThread : NULL,
|
= choose_next_thread(thisCPU, enqueueOldThread ? oldThread : NULL,
|
||||||
putOldThreadAtBack);
|
putOldThreadAtBack);
|
||||||
if (nextThread != oldThread) {
|
if (nextThread != oldThread) {
|
||||||
if (enqueueOldThread) {
|
if (enqueueOldThread) {
|
||||||
@@ -1198,7 +1198,7 @@ _scheduler_reschedule(void)
|
|||||||
acquire_spinlock(&nextThread->scheduler_lock);
|
acquire_spinlock(&nextThread->scheduler_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
TRACE("reschedule(): cpu %ld, next thread = %ld\n", thigCPU,
|
TRACE("reschedule(): cpu %ld, next thread = %ld\n", thisCPU,
|
||||||
nextThread->id);
|
nextThread->id);
|
||||||
|
|
||||||
T(ScheduleThread(nextThread, oldThread));
|
T(ScheduleThread(nextThread, oldThread));
|
||||||
@@ -1210,13 +1210,13 @@ _scheduler_reschedule(void)
|
|||||||
// update CPU heap
|
// update CPU heap
|
||||||
{
|
{
|
||||||
SpinLocker coreLocker(gCoreHeapsLock);
|
SpinLocker coreLocker(gCoreHeapsLock);
|
||||||
update_cpu_priority(thigCPU, get_effective_priority(nextThread));
|
update_cpu_priority(thisCPU, get_effective_priority(nextThread));
|
||||||
}
|
}
|
||||||
|
|
||||||
nextThread->state = B_THREAD_RUNNING;
|
nextThread->state = B_THREAD_RUNNING;
|
||||||
nextThread->next_state = B_THREAD_READY;
|
nextThread->next_state = B_THREAD_READY;
|
||||||
|
|
||||||
ASSERT(nextThread->scheduler_data->previous_core == thigCore);
|
ASSERT(nextThread->scheduler_data->previous_core == thisCore);
|
||||||
|
|
||||||
compute_thread_load(nextThread);
|
compute_thread_load(nextThread);
|
||||||
|
|
||||||
@@ -1224,7 +1224,7 @@ _scheduler_reschedule(void)
|
|||||||
scheduler_update_thread_times(oldThread, nextThread);
|
scheduler_update_thread_times(oldThread, nextThread);
|
||||||
|
|
||||||
// track CPU activity
|
// track CPU activity
|
||||||
track_cpu_activity(oldThread, nextThread, thigCore);
|
track_cpu_activity(oldThread, nextThread, thisCore);
|
||||||
|
|
||||||
if (nextThread != oldThread || oldThread->cpu->preempted) {
|
if (nextThread != oldThread || oldThread->cpu->preempted) {
|
||||||
timer* quantumTimer = &oldThread->cpu->quantum_timer;
|
timer* quantumTimer = &oldThread->cpu->quantum_timer;
|
||||||
@@ -1237,7 +1237,7 @@ _scheduler_reschedule(void)
|
|||||||
add_timer(quantumTimer, &reschedule_event, quantum,
|
add_timer(quantumTimer, &reschedule_event, quantum,
|
||||||
B_ONE_SHOT_RELATIVE_TIMER);
|
B_ONE_SHOT_RELATIVE_TIMER);
|
||||||
|
|
||||||
update_cpu_performance(nextThread, thigCore);
|
update_cpu_performance(nextThread, thisCore);
|
||||||
} else {
|
} else {
|
||||||
nextThread->scheduler_data->quantum_start = system_time();
|
nextThread->scheduler_data->quantum_start = system_time();
|
||||||
|
|
||||||
@@ -1631,3 +1631,4 @@ _user_estimate_max_scheduling_latency(thread_id id)
|
|||||||
|
|
||||||
return 2 * kMinThreadQuantum;
|
return 2 * kMinThreadQuantum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user