xref: /haiku/src/system/kernel/scheduler/scheduler_cpu.h (revision 9c465cc83bbd40732475db43bd870221b99bdbb7)
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