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:
parent
65625deb32
commit
f6bae09ee7
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue