2 * Copyright 2013, Paweł Dziepak, pdziepak@quarnos.org.
3 * Distributed under the terms of the MIT License.
6 #include "scheduler_thread.h"
9 using namespace Scheduler
;
12 static bigtime_t sQuantumLengths
[THREAD_MAX_SET_PRIORITY
+ 1];
14 const int32 kMaximumQuantumLengthsCount
= 20;
15 static bigtime_t sMaximumQuantumLengths
[kMaximumQuantumLengthsCount
];
19 ThreadData::_InitBase()
22 fAdditionalPenalty
= 0;
23 fEffectivePriority
= GetPriority();
24 fBaseQuantum
= sQuantumLengths
[GetEffectivePriority()];
29 fMeasureAvailableActiveTime
= 0;
30 fLastMeasureAvailableTime
= 0;
31 fMeasureAvailableTime
= 0;
42 ThreadData::_ChooseCore() const
44 SCHEDULER_ENTER_FUNCTION();
47 return gCurrentMode
->choose_core(this);
52 ThreadData::_ChooseCPU(CoreEntry
* core
, bool& rescheduleNeeded
) const
54 SCHEDULER_ENTER_FUNCTION();
56 int32 threadPriority
= GetEffectivePriority();
58 if (fThread
->previous_cpu
!= NULL
) {
60 = CPUEntry::GetCPU(fThread
->previous_cpu
->cpu_num
);
61 if (previousCPU
->Core() == core
&& !fThread
->previous_cpu
->disabled
) {
62 CoreCPUHeapLocker
_(core
);
63 if (CPUPriorityHeap::GetKey(previousCPU
) < threadPriority
) {
64 previousCPU
->UpdatePriority(threadPriority
);
65 rescheduleNeeded
= true;
71 CoreCPUHeapLocker
_(core
);
72 CPUEntry
* cpu
= core
->CPUHeap()->PeekRoot();
75 if (CPUPriorityHeap::GetKey(cpu
) < threadPriority
) {
76 cpu
->UpdatePriority(threadPriority
);
77 rescheduleNeeded
= true;
79 rescheduleNeeded
= false;
85 ThreadData::ThreadData(Thread
* thread
)
98 Thread
* currentThread
= thread_get_current_thread();
99 ThreadData
* currentThreadData
= currentThread
->scheduler_data
;
100 fNeededLoad
= currentThreadData
->fNeededLoad
;
103 fPriorityPenalty
= std::min(currentThreadData
->fPriorityPenalty
,
104 std::max(GetPriority() - _GetMinimalPriority(), int32(0)));
105 fAdditionalPenalty
= currentThreadData
->fAdditionalPenalty
;
107 _ComputeEffectivePriority();
113 ThreadData::Init(CoreEntry
* core
)
124 ThreadData::Dump() const
126 kprintf("\tpriority_penalty:\t%" B_PRId32
"\n", fPriorityPenalty
);
128 int32 priority
= GetPriority() - _GetPenalty();
129 priority
= std::max(priority
, int32(1));
130 kprintf("\tadditional_penalty:\t%" B_PRId32
" (%" B_PRId32
")\n",
131 fAdditionalPenalty
% priority
, fAdditionalPenalty
);
132 kprintf("\teffective_priority:\t%" B_PRId32
"\n", GetEffectivePriority());
134 kprintf("\ttime_used:\t\t%" B_PRId64
" us (quantum: %" B_PRId64
" us)\n",
135 fTimeUsed
, ComputeQuantum());
136 kprintf("\tstolen_time:\t\t%" B_PRId64
" us\n", fStolenTime
);
137 kprintf("\tquantum_start:\t\t%" B_PRId64
" us\n", fQuantumStart
);
138 kprintf("\tneeded_load:\t\t%" B_PRId32
"%%\n", fNeededLoad
/ 10);
139 kprintf("\twent_sleep:\t\t%" B_PRId64
"\n", fWentSleep
);
140 kprintf("\twent_sleep_active:\t%" B_PRId64
"\n", fWentSleepActive
);
141 kprintf("\tcore:\t\t\t%" B_PRId32
"\n",
142 fCore
!= NULL
? fCore
->ID() : -1);
143 if (fCore
!= NULL
&& HasCacheExpired())
144 kprintf("\tcache affinity has expired\n");
149 ThreadData::ChooseCoreAndCPU(CoreEntry
*& targetCore
, CPUEntry
*& targetCPU
)
151 SCHEDULER_ENTER_FUNCTION();
153 bool rescheduleNeeded
= false;
155 if (targetCore
== NULL
&& targetCPU
!= NULL
)
156 targetCore
= targetCPU
->Core();
157 else if (targetCore
!= NULL
&& targetCPU
== NULL
)
158 targetCPU
= _ChooseCPU(targetCore
, rescheduleNeeded
);
159 else if (targetCore
== NULL
&& targetCPU
== NULL
) {
160 targetCore
= _ChooseCore();
161 targetCPU
= _ChooseCPU(targetCore
, rescheduleNeeded
);
164 ASSERT(targetCore
!= NULL
);
165 ASSERT(targetCPU
!= NULL
);
167 if (fCore
!= targetCore
) {
168 fLoadMeasurementEpoch
= targetCore
->LoadMeasurementEpoch() - 1;
171 fCore
->RemoveLoad(fNeededLoad
, true);
172 targetCore
->AddLoad(fNeededLoad
, fLoadMeasurementEpoch
, true);
177 return rescheduleNeeded
;
182 ThreadData::ComputeQuantum() const
184 SCHEDULER_ENTER_FUNCTION();
189 int32 threadCount
= fCore
->ThreadCount();
190 if (fCore
->CPUCount() > 0)
191 threadCount
/= fCore
->CPUCount();
193 bigtime_t quantum
= fBaseQuantum
;
194 if (threadCount
< kMaximumQuantumLengthsCount
)
195 quantum
= std::min(sMaximumQuantumLengths
[threadCount
], quantum
);
201 ThreadData::UnassignCore(bool running
)
203 SCHEDULER_ENTER_FUNCTION();
205 ASSERT(fCore
!= NULL
);
206 if (running
|| fThread
->state
== B_THREAD_READY
)
214 ThreadData::ComputeQuantumLengths()
216 SCHEDULER_ENTER_FUNCTION();
218 for (int32 priority
= 0; priority
<= THREAD_MAX_SET_PRIORITY
; priority
++) {
219 const bigtime_t kQuantum0
= gCurrentMode
->base_quantum
;
220 if (priority
>= B_URGENT_DISPLAY_PRIORITY
) {
221 sQuantumLengths
[priority
] = kQuantum0
;
225 const bigtime_t kQuantum1
226 = kQuantum0
* gCurrentMode
->quantum_multipliers
[0];
227 if (priority
> B_NORMAL_PRIORITY
) {
228 sQuantumLengths
[priority
] = _ScaleQuantum(kQuantum1
, kQuantum0
,
229 B_URGENT_DISPLAY_PRIORITY
, B_NORMAL_PRIORITY
, priority
);
233 const bigtime_t kQuantum2
234 = kQuantum0
* gCurrentMode
->quantum_multipliers
[1];
235 sQuantumLengths
[priority
] = _ScaleQuantum(kQuantum2
, kQuantum1
,
236 B_NORMAL_PRIORITY
, B_IDLE_PRIORITY
, priority
);
239 for (int32 threadCount
= 0; threadCount
< kMaximumQuantumLengthsCount
;
242 bigtime_t quantum
= gCurrentMode
->maximum_latency
;
243 if (threadCount
!= 0)
244 quantum
/= threadCount
;
245 quantum
= std::max(quantum
, gCurrentMode
->minimal_quantum
);
246 sMaximumQuantumLengths
[threadCount
] = quantum
;
252 ThreadData::_GetPenalty() const
254 SCHEDULER_ENTER_FUNCTION();
255 return fPriorityPenalty
;
260 ThreadData::_ComputeNeededLoad()
262 SCHEDULER_ENTER_FUNCTION();
265 int32 oldLoad
= compute_load(fLastMeasureAvailableTime
,
266 fMeasureAvailableActiveTime
, fNeededLoad
, fMeasureAvailableTime
);
267 if (oldLoad
< 0 || oldLoad
== fNeededLoad
)
270 fCore
->ChangeLoad(fNeededLoad
- oldLoad
);
275 ThreadData::_ComputeEffectivePriority() const
277 SCHEDULER_ENTER_FUNCTION();
280 fEffectivePriority
= B_IDLE_PRIORITY
;
281 else if (IsRealTime())
282 fEffectivePriority
= GetPriority();
284 fEffectivePriority
= GetPriority();
285 fEffectivePriority
-= _GetPenalty();
286 if (fEffectivePriority
> 0)
287 fEffectivePriority
-= fAdditionalPenalty
% fEffectivePriority
;
289 ASSERT(fEffectivePriority
< B_FIRST_REAL_TIME_PRIORITY
);
290 ASSERT(fEffectivePriority
>= B_LOWEST_ACTIVE_PRIORITY
);
293 fBaseQuantum
= sQuantumLengths
[GetEffectivePriority()];
297 /* static */ bigtime_t
298 ThreadData::_ScaleQuantum(bigtime_t maxQuantum
, bigtime_t minQuantum
,
299 int32 maxPriority
, int32 minPriority
, int32 priority
)
301 SCHEDULER_ENTER_FUNCTION();
303 ASSERT(priority
<= maxPriority
);
304 ASSERT(priority
>= minPriority
);
306 bigtime_t result
= (maxQuantum
- minQuantum
) * (priority
- minPriority
);
307 result
/= maxPriority
- minPriority
;
308 return maxQuantum
- result
;
312 ThreadProcessing::~ThreadProcessing()