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 329216fc01SAugustin Cavalier class CPUEntry; 339216fc01SAugustin Cavalier class CoreEntry; 349216fc01SAugustin Cavalier class 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 85230d1fcfSPawel Dziepak void StartQuantumTimer(ThreadData* thread, 86230d1fcfSPawel Dziepak bool wasPreempted); 87230d1fcfSPawel Dziepak 88a08b40d4SPawel Dziepak static inline CPUEntry* GetCPU(int32 cpu); 89a08b40d4SPawel Dziepak 90a08b40d4SPawel Dziepak private: 91cb66faefSPawel Dziepak void _RequestPerformanceLevel( 92a08b40d4SPawel Dziepak ThreadData* threadData); 93a08b40d4SPawel Dziepak 94230d1fcfSPawel Dziepak static int32 _RescheduleEvent(timer* /* unused */); 95230d1fcfSPawel Dziepak static int32 _UpdateLoadEvent(timer* /* unused */); 96230d1fcfSPawel Dziepak 97d287274dSPawel Dziepak int32 fCPUNumber; 98d287274dSPawel Dziepak CoreEntry* fCore; 99d287274dSPawel Dziepak 100d287274dSPawel Dziepak rw_spinlock fSchedulerModeLock; 101d287274dSPawel Dziepak 102d287274dSPawel Dziepak ThreadRunQueue fRunQueue; 10326592750SPawel Dziepak spinlock fQueueLock; 104d287274dSPawel Dziepak 105d287274dSPawel Dziepak int32 fLoad; 106d287274dSPawel Dziepak 107d287274dSPawel Dziepak bigtime_t fMeasureActiveTime; 108d287274dSPawel Dziepak bigtime_t fMeasureTime; 109d287274dSPawel Dziepak 110230d1fcfSPawel Dziepak bool fUpdateLoadEvent; 111230d1fcfSPawel Dziepak 112a08b40d4SPawel Dziepak friend class DebugDumper; 113d287274dSPawel Dziepak } CACHE_LINE_ALIGN; 114d287274dSPawel Dziepak 115ef8e55a1SPawel Dziepak class CPUPriorityHeap : public Heap<CPUEntry, int32> { 116d287274dSPawel Dziepak public: 117d287274dSPawel Dziepak CPUPriorityHeap() { } 118d287274dSPawel Dziepak CPUPriorityHeap(int32 cpuCount); 119d287274dSPawel Dziepak 120d287274dSPawel Dziepak void Dump(); 121d287274dSPawel Dziepak }; 122d287274dSPawel Dziepak 123e1e7235cSPawel Dziepak class CoreEntry : public MinMaxHeapLinkImpl<CoreEntry, int32>, 124e1e7235cSPawel Dziepak public DoublyLinkedListLinkImpl<CoreEntry> { 125e1e7235cSPawel Dziepak public: 126d287274dSPawel Dziepak CoreEntry(); 127d287274dSPawel Dziepak 128e1e7235cSPawel Dziepak void Init(int32 id, PackageEntry* package); 129e1e7235cSPawel Dziepak 130e1e7235cSPawel Dziepak inline int32 ID() const { return fCoreID; } 131e1e7235cSPawel Dziepak inline PackageEntry* Package() const { return fPackage; } 132e1e7235cSPawel Dziepak inline int32 CPUCount() const 133e1e7235cSPawel Dziepak { return fCPUCount; } 134e1e7235cSPawel Dziepak 135e1e7235cSPawel Dziepak inline void LockCPUHeap(); 136e1e7235cSPawel Dziepak inline void UnlockCPUHeap(); 137e1e7235cSPawel Dziepak 138e1e7235cSPawel Dziepak inline CPUPriorityHeap* CPUHeap(); 139e1e7235cSPawel Dziepak 140a2634874SPawel Dziepak inline int32 ThreadCount() const; 141e1e7235cSPawel Dziepak 142e1e7235cSPawel Dziepak inline void LockRunQueue(); 143e1e7235cSPawel Dziepak inline void UnlockRunQueue(); 144e1e7235cSPawel Dziepak 145e1e7235cSPawel Dziepak void PushFront(ThreadData* thread, 146e1e7235cSPawel Dziepak int32 priority); 147e1e7235cSPawel Dziepak void PushBack(ThreadData* thread, 148e1e7235cSPawel Dziepak int32 priority); 149b24ea642SPawel Dziepak void Remove(ThreadData* thread); 150e1e7235cSPawel Dziepak inline ThreadData* PeekThread() const; 151e1e7235cSPawel Dziepak 152e1e7235cSPawel Dziepak inline bigtime_t GetActiveTime() const; 153e1e7235cSPawel Dziepak inline void IncreaseActiveTime( 154e1e7235cSPawel Dziepak bigtime_t activeTime); 155e1e7235cSPawel Dziepak 156d287274dSPawel Dziepak inline int32 GetLoad() const; 1576155ab7bSPawel Dziepak inline uint32 LoadMeasurementEpoch() const 1586155ab7bSPawel Dziepak { return fLoadMeasurementEpoch; } 1596155ab7bSPawel Dziepak 1606155ab7bSPawel Dziepak inline void AddLoad(int32 load, uint32 epoch, 1616155ab7bSPawel Dziepak bool updateLoad); 1626155ab7bSPawel Dziepak inline uint32 RemoveLoad(int32 load, bool force); 1636155ab7bSPawel Dziepak inline void ChangeLoad(int32 delta); 164e1e7235cSPawel Dziepak 165ef8e55a1SPawel Dziepak inline void CPUGoesIdle(CPUEntry* cpu); 166ef8e55a1SPawel Dziepak inline void CPUWakesUp(CPUEntry* cpu); 167ef8e55a1SPawel Dziepak 168e1e7235cSPawel Dziepak void AddCPU(CPUEntry* cpu); 169e1e7235cSPawel Dziepak void RemoveCPU(CPUEntry* cpu, 170e1e7235cSPawel Dziepak ThreadProcessing& 171e1e7235cSPawel Dziepak threadPostProcessing); 172d287274dSPawel Dziepak 173d287274dSPawel Dziepak static inline CoreEntry* GetCore(int32 cpu); 174d287274dSPawel Dziepak 175e1e7235cSPawel Dziepak private: 176667b23ddSPawel Dziepak void _UpdateLoad(bool forceUpdate = false); 1776155ab7bSPawel Dziepak 178e1e7235cSPawel Dziepak static void _UnassignThread(Thread* thread, 179e1e7235cSPawel Dziepak void* core); 180e1e7235cSPawel Dziepak 181d287274dSPawel Dziepak int32 fCoreID; 182d287274dSPawel Dziepak PackageEntry* fPackage; 183d287274dSPawel Dziepak 184d287274dSPawel Dziepak int32 fCPUCount; 185d36098e0SPawel Dziepak int32 fIdleCPUCount; 186d287274dSPawel Dziepak CPUPriorityHeap fCPUHeap; 187d287274dSPawel Dziepak spinlock fCPULock; 188d287274dSPawel Dziepak 189d287274dSPawel Dziepak int32 fThreadCount; 190d287274dSPawel Dziepak ThreadRunQueue fRunQueue; 191d287274dSPawel Dziepak spinlock fQueueLock; 192d287274dSPawel Dziepak 193d287274dSPawel Dziepak bigtime_t fActiveTime; 194e1e7235cSPawel Dziepak mutable seqlock fActiveTimeLock; 195d287274dSPawel Dziepak 196d287274dSPawel Dziepak int32 fLoad; 1976155ab7bSPawel Dziepak int32 fCurrentLoad; 1986155ab7bSPawel Dziepak uint32 fLoadMeasurementEpoch; 199d287274dSPawel Dziepak bool fHighLoad; 200a2634874SPawel Dziepak bigtime_t fLastLoadUpdate; 2016155ab7bSPawel Dziepak rw_spinlock fLoadLock; 202e1e7235cSPawel Dziepak 203e1e7235cSPawel Dziepak friend class DebugDumper; 204d287274dSPawel Dziepak } CACHE_LINE_ALIGN; 205d287274dSPawel Dziepak 206d287274dSPawel Dziepak class CoreLoadHeap : public MinMaxHeap<CoreEntry, int32> { 207d287274dSPawel Dziepak public: 208d287274dSPawel Dziepak CoreLoadHeap() { } 209d287274dSPawel Dziepak CoreLoadHeap(int32 coreCount); 210d287274dSPawel Dziepak 211d287274dSPawel Dziepak void Dump(); 212d287274dSPawel Dziepak }; 213d287274dSPawel Dziepak 214d287274dSPawel Dziepak // gPackageEntries are used to decide which core should be woken up from the 215d287274dSPawel Dziepak // idle state. When aiming for performance we should use as many packages as 216d287274dSPawel Dziepak // possible with as little cores active in each package as possible (so that the 217d287274dSPawel Dziepak // package can enter any boost mode if it has one and the active core have more 218d287274dSPawel Dziepak // of the shared cache for themselves. If power saving is the main priority we 219d287274dSPawel Dziepak // should keep active cores on as little packages as possible (so that other 220d287274dSPawel Dziepak // packages can go to the deep state of sleep). The heap stores only packages 221d287274dSPawel Dziepak // with at least one core active and one core idle. The packages with all cores 222d287274dSPawel Dziepak // idle are stored in gPackageIdleList (in LIFO manner). 22360e198f2SPawel Dziepak class PackageEntry : public DoublyLinkedListLinkImpl<PackageEntry> { 22460e198f2SPawel Dziepak public: 225d287274dSPawel Dziepak PackageEntry(); 226d287274dSPawel Dziepak 22760e198f2SPawel Dziepak void Init(int32 id); 22860e198f2SPawel Dziepak 22960e198f2SPawel Dziepak inline void CoreGoesIdle(CoreEntry* core); 23060e198f2SPawel Dziepak inline void CoreWakesUp(CoreEntry* core); 23160e198f2SPawel Dziepak 23260e198f2SPawel Dziepak inline CoreEntry* GetIdleCore() const; 23360e198f2SPawel Dziepak 23460e198f2SPawel Dziepak void AddIdleCore(CoreEntry* core); 23560e198f2SPawel Dziepak void RemoveIdleCore(CoreEntry* core); 23660e198f2SPawel Dziepak 23760e198f2SPawel Dziepak static inline PackageEntry* GetMostIdlePackage(); 23860e198f2SPawel Dziepak static inline PackageEntry* GetLeastIdlePackage(); 23960e198f2SPawel Dziepak 24060e198f2SPawel Dziepak private: 241d287274dSPawel Dziepak int32 fPackageID; 242d287274dSPawel Dziepak 243d287274dSPawel Dziepak DoublyLinkedList<CoreEntry> fIdleCores; 244d287274dSPawel Dziepak int32 fIdleCoreCount; 245d287274dSPawel Dziepak int32 fCoreCount; 246d287274dSPawel Dziepak rw_spinlock fCoreLock; 24760e198f2SPawel Dziepak 24860e198f2SPawel Dziepak friend class DebugDumper; 249d287274dSPawel Dziepak } CACHE_LINE_ALIGN; 250d287274dSPawel Dziepak typedef DoublyLinkedList<PackageEntry> IdlePackageList; 251d287274dSPawel Dziepak 252d287274dSPawel Dziepak extern CPUEntry* gCPUEntries; 253d287274dSPawel Dziepak 254d287274dSPawel Dziepak extern CoreEntry* gCoreEntries; 255d287274dSPawel Dziepak extern CoreLoadHeap gCoreLoadHeap; 256d287274dSPawel Dziepak extern CoreLoadHeap gCoreHighLoadHeap; 257d287274dSPawel Dziepak extern rw_spinlock gCoreHeapsLock; 258d287274dSPawel Dziepak extern int32 gCoreCount; 259d287274dSPawel Dziepak 260d287274dSPawel Dziepak extern PackageEntry* gPackageEntries; 261d287274dSPawel Dziepak extern IdlePackageList gIdlePackageList; 262d287274dSPawel Dziepak extern rw_spinlock gIdlePackageLock; 263d287274dSPawel Dziepak extern int32 gPackageCount; 264d287274dSPawel Dziepak 265d287274dSPawel Dziepak 266e1e7235cSPawel Dziepak inline void 267a08b40d4SPawel Dziepak CPUEntry::EnterScheduler() 268a08b40d4SPawel Dziepak { 26996dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 270a08b40d4SPawel Dziepak acquire_read_spinlock(&fSchedulerModeLock); 271a08b40d4SPawel Dziepak } 272a08b40d4SPawel Dziepak 273a08b40d4SPawel Dziepak 274a08b40d4SPawel Dziepak inline void 275a08b40d4SPawel Dziepak CPUEntry::ExitScheduler() 276a08b40d4SPawel Dziepak { 27796dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 278a08b40d4SPawel Dziepak release_read_spinlock(&fSchedulerModeLock); 279a08b40d4SPawel Dziepak } 280a08b40d4SPawel Dziepak 281a08b40d4SPawel Dziepak 282a08b40d4SPawel Dziepak inline void 283a08b40d4SPawel Dziepak CPUEntry::LockScheduler() 284a08b40d4SPawel Dziepak { 28596dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 286a08b40d4SPawel Dziepak acquire_write_spinlock(&fSchedulerModeLock); 287a08b40d4SPawel Dziepak } 288a08b40d4SPawel Dziepak 289a08b40d4SPawel Dziepak 290a08b40d4SPawel Dziepak inline void 291a08b40d4SPawel Dziepak CPUEntry::UnlockScheduler() 292a08b40d4SPawel Dziepak { 29396dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 294a08b40d4SPawel Dziepak release_write_spinlock(&fSchedulerModeLock); 295a08b40d4SPawel Dziepak } 296a08b40d4SPawel Dziepak 297a08b40d4SPawel Dziepak 29826592750SPawel Dziepak inline void 29926592750SPawel Dziepak CPUEntry::LockRunQueue() 30026592750SPawel Dziepak { 30126592750SPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 30226592750SPawel Dziepak acquire_spinlock(&fQueueLock); 30326592750SPawel Dziepak } 30426592750SPawel Dziepak 30526592750SPawel Dziepak 30626592750SPawel Dziepak inline void 30726592750SPawel Dziepak CPUEntry::UnlockRunQueue() 30826592750SPawel Dziepak { 30926592750SPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 31026592750SPawel Dziepak release_spinlock(&fQueueLock); 31126592750SPawel Dziepak } 31226592750SPawel Dziepak 31326592750SPawel Dziepak 314a08b40d4SPawel Dziepak /* static */ inline CPUEntry* 315a08b40d4SPawel Dziepak CPUEntry::GetCPU(int32 cpu) 316a08b40d4SPawel Dziepak { 31796dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 318a08b40d4SPawel Dziepak return &gCPUEntries[cpu]; 319a08b40d4SPawel Dziepak } 320a08b40d4SPawel Dziepak 321a08b40d4SPawel Dziepak 322a08b40d4SPawel Dziepak inline void 323e1e7235cSPawel Dziepak CoreEntry::LockCPUHeap() 324e1e7235cSPawel Dziepak { 32596dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 326e1e7235cSPawel Dziepak acquire_spinlock(&fCPULock); 327e1e7235cSPawel Dziepak } 328e1e7235cSPawel Dziepak 329e1e7235cSPawel Dziepak 330e1e7235cSPawel Dziepak inline void 331e1e7235cSPawel Dziepak CoreEntry::UnlockCPUHeap() 332e1e7235cSPawel Dziepak { 33396dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 334e1e7235cSPawel Dziepak release_spinlock(&fCPULock); 335e1e7235cSPawel Dziepak } 336e1e7235cSPawel Dziepak 337e1e7235cSPawel Dziepak 338e1e7235cSPawel Dziepak inline CPUPriorityHeap* 339e1e7235cSPawel Dziepak CoreEntry::CPUHeap() 340e1e7235cSPawel Dziepak { 34196dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 342e1e7235cSPawel Dziepak return &fCPUHeap; 343e1e7235cSPawel Dziepak } 344e1e7235cSPawel Dziepak 345e1e7235cSPawel Dziepak 346a2634874SPawel Dziepak inline int32 347a2634874SPawel Dziepak CoreEntry::ThreadCount() const 348a2634874SPawel Dziepak { 349a2634874SPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 350a2634874SPawel Dziepak return fThreadCount + fCPUCount - fIdleCPUCount; 351a2634874SPawel Dziepak } 352a2634874SPawel Dziepak 353a2634874SPawel Dziepak 354e1e7235cSPawel Dziepak inline void 355e1e7235cSPawel Dziepak CoreEntry::LockRunQueue() 356e1e7235cSPawel Dziepak { 35796dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 358e1e7235cSPawel Dziepak acquire_spinlock(&fQueueLock); 359e1e7235cSPawel Dziepak } 360e1e7235cSPawel Dziepak 361e1e7235cSPawel Dziepak 362e1e7235cSPawel Dziepak inline void 363e1e7235cSPawel Dziepak CoreEntry::UnlockRunQueue() 364e1e7235cSPawel Dziepak { 36596dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 366e1e7235cSPawel Dziepak release_spinlock(&fQueueLock); 367e1e7235cSPawel Dziepak } 368e1e7235cSPawel Dziepak 369e1e7235cSPawel Dziepak 370e1e7235cSPawel Dziepak inline void 371e1e7235cSPawel Dziepak CoreEntry::IncreaseActiveTime(bigtime_t activeTime) 372e1e7235cSPawel Dziepak { 37396dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 374e1e7235cSPawel Dziepak WriteSequentialLocker _(fActiveTimeLock); 375e1e7235cSPawel Dziepak fActiveTime += activeTime; 376e1e7235cSPawel Dziepak } 377e1e7235cSPawel Dziepak 378e1e7235cSPawel Dziepak 379e1e7235cSPawel Dziepak inline bigtime_t 380e1e7235cSPawel Dziepak CoreEntry::GetActiveTime() const 381e1e7235cSPawel Dziepak { 38296dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 383e1e7235cSPawel Dziepak 38496dcc73bSPawel Dziepak bigtime_t activeTime; 385e1e7235cSPawel Dziepak uint32 count; 386e1e7235cSPawel Dziepak do { 387e1e7235cSPawel Dziepak count = acquire_read_seqlock(&fActiveTimeLock); 388e1e7235cSPawel Dziepak activeTime = fActiveTime; 389e1e7235cSPawel Dziepak } while (!release_read_seqlock(&fActiveTimeLock, count)); 390e1e7235cSPawel Dziepak return activeTime; 391e1e7235cSPawel Dziepak } 392e1e7235cSPawel Dziepak 393e1e7235cSPawel Dziepak 394d287274dSPawel Dziepak inline int32 395d287274dSPawel Dziepak CoreEntry::GetLoad() const 396d287274dSPawel Dziepak { 39796dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 39896dcc73bSPawel Dziepak 3998aa1539bSPawel Dziepak ASSERT(fCPUCount > 0); 400*e632208bSJérôme Duval return std::min(fLoad / fCPUCount, kMaxLoad); 401d287274dSPawel Dziepak } 402d287274dSPawel Dziepak 403d287274dSPawel Dziepak 4046155ab7bSPawel Dziepak inline void 4056155ab7bSPawel Dziepak CoreEntry::AddLoad(int32 load, uint32 epoch, bool updateLoad) 4066155ab7bSPawel Dziepak { 4076155ab7bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 4086155ab7bSPawel Dziepak 4096155ab7bSPawel Dziepak ASSERT(gTrackCoreLoad); 4106155ab7bSPawel Dziepak ASSERT(load >= 0 && load <= kMaxLoad); 4116155ab7bSPawel Dziepak 4126155ab7bSPawel Dziepak ReadSpinLocker locker(fLoadLock); 4136155ab7bSPawel Dziepak atomic_add(&fCurrentLoad, load); 4146155ab7bSPawel Dziepak if (fLoadMeasurementEpoch != epoch) 4156155ab7bSPawel Dziepak atomic_add(&fLoad, load); 4166155ab7bSPawel Dziepak locker.Unlock(); 4176155ab7bSPawel Dziepak 4186155ab7bSPawel Dziepak if (updateLoad) 419667b23ddSPawel Dziepak _UpdateLoad(true); 4206155ab7bSPawel Dziepak } 4216155ab7bSPawel Dziepak 4226155ab7bSPawel Dziepak 4236155ab7bSPawel Dziepak inline uint32 4246155ab7bSPawel Dziepak CoreEntry::RemoveLoad(int32 load, bool force) 4256155ab7bSPawel Dziepak { 4266155ab7bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 4276155ab7bSPawel Dziepak 4286155ab7bSPawel Dziepak ASSERT(gTrackCoreLoad); 4296155ab7bSPawel Dziepak ASSERT(load >= 0 && load <= kMaxLoad); 4306155ab7bSPawel Dziepak 4316155ab7bSPawel Dziepak ReadSpinLocker locker(fLoadLock); 4326155ab7bSPawel Dziepak atomic_add(&fCurrentLoad, -load); 4336155ab7bSPawel Dziepak if (force) { 4346155ab7bSPawel Dziepak atomic_add(&fLoad, -load); 4356155ab7bSPawel Dziepak locker.Unlock(); 4366155ab7bSPawel Dziepak 437667b23ddSPawel Dziepak _UpdateLoad(true); 4386155ab7bSPawel Dziepak } 4396155ab7bSPawel Dziepak return fLoadMeasurementEpoch; 4406155ab7bSPawel Dziepak } 4416155ab7bSPawel Dziepak 4426155ab7bSPawel Dziepak 4436155ab7bSPawel Dziepak inline void 4446155ab7bSPawel Dziepak CoreEntry::ChangeLoad(int32 delta) 4456155ab7bSPawel Dziepak { 4466155ab7bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 4476155ab7bSPawel Dziepak 4486155ab7bSPawel Dziepak ASSERT(gTrackCoreLoad); 4496155ab7bSPawel Dziepak ASSERT(delta >= -kMaxLoad && delta <= kMaxLoad); 4506155ab7bSPawel Dziepak 451230d1fcfSPawel Dziepak if (delta != 0) { 4526155ab7bSPawel Dziepak ReadSpinLocker locker(fLoadLock); 4536155ab7bSPawel Dziepak atomic_add(&fCurrentLoad, delta); 4546155ab7bSPawel Dziepak atomic_add(&fLoad, delta); 455230d1fcfSPawel Dziepak } 4566155ab7bSPawel Dziepak 4576155ab7bSPawel Dziepak _UpdateLoad(); 4586155ab7bSPawel Dziepak } 4596155ab7bSPawel Dziepak 4606155ab7bSPawel Dziepak 461cb66faefSPawel Dziepak /* PackageEntry::CoreGoesIdle and PackageEntry::CoreWakesUp have to be defined 462cb66faefSPawel Dziepak before CoreEntry::CPUGoesIdle and CoreEntry::CPUWakesUp. If they weren't 463cb66faefSPawel Dziepak GCC2 wouldn't inline them as, apparently, it doesn't do enough optimization 464cb66faefSPawel Dziepak passes. 465cb66faefSPawel Dziepak */ 466cb66faefSPawel Dziepak inline void 467cb66faefSPawel Dziepak PackageEntry::CoreGoesIdle(CoreEntry* core) 468cb66faefSPawel Dziepak { 469cb66faefSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 470cb66faefSPawel Dziepak 471cb66faefSPawel Dziepak WriteSpinLocker _(fCoreLock); 472cb66faefSPawel Dziepak 473cb66faefSPawel Dziepak ASSERT(fIdleCoreCount >= 0); 474cb66faefSPawel Dziepak ASSERT(fIdleCoreCount < fCoreCount); 475cb66faefSPawel Dziepak 476cb66faefSPawel Dziepak fIdleCoreCount++; 477cb66faefSPawel Dziepak fIdleCores.Add(core); 478cb66faefSPawel Dziepak 479cb66faefSPawel Dziepak if (fIdleCoreCount == fCoreCount) { 480cb66faefSPawel Dziepak // package goes idle 481cb66faefSPawel Dziepak WriteSpinLocker _(gIdlePackageLock); 482cb66faefSPawel Dziepak gIdlePackageList.Add(this); 483cb66faefSPawel Dziepak } 484cb66faefSPawel Dziepak } 485cb66faefSPawel Dziepak 486cb66faefSPawel Dziepak 487cb66faefSPawel Dziepak inline void 488cb66faefSPawel Dziepak PackageEntry::CoreWakesUp(CoreEntry* core) 489cb66faefSPawel Dziepak { 490cb66faefSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 491cb66faefSPawel Dziepak 492cb66faefSPawel Dziepak WriteSpinLocker _(fCoreLock); 493cb66faefSPawel Dziepak 494cb66faefSPawel Dziepak ASSERT(fIdleCoreCount > 0); 495cb66faefSPawel Dziepak ASSERT(fIdleCoreCount <= fCoreCount); 496cb66faefSPawel Dziepak 497cb66faefSPawel Dziepak fIdleCoreCount--; 498cb66faefSPawel Dziepak fIdleCores.Remove(core); 499cb66faefSPawel Dziepak 500cb66faefSPawel Dziepak if (fIdleCoreCount + 1 == fCoreCount) { 501cb66faefSPawel Dziepak // package wakes up 502cb66faefSPawel Dziepak WriteSpinLocker _(gIdlePackageLock); 503cb66faefSPawel Dziepak gIdlePackageList.Remove(this); 504cb66faefSPawel Dziepak } 505cb66faefSPawel Dziepak } 506cb66faefSPawel Dziepak 507cb66faefSPawel Dziepak 508cb66faefSPawel Dziepak inline void 509cb66faefSPawel Dziepak CoreEntry::CPUGoesIdle(CPUEntry* /* cpu */) 510cb66faefSPawel Dziepak { 5119c465cc8SPawel Dziepak if (gSingleCore) 5129c465cc8SPawel Dziepak return; 5139c465cc8SPawel Dziepak 514d36098e0SPawel Dziepak ASSERT(fIdleCPUCount < fCPUCount); 515d36098e0SPawel Dziepak if (++fIdleCPUCount == fCPUCount) 516cb66faefSPawel Dziepak fPackage->CoreGoesIdle(this); 517cb66faefSPawel Dziepak } 518cb66faefSPawel Dziepak 519cb66faefSPawel Dziepak 520cb66faefSPawel Dziepak inline void 521cb66faefSPawel Dziepak CoreEntry::CPUWakesUp(CPUEntry* /* cpu */) 522cb66faefSPawel Dziepak { 5239c465cc8SPawel Dziepak if (gSingleCore) 5249c465cc8SPawel Dziepak return; 525cb66faefSPawel Dziepak 526d36098e0SPawel Dziepak ASSERT(fIdleCPUCount > 0); 527d36098e0SPawel Dziepak if (fIdleCPUCount-- == fCPUCount) 528cb66faefSPawel Dziepak fPackage->CoreWakesUp(this); 529cb66faefSPawel Dziepak } 530cb66faefSPawel Dziepak 531cb66faefSPawel Dziepak 532d287274dSPawel Dziepak /* static */ inline CoreEntry* 533d287274dSPawel Dziepak CoreEntry::GetCore(int32 cpu) 534d287274dSPawel Dziepak { 53596dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 536a08b40d4SPawel Dziepak return gCPUEntries[cpu].Core(); 537d287274dSPawel Dziepak } 538d287274dSPawel Dziepak 539d287274dSPawel Dziepak 54060e198f2SPawel Dziepak inline CoreEntry* 54160e198f2SPawel Dziepak PackageEntry::GetIdleCore() const 54260e198f2SPawel Dziepak { 54396dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 54460e198f2SPawel Dziepak return fIdleCores.Last(); 54560e198f2SPawel Dziepak } 54660e198f2SPawel Dziepak 54760e198f2SPawel Dziepak 54860e198f2SPawel Dziepak /* static */ inline PackageEntry* 54960e198f2SPawel Dziepak PackageEntry::GetMostIdlePackage() 55060e198f2SPawel Dziepak { 55196dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 55296dcc73bSPawel Dziepak 55360e198f2SPawel Dziepak PackageEntry* current = &gPackageEntries[0]; 55460e198f2SPawel Dziepak for (int32 i = 1; i < gPackageCount; i++) { 55560e198f2SPawel Dziepak if (gPackageEntries[i].fIdleCoreCount > current->fIdleCoreCount) 55660e198f2SPawel Dziepak current = &gPackageEntries[i]; 55760e198f2SPawel Dziepak } 55860e198f2SPawel Dziepak 55960e198f2SPawel Dziepak if (current->fIdleCoreCount == 0) 56060e198f2SPawel Dziepak return NULL; 56160e198f2SPawel Dziepak 56260e198f2SPawel Dziepak return current; 56360e198f2SPawel Dziepak } 56460e198f2SPawel Dziepak 56560e198f2SPawel Dziepak 56660e198f2SPawel Dziepak /* static */ inline PackageEntry* 56760e198f2SPawel Dziepak PackageEntry::GetLeastIdlePackage() 56860e198f2SPawel Dziepak { 56996dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION(); 57096dcc73bSPawel Dziepak 57160e198f2SPawel Dziepak PackageEntry* package = NULL; 57260e198f2SPawel Dziepak 57360e198f2SPawel Dziepak for (int32 i = 0; i < gPackageCount; i++) { 57460e198f2SPawel Dziepak PackageEntry* current = &gPackageEntries[i]; 57560e198f2SPawel Dziepak 57660e198f2SPawel Dziepak int32 currentIdleCoreCount = current->fIdleCoreCount; 57760e198f2SPawel Dziepak if (currentIdleCoreCount != 0 && (package == NULL 57860e198f2SPawel Dziepak || currentIdleCoreCount < package->fIdleCoreCount)) { 57960e198f2SPawel Dziepak package = current; 58060e198f2SPawel Dziepak } 58160e198f2SPawel Dziepak } 58260e198f2SPawel Dziepak 58360e198f2SPawel Dziepak return package; 58460e198f2SPawel Dziepak } 58560e198f2SPawel Dziepak 58660e198f2SPawel Dziepak 587d287274dSPawel Dziepak } // namespace Scheduler 588d287274dSPawel Dziepak 589d287274dSPawel Dziepak 590d287274dSPawel Dziepak #endif // KERNEL_SCHEDULER_CPU_H 591d287274dSPawel Dziepak 592