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