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: 88*cb66faefSPawel 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 11526592750SPawel Dziepak 116e1e7235cSPawel Dziepak class CoreEntry : public MinMaxHeapLinkImpl<CoreEntry, int32>, 117e1e7235cSPawel Dziepak public DoublyLinkedListLinkImpl<CoreEntry> { 118e1e7235cSPawel Dziepak public: 119d287274dSPawel Dziepak CoreEntry(); 120d287274dSPawel Dziepak 121e1e7235cSPawel Dziepak void Init(int32 id, PackageEntry* package); 122e1e7235cSPawel Dziepak 123e1e7235cSPawel Dziepak inline int32 ID() const { return fCoreID; } 124e1e7235cSPawel Dziepak inline PackageEntry* Package() const { return fPackage; } 125e1e7235cSPawel Dziepak inline int32 CPUCount() const 126e1e7235cSPawel Dziepak { return fCPUCount; } 127e1e7235cSPawel Dziepak 128e1e7235cSPawel Dziepak inline void LockCPUHeap(); 129e1e7235cSPawel Dziepak inline void UnlockCPUHeap(); 130e1e7235cSPawel Dziepak 131e1e7235cSPawel Dziepak inline CPUPriorityHeap* CPUHeap(); 132e1e7235cSPawel Dziepak 133e1e7235cSPawel Dziepak inline int32 ThreadCount() const 134e1e7235cSPawel Dziepak { return fThreadCount; } 135e1e7235cSPawel Dziepak 136e1e7235cSPawel Dziepak inline void LockRunQueue(); 137e1e7235cSPawel Dziepak inline void UnlockRunQueue(); 138e1e7235cSPawel Dziepak 139e1e7235cSPawel Dziepak void PushFront(ThreadData* thread, 140e1e7235cSPawel Dziepak int32 priority); 141e1e7235cSPawel Dziepak void PushBack(ThreadData* thread, 142e1e7235cSPawel Dziepak int32 priority); 143b24ea642SPawel Dziepak void Remove(ThreadData* thread); 144e1e7235cSPawel Dziepak inline ThreadData* PeekThread() const; 145e1e7235cSPawel Dziepak 146e1e7235cSPawel Dziepak inline bigtime_t GetActiveTime() const; 147e1e7235cSPawel Dziepak inline void IncreaseActiveTime( 148e1e7235cSPawel Dziepak bigtime_t activeTime); 149e1e7235cSPawel Dziepak 150d287274dSPawel Dziepak inline int32 GetLoad() const; 151e1e7235cSPawel Dziepak void UpdateLoad(int32 delta); 152e1e7235cSPawel Dziepak 153e1e7235cSPawel Dziepak inline int32 StarvationCounter() 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; 178d287274dSPawel Dziepak DoublyLinkedList<ThreadData> fThreadList; 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 193e1e7235cSPawel Dziepak 194d287274dSPawel Dziepak class CoreLoadHeap : public MinMaxHeap<CoreEntry, int32> { 195d287274dSPawel Dziepak public: 196d287274dSPawel Dziepak CoreLoadHeap() { } 197d287274dSPawel Dziepak CoreLoadHeap(int32 coreCount); 198d287274dSPawel Dziepak 199d287274dSPawel Dziepak void Dump(); 200d287274dSPawel Dziepak }; 201d287274dSPawel Dziepak 202d287274dSPawel Dziepak // gPackageEntries are used to decide which core should be woken up from the 203d287274dSPawel Dziepak // idle state. When aiming for performance we should use as many packages as 204d287274dSPawel Dziepak // possible with as little cores active in each package as possible (so that the 205d287274dSPawel Dziepak // package can enter any boost mode if it has one and the active core have more 206d287274dSPawel Dziepak // of the shared cache for themselves. If power saving is the main priority we 207d287274dSPawel Dziepak // should keep active cores on as little packages as possible (so that other 208d287274dSPawel Dziepak // packages can go to the deep state of sleep). The heap stores only packages 209d287274dSPawel Dziepak // with at least one core active and one core idle. The packages with all cores 210d287274dSPawel Dziepak // idle are stored in gPackageIdleList (in LIFO manner). 21160e198f2SPawel Dziepak class PackageEntry : public DoublyLinkedListLinkImpl<PackageEntry> { 21260e198f2SPawel Dziepak public: 213d287274dSPawel Dziepak PackageEntry(); 214d287274dSPawel Dziepak 21560e198f2SPawel Dziepak void Init(int32 id); 21660e198f2SPawel Dziepak 21760e198f2SPawel Dziepak inline void CoreGoesIdle(CoreEntry* core); 21860e198f2SPawel Dziepak inline void CoreWakesUp(CoreEntry* core); 21960e198f2SPawel Dziepak 22060e198f2SPawel Dziepak inline CoreEntry* GetIdleCore() const; 22160e198f2SPawel Dziepak 22260e198f2SPawel Dziepak void AddIdleCore(CoreEntry* core); 22360e198f2SPawel Dziepak void RemoveIdleCore(CoreEntry* core); 22460e198f2SPawel Dziepak 22560e198f2SPawel Dziepak static inline PackageEntry* GetMostIdlePackage(); 22660e198f2SPawel Dziepak static inline PackageEntry* GetLeastIdlePackage(); 22760e198f2SPawel Dziepak 22860e198f2SPawel Dziepak private: 229d287274dSPawel Dziepak int32 fPackageID; 230d287274dSPawel Dziepak 231d287274dSPawel Dziepak DoublyLinkedList<CoreEntry> fIdleCores; 232d287274dSPawel Dziepak int32 fIdleCoreCount; 233d287274dSPawel Dziepak int32 fCoreCount; 234d287274dSPawel Dziepak rw_spinlock fCoreLock; 23560e198f2SPawel Dziepak 23660e198f2SPawel Dziepak friend class DebugDumper; 237d287274dSPawel Dziepak } CACHE_LINE_ALIGN; 238d287274dSPawel Dziepak typedef DoublyLinkedList<PackageEntry> IdlePackageList; 239d287274dSPawel Dziepak 240d287274dSPawel Dziepak extern CPUEntry* gCPUEntries; 241d287274dSPawel Dziepak 242d287274dSPawel Dziepak extern CoreEntry* gCoreEntries; 243d287274dSPawel Dziepak extern CoreLoadHeap gCoreLoadHeap; 244d287274dSPawel Dziepak extern CoreLoadHeap gCoreHighLoadHeap; 245d287274dSPawel Dziepak extern rw_spinlock gCoreHeapsLock; 246d287274dSPawel Dziepak extern int32 gCoreCount; 247d287274dSPawel Dziepak 248d287274dSPawel Dziepak extern PackageEntry* gPackageEntries; 249d287274dSPawel Dziepak extern IdlePackageList gIdlePackageList; 250d287274dSPawel Dziepak extern rw_spinlock gIdlePackageLock; 251d287274dSPawel Dziepak extern int32 gPackageCount; 252d287274dSPawel Dziepak 253d287274dSPawel Dziepak 254e1e7235cSPawel Dziepak inline void 255a08b40d4SPawel Dziepak CPUEntry::EnterScheduler() 256a08b40d4SPawel Dziepak { 25796dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 258a08b40d4SPawel Dziepak acquire_read_spinlock(&fSchedulerModeLock); 259a08b40d4SPawel Dziepak } 260a08b40d4SPawel Dziepak 261a08b40d4SPawel Dziepak 262a08b40d4SPawel Dziepak inline void 263a08b40d4SPawel Dziepak CPUEntry::ExitScheduler() 264a08b40d4SPawel Dziepak { 26596dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 266a08b40d4SPawel Dziepak release_read_spinlock(&fSchedulerModeLock); 267a08b40d4SPawel Dziepak } 268a08b40d4SPawel Dziepak 269a08b40d4SPawel Dziepak 270a08b40d4SPawel Dziepak inline void 271a08b40d4SPawel Dziepak CPUEntry::LockScheduler() 272a08b40d4SPawel Dziepak { 27396dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 274a08b40d4SPawel Dziepak acquire_write_spinlock(&fSchedulerModeLock); 275a08b40d4SPawel Dziepak } 276a08b40d4SPawel Dziepak 277a08b40d4SPawel Dziepak 278a08b40d4SPawel Dziepak inline void 279a08b40d4SPawel Dziepak CPUEntry::UnlockScheduler() 280a08b40d4SPawel Dziepak { 28196dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 282a08b40d4SPawel Dziepak release_write_spinlock(&fSchedulerModeLock); 283a08b40d4SPawel Dziepak } 284a08b40d4SPawel Dziepak 285a08b40d4SPawel Dziepak 28626592750SPawel Dziepak inline void 28726592750SPawel Dziepak CPUEntry::LockRunQueue() 28826592750SPawel Dziepak { 28926592750SPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 29026592750SPawel Dziepak acquire_spinlock(&fQueueLock); 29126592750SPawel Dziepak } 29226592750SPawel Dziepak 29326592750SPawel Dziepak 29426592750SPawel Dziepak inline void 29526592750SPawel Dziepak CPUEntry::UnlockRunQueue() 29626592750SPawel Dziepak { 29726592750SPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 29826592750SPawel Dziepak release_spinlock(&fQueueLock); 29926592750SPawel Dziepak } 30026592750SPawel Dziepak 30126592750SPawel Dziepak 302a08b40d4SPawel Dziepak /* static */ inline CPUEntry* 303a08b40d4SPawel Dziepak CPUEntry::GetCPU(int32 cpu) 304a08b40d4SPawel Dziepak { 30596dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 306a08b40d4SPawel Dziepak return &gCPUEntries[cpu]; 307a08b40d4SPawel Dziepak } 308a08b40d4SPawel Dziepak 309a08b40d4SPawel Dziepak 310a08b40d4SPawel Dziepak inline void 311e1e7235cSPawel Dziepak CoreEntry::LockCPUHeap() 312e1e7235cSPawel Dziepak { 31396dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 314e1e7235cSPawel Dziepak acquire_spinlock(&fCPULock); 315e1e7235cSPawel Dziepak } 316e1e7235cSPawel Dziepak 317e1e7235cSPawel Dziepak 318e1e7235cSPawel Dziepak inline void 319e1e7235cSPawel Dziepak CoreEntry::UnlockCPUHeap() 320e1e7235cSPawel Dziepak { 32196dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 322e1e7235cSPawel Dziepak release_spinlock(&fCPULock); 323e1e7235cSPawel Dziepak } 324e1e7235cSPawel Dziepak 325e1e7235cSPawel Dziepak 326e1e7235cSPawel Dziepak inline CPUPriorityHeap* 327e1e7235cSPawel Dziepak CoreEntry::CPUHeap() 328e1e7235cSPawel Dziepak { 32996dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 330e1e7235cSPawel Dziepak return &fCPUHeap; 331e1e7235cSPawel Dziepak } 332e1e7235cSPawel Dziepak 333e1e7235cSPawel Dziepak 334e1e7235cSPawel Dziepak inline void 335e1e7235cSPawel Dziepak CoreEntry::LockRunQueue() 336e1e7235cSPawel Dziepak { 33796dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 338e1e7235cSPawel Dziepak acquire_spinlock(&fQueueLock); 339e1e7235cSPawel Dziepak } 340e1e7235cSPawel Dziepak 341e1e7235cSPawel Dziepak 342e1e7235cSPawel Dziepak inline void 343e1e7235cSPawel Dziepak CoreEntry::UnlockRunQueue() 344e1e7235cSPawel Dziepak { 34596dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 346e1e7235cSPawel Dziepak release_spinlock(&fQueueLock); 347e1e7235cSPawel Dziepak } 348e1e7235cSPawel Dziepak 349e1e7235cSPawel Dziepak 350e1e7235cSPawel Dziepak inline void 351e1e7235cSPawel Dziepak CoreEntry::IncreaseActiveTime(bigtime_t activeTime) 352e1e7235cSPawel Dziepak { 35396dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 354e1e7235cSPawel Dziepak WriteSequentialLocker _(fActiveTimeLock); 355e1e7235cSPawel Dziepak fActiveTime += activeTime; 356e1e7235cSPawel Dziepak } 357e1e7235cSPawel Dziepak 358e1e7235cSPawel Dziepak 359*cb66faefSPawel Dziepak inline ThreadData* 360*cb66faefSPawel Dziepak CoreEntry::PeekThread() const 361*cb66faefSPawel Dziepak { 362*cb66faefSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 363*cb66faefSPawel Dziepak return fRunQueue.PeekMaximum(); 364*cb66faefSPawel Dziepak } 365*cb66faefSPawel Dziepak 366*cb66faefSPawel Dziepak 367e1e7235cSPawel Dziepak inline bigtime_t 368e1e7235cSPawel Dziepak CoreEntry::GetActiveTime() const 369e1e7235cSPawel Dziepak { 37096dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 371e1e7235cSPawel Dziepak 37296dcc73bSPawel Dziepak bigtime_t activeTime; 373e1e7235cSPawel Dziepak uint32 count; 374e1e7235cSPawel Dziepak do { 375e1e7235cSPawel Dziepak count = acquire_read_seqlock(&fActiveTimeLock); 376e1e7235cSPawel Dziepak activeTime = fActiveTime; 377e1e7235cSPawel Dziepak } while (!release_read_seqlock(&fActiveTimeLock, count)); 378e1e7235cSPawel Dziepak return activeTime; 379e1e7235cSPawel Dziepak } 380e1e7235cSPawel Dziepak 381e1e7235cSPawel Dziepak 382d287274dSPawel Dziepak inline int32 383d287274dSPawel Dziepak CoreEntry::GetLoad() const 384d287274dSPawel Dziepak { 38596dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 38696dcc73bSPawel Dziepak 3878aa1539bSPawel Dziepak ASSERT(fCPUCount > 0); 388d287274dSPawel Dziepak return fLoad / fCPUCount; 389d287274dSPawel Dziepak } 390d287274dSPawel Dziepak 391d287274dSPawel Dziepak 392e1e7235cSPawel Dziepak inline int32 393e1e7235cSPawel Dziepak CoreEntry::StarvationCounter() const 394e1e7235cSPawel Dziepak { 39596dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 396e1e7235cSPawel Dziepak return fStarvationCounter; 397e1e7235cSPawel Dziepak } 398e1e7235cSPawel Dziepak 399e1e7235cSPawel Dziepak 400*cb66faefSPawel Dziepak /* PackageEntry::CoreGoesIdle and PackageEntry::CoreWakesUp have to be defined 401*cb66faefSPawel Dziepak before CoreEntry::CPUGoesIdle and CoreEntry::CPUWakesUp. If they weren't 402*cb66faefSPawel Dziepak GCC2 wouldn't inline them as, apparently, it doesn't do enough optimization 403*cb66faefSPawel Dziepak passes. 404*cb66faefSPawel Dziepak */ 405*cb66faefSPawel Dziepak inline void 406*cb66faefSPawel Dziepak PackageEntry::CoreGoesIdle(CoreEntry* core) 407*cb66faefSPawel Dziepak { 408*cb66faefSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 409*cb66faefSPawel Dziepak 410*cb66faefSPawel Dziepak WriteSpinLocker _(fCoreLock); 411*cb66faefSPawel Dziepak 412*cb66faefSPawel Dziepak ASSERT(fIdleCoreCount >= 0); 413*cb66faefSPawel Dziepak ASSERT(fIdleCoreCount < fCoreCount); 414*cb66faefSPawel Dziepak 415*cb66faefSPawel Dziepak fIdleCoreCount++; 416*cb66faefSPawel Dziepak fIdleCores.Add(core); 417*cb66faefSPawel Dziepak 418*cb66faefSPawel Dziepak if (fIdleCoreCount == fCoreCount) { 419*cb66faefSPawel Dziepak // package goes idle 420*cb66faefSPawel Dziepak WriteSpinLocker _(gIdlePackageLock); 421*cb66faefSPawel Dziepak gIdlePackageList.Add(this); 422*cb66faefSPawel Dziepak } 423*cb66faefSPawel Dziepak } 424*cb66faefSPawel Dziepak 425*cb66faefSPawel Dziepak 426*cb66faefSPawel Dziepak inline void 427*cb66faefSPawel Dziepak PackageEntry::CoreWakesUp(CoreEntry* core) 428*cb66faefSPawel Dziepak { 429*cb66faefSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 430*cb66faefSPawel Dziepak 431*cb66faefSPawel Dziepak WriteSpinLocker _(fCoreLock); 432*cb66faefSPawel Dziepak 433*cb66faefSPawel Dziepak ASSERT(fIdleCoreCount > 0); 434*cb66faefSPawel Dziepak ASSERT(fIdleCoreCount <= fCoreCount); 435*cb66faefSPawel Dziepak 436*cb66faefSPawel Dziepak fIdleCoreCount--; 437*cb66faefSPawel Dziepak fIdleCores.Remove(core); 438*cb66faefSPawel Dziepak 439*cb66faefSPawel Dziepak if (fIdleCoreCount + 1 == fCoreCount) { 440*cb66faefSPawel Dziepak // package wakes up 441*cb66faefSPawel Dziepak WriteSpinLocker _(gIdlePackageLock); 442*cb66faefSPawel Dziepak gIdlePackageList.Remove(this); 443*cb66faefSPawel Dziepak } 444*cb66faefSPawel Dziepak } 445*cb66faefSPawel Dziepak 446*cb66faefSPawel Dziepak 447*cb66faefSPawel Dziepak inline void 448*cb66faefSPawel Dziepak CoreEntry::CPUGoesIdle(CPUEntry* /* cpu */) 449*cb66faefSPawel Dziepak { 450*cb66faefSPawel Dziepak ASSERT(fCPUIdleCount < fCPUCount); 451*cb66faefSPawel Dziepak 452*cb66faefSPawel Dziepak if (++fCPUIdleCount == fCPUCount) 453*cb66faefSPawel Dziepak fPackage->CoreGoesIdle(this); 454*cb66faefSPawel Dziepak } 455*cb66faefSPawel Dziepak 456*cb66faefSPawel Dziepak 457*cb66faefSPawel Dziepak inline void 458*cb66faefSPawel Dziepak CoreEntry::CPUWakesUp(CPUEntry* /* cpu */) 459*cb66faefSPawel Dziepak { 460*cb66faefSPawel Dziepak ASSERT(fCPUIdleCount > 0); 461*cb66faefSPawel Dziepak 462*cb66faefSPawel Dziepak if (fCPUIdleCount-- == fCPUCount) 463*cb66faefSPawel Dziepak fPackage->CoreWakesUp(this); 464*cb66faefSPawel Dziepak } 465*cb66faefSPawel Dziepak 466*cb66faefSPawel Dziepak 467d287274dSPawel Dziepak /* static */ inline CoreEntry* 468d287274dSPawel Dziepak CoreEntry::GetCore(int32 cpu) 469d287274dSPawel Dziepak { 47096dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 471a08b40d4SPawel Dziepak return gCPUEntries[cpu].Core(); 472d287274dSPawel Dziepak } 473d287274dSPawel Dziepak 474d287274dSPawel Dziepak 47560e198f2SPawel Dziepak inline CoreEntry* 47660e198f2SPawel Dziepak PackageEntry::GetIdleCore() const 47760e198f2SPawel Dziepak { 47896dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 47960e198f2SPawel Dziepak return fIdleCores.Last(); 48060e198f2SPawel Dziepak } 48160e198f2SPawel Dziepak 48260e198f2SPawel Dziepak 48360e198f2SPawel Dziepak /* static */ inline PackageEntry* 48460e198f2SPawel Dziepak PackageEntry::GetMostIdlePackage() 48560e198f2SPawel Dziepak { 48696dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 48796dcc73bSPawel Dziepak 48860e198f2SPawel Dziepak PackageEntry* current = &gPackageEntries[0]; 48960e198f2SPawel Dziepak for (int32 i = 1; i < gPackageCount; i++) { 49060e198f2SPawel Dziepak if (gPackageEntries[i].fIdleCoreCount > current->fIdleCoreCount) 49160e198f2SPawel Dziepak current = &gPackageEntries[i]; 49260e198f2SPawel Dziepak } 49360e198f2SPawel Dziepak 49460e198f2SPawel Dziepak if (current->fIdleCoreCount == 0) 49560e198f2SPawel Dziepak return NULL; 49660e198f2SPawel Dziepak 49760e198f2SPawel Dziepak return current; 49860e198f2SPawel Dziepak } 49960e198f2SPawel Dziepak 50060e198f2SPawel Dziepak 50160e198f2SPawel Dziepak /* static */ inline PackageEntry* 50260e198f2SPawel Dziepak PackageEntry::GetLeastIdlePackage() 50360e198f2SPawel Dziepak { 50496dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 50596dcc73bSPawel Dziepak 50660e198f2SPawel Dziepak PackageEntry* package = NULL; 50760e198f2SPawel Dziepak 50860e198f2SPawel Dziepak for (int32 i = 0; i < gPackageCount; i++) { 50960e198f2SPawel Dziepak PackageEntry* current = &gPackageEntries[i]; 51060e198f2SPawel Dziepak 51160e198f2SPawel Dziepak int32 currentIdleCoreCount = current->fIdleCoreCount; 51260e198f2SPawel Dziepak if (currentIdleCoreCount != 0 && (package == NULL 51360e198f2SPawel Dziepak || currentIdleCoreCount < package->fIdleCoreCount)) { 51460e198f2SPawel Dziepak package = current; 51560e198f2SPawel Dziepak } 51660e198f2SPawel Dziepak } 51760e198f2SPawel Dziepak 51860e198f2SPawel Dziepak return package; 51960e198f2SPawel Dziepak } 52060e198f2SPawel Dziepak 52160e198f2SPawel Dziepak 522d287274dSPawel Dziepak } // namespace Scheduler 523d287274dSPawel Dziepak 524d287274dSPawel Dziepak 525d287274dSPawel Dziepak #endif // KERNEL_SCHEDULER_CPU_H 526d287274dSPawel Dziepak 527