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