diff --git a/miosix/kernel/cpu_time_counter.cpp b/miosix/kernel/cpu_time_counter.cpp index 3788053a18ab7135c16814d083c04a5dc4db9192..441d92382c002c2d1d5073ba2c6888c3b0b70051 100644 --- a/miosix/kernel/cpu_time_counter.cpp +++ b/miosix/kernel/cpu_time_counter.cpp @@ -26,7 +26,6 @@ ***************************************************************************/ #include "cpu_time_counter.h" -#include "cpu_time_counter_private.h" #include "kernel/kernel.h" #ifdef WITH_CPU_TIME_COUNTER @@ -43,8 +42,9 @@ long long CPUTimeCounter::getActiveThreadTime() { PauseKernelLock pk; curTime = IRQgetTime(); - usedTime = runningThread->timeCounterData.usedCpuTime; - lastAct = runningThread->timeCounterData.lastActivation; + auto cur = Thread::PKgetCurrentThread(); + usedTime = cur->timeCounterData.usedCpuTime; + lastAct = cur->timeCounterData.lastActivation; } return usedTime + (curTime - lastAct); } diff --git a/miosix/kernel/cpu_time_counter.h b/miosix/kernel/cpu_time_counter.h index b28ea5a7681b72b75718c1f75cdf0a17dd578340..ba3125790329f5db4060e3292127c4a023697d78 100644 --- a/miosix/kernel/cpu_time_counter.h +++ b/miosix/kernel/cpu_time_counter.h @@ -193,26 +193,26 @@ private: * threads. */ static void PKremoveDeadThreads(); - - /** - * \internal - * Notify that a context switch is about to happen. - * \returns The current time. - */ - static inline long long IRQwillSwitchContext(); - - /** - * \internal - * Notify that a context switch has just happened. - * \param t The time of the context switch. - */ - static inline void IRQdidSwitchContext(long long t); static Thread *head; ///< Head of the thread list static Thread *tail; ///< Tail of the thread list static volatile unsigned int nThreads; ///< Number of threads in the list }; +/** + * Function to be called in the context switch code to profile threads + * \param prev time count struct of previously running thread + * \param prev time count struct of thread to be scheduled next + * \param t (approximate) current time, a time point taken somewhere during + * the context switch code + */ +static inline void IRQprofileContextSwitch(CPUTimeCounterPrivateThreadData& prev, + CPUTimeCounterPrivateThreadData& next, long long t) +{ + prev.usedCpuTime += t - prev.lastActivation; + next.lastActivation = t; +} + /** * \} */ diff --git a/miosix/kernel/cpu_time_counter_private.h b/miosix/kernel/cpu_time_counter_private.h deleted file mode 100644 index 62d24a7256a0e70ed6755fb8a9c29303b9e3b7e4..0000000000000000000000000000000000000000 --- a/miosix/kernel/cpu_time_counter_private.h +++ /dev/null @@ -1,53 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2023 by Daniele Cattaneo * - * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * As a special exception, if other files instantiate templates or use * - * macros or inline functions from this file, or you compile this file * - * and link it with other works to produce a work based on this file, * - * this file does not by itself cause the resulting work to be covered * - * by the GNU General Public License. However the source code for this * - * file must still be made available in accordance with the GNU General * - * Public License. This exception does not invalidate any other reasons * - * why a work based on this file might be covered by the GNU General * - * Public License. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, see <http://www.gnu.org/licenses/> * - ***************************************************************************/ - -#pragma once - -#include "cpu_time_counter.h" - -#ifdef WITH_CPU_TIME_COUNTER - -namespace miosix { - -// Declared in kernel.cpp -extern volatile Thread *runningThread; - -long long CPUTimeCounter::IRQwillSwitchContext() -{ - long long t=IRQgetTime(); - runningThread->timeCounterData.usedCpuTime+=t-runningThread->timeCounterData.lastActivation; - return t; -} - -void CPUTimeCounter::IRQdidSwitchContext(long long t) -{ - runningThread->timeCounterData.lastActivation=t; -} - -} //namespace miosix - -#endif //WITH_CPU_TIME_COUNTER diff --git a/miosix/kernel/scheduler/control/control_scheduler.cpp b/miosix/kernel/scheduler/control/control_scheduler.cpp index 68630cfbea603375722610f664ecd4b76a1b3132..5a6b73944f68e9741584ad555d6e81b33d9705a3 100644 --- a/miosix/kernel/scheduler/control/control_scheduler.cpp +++ b/miosix/kernel/scheduler/control/control_scheduler.cpp @@ -51,7 +51,9 @@ static inline void IRQsetNextPreemptionForIdle() { if(sleepingList.empty()) nextPreemption=numeric_limits<long long>::max(); else nextPreemption=sleepingList.front()->wakeupTime; - + #ifdef WITH_CPU_TIME_COUNTER + burstStart=IRQgetTime(); + #endif // WITH_CPU_TIME_COUNTER //We could not set an interrupt if the sleeping list is empty but there's //no such hurry to run idle anyway, so why bother? internal::IRQosTimerSetInterrupt(nextPreemption); @@ -183,6 +185,9 @@ long long ControlScheduler::IRQgetNextPreemption() void ControlScheduler::IRQfindNextThread() { if(kernelRunning!=0) return;//If kernel is paused, do nothing + #ifdef WITH_CPU_TIME_COUNTER + Thread *prev=const_cast<Thread*>(runningThread); + #endif // WITH_CPU_TIME_COUNTER if(runningThread!=idle) { @@ -235,6 +240,10 @@ void ControlScheduler::IRQfindNextThread() miosix_private::MPUConfiguration::IRQdisable(); #endif IRQsetNextPreemptionForIdle(); + #ifdef WITH_CPU_TIME_COUNTER + IRQprofileContextSwitch(prev->timeCounterData, + idle->timeCounterData,burstStart); + #endif //WITH_CPU_TIME_COUNTER return; } @@ -261,6 +270,10 @@ void ControlScheduler::IRQfindNextThread() ctxsave=runningThread->ctxsave; #endif //WITH_PROCESSES IRQsetNextPreemption(curInRound->schedData.bo/multFactor); + #ifdef WITH_CPU_TIME_COUNTER + IRQprofileContextSwitch(prev->timeCounterData, + curInRound->timeCounterData,burstStart); + #endif //WITH_CPU_TIME_COUNTER return; } else { //If we get here we have a non ready thread that cannot run, @@ -585,6 +598,9 @@ long long ControlScheduler::IRQgetNextPreemption() void ControlScheduler::IRQfindNextThread() { if(kernelRunning!=0) return;//If kernel is paused, do nothing + #ifdef WITH_CPU_TIME_COUNTER + Thread *prev=const_cast<Thread*>(runningThread); + #endif // WITH_CPU_TIME_COUNTER if(runningThread!=idle) { @@ -632,6 +648,10 @@ void ControlScheduler::IRQfindNextThread() MPUConfiguration::IRQdisable(); #endif IRQsetNextPreemptionForIdle(); + #ifdef WITH_CPU_TIME_COUNTER + IRQprofileContextSwitch(prev->timeCounterData, + idle->timeCounterData,burstStart); + #endif //WITH_CPU_TIME_COUNTER return; } @@ -658,6 +678,10 @@ void ControlScheduler::IRQfindNextThread() ctxsave=runningThread->ctxsave; #endif //WITH_PROCESSES IRQsetNextPreemption(runningThread->schedData.bo/multFactor); + #ifdef WITH_CPU_TIME_COUNTER + IRQprofileContextSwitch(prev->timeCounterData, + (*curInRound)->t->timeCounterData,burstStart); + #endif //WITH_CPU_TIME_COUNTER return; } else { //Error: a not ready thread end up in the ready list diff --git a/miosix/kernel/scheduler/edf/edf_scheduler.cpp b/miosix/kernel/scheduler/edf/edf_scheduler.cpp index dc21918f6caf699dea0300a6b5234f8caeec31ba..9f7bdd7be6b85a931a328872f61b4947f3a27639 100644 --- a/miosix/kernel/scheduler/edf/edf_scheduler.cpp +++ b/miosix/kernel/scheduler/edf/edf_scheduler.cpp @@ -129,6 +129,9 @@ static void IRQsetNextPreemption() void EDFScheduler::IRQfindNextThread() { if(kernelRunning!=0) return;//If kernel is paused, do nothing + #ifdef WITH_CPU_TIME_COUNTER + Thread *prev=const_cast<Thread*>(runningThread); + #endif // WITH_CPU_TIME_COUNTER Thread *walk=head; for(;;) { @@ -150,6 +153,10 @@ void EDFScheduler::IRQfindNextThread() ctxsave=runningThread->ctxsave; #endif //WITH_PROCESSES IRQsetNextPreemption(); + #ifdef WITH_CPU_TIME_COUNTER + IRQprofileContextSwitch(prev->timeCounterData,walk->timeCounterData, + IRQgetTime()); + #endif //WITH_CPU_TIME_COUNTER return; } walk=walk->schedData.next; diff --git a/miosix/kernel/scheduler/priority/priority_scheduler.cpp b/miosix/kernel/scheduler/priority/priority_scheduler.cpp index ee1425c2d99c88342e4454520c7967839ddf45ef..2d6f9780175591e81b9e6354fd56bfc07783a415 100644 --- a/miosix/kernel/scheduler/priority/priority_scheduler.cpp +++ b/miosix/kernel/scheduler/priority/priority_scheduler.cpp @@ -203,23 +203,28 @@ long long PriorityScheduler::IRQgetNextPreemption() return nextPeriodicPreemption; } -static void IRQsetNextPreemption(bool runningIdleThread) +static long long IRQsetNextPreemption(bool runningIdleThread) { long long first; if(sleepingList.empty()) first=std::numeric_limits<long long>::max(); else first=sleepingList.front()->wakeupTime; + long long t=IRQgetTime(); if(runningIdleThread) nextPeriodicPreemption=first; - else nextPeriodicPreemption=std::min(first,IRQgetTime()+MAX_TIME_SLICE); + else nextPeriodicPreemption=std::min(first,t+MAX_TIME_SLICE); //We could not set an interrupt if the sleeping list is empty and runningThread //is idle but there's no such hurry to run idle anyway, so why bother? internal::IRQosTimerSetInterrupt(nextPeriodicPreemption); + return t; } void PriorityScheduler::IRQfindNextThread() { if(kernelRunning!=0) return;//If kernel is paused, do nothing + #ifdef WITH_CPU_TIME_COUNTER + Thread *prev=const_cast<Thread*>(runningThread); + #endif // WITH_CPU_TIME_COUNTER for(int i=PRIORITY_MAX-1;i>=0;i--) { if(threadList[i]==nullptr) continue; @@ -246,7 +251,12 @@ void PriorityScheduler::IRQfindNextThread() //Rotate to next thread so that next time the list is walked //a different thread, if available, will be chosen first threadList[i]=temp; + #ifndef WITH_CPU_TIME_COUNTER IRQsetNextPreemption(false); + #else //WITH_CPU_TIME_COUNTER + auto t=IRQsetNextPreemption(false); + IRQprofileContextSwitch(prev->timeCounterData,temp->timeCounterData,t); + #endif //WITH_CPU_TIME_COUNTER return; } else temp=temp->schedData.next; if(temp==threadList[i]->schedData.next) break; @@ -258,7 +268,12 @@ void PriorityScheduler::IRQfindNextThread() #ifdef WITH_PROCESSES MPUConfiguration::IRQdisable(); #endif //WITH_PROCESSES + #ifndef WITH_CPU_TIME_COUNTER IRQsetNextPreemption(true); + #else //WITH_CPU_TIME_COUNTER + auto t=IRQsetNextPreemption(true); + IRQprofileContextSwitch(prev->timeCounterData,idle->timeCounterData,t); + #endif //WITH_CPU_TIME_COUNTER } Thread *PriorityScheduler::threadList[PRIORITY_MAX]={nullptr}; diff --git a/miosix/kernel/scheduler/scheduler.h b/miosix/kernel/scheduler/scheduler.h index 85888f4f48af0f9c198646479019d68e9d69577f..f11e678cd970725f929d5dad11978106667cb917 100755 --- a/miosix/kernel/scheduler/scheduler.h +++ b/miosix/kernel/scheduler/scheduler.h @@ -31,7 +31,7 @@ #include "kernel/scheduler/priority/priority_scheduler.h" #include "kernel/scheduler/control/control_scheduler.h" #include "kernel/scheduler/edf/edf_scheduler.h" -#include "kernel/cpu_time_counter_private.h" +#include "kernel/cpu_time_counter.h" namespace miosix { @@ -165,13 +165,7 @@ public: */ static void IRQfindNextThread() { - #ifdef WITH_CPU_TIME_COUNTER - long long t=CPUTimeCounter::IRQwillSwitchContext(); - #endif T::IRQfindNextThread(); - #ifdef WITH_CPU_TIME_COUNTER - CPUTimeCounter::IRQdidSwitchContext(t); - #endif } /**