From 9c690222486361b7b14a824ee88c18fa7df39e0a Mon Sep 17 00:00:00 2001 From: Sasan Golchin <ahmad.golchin@mail.polimi.it> Date: Thu, 26 May 2016 17:29:13 +0200 Subject: [PATCH] Context Switch time optimization (reduced by 0.6 us) --- miosix/kernel/intrusive.h | 198 +++++++++++++++++--------------------- miosix/kernel/kernel.cpp | 30 ++++-- 2 files changed, 114 insertions(+), 114 deletions(-) diff --git a/miosix/kernel/intrusive.h b/miosix/kernel/intrusive.h index 18c26560..1031d57f 100644 --- a/miosix/kernel/intrusive.h +++ b/miosix/kernel/intrusive.h @@ -694,30 +694,114 @@ public: emptyListItem.prev = &emptyListItem; } - void push_back(T *item); + void push_back(T *item) + { + item->next = &emptyListItem; + item->prev = tail; + tail = item; + emptyListItem.prev = item; + if(head==&emptyListItem) + { + head = tail; + emptyListItem.next = head; + } else item->prev->next = item; + } /** * Removes the last element in the list. */ - void pop_back(); + void pop_back() + { + if(tail == head) + { + //Note: this is safe also in the case of pop_back of an empty list + //by mistake + removeLastItem(); + } else { + tail->prev->next = &emptyListItem; + emptyListItem.prev = tail->prev; + tail->prev = nullptr; + tail->next = nullptr; + tail = static_cast<T*>(emptyListItem.prev); + } + } - void push_front(T *item); + void push_front(T *item) + { + item->prev = &emptyListItem; + if(head != &emptyListItem) + { + item->next = head; + item->next->prev = item; + emptyListItem.next = item; + } else { + item->next = &emptyListItem; + tail = item; + emptyListItem.prev = item; + emptyListItem.next = item; + } + head = item; + } /** * Removes the first item (head) of the list. */ - void pop_front(); + void pop_front() + { + if(tail == head) + { + //Note: this is safe also in the case of pop_back of an empty list + //by mistake + removeLastItem(); + } else { + head->next->prev = &emptyListItem; + head->prev = nullptr; + emptyListItem.next = head->next; + head->next = nullptr; + head = static_cast<T*>(emptyListItem.next); + } + } /** * Inserts the given item before the position indicated by the iterator */ - void insert(iterator position, T *item); + void insert(iterator position, T *item) + { + if(head==&emptyListItem) + { + head = item; + tail = item; + item->next = &emptyListItem; + item->prev = &emptyListItem; + emptyListItem.next = item; + emptyListItem.prev = item; + return; + } + item->next = static_cast<IntrusiveListItem *>(*position); //FIXME: do we need this upcast? + item->prev = static_cast<IntrusiveListItem *>(*position)->prev; + item->prev->next = item; + (*position)->prev = item; + if(item->prev == &emptyListItem) head = item; + if(item->next == &emptyListItem) tail = item; + } /** * Removes the specified item from the list. * @param an iterator to the next item */ - iterator erase(iterator it); + iterator erase(iterator it) + { + if((*it)==&emptyListItem) return it; + iterator result = it; + result++; + (*it)->next->prev = (*it)->prev; + (*it)->prev->next = (*it)->next; + (*it)->next = nullptr; + (*it)->prev = nullptr; + head = static_cast<T*>(emptyListItem.next); + tail = static_cast<T*>(emptyListItem.prev); + return result; + } iterator begin() { @@ -760,108 +844,6 @@ private: T emptyListItem; }; -template<typename T> -void IntrusiveList<T>::push_back(T *item) -{ - item->next = &emptyListItem; - item->prev = tail; - tail = item; - emptyListItem.prev = item; - if(head==&emptyListItem) - { - head = tail; - emptyListItem.next = head; - } else item->prev->next = item; -} - -template<typename T> -void IntrusiveList<T>::pop_back() -{ - if(tail == head) - { - //Note: this is safe also in the case of pop_back of an empty list - //by mistake - removeLastItem(); - } else { - tail->prev->next = &emptyListItem; - emptyListItem.prev = tail->prev; - tail->prev = nullptr; - tail->next = nullptr; - tail = static_cast<T*>(emptyListItem.prev); - } -} - -template<typename T> -void IntrusiveList<T>::push_front(T *item) -{ - item->prev = &emptyListItem; - if(head != &emptyListItem) - { - item->next = head; - item->next->prev = item; - emptyListItem.next = item; - } else { - item->next = &emptyListItem; - tail = item; - emptyListItem.prev = item; - emptyListItem.next = item; - } - head = item; -} - -template<typename T> -void IntrusiveList<T>::pop_front() -{ - if(tail == head) - { - //Note: this is safe also in the case of pop_back of an empty list - //by mistake - removeLastItem(); - } else { - head->next->prev = &emptyListItem; - head->prev = nullptr; - emptyListItem.next = head->next; - head->next = nullptr; - head = static_cast<T*>(emptyListItem.next); - } -} - -template<typename T> -void IntrusiveList<T>::insert(iterator position, T *item) -{ - if(head==&emptyListItem) - { - head = item; - tail = item; - item->next = &emptyListItem; - item->prev = &emptyListItem; - emptyListItem.next = item; - emptyListItem.prev = item; - return; - } - item->next = static_cast<IntrusiveListItem *>(*position); //FIXME: do we need this upcast? - item->prev = static_cast<IntrusiveListItem *>(*position)->prev; - item->prev->next = item; - (*position)->prev = item; - if(item->prev == &emptyListItem) head = item; - if(item->next == &emptyListItem) tail = item; -} - -template<typename T> -typename IntrusiveList<T>::iterator IntrusiveList<T>::erase(iterator it) -{ - if((*it)==&emptyListItem) return it; - iterator result = it; - result++; - (*it)->next->prev = (*it)->prev; - (*it)->prev->next = (*it)->next; - (*it)->next = nullptr; - (*it)->prev = nullptr; - head = static_cast<T*>(emptyListItem.next); - tail = static_cast<T*>(emptyListItem.prev); - return result; -} - } //namespace miosix #endif //INTRUSIVE_H diff --git a/miosix/kernel/kernel.cpp b/miosix/kernel/kernel.cpp index 81fae38d..6a940657 100644 --- a/miosix/kernel/kernel.cpp +++ b/miosix/kernel/kernel.cpp @@ -67,6 +67,8 @@ static volatile bool exist_deleted=false; static IntrusiveList<SleepData> *sleepingList=nullptr;///list of sleeping threads +static ContextSwitchTimer *timer = nullptr; // FIXME please + #ifndef USE_CSTIMER static volatile long long tick=0;///<\internal Kernel tick #endif //USE_CSTIMER @@ -175,6 +177,7 @@ bool areInterruptsEnabled() void startKernel() { + timer = &ContextSwitchTimer::instance(); sleepingList = new(std::nothrow) IntrusiveList<SleepData>; csRecord = new(std::nothrow) SleepData; if(sleepingList==nullptr || csRecord==nullptr) @@ -219,10 +222,10 @@ void startKernel() // Dispatch the task to the architecture-specific function #ifdef USE_CSTIMER // Set the first checkpoint interrupt - csRecord->p = 0; + csRecord->p = nullptr; csRecord->wakeup_time = CSQUANTUM; sleepingList->push_front(csRecord); - miosix::ContextSwitchTimer::instance().IRQsetNextInterrupt(CSQUANTUM); + timer->IRQsetNextInterrupt(CSQUANTUM); #endif //USE_CSTIMER miosix_private::IRQportableStartKernel(); kernel_started=true; @@ -251,7 +254,7 @@ long long getTick() if(a==b) return a; } #else //USE_CSTIMER - return ContextSwitchTimer::instance().getCurrentTick(); + return timer->getCurrentTick(); #endif //USE_CSTIMER } @@ -279,7 +282,7 @@ void IRQaddToSleepingList(SleepData *x) //Upon any change to the sleepingList the ContextSwitchTimer should have //its interrupt set to the head of the list in order to keep it sync with //the list - ContextSwitchTimer::instance().IRQsetNextInterrupt(sleepingList->front()->wakeup_time); + timer->IRQsetNextInterrupt(sleepingList->front()->wakeup_time); #endif } @@ -289,12 +292,27 @@ void IRQaddToSleepingList(SleepData *x) */ void IRQsetNextPreemption(long long preemptionTime) { +#ifdef USE_CSTIMER // Remove all the preemption points from the list IntrusiveList<SleepData>::iterator it(csRecord); sleepingList->erase(it); - // + + //This piece of code is a duplication of IRQaddToSleepingList + //that is in-lined for performance issues csRecord->wakeup_time = preemptionTime; - IRQaddToSleepingList(csRecord); //It would also set the next timer interrupt + if(sleepingList->empty() || sleepingList->front()->wakeup_time >= preemptionTime) + { + sleepingList->push_front(csRecord); + } else { + auto it = sleepingList->begin(); + while (it != sleepingList->end() && (*it)->wakeup_time < preemptionTime ) ++it; + sleepingList->insert(it,csRecord); + } + //Upon any change to the sleepingList the ContextSwitchTimer should have + //its interrupt set to the head of the list in order to keep it sync with + //the list + timer->IRQsetNextInterrupt(sleepingList->front()->wakeup_time); +#endif } /** * \internal -- GitLab