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
11*f7a85eeaSJérôme Duval #include <smp.h>
12d287274dSPawel Dziepak #include <thread.h>
13e1e7235cSPawel Dziepak #include <util/AutoLock.h>
14ef8e55a1SPawel Dziepak #include <util/Heap.h>
157c92dffeSPawel Dziepak #include <util/MinMaxHeap.h>
16d287274dSPawel Dziepak
17d287274dSPawel Dziepak #include <cpufreq.h>
18d287274dSPawel Dziepak
19d287274dSPawel Dziepak #include "RunQueue.h"
20d287274dSPawel Dziepak #include "scheduler_common.h"
21d287274dSPawel Dziepak #include "scheduler_modes.h"
2296dcc73bSPawel Dziepak #include "scheduler_profiler.h"
23d287274dSPawel Dziepak
24d287274dSPawel Dziepak
25d287274dSPawel Dziepak namespace Scheduler {
26d287274dSPawel Dziepak
27d287274dSPawel Dziepak
2860e198f2SPawel Dziepak class DebugDumper;
2960e198f2SPawel Dziepak
30d287274dSPawel Dziepak struct ThreadData;
31e1e7235cSPawel Dziepak class ThreadProcessing;
32d287274dSPawel Dziepak
339216fc01SAugustin Cavalier class CPUEntry;
349216fc01SAugustin Cavalier class CoreEntry;
359216fc01SAugustin Cavalier class PackageEntry;
36d287274dSPawel Dziepak
37d287274dSPawel Dziepak // The run queues. Holds the threads ready to run ordered by priority.
38d287274dSPawel Dziepak // One queue per schedulable target per core. Additionally, each
39d287274dSPawel Dziepak // logical processor has its sPinnedRunQueues used for scheduling
40d287274dSPawel Dziepak // pinned threads.
41d287274dSPawel Dziepak class ThreadRunQueue : public RunQueue<ThreadData, THREAD_MAX_SET_PRIORITY> {
42d287274dSPawel Dziepak public:
43d287274dSPawel Dziepak void Dump() const;
44d287274dSPawel Dziepak };
45d287274dSPawel Dziepak
46ef8e55a1SPawel Dziepak class CPUEntry : public HeapLinkImpl<CPUEntry, int32> {
47a08b40d4SPawel Dziepak public:
48d287274dSPawel Dziepak CPUEntry();
49d287274dSPawel Dziepak
50a08b40d4SPawel Dziepak void Init(int32 id, CoreEntry* core);
51a08b40d4SPawel Dziepak
ID()52a08b40d4SPawel Dziepak inline int32 ID() const { return fCPUNumber; }
Core()53a08b40d4SPawel Dziepak inline CoreEntry* Core() const { return fCore; }
54a08b40d4SPawel Dziepak
55a08b40d4SPawel Dziepak void Start();
56a08b40d4SPawel Dziepak void Stop();
57a08b40d4SPawel Dziepak
58a08b40d4SPawel Dziepak inline void EnterScheduler();
59a08b40d4SPawel Dziepak inline void ExitScheduler();
60a08b40d4SPawel Dziepak
61a08b40d4SPawel Dziepak inline void LockScheduler();
62a08b40d4SPawel Dziepak inline void UnlockScheduler();
63a08b40d4SPawel Dziepak
6426592750SPawel Dziepak inline void LockRunQueue();
6526592750SPawel Dziepak inline void UnlockRunQueue();
6626592750SPawel Dziepak
67a08b40d4SPawel Dziepak void PushFront(ThreadData* thread,
68a08b40d4SPawel Dziepak int32 priority);
69a08b40d4SPawel Dziepak void PushBack(ThreadData* thread,
70a08b40d4SPawel Dziepak int32 priority);
71a08b40d4SPawel Dziepak void Remove(ThreadData* thread);
72bad677beSAugustin Cavalier ThreadData* PeekThread() const;
73a08b40d4SPawel Dziepak ThreadData* PeekIdleThread() const;
74a08b40d4SPawel Dziepak
75d287274dSPawel Dziepak void UpdatePriority(int32 priority);
76d287274dSPawel Dziepak
GetLoad()77a08b40d4SPawel Dziepak inline int32 GetLoad() const { return fLoad; }
78d287274dSPawel Dziepak void ComputeLoad();
79d287274dSPawel Dziepak
80d287274dSPawel Dziepak ThreadData* ChooseNextThread(ThreadData* oldThread,
81d287274dSPawel Dziepak bool putAtBack);
82d287274dSPawel Dziepak
83d287274dSPawel Dziepak void TrackActivity(ThreadData* oldThreadData,
84d287274dSPawel Dziepak ThreadData* nextThreadData);
85d287274dSPawel Dziepak
86230d1fcfSPawel Dziepak void StartQuantumTimer(ThreadData* thread,
87230d1fcfSPawel Dziepak bool wasPreempted);
88230d1fcfSPawel Dziepak
89a08b40d4SPawel Dziepak static inline CPUEntry* GetCPU(int32 cpu);
90a08b40d4SPawel Dziepak
91a08b40d4SPawel Dziepak private:
92cb66faefSPawel Dziepak void _RequestPerformanceLevel(
93a08b40d4SPawel Dziepak ThreadData* threadData);
94a08b40d4SPawel Dziepak
95230d1fcfSPawel Dziepak static int32 _RescheduleEvent(timer* /* unused */);
96230d1fcfSPawel Dziepak static int32 _UpdateLoadEvent(timer* /* unused */);
97230d1fcfSPawel Dziepak
98d287274dSPawel Dziepak int32 fCPUNumber;
99d287274dSPawel Dziepak CoreEntry* fCore;
100d287274dSPawel Dziepak
101d287274dSPawel Dziepak rw_spinlock fSchedulerModeLock;
102d287274dSPawel Dziepak
103d287274dSPawel Dziepak ThreadRunQueue fRunQueue;
10426592750SPawel Dziepak spinlock fQueueLock;
105d287274dSPawel Dziepak
106d287274dSPawel Dziepak int32 fLoad;
107d287274dSPawel Dziepak
108d287274dSPawel Dziepak bigtime_t fMeasureActiveTime;
109d287274dSPawel Dziepak bigtime_t fMeasureTime;
110d287274dSPawel Dziepak
111230d1fcfSPawel Dziepak bool fUpdateLoadEvent;
112230d1fcfSPawel Dziepak
113a08b40d4SPawel Dziepak friend class DebugDumper;
114d287274dSPawel Dziepak } CACHE_LINE_ALIGN;
115d287274dSPawel Dziepak
116ef8e55a1SPawel Dziepak class CPUPriorityHeap : public Heap<CPUEntry, int32> {
117d287274dSPawel Dziepak public:
CPUPriorityHeap()118d287274dSPawel Dziepak CPUPriorityHeap() { }
119d287274dSPawel Dziepak CPUPriorityHeap(int32 cpuCount);
120d287274dSPawel Dziepak
121d287274dSPawel Dziepak void Dump();
122d287274dSPawel Dziepak };
123d287274dSPawel Dziepak
124e1e7235cSPawel Dziepak class CoreEntry : public MinMaxHeapLinkImpl<CoreEntry, int32>,
125e1e7235cSPawel Dziepak public DoublyLinkedListLinkImpl<CoreEntry> {
126e1e7235cSPawel Dziepak public:
127d287274dSPawel Dziepak CoreEntry();
128d287274dSPawel Dziepak
129e1e7235cSPawel Dziepak void Init(int32 id, PackageEntry* package);
130e1e7235cSPawel Dziepak
ID()131e1e7235cSPawel Dziepak inline int32 ID() const { return fCoreID; }
Package()132e1e7235cSPawel Dziepak inline PackageEntry* Package() const { return fPackage; }
CPUCount()133e1e7235cSPawel Dziepak inline int32 CPUCount() const
134e1e7235cSPawel Dziepak { return fCPUCount; }
CPUMask()135*f7a85eeaSJérôme Duval inline const CPUSet& CPUMask() const
136*f7a85eeaSJérôme Duval { return fCPUSet; }
137e1e7235cSPawel Dziepak
138e1e7235cSPawel Dziepak inline void LockCPUHeap();
139e1e7235cSPawel Dziepak inline void UnlockCPUHeap();
140e1e7235cSPawel Dziepak
141e1e7235cSPawel Dziepak inline CPUPriorityHeap* CPUHeap();
142e1e7235cSPawel Dziepak
143a2634874SPawel Dziepak inline int32 ThreadCount() const;
144e1e7235cSPawel Dziepak
145e1e7235cSPawel Dziepak inline void LockRunQueue();
146e1e7235cSPawel Dziepak inline void UnlockRunQueue();
147e1e7235cSPawel Dziepak
148e1e7235cSPawel Dziepak void PushFront(ThreadData* thread,
149e1e7235cSPawel Dziepak int32 priority);
150e1e7235cSPawel Dziepak void PushBack(ThreadData* thread,
151e1e7235cSPawel Dziepak int32 priority);
152b24ea642SPawel Dziepak void Remove(ThreadData* thread);
153bad677beSAugustin Cavalier ThreadData* PeekThread() const;
154e1e7235cSPawel Dziepak
155e1e7235cSPawel Dziepak inline bigtime_t GetActiveTime() const;
156e1e7235cSPawel Dziepak inline void IncreaseActiveTime(
157e1e7235cSPawel Dziepak bigtime_t activeTime);
158e1e7235cSPawel Dziepak
159d287274dSPawel Dziepak inline int32 GetLoad() const;
LoadMeasurementEpoch()1606155ab7bSPawel Dziepak inline uint32 LoadMeasurementEpoch() const
1616155ab7bSPawel Dziepak { return fLoadMeasurementEpoch; }
1626155ab7bSPawel Dziepak
1636155ab7bSPawel Dziepak inline void AddLoad(int32 load, uint32 epoch,
1646155ab7bSPawel Dziepak bool updateLoad);
1656155ab7bSPawel Dziepak inline uint32 RemoveLoad(int32 load, bool force);
1666155ab7bSPawel Dziepak inline void ChangeLoad(int32 delta);
167e1e7235cSPawel Dziepak
168ef8e55a1SPawel Dziepak inline void CPUGoesIdle(CPUEntry* cpu);
169ef8e55a1SPawel Dziepak inline void CPUWakesUp(CPUEntry* cpu);
170ef8e55a1SPawel Dziepak
171e1e7235cSPawel Dziepak void AddCPU(CPUEntry* cpu);
172e1e7235cSPawel Dziepak void RemoveCPU(CPUEntry* cpu,
173e1e7235cSPawel Dziepak ThreadProcessing&
174e1e7235cSPawel Dziepak threadPostProcessing);
175d287274dSPawel Dziepak
176d287274dSPawel Dziepak static inline CoreEntry* GetCore(int32 cpu);
177d287274dSPawel Dziepak
178e1e7235cSPawel Dziepak private:
179667b23ddSPawel Dziepak void _UpdateLoad(bool forceUpdate = false);
1806155ab7bSPawel Dziepak
181e1e7235cSPawel Dziepak static void _UnassignThread(Thread* thread,
182e1e7235cSPawel Dziepak void* core);
183e1e7235cSPawel Dziepak
184d287274dSPawel Dziepak int32 fCoreID;
185d287274dSPawel Dziepak PackageEntry* fPackage;
186d287274dSPawel Dziepak
187d287274dSPawel Dziepak int32 fCPUCount;
188*f7a85eeaSJérôme Duval CPUSet fCPUSet;
189d36098e0SPawel Dziepak int32 fIdleCPUCount;
190d287274dSPawel Dziepak CPUPriorityHeap fCPUHeap;
191d287274dSPawel Dziepak spinlock fCPULock;
192d287274dSPawel Dziepak
193d287274dSPawel Dziepak int32 fThreadCount;
194d287274dSPawel Dziepak ThreadRunQueue fRunQueue;
195d287274dSPawel Dziepak spinlock fQueueLock;
196d287274dSPawel Dziepak
197d287274dSPawel Dziepak bigtime_t fActiveTime;
198e1e7235cSPawel Dziepak mutable seqlock fActiveTimeLock;
199d287274dSPawel Dziepak
200d287274dSPawel Dziepak int32 fLoad;
2016155ab7bSPawel Dziepak int32 fCurrentLoad;
2026155ab7bSPawel Dziepak uint32 fLoadMeasurementEpoch;
203d287274dSPawel Dziepak bool fHighLoad;
204a2634874SPawel Dziepak bigtime_t fLastLoadUpdate;
2056155ab7bSPawel Dziepak rw_spinlock fLoadLock;
206e1e7235cSPawel Dziepak
207e1e7235cSPawel Dziepak friend class DebugDumper;
208d287274dSPawel Dziepak } CACHE_LINE_ALIGN;
209d287274dSPawel Dziepak
210d287274dSPawel Dziepak class CoreLoadHeap : public MinMaxHeap<CoreEntry, int32> {
211d287274dSPawel Dziepak public:
CoreLoadHeap()212d287274dSPawel Dziepak CoreLoadHeap() { }
213d287274dSPawel Dziepak CoreLoadHeap(int32 coreCount);
214d287274dSPawel Dziepak
215d287274dSPawel Dziepak void Dump();
216d287274dSPawel Dziepak };
217d287274dSPawel Dziepak
218d287274dSPawel Dziepak // gPackageEntries are used to decide which core should be woken up from the
219d287274dSPawel Dziepak // idle state. When aiming for performance we should use as many packages as
220d287274dSPawel Dziepak // possible with as little cores active in each package as possible (so that the
221d287274dSPawel Dziepak // package can enter any boost mode if it has one and the active core have more
222d287274dSPawel Dziepak // of the shared cache for themselves. If power saving is the main priority we
223d287274dSPawel Dziepak // should keep active cores on as little packages as possible (so that other
224d287274dSPawel Dziepak // packages can go to the deep state of sleep). The heap stores only packages
225d287274dSPawel Dziepak // with at least one core active and one core idle. The packages with all cores
226d287274dSPawel Dziepak // idle are stored in gPackageIdleList (in LIFO manner).
22760e198f2SPawel Dziepak class PackageEntry : public DoublyLinkedListLinkImpl<PackageEntry> {
22860e198f2SPawel Dziepak public:
229d287274dSPawel Dziepak PackageEntry();
230d287274dSPawel Dziepak
23160e198f2SPawel Dziepak void Init(int32 id);
23260e198f2SPawel Dziepak
23360e198f2SPawel Dziepak inline void CoreGoesIdle(CoreEntry* core);
23460e198f2SPawel Dziepak inline void CoreWakesUp(CoreEntry* core);
23560e198f2SPawel Dziepak
236*f7a85eeaSJérôme Duval inline CoreEntry* GetIdleCore(int32 index = 0) const;
23760e198f2SPawel Dziepak
23860e198f2SPawel Dziepak void AddIdleCore(CoreEntry* core);
23960e198f2SPawel Dziepak void RemoveIdleCore(CoreEntry* core);
24060e198f2SPawel Dziepak
24160e198f2SPawel Dziepak static inline PackageEntry* GetMostIdlePackage();
24260e198f2SPawel Dziepak static inline PackageEntry* GetLeastIdlePackage();
24360e198f2SPawel Dziepak
24460e198f2SPawel Dziepak private:
245d287274dSPawel Dziepak int32 fPackageID;
246d287274dSPawel Dziepak
247d287274dSPawel Dziepak DoublyLinkedList<CoreEntry> fIdleCores;
248d287274dSPawel Dziepak int32 fIdleCoreCount;
249d287274dSPawel Dziepak int32 fCoreCount;
250d287274dSPawel Dziepak rw_spinlock fCoreLock;
25160e198f2SPawel Dziepak
25260e198f2SPawel Dziepak friend class DebugDumper;
253d287274dSPawel Dziepak } CACHE_LINE_ALIGN;
254d287274dSPawel Dziepak typedef DoublyLinkedList<PackageEntry> IdlePackageList;
255d287274dSPawel Dziepak
256d287274dSPawel Dziepak extern CPUEntry* gCPUEntries;
257d287274dSPawel Dziepak
258d287274dSPawel Dziepak extern CoreEntry* gCoreEntries;
259d287274dSPawel Dziepak extern CoreLoadHeap gCoreLoadHeap;
260d287274dSPawel Dziepak extern CoreLoadHeap gCoreHighLoadHeap;
261d287274dSPawel Dziepak extern rw_spinlock gCoreHeapsLock;
262d287274dSPawel Dziepak extern int32 gCoreCount;
263d287274dSPawel Dziepak
264d287274dSPawel Dziepak extern PackageEntry* gPackageEntries;
265d287274dSPawel Dziepak extern IdlePackageList gIdlePackageList;
266d287274dSPawel Dziepak extern rw_spinlock gIdlePackageLock;
267d287274dSPawel Dziepak extern int32 gPackageCount;
268d287274dSPawel Dziepak
269d287274dSPawel Dziepak
270e1e7235cSPawel Dziepak inline void
EnterScheduler()271a08b40d4SPawel Dziepak CPUEntry::EnterScheduler()
272a08b40d4SPawel Dziepak {
27396dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
274a08b40d4SPawel Dziepak acquire_read_spinlock(&fSchedulerModeLock);
275a08b40d4SPawel Dziepak }
276a08b40d4SPawel Dziepak
277a08b40d4SPawel Dziepak
278a08b40d4SPawel Dziepak inline void
ExitScheduler()279a08b40d4SPawel Dziepak CPUEntry::ExitScheduler()
280a08b40d4SPawel Dziepak {
28196dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
282a08b40d4SPawel Dziepak release_read_spinlock(&fSchedulerModeLock);
283a08b40d4SPawel Dziepak }
284a08b40d4SPawel Dziepak
285a08b40d4SPawel Dziepak
286a08b40d4SPawel Dziepak inline void
LockScheduler()287a08b40d4SPawel Dziepak CPUEntry::LockScheduler()
288a08b40d4SPawel Dziepak {
28996dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
290a08b40d4SPawel Dziepak acquire_write_spinlock(&fSchedulerModeLock);
291a08b40d4SPawel Dziepak }
292a08b40d4SPawel Dziepak
293a08b40d4SPawel Dziepak
294a08b40d4SPawel Dziepak inline void
UnlockScheduler()295a08b40d4SPawel Dziepak CPUEntry::UnlockScheduler()
296a08b40d4SPawel Dziepak {
29796dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
298a08b40d4SPawel Dziepak release_write_spinlock(&fSchedulerModeLock);
299a08b40d4SPawel Dziepak }
300a08b40d4SPawel Dziepak
301a08b40d4SPawel Dziepak
30226592750SPawel Dziepak inline void
LockRunQueue()30326592750SPawel Dziepak CPUEntry::LockRunQueue()
30426592750SPawel Dziepak {
30526592750SPawel Dziepak SCHEDULER_ENTER_FUNCTION();
30626592750SPawel Dziepak acquire_spinlock(&fQueueLock);
30726592750SPawel Dziepak }
30826592750SPawel Dziepak
30926592750SPawel Dziepak
31026592750SPawel Dziepak inline void
UnlockRunQueue()31126592750SPawel Dziepak CPUEntry::UnlockRunQueue()
31226592750SPawel Dziepak {
31326592750SPawel Dziepak SCHEDULER_ENTER_FUNCTION();
31426592750SPawel Dziepak release_spinlock(&fQueueLock);
31526592750SPawel Dziepak }
31626592750SPawel Dziepak
31726592750SPawel Dziepak
318a08b40d4SPawel Dziepak /* static */ inline CPUEntry*
GetCPU(int32 cpu)319a08b40d4SPawel Dziepak CPUEntry::GetCPU(int32 cpu)
320a08b40d4SPawel Dziepak {
32196dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
322a08b40d4SPawel Dziepak return &gCPUEntries[cpu];
323a08b40d4SPawel Dziepak }
324a08b40d4SPawel Dziepak
325a08b40d4SPawel Dziepak
326a08b40d4SPawel Dziepak inline void
LockCPUHeap()327e1e7235cSPawel Dziepak CoreEntry::LockCPUHeap()
328e1e7235cSPawel Dziepak {
32996dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
330e1e7235cSPawel Dziepak acquire_spinlock(&fCPULock);
331e1e7235cSPawel Dziepak }
332e1e7235cSPawel Dziepak
333e1e7235cSPawel Dziepak
334e1e7235cSPawel Dziepak inline void
UnlockCPUHeap()335e1e7235cSPawel Dziepak CoreEntry::UnlockCPUHeap()
336e1e7235cSPawel Dziepak {
33796dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
338e1e7235cSPawel Dziepak release_spinlock(&fCPULock);
339e1e7235cSPawel Dziepak }
340e1e7235cSPawel Dziepak
341e1e7235cSPawel Dziepak
342e1e7235cSPawel Dziepak inline CPUPriorityHeap*
CPUHeap()343e1e7235cSPawel Dziepak CoreEntry::CPUHeap()
344e1e7235cSPawel Dziepak {
34596dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
346e1e7235cSPawel Dziepak return &fCPUHeap;
347e1e7235cSPawel Dziepak }
348e1e7235cSPawel Dziepak
349e1e7235cSPawel Dziepak
350a2634874SPawel Dziepak inline int32
ThreadCount()351a2634874SPawel Dziepak CoreEntry::ThreadCount() const
352a2634874SPawel Dziepak {
353a2634874SPawel Dziepak SCHEDULER_ENTER_FUNCTION();
354a2634874SPawel Dziepak return fThreadCount + fCPUCount - fIdleCPUCount;
355a2634874SPawel Dziepak }
356a2634874SPawel Dziepak
357a2634874SPawel Dziepak
358e1e7235cSPawel Dziepak inline void
LockRunQueue()359e1e7235cSPawel Dziepak CoreEntry::LockRunQueue()
360e1e7235cSPawel Dziepak {
36196dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
362e1e7235cSPawel Dziepak acquire_spinlock(&fQueueLock);
363e1e7235cSPawel Dziepak }
364e1e7235cSPawel Dziepak
365e1e7235cSPawel Dziepak
366e1e7235cSPawel Dziepak inline void
UnlockRunQueue()367e1e7235cSPawel Dziepak CoreEntry::UnlockRunQueue()
368e1e7235cSPawel Dziepak {
36996dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
370e1e7235cSPawel Dziepak release_spinlock(&fQueueLock);
371e1e7235cSPawel Dziepak }
372e1e7235cSPawel Dziepak
373e1e7235cSPawel Dziepak
374e1e7235cSPawel Dziepak inline void
IncreaseActiveTime(bigtime_t activeTime)375e1e7235cSPawel Dziepak CoreEntry::IncreaseActiveTime(bigtime_t activeTime)
376e1e7235cSPawel Dziepak {
37796dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
378e1e7235cSPawel Dziepak WriteSequentialLocker _(fActiveTimeLock);
379e1e7235cSPawel Dziepak fActiveTime += activeTime;
380e1e7235cSPawel Dziepak }
381e1e7235cSPawel Dziepak
382e1e7235cSPawel Dziepak
383e1e7235cSPawel Dziepak inline bigtime_t
GetActiveTime()384e1e7235cSPawel Dziepak CoreEntry::GetActiveTime() const
385e1e7235cSPawel Dziepak {
38696dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
387e1e7235cSPawel Dziepak
38896dcc73bSPawel Dziepak bigtime_t activeTime;
389e1e7235cSPawel Dziepak uint32 count;
390e1e7235cSPawel Dziepak do {
391e1e7235cSPawel Dziepak count = acquire_read_seqlock(&fActiveTimeLock);
392e1e7235cSPawel Dziepak activeTime = fActiveTime;
393e1e7235cSPawel Dziepak } while (!release_read_seqlock(&fActiveTimeLock, count));
394e1e7235cSPawel Dziepak return activeTime;
395e1e7235cSPawel Dziepak }
396e1e7235cSPawel Dziepak
397e1e7235cSPawel Dziepak
398d287274dSPawel Dziepak inline int32
GetLoad()399d287274dSPawel Dziepak CoreEntry::GetLoad() const
400d287274dSPawel Dziepak {
40196dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
40296dcc73bSPawel Dziepak
4038aa1539bSPawel Dziepak ASSERT(fCPUCount > 0);
404e632208bSJérôme Duval return std::min(fLoad / fCPUCount, kMaxLoad);
405d287274dSPawel Dziepak }
406d287274dSPawel Dziepak
407d287274dSPawel Dziepak
4086155ab7bSPawel Dziepak inline void
AddLoad(int32 load,uint32 epoch,bool updateLoad)4096155ab7bSPawel Dziepak CoreEntry::AddLoad(int32 load, uint32 epoch, bool updateLoad)
4106155ab7bSPawel Dziepak {
4116155ab7bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
4126155ab7bSPawel Dziepak
4136155ab7bSPawel Dziepak ASSERT(gTrackCoreLoad);
4146155ab7bSPawel Dziepak ASSERT(load >= 0 && load <= kMaxLoad);
4156155ab7bSPawel Dziepak
4166155ab7bSPawel Dziepak ReadSpinLocker locker(fLoadLock);
4176155ab7bSPawel Dziepak atomic_add(&fCurrentLoad, load);
4186155ab7bSPawel Dziepak if (fLoadMeasurementEpoch != epoch)
4196155ab7bSPawel Dziepak atomic_add(&fLoad, load);
4206155ab7bSPawel Dziepak locker.Unlock();
4216155ab7bSPawel Dziepak
4226155ab7bSPawel Dziepak if (updateLoad)
423667b23ddSPawel Dziepak _UpdateLoad(true);
4246155ab7bSPawel Dziepak }
4256155ab7bSPawel Dziepak
4266155ab7bSPawel Dziepak
4276155ab7bSPawel Dziepak inline uint32
RemoveLoad(int32 load,bool force)4286155ab7bSPawel Dziepak CoreEntry::RemoveLoad(int32 load, bool force)
4296155ab7bSPawel Dziepak {
4306155ab7bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
4316155ab7bSPawel Dziepak
4326155ab7bSPawel Dziepak ASSERT(gTrackCoreLoad);
4336155ab7bSPawel Dziepak ASSERT(load >= 0 && load <= kMaxLoad);
4346155ab7bSPawel Dziepak
4356155ab7bSPawel Dziepak ReadSpinLocker locker(fLoadLock);
4366155ab7bSPawel Dziepak atomic_add(&fCurrentLoad, -load);
4376155ab7bSPawel Dziepak if (force) {
4386155ab7bSPawel Dziepak atomic_add(&fLoad, -load);
4396155ab7bSPawel Dziepak locker.Unlock();
4406155ab7bSPawel Dziepak
441667b23ddSPawel Dziepak _UpdateLoad(true);
4426155ab7bSPawel Dziepak }
4436155ab7bSPawel Dziepak return fLoadMeasurementEpoch;
4446155ab7bSPawel Dziepak }
4456155ab7bSPawel Dziepak
4466155ab7bSPawel Dziepak
4476155ab7bSPawel Dziepak inline void
ChangeLoad(int32 delta)4486155ab7bSPawel Dziepak CoreEntry::ChangeLoad(int32 delta)
4496155ab7bSPawel Dziepak {
4506155ab7bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
4516155ab7bSPawel Dziepak
4526155ab7bSPawel Dziepak ASSERT(gTrackCoreLoad);
4536155ab7bSPawel Dziepak ASSERT(delta >= -kMaxLoad && delta <= kMaxLoad);
4546155ab7bSPawel Dziepak
455230d1fcfSPawel Dziepak if (delta != 0) {
4566155ab7bSPawel Dziepak ReadSpinLocker locker(fLoadLock);
4576155ab7bSPawel Dziepak atomic_add(&fCurrentLoad, delta);
4586155ab7bSPawel Dziepak atomic_add(&fLoad, delta);
459230d1fcfSPawel Dziepak }
4606155ab7bSPawel Dziepak
4616155ab7bSPawel Dziepak _UpdateLoad();
4626155ab7bSPawel Dziepak }
4636155ab7bSPawel Dziepak
4646155ab7bSPawel Dziepak
465cb66faefSPawel Dziepak /* PackageEntry::CoreGoesIdle and PackageEntry::CoreWakesUp have to be defined
466cb66faefSPawel Dziepak before CoreEntry::CPUGoesIdle and CoreEntry::CPUWakesUp. If they weren't
467cb66faefSPawel Dziepak GCC2 wouldn't inline them as, apparently, it doesn't do enough optimization
468cb66faefSPawel Dziepak passes.
469cb66faefSPawel Dziepak */
470cb66faefSPawel Dziepak inline void
CoreGoesIdle(CoreEntry * core)471cb66faefSPawel Dziepak PackageEntry::CoreGoesIdle(CoreEntry* core)
472cb66faefSPawel Dziepak {
473cb66faefSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
474cb66faefSPawel Dziepak
475cb66faefSPawel Dziepak WriteSpinLocker _(fCoreLock);
476cb66faefSPawel Dziepak
477cb66faefSPawel Dziepak ASSERT(fIdleCoreCount >= 0);
478cb66faefSPawel Dziepak ASSERT(fIdleCoreCount < fCoreCount);
479cb66faefSPawel Dziepak
480cb66faefSPawel Dziepak fIdleCoreCount++;
481cb66faefSPawel Dziepak fIdleCores.Add(core);
482cb66faefSPawel Dziepak
483cb66faefSPawel Dziepak if (fIdleCoreCount == fCoreCount) {
484cb66faefSPawel Dziepak // package goes idle
485cb66faefSPawel Dziepak WriteSpinLocker _(gIdlePackageLock);
486cb66faefSPawel Dziepak gIdlePackageList.Add(this);
487cb66faefSPawel Dziepak }
488cb66faefSPawel Dziepak }
489cb66faefSPawel Dziepak
490cb66faefSPawel Dziepak
491cb66faefSPawel Dziepak inline void
CoreWakesUp(CoreEntry * core)492cb66faefSPawel Dziepak PackageEntry::CoreWakesUp(CoreEntry* core)
493cb66faefSPawel Dziepak {
494cb66faefSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
495cb66faefSPawel Dziepak
496cb66faefSPawel Dziepak WriteSpinLocker _(fCoreLock);
497cb66faefSPawel Dziepak
498cb66faefSPawel Dziepak ASSERT(fIdleCoreCount > 0);
499cb66faefSPawel Dziepak ASSERT(fIdleCoreCount <= fCoreCount);
500cb66faefSPawel Dziepak
501cb66faefSPawel Dziepak fIdleCoreCount--;
502cb66faefSPawel Dziepak fIdleCores.Remove(core);
503cb66faefSPawel Dziepak
504cb66faefSPawel Dziepak if (fIdleCoreCount + 1 == fCoreCount) {
505cb66faefSPawel Dziepak // package wakes up
506cb66faefSPawel Dziepak WriteSpinLocker _(gIdlePackageLock);
507cb66faefSPawel Dziepak gIdlePackageList.Remove(this);
508cb66faefSPawel Dziepak }
509cb66faefSPawel Dziepak }
510cb66faefSPawel Dziepak
511cb66faefSPawel Dziepak
512cb66faefSPawel Dziepak inline void
CPUGoesIdle(CPUEntry *)513cb66faefSPawel Dziepak CoreEntry::CPUGoesIdle(CPUEntry* /* cpu */)
514cb66faefSPawel Dziepak {
5159c465cc8SPawel Dziepak if (gSingleCore)
5169c465cc8SPawel Dziepak return;
5179c465cc8SPawel Dziepak
518d36098e0SPawel Dziepak ASSERT(fIdleCPUCount < fCPUCount);
519d36098e0SPawel Dziepak if (++fIdleCPUCount == fCPUCount)
520cb66faefSPawel Dziepak fPackage->CoreGoesIdle(this);
521cb66faefSPawel Dziepak }
522cb66faefSPawel Dziepak
523cb66faefSPawel Dziepak
524cb66faefSPawel Dziepak inline void
CPUWakesUp(CPUEntry *)525cb66faefSPawel Dziepak CoreEntry::CPUWakesUp(CPUEntry* /* cpu */)
526cb66faefSPawel Dziepak {
5279c465cc8SPawel Dziepak if (gSingleCore)
5289c465cc8SPawel Dziepak return;
529cb66faefSPawel Dziepak
530d36098e0SPawel Dziepak ASSERT(fIdleCPUCount > 0);
531d36098e0SPawel Dziepak if (fIdleCPUCount-- == fCPUCount)
532cb66faefSPawel Dziepak fPackage->CoreWakesUp(this);
533cb66faefSPawel Dziepak }
534cb66faefSPawel Dziepak
535cb66faefSPawel Dziepak
536d287274dSPawel Dziepak /* static */ inline CoreEntry*
GetCore(int32 cpu)537d287274dSPawel Dziepak CoreEntry::GetCore(int32 cpu)
538d287274dSPawel Dziepak {
53996dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
540a08b40d4SPawel Dziepak return gCPUEntries[cpu].Core();
541d287274dSPawel Dziepak }
542d287274dSPawel Dziepak
543d287274dSPawel Dziepak
54460e198f2SPawel Dziepak inline CoreEntry*
GetIdleCore(int32 index)545*f7a85eeaSJérôme Duval PackageEntry::GetIdleCore(int32 index) const
54660e198f2SPawel Dziepak {
54796dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
548*f7a85eeaSJérôme Duval CoreEntry* element = fIdleCores.Last();
549*f7a85eeaSJérôme Duval for (int32 i = 0; element != NULL && i < index; i++)
550*f7a85eeaSJérôme Duval element = fIdleCores.GetPrevious(element);
551*f7a85eeaSJérôme Duval
552*f7a85eeaSJérôme Duval return element;
55360e198f2SPawel Dziepak }
55460e198f2SPawel Dziepak
55560e198f2SPawel Dziepak
55660e198f2SPawel Dziepak /* static */ inline PackageEntry*
GetMostIdlePackage()55760e198f2SPawel Dziepak PackageEntry::GetMostIdlePackage()
55860e198f2SPawel Dziepak {
55996dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
56096dcc73bSPawel Dziepak
56160e198f2SPawel Dziepak PackageEntry* current = &gPackageEntries[0];
56260e198f2SPawel Dziepak for (int32 i = 1; i < gPackageCount; i++) {
56360e198f2SPawel Dziepak if (gPackageEntries[i].fIdleCoreCount > current->fIdleCoreCount)
56460e198f2SPawel Dziepak current = &gPackageEntries[i];
56560e198f2SPawel Dziepak }
56660e198f2SPawel Dziepak
56760e198f2SPawel Dziepak if (current->fIdleCoreCount == 0)
56860e198f2SPawel Dziepak return NULL;
56960e198f2SPawel Dziepak
57060e198f2SPawel Dziepak return current;
57160e198f2SPawel Dziepak }
57260e198f2SPawel Dziepak
57360e198f2SPawel Dziepak
57460e198f2SPawel Dziepak /* static */ inline PackageEntry*
GetLeastIdlePackage()57560e198f2SPawel Dziepak PackageEntry::GetLeastIdlePackage()
57660e198f2SPawel Dziepak {
57796dcc73bSPawel Dziepak SCHEDULER_ENTER_FUNCTION();
57896dcc73bSPawel Dziepak
57960e198f2SPawel Dziepak PackageEntry* package = NULL;
58060e198f2SPawel Dziepak
58160e198f2SPawel Dziepak for (int32 i = 0; i < gPackageCount; i++) {
58260e198f2SPawel Dziepak PackageEntry* current = &gPackageEntries[i];
58360e198f2SPawel Dziepak
58460e198f2SPawel Dziepak int32 currentIdleCoreCount = current->fIdleCoreCount;
58560e198f2SPawel Dziepak if (currentIdleCoreCount != 0 && (package == NULL
58660e198f2SPawel Dziepak || currentIdleCoreCount < package->fIdleCoreCount)) {
58760e198f2SPawel Dziepak package = current;
58860e198f2SPawel Dziepak }
58960e198f2SPawel Dziepak }
59060e198f2SPawel Dziepak
59160e198f2SPawel Dziepak return package;
59260e198f2SPawel Dziepak }
59360e198f2SPawel Dziepak
59460e198f2SPawel Dziepak
595d287274dSPawel Dziepak } // namespace Scheduler
596d287274dSPawel Dziepak
597d287274dSPawel Dziepak
598d287274dSPawel Dziepak #endif // KERNEL_SCHEDULER_CPU_H
599d287274dSPawel Dziepak
600