spinwait for events in the near future (#1491)

* add spinwait

* simplify and reduce lateDelay

* maybe probably fix tests

* comments

Co-authored-by: Matthew Kennedy <makenne@microsoft.com>
This commit is contained in:
Matthew Kennedy 2020-06-16 19:13:42 -07:00 committed by GitHub
parent 65625deb32
commit f6bae09ee7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 26 deletions

View File

@ -24,11 +24,6 @@ extern bool verboseMode;
uint32_t maxSchedulingPrecisionLoss = 0; uint32_t maxSchedulingPrecisionLoss = 0;
EventQueue::EventQueue() {
head = nullptr;
setLateDelay(100);
}
bool EventQueue::checkIfPending(scheduling_s *scheduling) { bool EventQueue::checkIfPending(scheduling_s *scheduling) {
assertNotInListMethodBody(scheduling_s, head, scheduling, nextScheduling_s); assertNotInListMethodBody(scheduling_s, head, scheduling, nextScheduling_s);
} }
@ -100,10 +95,8 @@ efitime_t EventQueue::getNextEventTime(efitime_t nowX) const {
* *
* looks like we end up here after 'writeconfig' (which freezes the firmware) - we are late * looks like we end up here after 'writeconfig' (which freezes the firmware) - we are late
* for the next scheduled event * for the next scheduled event
*
*/ */
efitime_t aBitInTheFuture = nowX + lateDelay; return nowX + lateDelay;
return aBitInTheFuture;
} else { } else {
return head->momentX; return head->momentX;
} }
@ -139,13 +132,20 @@ int EventQueue::executeAll(efitime_t now) {
break; break;
} }
// Only execute events that occured in the past. // If the next event is far in the future, we'll reschedule
// The list is sorted, so as soon as we see an event // and execute it next time.
// in the future, we're done. // We do this when the next event is close enough that the overhead of
if (current->momentX > now) { // resetting the timer and scheduling an new interrupt is greater than just
// waiting for the time to arrive. On current CPUs, this is reasonable to set
// around 10 microseconds.
if (current->momentX > now + lateDelay) {
break; break;
} }
// near future - spin wait for the event to happen and avoid the
// overhead of rescheduling the timer.
while (current->momentX > getTimeNowNt()) ;
executionCounter++; executionCounter++;
// step the head forward, unlink this element, clear scheduled flag // step the head forward, unlink this element, clear scheduled flag
@ -187,10 +187,6 @@ void EventQueue::assertListIsSorted() const {
} }
} }
void EventQueue::setLateDelay(int value) {
lateDelay = value;
}
scheduling_s * EventQueue::getHead() { scheduling_s * EventQueue::getHead() {
return head; return head;
} }

View File

@ -45,7 +45,10 @@
*/ */
class EventQueue { class EventQueue {
public: public:
EventQueue(); // See comment in EventQueue::executeAll for info about lateDelay - it sets the
// time gap between events for which we will wait instead of rescheduling the next
// event in a group of events near one another.
EventQueue(efitime_t lateDelay = 0) : lateDelay(lateDelay) {}
/** /**
* O(size) - linear search in sorted linked list * O(size) - linear search in sorted linked list
@ -58,7 +61,6 @@ public:
void clear(void); void clear(void);
int size(void) const; int size(void) const;
scheduling_s *getElementAtIndexForUnitText(int index); scheduling_s *getElementAtIndexForUnitText(int index);
void setLateDelay(int value);
scheduling_s * getHead(); scheduling_s * getHead();
void assertListIsSorted() const; void assertListIsSorted() const;
private: private:
@ -66,7 +68,7 @@ private:
/** /**
* this list is sorted * this list is sorted
*/ */
scheduling_s *head; scheduling_s *head = nullptr;
efitime_t lateDelay; const efitime_t lateDelay;
}; };

View File

@ -49,12 +49,10 @@ void globalTimerCallback() {
___engine.executor.onTimerCallback(); ___engine.executor.onTimerCallback();
} }
SingleTimerExecutor::SingleTimerExecutor() { SingleTimerExecutor::SingleTimerExecutor()
/** // 10us is roughly double the cost of the interrupt + overhead of a single timer event
* See comments in "getNextEventTime" : queue(US2NT(10))
* 10us is roughly double the cost of the interrupt + overhead of a single timer event {
*/
queue.setLateDelay(US2NT(10));
} }
void SingleTimerExecutor::scheduleForLater(scheduling_s *scheduling, int delayUs, action_s action) { void SingleTimerExecutor::scheduleForLater(scheduling_s *scheduling, int delayUs, action_s action) {