-
Notifications
You must be signed in to change notification settings - Fork 3k
Add tickless idle loop #4956
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add tickless idle loop #4956
Conversation
Add tickless support to the rtos idle loop. Using low power ticker and RTOS suspend/resume functionality. We set the next event according to the kernel, and wake-up within this period. If lowpower ticker is not available, we fallback to the previous only sleep function.
7327d0f
to
4b4b6f3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good submission but I'm under the impression the test included is pointless because it test the wait function, not the function putting the MCU to sleep.
If the function default_idle_hook
was public it would be possible to test it directly instead of indirectly. Would it be possible to also add tests ensuring that the MCU wakeup when an IRQ is raised while it is asleep ?
timestamp_t time_in_sleep = 0UL; | ||
|
||
core_util_critical_section_enter(); | ||
uint32_t tick_freq = svcRtxKernelGetTickFreq(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be a static constant initialized once. SVC calls are not free.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are in C world, this would need to be a constant. This is not anywhere as const, only as RTX macro that we might not want to pull in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.
😞
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also it would be good to at least add a note that people shouldn't use the lowpower ticker if the tickless mode is in use.
Unfortunately, this usually requires disconnecting the interface chip (debugger). | ||
This can be done, but it would break the local file system. | ||
*/ | ||
#if DEVICE_LOWPOWERTIMER |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would add another device cap "TICKLESS" because to be fair I can see that device has both sleep and lowpower ticker and it still fails to do it properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We got test for that - lp ticker in HAL tests - sleep and wake up by lp ticker. if that fails, then this would fail also. lp ticker had always a requirement to wake up from sleep and also deepsleep. This one does at the moment only sleep, if it does not work it's a bug.
rtos/rtos_idle.c
Outdated
if (ticks_to_sleep) { | ||
uint64_t us_to_sleep = 1000000 * ticks_to_sleep / tick_freq; | ||
// Calculate the maximum period we can sleep and stay within | ||
if (us_to_sleep >= INT_MAX) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UINT32_MAX?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed the truncation is not needed because ticker_insert_event_us
is used.
timestamp_t time_in_sleep = 0UL; | ||
|
||
core_util_critical_section_enter(); | ||
uint32_t tick_freq = svcRtxKernelGetTickFreq(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't use internal RTX functions. The API is osKernel*
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason for this is to use critical sections. I had it previously (see the earlier commit) but then there might be a race condition. osKernel function cannot be invoked within critical section :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see much harm in having interrupt there, if you think it's a problem we should create an issue for RTOS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the critical section is removed and svcRtxKernelSuspend
is replaced by osKernelSuspend
and a thread is set as ready and run between the osKernelSuspend
and sleep
then the number of ticks acquired by then it won't be serviced immediately which can be critical for IRQ deferring the work in userland.osKernelSuspend
is invalid and the OS might be put to sleep for an incorrect amount of time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed.
Why ? Ticker events are serialized in a queue, if an event registered by the user is fired before the event registered by |
fc67bd2
to
d812281
Compare
Basic functionality, to test Thread::wait() with tickless. This is not accurancy test, just that an application wakes up within the expected period + some margin.
d812281
to
45f9423
Compare
@pan- The testing needs more love. I reworked it a bit (fixed Thread::wait(), add kernel tick check). One more addition would be to make idle loop pointer public and test that directly (one thing there to be done is to set kernel next event = that would be our expected wake up time). Any other suggestions? |
8639575
to
fc069d1
Compare
I run only rtos tests on one platform , this is the result:
Feel free to push to this branch to update if I am not around. |
I'll have a look at the failures. |
The tests are timing out, when the timeout is risen we get sleep accuracy errors. eg
The differences between sleep requested and actual are up to 50% Removing call to |
rtos/rtos_idle.c
Outdated
ticker_remove_event(lp_ticker_data, &idle_loop_event); | ||
ticker_set_handler(lp_ticker_data, &idle_loop_handler); | ||
timestamp_t start_time = lp_ticker_read(); | ||
ticker_insert_event_us(lp_ticker_data, &idle_loop_event, us_to_sleep, (uint32_t)&idle_loop_event); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's correct, us_to_sleep
should be a time stamp not delay to wait https://github.com/ARMmbed/mbed-os/blob/master/hal/ticker_api.h#L143
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
Change over os calls to use the svc equivalent. Also fixed time calculations.
fc069d1
to
091a6aa
Compare
https://github.com/ARMmbed/mbed-os/blob/master/rtos/Thread.cpp#L321 - look at this implementation, osDelay was changed in RTOS2, the argument is ticks now, previously it was milliseconds. If someone changes tick freq, the code becomes incorrect. |
Most likely replaced by Add tickless to some mbed-os devices #4991. I'll close this one. |
Use low power ticker if it is available to suspend kernel and keep ticks.
I added simple test that just waits and make sure we wake up.
cc @c1728p9 @pan- @bulislaw