Skip to content

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

Closed
wants to merge 4 commits into from
Closed

Conversation

0xc0170
Copy link
Contributor

@0xc0170 0xc0170 commented Aug 22, 2017

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

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.
Copy link
Member

@pan- pan- left a 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();
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Member

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.

😞

Copy link
Member

@bulislaw bulislaw left a 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
Copy link
Member

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.

Copy link
Contributor Author

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) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UINT32_MAX?

Copy link
Member

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();
Copy link
Member

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*

Copy link
Contributor Author

@0xc0170 0xc0170 Aug 23, 2017

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 :(

Copy link
Member

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.

Copy link
Member

@pan- pan- Aug 23, 2017

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 osKernelSuspend is invalid and the OS might be put to sleep for an incorrect amount of time then it won't be serviced immediately which can be critical for IRQ deferring the work in userland.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed.

@pan-
Copy link
Member

pan- commented Aug 23, 2017

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.

Why ? Ticker events are serialized in a queue, if an event registered by the user is fired before the event registered by default_idle_hook then like with any other IRQ the kernel is awaken. It might be good to remove idle_loop_event from the queue, after sleep, if it wasn't fired though.

@0xc0170 0xc0170 force-pushed the dev_tickless_rtos branch 2 times, most recently from fc67bd2 to d812281 Compare August 23, 2017 10:24
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.
@0xc0170 0xc0170 force-pushed the dev_tickless_rtos branch from d812281 to 45f9423 Compare August 23, 2017 12:07
@0xc0170
Copy link
Contributor Author

0xc0170 commented Aug 23, 2017

@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?

@0xc0170 0xc0170 force-pushed the dev_tickless_rtos branch from 8639575 to fc069d1 Compare August 23, 2017 12:26
@0xc0170
Copy link
Contributor Author

0xc0170 commented Aug 23, 2017

I run only rtos tests on one platform , this is the result:

+--------------+---------------+-------------------------------------+--------+--------------------+-------------+
| target       | platform_name | test suite                          | result | elapsed_time (sec) | copy_method |
+--------------+---------------+-------------------------------------+--------+--------------------+-------------+
| K64F-GCC_ARM | K64F          | tests-mbedmicro-rtos-mbed-basic     | OK     | 20.85              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbedmicro-rtos-mbed-idle_loop | OK     | 13.29              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbedmicro-rtos-mbed-isr       | OK     | 16.96              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbedmicro-rtos-mbed-mail      | OK     | 14.08              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbedmicro-rtos-mbed-malloc    | OK     | 26.41              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbedmicro-rtos-mbed-mutex     | OK     | 17.95              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbedmicro-rtos-mbed-queue     | FAIL   | 14.08              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbedmicro-rtos-mbed-semaphore | FAIL   | 12.98              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbedmicro-rtos-mbed-signals   | OK     | 19.92              | shell       |
| K64F-GCC_ARM | K64F          | tests-mbedmicro-rtos-mbed-threads   | FAIL   | 22.51              | shell       |
+--------------+---------------+-------------------------------------+--------+--------------------+-------------+
mbedgt: test suite results: 3 FAIL / 7 OK

Feel free to push to this branch to update if I am not around.

@bulislaw
Copy link
Member

I'll have a look at the failures.

@bulislaw
Copy link
Member

bulislaw commented Aug 25, 2017

The tests are timing out, when the timeout is risen we get sleep accuracy errors. eg

:374::FAIL: Values Not Within Delta 50000 Expected 500000 Was 726460

:374::FAIL: Values Not Within Delta 50000 Expected 1500000 Was 259272

The differences between sleep requested and actual are up to 50%

Removing call to sleep from the idle handler doesn't change anything - still takes to much time.

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);
Copy link
Member

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

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

c1728p9 and others added 2 commits August 29, 2017 06:53
Change over os calls to use the svc equivalent. Also fixed time calculations.
@0xc0170 0xc0170 force-pushed the dev_tickless_rtos branch from fc069d1 to 091a6aa Compare August 29, 2017 05:54
@0xc0170
Copy link
Contributor Author

0xc0170 commented Aug 29, 2017

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.

@0xc0170
Copy link
Contributor Author

0xc0170 commented Sep 4, 2017

Most likely replaced by Add tickless to some mbed-os devices #4991. I'll close this one.

@0xc0170 0xc0170 closed this Sep 4, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants