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;
EventQueue::EventQueue() {
head = nullptr;
setLateDelay(100);
}
bool EventQueue::checkIfPending(scheduling_s *scheduling) {
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
* for the next scheduled event
*
*/
efitime_t aBitInTheFuture = nowX + lateDelay;
return aBitInTheFuture;
return nowX + lateDelay;
} else {
return head->momentX;
}
@ -139,13 +132,20 @@ int EventQueue::executeAll(efitime_t now) {
break;
}
// Only execute events that occured in the past.
// The list is sorted, so as soon as we see an event
// in the future, we're done.
if (current->momentX > now) {
// If the next event is far in the future, we'll reschedule
// and execute it next time.
// We do this when the next event is close enough that the overhead of
// 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;
}
// near future - spin wait for the event to happen and avoid the
// overhead of rescheduling the timer.
while (current->momentX > getTimeNowNt()) ;
executionCounter++;
// 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() {
return head;
}

View File

@ -45,7 +45,10 @@
*/
class EventQueue {
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
@ -58,7 +61,6 @@ public:
void clear(void);
int size(void) const;
scheduling_s *getElementAtIndexForUnitText(int index);
void setLateDelay(int value);
scheduling_s * getHead();
void assertListIsSorted() const;
private:
@ -66,7 +68,7 @@ private:
/**
* this list is sorted
*/
scheduling_s *head;
efitime_t lateDelay;
scheduling_s *head = nullptr;
const efitime_t lateDelay;
};

View File

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