added 3 changesets to branch 'refs/remotes/pdziepak-github/scheduler' old head: 9caf7f4fb95b33daa9e2caf2267c2636ba24ce49 new head: f9ee217ad6c59122fefd39a445c99f2c0fb2af1e overview: https://github.com/pdziepak/Haiku/compare/9caf7f4...f9ee217 ---------------------------------------------------------------------------- 8711571: scheduler: Protect package data with rw_spinlock 286b341: kernel: Merge two occurences of thread resume code f9ee217: scheduler: Migrate threads less often in power saving mode [ Pawel Dziepak <pdziepak@xxxxxxxxxxx> ] ---------------------------------------------------------------------------- 6 files changed, 117 insertions(+), 108 deletions(-) headers/private/kernel/kscheduler.h | 2 + src/system/kernel/scheduler/low_latency.cpp | 7 +- src/system/kernel/scheduler/power_saving.cpp | 64 +++++------ src/system/kernel/scheduler/scheduler.cpp | 128 +++++++++++++-------- src/system/kernel/scheduler/scheduler_common.h | 6 +- src/system/kernel/thread.cpp | 18 +-- ############################################################################ Commit: 87115715b40c394b08de08b6709863eb257b020d Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Wed Nov 27 03:57:26 2013 UTC scheduler: Protect package data with rw_spinlock ---------------------------------------------------------------------------- diff --git a/src/system/kernel/scheduler/low_latency.cpp b/src/system/kernel/scheduler/low_latency.cpp index 832b7ab..a3eb28b 100644 --- a/src/system/kernel/scheduler/low_latency.cpp +++ b/src/system/kernel/scheduler/low_latency.cpp @@ -63,7 +63,7 @@ choose_core(Thread* thread) { CoreEntry* entry = NULL; - SpinLocker locker(gIdlePackageLock); + ReadSpinLocker locker(gIdlePackageLock); // wake new package PackageEntry* package = gIdlePackageList->Last(); if (package == NULL) { @@ -73,7 +73,7 @@ choose_core(Thread* thread) locker.Unlock(); if (package != NULL) { - SpinLocker _(package->fCoreLock); + ReadSpinLocker _(package->fCoreLock); entry = package->fIdleCores.Last(); } diff --git a/src/system/kernel/scheduler/power_saving.cpp b/src/system/kernel/scheduler/power_saving.cpp index 63ad0e3..75d754f 100644 --- a/src/system/kernel/scheduler/power_saving.cpp +++ b/src/system/kernel/scheduler/power_saving.cpp @@ -89,12 +89,12 @@ choose_idle_core(void) } if (current == NULL) { - SpinLocker _(gIdlePackageLock); + ReadSpinLocker _(gIdlePackageLock); current = gIdlePackageList->Last(); } if (current != NULL) { - SpinLocker _(current->fCoreLock); + ReadSpinLocker _(current->fCoreLock); return current->fIdleCores.Last(); } diff --git a/src/system/kernel/scheduler/scheduler.cpp b/src/system/kernel/scheduler/scheduler.cpp index 6f105f6..ede18e6 100644 --- a/src/system/kernel/scheduler/scheduler.cpp +++ b/src/system/kernel/scheduler/scheduler.cpp @@ -66,7 +66,7 @@ int32 gCoreCount; PackageEntry* gPackageEntries; IdlePackageList* gIdlePackageList; -spinlock gIdlePackageLock = B_SPINLOCK_INITIALIZER; +rw_spinlock gIdlePackageLock = B_RW_SPINLOCK_INITIALIZER; int32 gPackageCount; ThreadRunQueue* gRunQueues; @@ -132,7 +132,7 @@ PackageEntry::PackageEntry() fIdleCoreCount(0), fCoreCount(0) { - B_INITIALIZE_SPINLOCK(&fCoreLock); + B_INITIALIZE_RW_SPINLOCK(&fCoreLock); } @@ -457,7 +457,7 @@ update_cpu_priority(int32 cpu, int32 priority) int32 package = gCPUToPackage[cpu]; PackageEntry* packageEntry = &gPackageEntries[package]; if (maxPriority == B_IDLE_PRIORITY) { - SpinLocker _(packageEntry->fCoreLock); + WriteSpinLocker _(packageEntry->fCoreLock); // core goes idle ASSERT(packageEntry->fIdleCoreCount >= 0); @@ -468,11 +468,11 @@ update_cpu_priority(int32 cpu, int32 priority) if (packageEntry->fIdleCoreCount == packageEntry->fCoreCount) { // package goes idle - SpinLocker _(gIdlePackageLock); + WriteSpinLocker _(gIdlePackageLock); gIdlePackageList->Add(packageEntry); } } else if (corePriority == B_IDLE_PRIORITY) { - SpinLocker _(packageEntry->fCoreLock); + WriteSpinLocker _(packageEntry->fCoreLock); // core wakes up ASSERT(packageEntry->fIdleCoreCount > 0); @@ -483,7 +483,7 @@ update_cpu_priority(int32 cpu, int32 priority) if (packageEntry->fIdleCoreCount + 1 == packageEntry->fCoreCount) { // package wakes up - SpinLocker _(gIdlePackageLock); + WriteSpinLocker _(gIdlePackageLock); gIdlePackageList->Remove(packageEntry); } } @@ -956,9 +956,6 @@ choose_next_thread(int32 thisCPU, Thread* oldThread, bool putAtBack) static inline void track_cpu_activity(Thread* oldThread, Thread* nextThread, int32 thisCore) { - bigtime_t now = system_time(); - bigtime_t usedTime = now - oldThread->scheduler_data->quantum_start; - if (!thread_is_idle_thread(oldThread)) { bigtime_t active = (oldThread->kernel_time - oldThread->cpu->last_kernel_time) @@ -976,9 +973,6 @@ track_cpu_activity(Thread* oldThread, Thread* nextThread, int32 thisCore) if (!gSingleCore && !gCPU[smp_get_current_cpu()].disabled) compute_cpu_load(smp_get_current_cpu()); - int32 oldPriority = get_effective_priority(oldThread); - int32 nextPriority = get_effective_priority(nextThread); - if (!thread_is_idle_thread(nextThread)) { oldThread->cpu->last_kernel_time = nextThread->kernel_time; oldThread->cpu->last_user_time = nextThread->user_time; diff --git a/src/system/kernel/scheduler/scheduler_common.h b/src/system/kernel/scheduler/scheduler_common.h index 1fdb26f..f379ba9 100644 --- a/src/system/kernel/scheduler/scheduler_common.h +++ b/src/system/kernel/scheduler/scheduler_common.h @@ -106,7 +106,7 @@ struct PackageEntry : public DoublyLinkedListLinkImpl<PackageEntry> { int32 fPackageID; - spinlock fCoreLock; + rw_spinlock fCoreLock; DoublyLinkedList<CoreEntry> fIdleCores; int32 fIdleCoreCount; @@ -117,7 +117,7 @@ typedef DoublyLinkedList<PackageEntry> IdlePackageList; extern PackageEntry* gPackageEntries; extern IdlePackageList* gIdlePackageList; -extern spinlock gIdlePackageLock; +extern rw_spinlock gIdlePackageLock; extern int32 gPackageCount; // The run queues. Holds the threads ready to run ordered by priority. ############################################################################ Commit: 286b341a400e8d12060a8be52214618b8f02df87 Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Thu Nov 28 13:03:57 2013 UTC kernel: Merge two occurences of thread resume code ---------------------------------------------------------------------------- diff --git a/headers/private/kernel/kscheduler.h b/headers/private/kernel/kscheduler.h index 2d8222e..cbad85d 100644 --- a/headers/private/kernel/kscheduler.h +++ b/headers/private/kernel/kscheduler.h @@ -83,6 +83,8 @@ status_t scheduler_set_operation_mode(scheduler_mode mode); */ void scheduler_dump_thread_data(Thread* thread); +void scheduler_new_thread_entry(Thread* thread); + void scheduler_set_cpu_enabled(int32 cpu, bool enabled); void scheduler_add_listener(struct SchedulerListener* listener); diff --git a/src/system/kernel/scheduler/scheduler.cpp b/src/system/kernel/scheduler/scheduler.cpp index ede18e6..b1bcef7 100644 --- a/src/system/kernel/scheduler/scheduler.cpp +++ b/src/system/kernel/scheduler/scheduler.cpp @@ -1007,6 +1007,58 @@ update_cpu_performance(Thread* thread, int32 thisCore) } +static inline void +stop_cpu_timers(Thread* fromThread, Thread* toThread) +{ + SpinLocker teamLocker(&fromThread->team->time_lock); + SpinLocker threadLocker(&fromThread->time_lock); + + if (fromThread->HasActiveCPUTimeUserTimers() + || fromThread->team->HasActiveCPUTimeUserTimers()) { + user_timer_stop_cpu_timers(fromThread, toThread); + } +} + + +static inline void +continue_cpu_timers(Thread* thread, cpu_ent* cpu) +{ + SpinLocker teamLocker(&thread->team->time_lock); + SpinLocker threadLocker(&thread->time_lock); + + if (thread->HasActiveCPUTimeUserTimers() + || thread->team->HasActiveCPUTimeUserTimers()) { + user_timer_continue_cpu_timers(thread, cpu->previous_thread); + } +} + + +static void +thread_resumes(Thread* thread) +{ + cpu_ent* cpu = thread->cpu; + + release_spinlock(&cpu->previous_thread->scheduler_lock); + + // continue CPU time based user timers + continue_cpu_timers(thread, cpu); + + // notify the user debugger code + if ((thread->flags & THREAD_FLAGS_DEBUGGER_INSTALLED) != 0) + user_debug_thread_scheduled(thread); +} + + +void +scheduler_new_thread_entry(Thread* thread) +{ + thread_resumes(thread); + + SpinLocker locker(thread->time_lock); + thread->last_time = system_time(); +} + + /*! Switches the currently running thread. This is a service function for scheduler implementations. @@ -1022,14 +1074,7 @@ switch_thread(Thread* fromThread, Thread* toThread) user_debug_thread_unscheduled(fromThread); // stop CPU time based user timers - acquire_spinlock(&fromThread->team->time_lock); - acquire_spinlock(&fromThread->time_lock); - if (fromThread->HasActiveCPUTimeUserTimers() - || fromThread->team->HasActiveCPUTimeUserTimers()) { - user_timer_stop_cpu_timers(fromThread, toThread); - } - release_spinlock(&fromThread->time_lock); - release_spinlock(&fromThread->team->time_lock); + stop_cpu_timers(fromThread, toThread); // update CPU and Thread structures and perform the context switch cpu_ent* cpu = fromThread->cpu; @@ -1041,25 +1086,10 @@ switch_thread(Thread* fromThread, Thread* toThread) arch_thread_set_current_thread(toThread); arch_thread_context_switch(fromThread, toThread); - release_spinlock(&fromThread->cpu->previous_thread->scheduler_lock); - // The use of fromThread below looks weird, but is correct. fromThread had // been unscheduled earlier, but is back now. For a thread scheduled the // first time the same is done in thread.cpp:common_thread_entry(). - - // continue CPU time based user timers - acquire_spinlock(&fromThread->team->time_lock); - acquire_spinlock(&fromThread->time_lock); - if (fromThread->HasActiveCPUTimeUserTimers() - || fromThread->team->HasActiveCPUTimeUserTimers()) { - user_timer_continue_cpu_timers(fromThread, cpu->previous_thread); - } - release_spinlock(&fromThread->time_lock); - release_spinlock(&fromThread->team->time_lock); - - // notify the user debugger code - if ((fromThread->flags & THREAD_FLAGS_DEBUGGER_INSTALLED) != 0) - user_debug_thread_scheduled(fromThread); + thread_resumes(fromThread); } @@ -1068,28 +1098,25 @@ update_thread_times(Thread* oldThread, Thread* nextThread) { bigtime_t now = system_time(); if (oldThread == nextThread) { - acquire_spinlock(&oldThread->time_lock); + SpinLocker _(oldThread->time_lock); oldThread->kernel_time += now - oldThread->last_time; oldThread->last_time = now; - release_spinlock(&oldThread->time_lock); } else { - acquire_spinlock(&oldThread->time_lock); + SpinLocker locker(oldThread->time_lock); oldThread->kernel_time += now - oldThread->last_time; oldThread->last_time = 0; - release_spinlock(&oldThread->time_lock); + locker.Unlock(); - acquire_spinlock(&nextThread->time_lock); + locker.SetTo(nextThread->time_lock, false); nextThread->last_time = now; - release_spinlock(&nextThread->time_lock); } // If the old thread's team has user time timers, check them now. Team* team = oldThread->team; - acquire_spinlock(&team->time_lock); + SpinLocker _(team->time_lock); if (team->HasActiveUserTimeUserTimers()) user_timer_check_team_user_timers(team); - release_spinlock(&team->time_lock); } diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index ca66a46..f3474b5 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -698,25 +698,9 @@ common_thread_entry(void* _args) // The thread is new and has been scheduled the first time. - // start CPU time based user timers - acquire_spinlock(&thread->team->time_lock); - acquire_spinlock(&thread->time_lock); - if (thread->HasActiveCPUTimeUserTimers() - || thread->team->HasActiveCPUTimeUserTimers()) { - user_timer_continue_cpu_timers(thread, thread->cpu->previous_thread); - } - - // start tracking time - thread->last_time = system_time(); - release_spinlock(&thread->time_lock); - release_spinlock(&thread->team->time_lock); - - // notify the user debugger code - if ((thread->flags & THREAD_FLAGS_DEBUGGER_INSTALLED) != 0) - user_debug_thread_scheduled(thread); + scheduler_new_thread_entry(thread); // unlock the scheduler lock and enable interrupts - release_spinlock(&thread->cpu->previous_thread->scheduler_lock); release_spinlock(&thread->scheduler_lock); enable_interrupts(); ############################################################################ Commit: f9ee217ad6c59122fefd39a445c99f2c0fb2af1e Author: Pawel Dziepak <pdziepak@xxxxxxxxxxx> Date: Thu Nov 28 15:33:50 2013 UTC scheduler: Migrate threads less often in power saving mode ---------------------------------------------------------------------------- diff --git a/src/system/kernel/scheduler/low_latency.cpp b/src/system/kernel/scheduler/low_latency.cpp index a3eb28b..3e43657 100644 --- a/src/system/kernel/scheduler/low_latency.cpp +++ b/src/system/kernel/scheduler/low_latency.cpp @@ -30,9 +30,6 @@ has_cache_expired(Thread* thread) { ASSERT(!gSingleCore); - if (thread_is_idle_thread(thread)) - return false; - scheduler_thread_data* schedulerThreadData = thread->scheduler_data; ASSERT(schedulerThreadData->previous_core >= 0); diff --git a/src/system/kernel/scheduler/power_saving.cpp b/src/system/kernel/scheduler/power_saving.cpp index 75d754f..aa960e4 100644 --- a/src/system/kernel/scheduler/power_saving.cpp +++ b/src/system/kernel/scheduler/power_saving.cpp @@ -36,9 +36,6 @@ has_cache_expired(Thread* thread) { ASSERT(!gSingleCore); - if (thread_is_idle_thread(thread)) - return false; - scheduler_thread_data* schedulerThreadData = thread->scheduler_data; ASSERT(schedulerThreadData->previous_core >= 0); @@ -46,19 +43,6 @@ has_cache_expired(Thread* thread) } -static bool -try_small_task_packing(Thread* thread) -{ - ReadSpinLocker locker(gCoreHeapsLock); - - int32 core = sSmallTaskCore; - return (core == -1 && gCoreLoadHeap->PeekMaximum() != NULL) - || (core != -1 - && get_core_load(&gCoreEntries[core]) + thread->scheduler_data->load - < kHighLoad); -} - - static int32 choose_small_task_core(void) { @@ -107,24 +91,27 @@ choose_core(Thread* thread) { CoreEntry* entry; - if (try_small_task_packing(thread)) { - // try to pack all threads on one core - entry = &gCoreEntries[choose_small_task_core()]; + int32 core = -1; + // try to pack all threads on one core + core = choose_small_task_core(); + + if (core != -1 + && get_core_load(&gCoreEntries[core]) + thread->scheduler_data->load + < kHighLoad) { + entry = &gCoreEntries[core]; } else { ReadSpinLocker coreLocker(gCoreHeapsLock); - if (gCoreLoadHeap->PeekMinimum() != NULL) { - // run immediately on already woken core - entry = gCoreLoadHeap->PeekMinimum(); - } else { + // run immediately on already woken core + entry = gCoreLoadHeap->PeekMinimum(); + if (entry == NULL) { coreLocker.Unlock(); entry = choose_idle_core(); - coreLocker.Lock(); - if (entry == NULL) - entry = gCoreLoadHeap->PeekMinimum(); - if (entry == NULL) + if (entry == NULL) { + coreLocker.Lock(); entry = gCoreHighLoadHeap->PeekMinimum(); + } } } @@ -138,9 +125,6 @@ should_rebalance(Thread* thread) { ASSERT(!gSingleCore); - if (thread_is_idle_thread(thread)) - return false; - scheduler_thread_data* schedulerThreadData = thread->scheduler_data; ASSERT(schedulerThreadData->previous_core >= 0); @@ -151,13 +135,16 @@ should_rebalance(Thread* thread) if (coreLoad > kHighLoad) { ReadSpinLocker coreLocker(gCoreHeapsLock); if (sSmallTaskCore == core) { - if (coreLoad - schedulerThreadData->load < kHighLoad) - return true; - + sSmallTaskCore = -1; choose_small_task_core(); + if (schedulerThreadData->load > coreLoad / 3) + return false; return coreLoad > kVeryHighLoad; } + if (schedulerThreadData->load >= coreLoad / 2) + return false; + CoreEntry* other = gCoreLoadHeap->PeekMaximum(); if (other == NULL) other = gCoreHighLoadHeap->PeekMinimum(); @@ -165,10 +152,15 @@ should_rebalance(Thread* thread) return coreLoad - get_core_load(other) >= kLoadDifference / 2; } + if (coreLoad >= kMediumLoad) + return false; + int32 smallTaskCore = choose_small_task_core(); if (smallTaskCore == -1) return false; - return smallTaskCore != core; + return smallTaskCore != core + && get_core_load(&gCoreEntries[smallTaskCore]) + + thread->scheduler_data->load < kHighLoad; } diff --git a/src/system/kernel/scheduler/scheduler.cpp b/src/system/kernel/scheduler/scheduler.cpp index b1bcef7..8fb6cf9 100644 --- a/src/system/kernel/scheduler/scheduler.cpp +++ b/src/system/kernel/scheduler/scheduler.cpp @@ -120,7 +120,8 @@ CoreEntry::CoreEntry() fCPUCount(0), fThreadCount(0), fActiveTime(0), - fLoad(0) + fLoad(0), + fHighLoad(false) { B_INITIALIZE_SPINLOCK(&fCPULock); B_INITIALIZE_SPINLOCK(&fQueueLock); @@ -264,6 +265,7 @@ dump_cpu_heap(int argc, char** argv) { kprintf("core load\n"); dump_core_load_heap(gCoreLoadHeap); + kprintf("\n"); dump_core_load_heap(gCoreHighLoadHeap); for (int32 i = 0; i < gCoreCount; i++) { @@ -376,23 +378,32 @@ update_load_heaps(int32 core) return; if (newKey > kHighLoad) { - if (oldKey <= kHighLoad) { + if (!entry->fHighLoad) { gCoreLoadHeap->ModifyKey(entry, -1); ASSERT(gCoreLoadHeap->PeekMinimum() == entry); gCoreLoadHeap->RemoveMinimum(); gCoreHighLoadHeap->Insert(entry, newKey); + + entry->fHighLoad = true; } else gCoreHighLoadHeap->ModifyKey(entry, newKey); - } else { - if (oldKey > kHighLoad) { + } else if (newKey < kMediumLoad) { + if (entry->fHighLoad) { gCoreHighLoadHeap->ModifyKey(entry, -1); ASSERT(gCoreHighLoadHeap->PeekMinimum() == entry); gCoreHighLoadHeap->RemoveMinimum(); gCoreLoadHeap->Insert(entry, newKey); + + entry->fHighLoad = false; } else gCoreLoadHeap->ModifyKey(entry, newKey); + } else { + if (entry->fHighLoad) + gCoreHighLoadHeap->ModifyKey(entry, newKey); + else + gCoreLoadHeap->ModifyKey(entry, newKey); } } diff --git a/src/system/kernel/scheduler/scheduler_common.h b/src/system/kernel/scheduler/scheduler_common.h index f379ba9..e92b3a6 100644 --- a/src/system/kernel/scheduler/scheduler_common.h +++ b/src/system/kernel/scheduler/scheduler_common.h @@ -36,6 +36,7 @@ const bigtime_t kCacheExpire = 100000; const int kLowLoad = kMaxLoad * 20 / 100; const int kTargetLoad = kMaxLoad * 55 / 100; const int kHighLoad = kMaxLoad * 70 / 100; +const int kMediumLoad = (kHighLoad + kTargetLoad) / 2; const int kVeryHighLoad = (kMaxLoad + kHighLoad) / 2; const int kLoadDifference = kMaxLoad * 20 / 100; @@ -83,6 +84,7 @@ struct CoreEntry : public MinMaxHeapLinkImpl<CoreEntry, int32>, bigtime_t fActiveTime; int32 fLoad; + bool fHighLoad; } CACHE_LINE_ALIGN; typedef MinMaxHeap<CoreEntry, int32> CoreLoadHeap;