1d287274dSPawel Dziepak /* 2d287274dSPawel Dziepak * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org. 3d287274dSPawel Dziepak * Distributed under the terms of the MIT License. 4d287274dSPawel Dziepak */ 5d287274dSPawel Dziepak #ifndef KERNEL_SCHEDULER_CPU_H 6d287274dSPawel Dziepak #define KERNEL_SCHEDULER_CPU_H 7d287274dSPawel Dziepak 8d287274dSPawel Dziepak 9d287274dSPawel Dziepak #include <OS.h> 10d287274dSPawel Dziepak 11d287274dSPawel Dziepak #include <thread.h> 12e1e7235cSPawel Dziepak #include <util/AutoLock.h> 13ef8e55a1SPawel Dziepak #include <util/Heap.h> 147c92dffeSPawel Dziepak #include <util/MinMaxHeap.h> 15d287274dSPawel Dziepak 16d287274dSPawel Dziepak #include <cpufreq.h> 17d287274dSPawel Dziepak 18d287274dSPawel Dziepak #include "RunQueue.h" 19d287274dSPawel Dziepak #include "scheduler_common.h" 20d287274dSPawel Dziepak #include "scheduler_modes.h" 2196dcc73bSPawel Dziepak #include "scheduler_profiler.h" 22d287274dSPawel Dziepak 23d287274dSPawel Dziepak 24d287274dSPawel Dziepak namespace Scheduler { 25d287274dSPawel Dziepak 26d287274dSPawel Dziepak 2760e198f2SPawel Dziepak class DebugDumper; 2860e198f2SPawel Dziepak 29d287274dSPawel Dziepak struct ThreadData; 30e1e7235cSPawel Dziepak class ThreadProcessing; 31d287274dSPawel Dziepak 32d287274dSPawel Dziepak struct CPUEntry; 33d287274dSPawel Dziepak struct CoreEntry; 34d287274dSPawel Dziepak struct PackageEntry; 35d287274dSPawel Dziepak 36d287274dSPawel Dziepak // The run queues. Holds the threads ready to run ordered by priority. 37d287274dSPawel Dziepak // One queue per schedulable target per core. Additionally, each 38d287274dSPawel Dziepak // logical processor has its sPinnedRunQueues used for scheduling 39d287274dSPawel Dziepak // pinned threads. 40d287274dSPawel Dziepak class ThreadRunQueue : public RunQueue<ThreadData, THREAD_MAX_SET_PRIORITY> { 41d287274dSPawel Dziepak public: 42d287274dSPawel Dziepak void Dump() const; 43d287274dSPawel Dziepak }; 44d287274dSPawel Dziepak 45ef8e55a1SPawel Dziepak class CPUEntry : public HeapLinkImpl<CPUEntry, int32> { 46a08b40d4SPawel Dziepak public: 47d287274dSPawel Dziepak CPUEntry(); 48d287274dSPawel Dziepak 49a08b40d4SPawel Dziepak void Init(int32 id, CoreEntry* core); 50a08b40d4SPawel Dziepak 51a08b40d4SPawel Dziepak inline int32 ID() const { return fCPUNumber; } 52a08b40d4SPawel Dziepak inline CoreEntry* Core() const { return fCore; } 53a08b40d4SPawel Dziepak 54a08b40d4SPawel Dziepak void Start(); 55a08b40d4SPawel Dziepak void Stop(); 56a08b40d4SPawel Dziepak 57a08b40d4SPawel Dziepak inline void EnterScheduler(); 58a08b40d4SPawel Dziepak inline void ExitScheduler(); 59a08b40d4SPawel Dziepak 60a08b40d4SPawel Dziepak inline void LockScheduler(); 61a08b40d4SPawel Dziepak inline void UnlockScheduler(); 62a08b40d4SPawel Dziepak 6326592750SPawel Dziepak inline void LockRunQueue(); 6426592750SPawel Dziepak inline void UnlockRunQueue(); 6526592750SPawel Dziepak 66a08b40d4SPawel Dziepak void PushFront(ThreadData* thread, 67a08b40d4SPawel Dziepak int32 priority); 68a08b40d4SPawel Dziepak void PushBack(ThreadData* thread, 69a08b40d4SPawel Dziepak int32 priority); 70a08b40d4SPawel Dziepak void Remove(ThreadData* thread); 71a08b40d4SPawel Dziepak inline ThreadData* PeekThread() const; 72a08b40d4SPawel Dziepak ThreadData* PeekIdleThread() const; 73a08b40d4SPawel Dziepak 74d287274dSPawel Dziepak void UpdatePriority(int32 priority); 75d287274dSPawel Dziepak 76a08b40d4SPawel Dziepak inline int32 GetLoad() const { return fLoad; } 77d287274dSPawel Dziepak void ComputeLoad(); 78d287274dSPawel Dziepak 79d287274dSPawel Dziepak ThreadData* ChooseNextThread(ThreadData* oldThread, 80d287274dSPawel Dziepak bool putAtBack); 81d287274dSPawel Dziepak 82d287274dSPawel Dziepak void TrackActivity(ThreadData* oldThreadData, 83d287274dSPawel Dziepak ThreadData* nextThreadData); 84d287274dSPawel Dziepak 85a08b40d4SPawel Dziepak static inline CPUEntry* GetCPU(int32 cpu); 86a08b40d4SPawel Dziepak 87a08b40d4SPawel Dziepak private: 88cb66faefSPawel Dziepak void _RequestPerformanceLevel( 89a08b40d4SPawel Dziepak ThreadData* threadData); 90a08b40d4SPawel Dziepak 91d287274dSPawel Dziepak int32 fCPUNumber; 92d287274dSPawel Dziepak CoreEntry* fCore; 93d287274dSPawel Dziepak 94d287274dSPawel Dziepak rw_spinlock fSchedulerModeLock; 95d287274dSPawel Dziepak 96d287274dSPawel Dziepak ThreadRunQueue fRunQueue; 9726592750SPawel Dziepak spinlock fQueueLock; 98d287274dSPawel Dziepak 99d287274dSPawel Dziepak int32 fLoad; 100d287274dSPawel Dziepak 101d287274dSPawel Dziepak bigtime_t fMeasureActiveTime; 102d287274dSPawel Dziepak bigtime_t fMeasureTime; 103d287274dSPawel Dziepak 104a08b40d4SPawel Dziepak friend class DebugDumper; 105d287274dSPawel Dziepak } CACHE_LINE_ALIGN; 106d287274dSPawel Dziepak 107ef8e55a1SPawel Dziepak class CPUPriorityHeap : public Heap<CPUEntry, int32> { 108d287274dSPawel Dziepak public: 109d287274dSPawel Dziepak CPUPriorityHeap() { } 110d287274dSPawel Dziepak CPUPriorityHeap(int32 cpuCount); 111d287274dSPawel Dziepak 112d287274dSPawel Dziepak void Dump(); 113d287274dSPawel Dziepak }; 114d287274dSPawel Dziepak 115e1e7235cSPawel Dziepak class CoreEntry : public MinMaxHeapLinkImpl<CoreEntry, int32>, 116e1e7235cSPawel Dziepak public DoublyLinkedListLinkImpl<CoreEntry> { 117e1e7235cSPawel Dziepak public: 118d287274dSPawel Dziepak CoreEntry(); 119d287274dSPawel Dziepak 120e1e7235cSPawel Dziepak void Init(int32 id, PackageEntry* package); 121e1e7235cSPawel Dziepak 122e1e7235cSPawel Dziepak inline int32 ID() const { return fCoreID; } 123e1e7235cSPawel Dziepak inline PackageEntry* Package() const { return fPackage; } 124e1e7235cSPawel Dziepak inline int32 CPUCount() const 125e1e7235cSPawel Dziepak { return fCPUCount; } 126e1e7235cSPawel Dziepak 127e1e7235cSPawel Dziepak inline void LockCPUHeap(); 128e1e7235cSPawel Dziepak inline void UnlockCPUHeap(); 129e1e7235cSPawel Dziepak 130e1e7235cSPawel Dziepak inline CPUPriorityHeap* CPUHeap(); 131e1e7235cSPawel Dziepak 132e1e7235cSPawel Dziepak inline int32 ThreadCount() const 133e1e7235cSPawel Dziepak { return fThreadCount; } 134e1e7235cSPawel Dziepak 135e1e7235cSPawel Dziepak inline void LockRunQueue(); 136e1e7235cSPawel Dziepak inline void UnlockRunQueue(); 137e1e7235cSPawel Dziepak 138e1e7235cSPawel Dziepak void PushFront(ThreadData* thread, 139e1e7235cSPawel Dziepak int32 priority); 140e1e7235cSPawel Dziepak void PushBack(ThreadData* thread, 141e1e7235cSPawel Dziepak int32 priority); 142b24ea642SPawel Dziepak void Remove(ThreadData* thread); 143e1e7235cSPawel Dziepak inline ThreadData* PeekThread() const; 144e1e7235cSPawel Dziepak 145e1e7235cSPawel Dziepak inline bigtime_t GetActiveTime() const; 146e1e7235cSPawel Dziepak inline void IncreaseActiveTime( 147e1e7235cSPawel Dziepak bigtime_t activeTime); 148e1e7235cSPawel Dziepak 149d287274dSPawel Dziepak inline int32 GetLoad() const; 150e1e7235cSPawel Dziepak void UpdateLoad(int32 delta); 151e1e7235cSPawel Dziepak 152e1e7235cSPawel Dziepak inline int32 StarvationCounter() const; 153*9c465cc8SPawel Dziepak inline int32 StarvationCounterIdle() const; 154e1e7235cSPawel Dziepak 155ef8e55a1SPawel Dziepak inline void CPUGoesIdle(CPUEntry* cpu); 156ef8e55a1SPawel Dziepak inline void CPUWakesUp(CPUEntry* cpu); 157ef8e55a1SPawel Dziepak 158e1e7235cSPawel Dziepak void AddCPU(CPUEntry* cpu); 159e1e7235cSPawel Dziepak void RemoveCPU(CPUEntry* cpu, 160e1e7235cSPawel Dziepak ThreadProcessing& 161e1e7235cSPawel Dziepak threadPostProcessing); 162d287274dSPawel Dziepak 163d287274dSPawel Dziepak static inline CoreEntry* GetCore(int32 cpu); 164d287274dSPawel Dziepak 165e1e7235cSPawel Dziepak private: 166e1e7235cSPawel Dziepak static void _UnassignThread(Thread* thread, 167e1e7235cSPawel Dziepak void* core); 168e1e7235cSPawel Dziepak 169d287274dSPawel Dziepak int32 fCoreID; 170d287274dSPawel Dziepak PackageEntry* fPackage; 171d287274dSPawel Dziepak 172d287274dSPawel Dziepak int32 fCPUCount; 173ef8e55a1SPawel Dziepak int32 fCPUIdleCount; 174d287274dSPawel Dziepak CPUPriorityHeap fCPUHeap; 175d287274dSPawel Dziepak spinlock fCPULock; 176d287274dSPawel Dziepak 177d287274dSPawel Dziepak int32 fStarvationCounter; 178*9c465cc8SPawel Dziepak int32 fStarvationCounterIdle; 179d287274dSPawel Dziepak 180d287274dSPawel Dziepak int32 fThreadCount; 181d287274dSPawel Dziepak ThreadRunQueue fRunQueue; 182d287274dSPawel Dziepak spinlock fQueueLock; 183d287274dSPawel Dziepak 184d287274dSPawel Dziepak bigtime_t fActiveTime; 185e1e7235cSPawel Dziepak mutable seqlock fActiveTimeLock; 186d287274dSPawel Dziepak 187d287274dSPawel Dziepak int32 fLoad; 188d287274dSPawel Dziepak bool fHighLoad; 189e1e7235cSPawel Dziepak 190e1e7235cSPawel Dziepak friend class DebugDumper; 191d287274dSPawel Dziepak } CACHE_LINE_ALIGN; 192d287274dSPawel Dziepak 193d287274dSPawel Dziepak class CoreLoadHeap : public MinMaxHeap<CoreEntry, int32> { 194d287274dSPawel Dziepak public: 195d287274dSPawel Dziepak CoreLoadHeap() { } 196d287274dSPawel Dziepak CoreLoadHeap(int32 coreCount); 197d287274dSPawel Dziepak 198d287274dSPawel Dziepak void Dump(); 199d287274dSPawel Dziepak }; 200d287274dSPawel Dziepak 201d287274dSPawel Dziepak // gPackageEntries are used to decide which core should be woken up from the 202d287274dSPawel Dziepak // idle state. When aiming for performance we should use as many packages as 203d287274dSPawel Dziepak // possible with as little cores active in each package as possible (so that the 204d287274dSPawel Dziepak // package can enter any boost mode if it has one and the active core have more 205d287274dSPawel Dziepak // of the shared cache for themselves. If power saving is the main priority we 206d287274dSPawel Dziepak // should keep active cores on as little packages as possible (so that other 207d287274dSPawel Dziepak // packages can go to the deep state of sleep). The heap stores only packages 208d287274dSPawel Dziepak // with at least one core active and one core idle. The packages with all cores 209d287274dSPawel Dziepak // idle are stored in gPackageIdleList (in LIFO manner). 21060e198f2SPawel Dziepak class PackageEntry : public DoublyLinkedListLinkImpl<PackageEntry> { 21160e198f2SPawel Dziepak public: 212d287274dSPawel Dziepak PackageEntry(); 213d287274dSPawel Dziepak 21460e198f2SPawel Dziepak void Init(int32 id); 21560e198f2SPawel Dziepak 21660e198f2SPawel Dziepak inline void CoreGoesIdle(CoreEntry* core); 21760e198f2SPawel Dziepak inline void CoreWakesUp(CoreEntry* core); 21860e198f2SPawel Dziepak 21960e198f2SPawel Dziepak inline CoreEntry* GetIdleCore() const; 22060e198f2SPawel Dziepak 22160e198f2SPawel Dziepak void AddIdleCore(CoreEntry* core); 22260e198f2SPawel Dziepak void RemoveIdleCore(CoreEntry* core); 22360e198f2SPawel Dziepak 22460e198f2SPawel Dziepak static inline PackageEntry* GetMostIdlePackage(); 22560e198f2SPawel Dziepak static inline PackageEntry* GetLeastIdlePackage(); 22660e198f2SPawel Dziepak 22760e198f2SPawel Dziepak private: 228d287274dSPawel Dziepak int32 fPackageID; 229d287274dSPawel Dziepak 230d287274dSPawel Dziepak DoublyLinkedList<CoreEntry> fIdleCores; 231d287274dSPawel Dziepak int32 fIdleCoreCount; 232d287274dSPawel Dziepak int32 fCoreCount; 233d287274dSPawel Dziepak rw_spinlock fCoreLock; 23460e198f2SPawel Dziepak 23560e198f2SPawel Dziepak friend class DebugDumper; 236d287274dSPawel Dziepak } CACHE_LINE_ALIGN; 237d287274dSPawel Dziepak typedef DoublyLinkedList<PackageEntry> IdlePackageList; 238d287274dSPawel Dziepak 239d287274dSPawel Dziepak extern CPUEntry* gCPUEntries; 240d287274dSPawel Dziepak 241d287274dSPawel Dziepak extern CoreEntry* gCoreEntries; 242d287274dSPawel Dziepak extern CoreLoadHeap gCoreLoadHeap; 243d287274dSPawel Dziepak extern CoreLoadHeap gCoreHighLoadHeap; 244d287274dSPawel Dziepak extern rw_spinlock gCoreHeapsLock; 245d287274dSPawel Dziepak extern int32 gCoreCount; 246d287274dSPawel Dziepak 247d287274dSPawel Dziepak extern PackageEntry* gPackageEntries; 248d287274dSPawel Dziepak extern IdlePackageList gIdlePackageList; 249d287274dSPawel Dziepak extern rw_spinlock gIdlePackageLock; 250d287274dSPawel Dziepak extern int32 gPackageCount; 251d287274dSPawel Dziepak 252d287274dSPawel Dziepak 253e1e7235cSPawel Dziepak inline void 254a08b40d4SPawel Dziepak CPUEntry::EnterScheduler() 255a08b40d4SPawel Dziepak { 25696dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 257a08b40d4SPawel Dziepak acquire_read_spinlock(&fSchedulerModeLock); 258a08b40d4SPawel Dziepak } 259a08b40d4SPawel Dziepak 260a08b40d4SPawel Dziepak 261a08b40d4SPawel Dziepak inline void 262a08b40d4SPawel Dziepak CPUEntry::ExitScheduler() 263a08b40d4SPawel Dziepak { 26496dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 265a08b40d4SPawel Dziepak release_read_spinlock(&fSchedulerModeLock); 266a08b40d4SPawel Dziepak } 267a08b40d4SPawel Dziepak 268a08b40d4SPawel Dziepak 269a08b40d4SPawel Dziepak inline void 270a08b40d4SPawel Dziepak CPUEntry::LockScheduler() 271a08b40d4SPawel Dziepak { 27296dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 273a08b40d4SPawel Dziepak acquire_write_spinlock(&fSchedulerModeLock); 274a08b40d4SPawel Dziepak } 275a08b40d4SPawel Dziepak 276a08b40d4SPawel Dziepak 277a08b40d4SPawel Dziepak inline void 278a08b40d4SPawel Dziepak CPUEntry::UnlockScheduler() 279a08b40d4SPawel Dziepak { 28096dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 281a08b40d4SPawel Dziepak release_write_spinlock(&fSchedulerModeLock); 282a08b40d4SPawel Dziepak } 283a08b40d4SPawel Dziepak 284a08b40d4SPawel Dziepak 28526592750SPawel Dziepak inline void 28626592750SPawel Dziepak CPUEntry::LockRunQueue() 28726592750SPawel Dziepak { 28826592750SPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 28926592750SPawel Dziepak acquire_spinlock(&fQueueLock); 29026592750SPawel Dziepak } 29126592750SPawel Dziepak 29226592750SPawel Dziepak 29326592750SPawel Dziepak inline void 29426592750SPawel Dziepak CPUEntry::UnlockRunQueue() 29526592750SPawel Dziepak { 29626592750SPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 29726592750SPawel Dziepak release_spinlock(&fQueueLock); 29826592750SPawel Dziepak } 29926592750SPawel Dziepak 30026592750SPawel Dziepak 301a08b40d4SPawel Dziepak /* static */ inline CPUEntry* 302a08b40d4SPawel Dziepak CPUEntry::GetCPU(int32 cpu) 303a08b40d4SPawel Dziepak { 30496dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 305a08b40d4SPawel Dziepak return &gCPUEntries[cpu]; 306a08b40d4SPawel Dziepak } 307a08b40d4SPawel Dziepak 308a08b40d4SPawel Dziepak 309a08b40d4SPawel Dziepak inline void 310e1e7235cSPawel Dziepak CoreEntry::LockCPUHeap() 311e1e7235cSPawel Dziepak { 31296dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 313e1e7235cSPawel Dziepak acquire_spinlock(&fCPULock); 314e1e7235cSPawel Dziepak } 315e1e7235cSPawel Dziepak 316e1e7235cSPawel Dziepak 317e1e7235cSPawel Dziepak inline void 318e1e7235cSPawel Dziepak CoreEntry::UnlockCPUHeap() 319e1e7235cSPawel Dziepak { 32096dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 321e1e7235cSPawel Dziepak release_spinlock(&fCPULock); 322e1e7235cSPawel Dziepak } 323e1e7235cSPawel Dziepak 324e1e7235cSPawel Dziepak 325e1e7235cSPawel Dziepak inline CPUPriorityHeap* 326e1e7235cSPawel Dziepak CoreEntry::CPUHeap() 327e1e7235cSPawel Dziepak { 32896dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 329e1e7235cSPawel Dziepak return &fCPUHeap; 330e1e7235cSPawel Dziepak } 331e1e7235cSPawel Dziepak 332e1e7235cSPawel Dziepak 333e1e7235cSPawel Dziepak inline void 334e1e7235cSPawel Dziepak CoreEntry::LockRunQueue() 335e1e7235cSPawel Dziepak { 33696dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 337e1e7235cSPawel Dziepak acquire_spinlock(&fQueueLock); 338e1e7235cSPawel Dziepak } 339e1e7235cSPawel Dziepak 340e1e7235cSPawel Dziepak 341e1e7235cSPawel Dziepak inline void 342e1e7235cSPawel Dziepak CoreEntry::UnlockRunQueue() 343e1e7235cSPawel Dziepak { 34496dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 345e1e7235cSPawel Dziepak release_spinlock(&fQueueLock); 346e1e7235cSPawel Dziepak } 347e1e7235cSPawel Dziepak 348e1e7235cSPawel Dziepak 349e1e7235cSPawel Dziepak inline void 350e1e7235cSPawel Dziepak CoreEntry::IncreaseActiveTime(bigtime_t activeTime) 351e1e7235cSPawel Dziepak { 35296dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 353e1e7235cSPawel Dziepak WriteSequentialLocker _(fActiveTimeLock); 354e1e7235cSPawel Dziepak fActiveTime += activeTime; 355e1e7235cSPawel Dziepak } 356e1e7235cSPawel Dziepak 357e1e7235cSPawel Dziepak 358e1e7235cSPawel Dziepak inline bigtime_t 359e1e7235cSPawel Dziepak CoreEntry::GetActiveTime() const 360e1e7235cSPawel Dziepak { 36196dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 362e1e7235cSPawel Dziepak 36396dcc73bSPawel Dziepak bigtime_t activeTime; 364e1e7235cSPawel Dziepak uint32 count; 365e1e7235cSPawel Dziepak do { 366e1e7235cSPawel Dziepak count = acquire_read_seqlock(&fActiveTimeLock); 367e1e7235cSPawel Dziepak activeTime = fActiveTime; 368e1e7235cSPawel Dziepak } while (!release_read_seqlock(&fActiveTimeLock, count)); 369e1e7235cSPawel Dziepak return activeTime; 370e1e7235cSPawel Dziepak } 371e1e7235cSPawel Dziepak 372e1e7235cSPawel Dziepak 373d287274dSPawel Dziepak inline int32 374d287274dSPawel Dziepak CoreEntry::GetLoad() const 375d287274dSPawel Dziepak { 37696dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 37796dcc73bSPawel Dziepak 3788aa1539bSPawel Dziepak ASSERT(fCPUCount > 0); 379d287274dSPawel Dziepak return fLoad / fCPUCount; 380d287274dSPawel Dziepak } 381d287274dSPawel Dziepak 382d287274dSPawel Dziepak 383e1e7235cSPawel Dziepak inline int32 384e1e7235cSPawel Dziepak CoreEntry::StarvationCounter() const 385e1e7235cSPawel Dziepak { 38696dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 387e1e7235cSPawel Dziepak return fStarvationCounter; 388e1e7235cSPawel Dziepak } 389e1e7235cSPawel Dziepak 390e1e7235cSPawel Dziepak 391*9c465cc8SPawel Dziepak inline int32 392*9c465cc8SPawel Dziepak CoreEntry::StarvationCounterIdle() const 393*9c465cc8SPawel Dziepak { 394*9c465cc8SPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 395*9c465cc8SPawel Dziepak return fStarvationCounterIdle; 396*9c465cc8SPawel Dziepak } 397*9c465cc8SPawel Dziepak 398*9c465cc8SPawel Dziepak 399cb66faefSPawel Dziepak /* PackageEntry::CoreGoesIdle and PackageEntry::CoreWakesUp have to be defined 400cb66faefSPawel Dziepak before CoreEntry::CPUGoesIdle and CoreEntry::CPUWakesUp. If they weren't 401cb66faefSPawel Dziepak GCC2 wouldn't inline them as, apparently, it doesn't do enough optimization 402cb66faefSPawel Dziepak passes. 403cb66faefSPawel Dziepak */ 404cb66faefSPawel Dziepak inline void 405cb66faefSPawel Dziepak PackageEntry::CoreGoesIdle(CoreEntry* core) 406cb66faefSPawel Dziepak { 407cb66faefSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 408cb66faefSPawel Dziepak 409cb66faefSPawel Dziepak WriteSpinLocker _(fCoreLock); 410cb66faefSPawel Dziepak 411cb66faefSPawel Dziepak ASSERT(fIdleCoreCount >= 0); 412cb66faefSPawel Dziepak ASSERT(fIdleCoreCount < fCoreCount); 413cb66faefSPawel Dziepak 414cb66faefSPawel Dziepak fIdleCoreCount++; 415cb66faefSPawel Dziepak fIdleCores.Add(core); 416cb66faefSPawel Dziepak 417cb66faefSPawel Dziepak if (fIdleCoreCount == fCoreCount) { 418cb66faefSPawel Dziepak // package goes idle 419cb66faefSPawel Dziepak WriteSpinLocker _(gIdlePackageLock); 420cb66faefSPawel Dziepak gIdlePackageList.Add(this); 421cb66faefSPawel Dziepak } 422cb66faefSPawel Dziepak } 423cb66faefSPawel Dziepak 424cb66faefSPawel Dziepak 425cb66faefSPawel Dziepak inline void 426cb66faefSPawel Dziepak PackageEntry::CoreWakesUp(CoreEntry* core) 427cb66faefSPawel Dziepak { 428cb66faefSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 429cb66faefSPawel Dziepak 430cb66faefSPawel Dziepak WriteSpinLocker _(fCoreLock); 431cb66faefSPawel Dziepak 432cb66faefSPawel Dziepak ASSERT(fIdleCoreCount > 0); 433cb66faefSPawel Dziepak ASSERT(fIdleCoreCount <= fCoreCount); 434cb66faefSPawel Dziepak 435cb66faefSPawel Dziepak fIdleCoreCount--; 436cb66faefSPawel Dziepak fIdleCores.Remove(core); 437cb66faefSPawel Dziepak 438cb66faefSPawel Dziepak if (fIdleCoreCount + 1 == fCoreCount) { 439cb66faefSPawel Dziepak // package wakes up 440cb66faefSPawel Dziepak WriteSpinLocker _(gIdlePackageLock); 441cb66faefSPawel Dziepak gIdlePackageList.Remove(this); 442cb66faefSPawel Dziepak } 443cb66faefSPawel Dziepak } 444cb66faefSPawel Dziepak 445cb66faefSPawel Dziepak 446cb66faefSPawel Dziepak inline void 447cb66faefSPawel Dziepak CoreEntry::CPUGoesIdle(CPUEntry* /* cpu */) 448cb66faefSPawel Dziepak { 449*9c465cc8SPawel Dziepak atomic_add(&fStarvationCounter, 1); 450*9c465cc8SPawel Dziepak atomic_add(&fStarvationCounterIdle, 1); 451cb66faefSPawel Dziepak 452*9c465cc8SPawel Dziepak if (gSingleCore) 453*9c465cc8SPawel Dziepak return; 454*9c465cc8SPawel Dziepak 455*9c465cc8SPawel Dziepak ASSERT(fCPUIdleCount < fCPUCount); 456cb66faefSPawel Dziepak if (++fCPUIdleCount == fCPUCount) 457cb66faefSPawel Dziepak fPackage->CoreGoesIdle(this); 458cb66faefSPawel Dziepak } 459cb66faefSPawel Dziepak 460cb66faefSPawel Dziepak 461cb66faefSPawel Dziepak inline void 462cb66faefSPawel Dziepak CoreEntry::CPUWakesUp(CPUEntry* /* cpu */) 463cb66faefSPawel Dziepak { 464*9c465cc8SPawel Dziepak if (gSingleCore) 465*9c465cc8SPawel Dziepak return; 466cb66faefSPawel Dziepak 467*9c465cc8SPawel Dziepak ASSERT(fCPUIdleCount > 0); 468cb66faefSPawel Dziepak if (fCPUIdleCount-- == fCPUCount) 469cb66faefSPawel Dziepak fPackage->CoreWakesUp(this); 470cb66faefSPawel Dziepak } 471cb66faefSPawel Dziepak 472cb66faefSPawel Dziepak 473d287274dSPawel Dziepak /* static */ inline CoreEntry* 474d287274dSPawel Dziepak CoreEntry::GetCore(int32 cpu) 475d287274dSPawel Dziepak { 47696dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 477a08b40d4SPawel Dziepak return gCPUEntries[cpu].Core(); 478d287274dSPawel Dziepak } 479d287274dSPawel Dziepak 480d287274dSPawel Dziepak 48160e198f2SPawel Dziepak inline CoreEntry* 48260e198f2SPawel Dziepak PackageEntry::GetIdleCore() const 48360e198f2SPawel Dziepak { 48496dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 48560e198f2SPawel Dziepak return fIdleCores.Last(); 48660e198f2SPawel Dziepak } 48760e198f2SPawel Dziepak 48860e198f2SPawel Dziepak 48960e198f2SPawel Dziepak /* static */ inline PackageEntry* 49060e198f2SPawel Dziepak PackageEntry::GetMostIdlePackage() 49160e198f2SPawel Dziepak { 49296dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 49396dcc73bSPawel Dziepak 49460e198f2SPawel Dziepak PackageEntry* current = &gPackageEntries[0]; 49560e198f2SPawel Dziepak for (int32 i = 1; i < gPackageCount; i++) { 49660e198f2SPawel Dziepak if (gPackageEntries[i].fIdleCoreCount > current->fIdleCoreCount) 49760e198f2SPawel Dziepak current = &gPackageEntries[i]; 49860e198f2SPawel Dziepak } 49960e198f2SPawel Dziepak 50060e198f2SPawel Dziepak if (current->fIdleCoreCount == 0) 50160e198f2SPawel Dziepak return NULL; 50260e198f2SPawel Dziepak 50360e198f2SPawel Dziepak return current; 50460e198f2SPawel Dziepak } 50560e198f2SPawel Dziepak 50660e198f2SPawel Dziepak 50760e198f2SPawel Dziepak /* static */ inline PackageEntry* 50860e198f2SPawel Dziepak PackageEntry::GetLeastIdlePackage() 50960e198f2SPawel Dziepak { 51096dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 51196dcc73bSPawel Dziepak 51260e198f2SPawel Dziepak PackageEntry* package = NULL; 51360e198f2SPawel Dziepak 51460e198f2SPawel Dziepak for (int32 i = 0; i < gPackageCount; i++) { 51560e198f2SPawel Dziepak PackageEntry* current = &gPackageEntries[i]; 51660e198f2SPawel Dziepak 51760e198f2SPawel Dziepak int32 currentIdleCoreCount = current->fIdleCoreCount; 51860e198f2SPawel Dziepak if (currentIdleCoreCount != 0 && (package == NULL 51960e198f2SPawel Dziepak || currentIdleCoreCount < package->fIdleCoreCount)) { 52060e198f2SPawel Dziepak package = current; 52160e198f2SPawel Dziepak } 52260e198f2SPawel Dziepak } 52360e198f2SPawel Dziepak 52460e198f2SPawel Dziepak return package; 52560e198f2SPawel Dziepak } 52660e198f2SPawel Dziepak 52760e198f2SPawel Dziepak 528d287274dSPawel Dziepak } // namespace Scheduler 529d287274dSPawel Dziepak 530d287274dSPawel Dziepak 531d287274dSPawel Dziepak #endif // KERNEL_SCHEDULER_CPU_H 532d287274dSPawel Dziepak 533