scheduler: Improve latencies
This commit is contained in:
@@ -161,10 +161,10 @@ scheduler_mode_operations gSchedulerLowLatencyMode = {
|
|||||||
"low latency",
|
"low latency",
|
||||||
|
|
||||||
1000,
|
1000,
|
||||||
50,
|
100,
|
||||||
{ 2, 50 },
|
{ 2, 5 },
|
||||||
|
|
||||||
50000,
|
5000,
|
||||||
|
|
||||||
switch_to_mode,
|
switch_to_mode,
|
||||||
set_cpu_enabled,
|
set_cpu_enabled,
|
||||||
|
|||||||
@@ -236,11 +236,11 @@ rebalance_irqs(bool idle)
|
|||||||
scheduler_mode_operations gSchedulerPowerSavingMode = {
|
scheduler_mode_operations gSchedulerPowerSavingMode = {
|
||||||
"power saving",
|
"power saving",
|
||||||
|
|
||||||
3000,
|
2000,
|
||||||
1000,
|
500,
|
||||||
{ 3, 60 },
|
{ 3, 10 },
|
||||||
|
|
||||||
200000,
|
20000,
|
||||||
|
|
||||||
switch_to_mode,
|
switch_to_mode,
|
||||||
set_cpu_enabled,
|
set_cpu_enabled,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2013, Paweł Dziepak, [email protected].
|
* Copyright 2013-2014, Paweł Dziepak, [email protected].
|
||||||
* Copyright 2009, Rene Gollent, [email protected].
|
* Copyright 2009, Rene Gollent, [email protected].
|
||||||
* Copyright 2008-2011, Ingo Weinhold, [email protected].
|
* Copyright 2008-2011, Ingo Weinhold, [email protected].
|
||||||
* Copyright 2002-2010, Axel Dörfler, [email protected].
|
* Copyright 2002-2010, Axel Dörfler, [email protected].
|
||||||
@@ -484,7 +484,7 @@ reschedule(int32 nextState)
|
|||||||
|
|
||||||
oldThread->cpu->preempted = false;
|
oldThread->cpu->preempted = false;
|
||||||
if (!thread_is_idle_thread(nextThread)) {
|
if (!thread_is_idle_thread(nextThread)) {
|
||||||
bigtime_t quantum = nextThreadData->ComputeQuantum();
|
bigtime_t quantum = nextThreadData->GetQuantumLeft();
|
||||||
add_timer(quantumTimer, &reschedule_event, quantum,
|
add_timer(quantumTimer, &reschedule_event, quantum,
|
||||||
B_ONE_SHOT_RELATIVE_TIMER);
|
B_ONE_SHOT_RELATIVE_TIMER);
|
||||||
|
|
||||||
|
|||||||
@@ -19,10 +19,7 @@ ThreadData::_InitBase()
|
|||||||
fAdditionalPenalty = 0;
|
fAdditionalPenalty = 0;
|
||||||
fEffectivePriority = fThread->priority;
|
fEffectivePriority = fThread->priority;
|
||||||
|
|
||||||
fReceivedPenalty = false;
|
fTimeUsed = 0;
|
||||||
fHasSlept = false;
|
|
||||||
|
|
||||||
fTimeLeft = 0;
|
|
||||||
fStolenTime = 0;
|
fStolenTime = 0;
|
||||||
|
|
||||||
fMeasureAvailableActiveTime = 0;
|
fMeasureAvailableActiveTime = 0;
|
||||||
@@ -111,11 +108,6 @@ ThreadData::Init()
|
|||||||
fCore = currentThreadData->fCore;
|
fCore = currentThreadData->fCore;
|
||||||
|
|
||||||
if (fThread->priority < B_FIRST_REAL_TIME_PRIORITY) {
|
if (fThread->priority < B_FIRST_REAL_TIME_PRIORITY) {
|
||||||
if (!thread_is_idle_thread(currentThread)
|
|
||||||
&& currentThread->priority < B_FIRST_REAL_TIME_PRIORITY) {
|
|
||||||
currentThreadData->_IncreasePenalty(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
fPriorityPenalty = std::min(currentThreadData->fPriorityPenalty,
|
fPriorityPenalty = std::min(currentThreadData->fPriorityPenalty,
|
||||||
std::max(fThread->priority - _GetMinimalPriority(), int32(0)));
|
std::max(fThread->priority - _GetMinimalPriority(), int32(0)));
|
||||||
fAdditionalPenalty = currentThreadData->fAdditionalPenalty;
|
fAdditionalPenalty = currentThreadData->fAdditionalPenalty;
|
||||||
@@ -148,21 +140,8 @@ ThreadData::Dump() const
|
|||||||
additionalPenalty, fAdditionalPenalty);
|
additionalPenalty, fAdditionalPenalty);
|
||||||
kprintf("\teffective_priority:\t%" B_PRId32 "\n", GetEffectivePriority());
|
kprintf("\teffective_priority:\t%" B_PRId32 "\n", GetEffectivePriority());
|
||||||
|
|
||||||
kprintf("\treceived_penalty:\t%s\n", fReceivedPenalty ? "true" : "false");
|
kprintf("\ttime_used:\t\t%" B_PRId64 " us (quantum: %" B_PRId64 " us)\n",
|
||||||
kprintf("\thas_slept:\t\t%s\n", fHasSlept ? "true" : "false");
|
fTimeUsed, ComputeQuantum());
|
||||||
|
|
||||||
bigtime_t quantum = _GetBaseQuantum();
|
|
||||||
if (fThread->priority < B_FIRST_REAL_TIME_PRIORITY) {
|
|
||||||
int32 threadCount = (fCore->ThreadCount() + 1) / fCore->CPUCount();
|
|
||||||
threadCount = max_c(threadCount, 1);
|
|
||||||
|
|
||||||
quantum
|
|
||||||
= std::min(gCurrentMode->maximum_latency / threadCount, quantum);
|
|
||||||
quantum = std::max(quantum, gCurrentMode->minimal_quantum);
|
|
||||||
}
|
|
||||||
kprintf("\ttime_left:\t\t%" B_PRId64 " us (quantum: %" B_PRId64 " us)\n",
|
|
||||||
fTimeLeft, quantum);
|
|
||||||
|
|
||||||
kprintf("\tstolen_time:\t\t%" B_PRId64 " us\n", fStolenTime);
|
kprintf("\tstolen_time:\t\t%" B_PRId64 " us\n", fStolenTime);
|
||||||
kprintf("\tquantum_start:\t\t%" B_PRId64 " us\n", fQuantumStart);
|
kprintf("\tquantum_start:\t\t%" B_PRId64 " us\n", fQuantumStart);
|
||||||
kprintf("\tneeded_load:\t\t%" B_PRId32 "%%\n", fNeededLoad / 10);
|
kprintf("\tneeded_load:\t\t%" B_PRId32 "%%\n", fNeededLoad / 10);
|
||||||
@@ -206,22 +185,14 @@ ThreadData::ChooseCoreAndCPU(CoreEntry*& targetCore, CPUEntry*& targetCPU)
|
|||||||
|
|
||||||
|
|
||||||
bigtime_t
|
bigtime_t
|
||||||
ThreadData::ComputeQuantum()
|
ThreadData::ComputeQuantum() const
|
||||||
{
|
{
|
||||||
SCHEDULER_ENTER_FUNCTION();
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
|
||||||
bigtime_t quantum;
|
bigtime_t quantum = _GetBaseQuantum();
|
||||||
if (fTimeLeft != 0)
|
|
||||||
quantum = fTimeLeft;
|
|
||||||
else
|
|
||||||
quantum = _GetBaseQuantum();
|
|
||||||
|
|
||||||
if (fThread->priority >= B_FIRST_REAL_TIME_PRIORITY)
|
if (fThread->priority >= B_FIRST_REAL_TIME_PRIORITY)
|
||||||
return quantum;
|
return quantum;
|
||||||
|
|
||||||
quantum += fStolenTime;
|
|
||||||
fStolenTime = 0;
|
|
||||||
|
|
||||||
int32 threadCount = fCore->ThreadCount() / fCore->CPUCount();
|
int32 threadCount = fCore->ThreadCount() / fCore->CPUCount();
|
||||||
if (threadCount >= 1) {
|
if (threadCount >= 1) {
|
||||||
quantum
|
quantum
|
||||||
@@ -229,7 +200,6 @@ ThreadData::ComputeQuantum()
|
|||||||
quantum = std::max(quantum, gCurrentMode->minimal_quantum);
|
quantum = std::max(quantum, gCurrentMode->minimal_quantum);
|
||||||
}
|
}
|
||||||
|
|
||||||
fTimeLeft = quantum;
|
|
||||||
return quantum;
|
return quantum;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,14 +236,7 @@ inline int32
|
|||||||
ThreadData::_GetPenalty() const
|
ThreadData::_GetPenalty() const
|
||||||
{
|
{
|
||||||
SCHEDULER_ENTER_FUNCTION();
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
return fPriorityPenalty;
|
||||||
int32 penalty = fPriorityPenalty;
|
|
||||||
|
|
||||||
const int kMinimalPriority = _GetMinimalPriority();
|
|
||||||
if (kMinimalPriority > 0)
|
|
||||||
penalty += fAdditionalPenalty % kMinimalPriority;
|
|
||||||
|
|
||||||
return penalty;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -304,6 +267,8 @@ ThreadData::_ComputeEffectivePriority() const
|
|||||||
else {
|
else {
|
||||||
fEffectivePriority = fThread->priority;
|
fEffectivePriority = fThread->priority;
|
||||||
fEffectivePriority -= _GetPenalty();
|
fEffectivePriority -= _GetPenalty();
|
||||||
|
if (fEffectivePriority > 0)
|
||||||
|
fEffectivePriority -= fAdditionalPenalty % fEffectivePriority;
|
||||||
|
|
||||||
ASSERT(fEffectivePriority < B_FIRST_REAL_TIME_PRIORITY);
|
ASSERT(fEffectivePriority < B_FIRST_REAL_TIME_PRIORITY);
|
||||||
ASSERT(fEffectivePriority >= B_LOWEST_ACTIVE_PRIORITY);
|
ASSERT(fEffectivePriority >= B_LOWEST_ACTIVE_PRIORITY);
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ public:
|
|||||||
{ fLastInterruptTime = interruptTime; }
|
{ fLastInterruptTime = interruptTime; }
|
||||||
inline void SetStolenInterruptTime(bigtime_t interruptTime);
|
inline void SetStolenInterruptTime(bigtime_t interruptTime);
|
||||||
|
|
||||||
|
bigtime_t ComputeQuantum() const;
|
||||||
|
inline bigtime_t GetQuantumLeft();
|
||||||
|
inline void StartQuantum();
|
||||||
|
inline bool HasQuantumEnded(bool wasPreempted, bool hasYielded);
|
||||||
|
|
||||||
inline void Continues();
|
inline void Continues();
|
||||||
inline void GoesAway();
|
inline void GoesAway();
|
||||||
inline void Dies();
|
inline void Dies();
|
||||||
@@ -69,10 +74,6 @@ public:
|
|||||||
|
|
||||||
inline void UpdateActivity(bigtime_t active);
|
inline void UpdateActivity(bigtime_t active);
|
||||||
|
|
||||||
inline bool HasQuantumEnded(bool wasPreempted, bool hasYielded);
|
|
||||||
bigtime_t ComputeQuantum();
|
|
||||||
inline void StartQuantum();
|
|
||||||
|
|
||||||
inline bool IsEnqueued() const { return fEnqueued; }
|
inline bool IsEnqueued() const { return fEnqueued; }
|
||||||
inline void SetDequeued() { fEnqueued = false; }
|
inline void SetDequeued() { fEnqueued = false; }
|
||||||
|
|
||||||
@@ -85,7 +86,7 @@ public:
|
|||||||
static void ComputeQuantumLengths();
|
static void ComputeQuantumLengths();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void _IncreasePenalty(bool strong);
|
inline void _IncreasePenalty();
|
||||||
inline int32 _GetPenalty() const;
|
inline int32 _GetPenalty() const;
|
||||||
|
|
||||||
void _ComputeNeededLoad();
|
void _ComputeNeededLoad();
|
||||||
@@ -112,12 +113,10 @@ private:
|
|||||||
|
|
||||||
int32 fPriorityPenalty;
|
int32 fPriorityPenalty;
|
||||||
int32 fAdditionalPenalty;
|
int32 fAdditionalPenalty;
|
||||||
bool fReceivedPenalty;
|
|
||||||
bool fHasSlept;
|
|
||||||
|
|
||||||
mutable int32 fEffectivePriority;
|
mutable int32 fEffectivePriority;
|
||||||
|
|
||||||
bigtime_t fTimeLeft;
|
bigtime_t fTimeUsed;
|
||||||
|
|
||||||
bigtime_t fMeasureAvailableActiveTime;
|
bigtime_t fMeasureAvailableActiveTime;
|
||||||
bigtime_t fMeasureAvailableTime;
|
bigtime_t fMeasureAvailableTime;
|
||||||
@@ -178,7 +177,7 @@ ThreadData::GetEffectivePriority() const
|
|||||||
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
ThreadData::_IncreasePenalty(bool strong)
|
ThreadData::_IncreasePenalty()
|
||||||
{
|
{
|
||||||
SCHEDULER_ENTER_FUNCTION();
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
|
||||||
@@ -189,18 +188,10 @@ ThreadData::_IncreasePenalty(bool strong)
|
|||||||
|
|
||||||
TRACE("increasing thread %ld penalty\n", fThread->id);
|
TRACE("increasing thread %ld penalty\n", fThread->id);
|
||||||
|
|
||||||
fReceivedPenalty = true;
|
int32 oldPenalty = fPriorityPenalty++;
|
||||||
int32 oldPenalty = fPriorityPenalty;
|
|
||||||
if (strong)
|
|
||||||
fPriorityPenalty++;
|
|
||||||
|
|
||||||
ASSERT(fThread->priority - oldPenalty >= B_LOWEST_ACTIVE_PRIORITY);
|
|
||||||
|
|
||||||
const int kMinimalPriority = _GetMinimalPriority();
|
const int kMinimalPriority = _GetMinimalPriority();
|
||||||
if (!strong || fThread->priority - oldPenalty <= kMinimalPriority) {
|
if (fThread->priority - oldPenalty <= kMinimalPriority)
|
||||||
fPriorityPenalty = oldPenalty;
|
fPriorityPenalty = oldPenalty;
|
||||||
fAdditionalPenalty++;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ComputeEffectivePriority();
|
_ComputeEffectivePriority();
|
||||||
}
|
}
|
||||||
@@ -210,7 +201,7 @@ inline bool
|
|||||||
ThreadData::IsCPUBound() const
|
ThreadData::IsCPUBound() const
|
||||||
{
|
{
|
||||||
SCHEDULER_ENTER_FUNCTION();
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
return fAdditionalPenalty != 0 && fPriorityPenalty != 0;
|
return GetThread()->priority - fPriorityPenalty == _GetMinimalPriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -220,8 +211,6 @@ ThreadData::CancelPenalty()
|
|||||||
SCHEDULER_ENTER_FUNCTION();
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
|
||||||
int32 oldPenalty = fPriorityPenalty;
|
int32 oldPenalty = fPriorityPenalty;
|
||||||
|
|
||||||
fAdditionalPenalty = 0;
|
|
||||||
fPriorityPenalty = 0;
|
fPriorityPenalty = 0;
|
||||||
|
|
||||||
if (oldPenalty != 0) {
|
if (oldPenalty != 0) {
|
||||||
@@ -239,8 +228,7 @@ ThreadData::ShouldCancelPenalty() const
|
|||||||
if (fCore == NULL)
|
if (fCore == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (GetEffectivePriority() != B_LOWEST_ACTIVE_PRIORITY
|
if (GetEffectivePriority() != B_LOWEST_ACTIVE_PRIORITY && !IsCPUBound()) {
|
||||||
&& !IsCPUBound()) {
|
|
||||||
if (fCore->StarvationCounter() != fWentSleepCount)
|
if (fCore->StarvationCounter() != fWentSleepCount)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -259,6 +247,61 @@ ThreadData::SetStolenInterruptTime(bigtime_t interruptTime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bigtime_t
|
||||||
|
ThreadData::GetQuantumLeft()
|
||||||
|
{
|
||||||
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
|
||||||
|
bigtime_t stolenTime = std::min(fStolenTime, gCurrentMode->minimal_quantum);
|
||||||
|
ASSERT(stolenTime >= 0);
|
||||||
|
fStolenTime -= stolenTime;
|
||||||
|
|
||||||
|
bigtime_t quantum = ComputeQuantum() - fTimeUsed;
|
||||||
|
quantum += stolenTime;
|
||||||
|
quantum = std::max(quantum, gCurrentMode->minimal_quantum);
|
||||||
|
|
||||||
|
return quantum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void
|
||||||
|
ThreadData::StartQuantum()
|
||||||
|
{
|
||||||
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
fQuantumStart = system_time();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline bool
|
||||||
|
ThreadData::HasQuantumEnded(bool wasPreempted, bool hasYielded)
|
||||||
|
{
|
||||||
|
SCHEDULER_ENTER_FUNCTION();
|
||||||
|
|
||||||
|
bigtime_t timeUsed = system_time() - fQuantumStart;
|
||||||
|
ASSERT(timeUsed >= 0);
|
||||||
|
fTimeUsed += timeUsed;
|
||||||
|
|
||||||
|
bigtime_t timeLeft = ComputeQuantum() - fTimeUsed;
|
||||||
|
timeLeft = std::max(bigtime_t(0), timeLeft);
|
||||||
|
|
||||||
|
// too little time left, it's better make the next quantum a bit longer
|
||||||
|
bigtime_t skipTime = gCurrentMode->minimal_quantum / 2;
|
||||||
|
if (hasYielded || wasPreempted || timeLeft <= skipTime) {
|
||||||
|
fStolenTime += timeLeft;
|
||||||
|
timeLeft = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeLeft == 0) {
|
||||||
|
fAdditionalPenalty++;
|
||||||
|
_IncreasePenalty();
|
||||||
|
fTimeUsed = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
ThreadData::Continues()
|
ThreadData::Continues()
|
||||||
{
|
{
|
||||||
@@ -277,20 +320,17 @@ ThreadData::GoesAway()
|
|||||||
|
|
||||||
ASSERT(fReady);
|
ASSERT(fReady);
|
||||||
|
|
||||||
bigtime_t timeUsed = system_time() - fQuantumStart;
|
if (!HasQuantumEnded(false, false)) {
|
||||||
ASSERT(timeUsed >= 0);
|
fAdditionalPenalty++;
|
||||||
fTimeLeft -= timeUsed;
|
_ComputeEffectivePriority();
|
||||||
|
}
|
||||||
if (!fReceivedPenalty)
|
|
||||||
_IncreasePenalty(false);
|
|
||||||
fHasSlept = true;
|
|
||||||
|
|
||||||
fLastInterruptTime = 0;
|
fLastInterruptTime = 0;
|
||||||
|
|
||||||
fWentSleep = system_time();
|
fWentSleep = system_time();
|
||||||
|
fWentSleepActive = fCore->GetActiveTime();
|
||||||
fWentSleepCount = fCore->StarvationCounter();
|
fWentSleepCount = fCore->StarvationCounter();
|
||||||
fWentSleepCountIdle = fCore->StarvationCounterIdle();
|
fWentSleepCountIdle = fCore->StarvationCounterIdle();
|
||||||
fWentSleepActive = fCore->GetActiveTime();
|
|
||||||
|
|
||||||
if (gTrackCoreLoad)
|
if (gTrackCoreLoad)
|
||||||
fCore->UpdateLoad(-fNeededLoad);
|
fCore->UpdateLoad(-fNeededLoad);
|
||||||
@@ -415,46 +455,6 @@ ThreadData::UpdateActivity(bigtime_t active)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline bool
|
|
||||||
ThreadData::HasQuantumEnded(bool wasPreempted, bool hasYielded)
|
|
||||||
{
|
|
||||||
SCHEDULER_ENTER_FUNCTION();
|
|
||||||
|
|
||||||
bigtime_t timeUsed = system_time() - fQuantumStart;
|
|
||||||
ASSERT(timeUsed >= 0);
|
|
||||||
fTimeLeft -= timeUsed;
|
|
||||||
|
|
||||||
if (hasYielded) {
|
|
||||||
fTimeLeft = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// too little time left, it's better make the next quantum a bit longer
|
|
||||||
int32 skipTime = gCurrentMode->minimal_quantum / 2;
|
|
||||||
if (wasPreempted || fTimeLeft <= skipTime) {
|
|
||||||
fStolenTime += fTimeLeft;
|
|
||||||
fTimeLeft = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fTimeLeft == 0) {
|
|
||||||
if (!fReceivedPenalty && !fHasSlept)
|
|
||||||
_IncreasePenalty(true);
|
|
||||||
fReceivedPenalty = false;
|
|
||||||
fHasSlept = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fTimeLeft == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void
|
|
||||||
ThreadData::StartQuantum()
|
|
||||||
{
|
|
||||||
SCHEDULER_ENTER_FUNCTION();
|
|
||||||
fQuantumStart = system_time();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
ThreadData::UnassignCore(bool running)
|
ThreadData::UnassignCore(bool running)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user