← index #5994Issue #8301
Related · high · value 1.339
QUERY · ISSUE

esp32/mpconfigport: MICROPY_EVENT_POLL_HOOK fails to yield

openby tveopened 2020-05-01updated 2020-05-03
port-esp32

On the STM32 MICROPY_EVENT_POLL_HOOK contains either a pyb_thread_yield() or a __WFI() causing the flow of execution to pause for a tad and thereby give other threads a chance at the cpu or provide an opportunity to save power. On the esp32 MICROPY_EVENT_POLL_HOOK does not contain any form of yield (https://github.com/micropython/micropython/blob/master/ports/esp32/mpconfigport.h#L245-L252). Instead, mp_hal_delay_ms both calls MICROPY_EVENT_POLL_HOOK and yields (https://github.com/micropython/micropython/blob/master/ports/esp32/mphalport.c#L164-L165) and mp_hal_stdin_rx_chr also calls both. However, in modselect poll_poll_internal just has the MICROPY_EVENT_POLL_HOOK macro (https://github.com/micropython/micropython/blob/master/extmod/moduselect.c#L256) with the result that on the esp32 it busy-waits, hogging the cpu, while on stm32 it yields as expected.

It's pretty easy to fix the esp32 situation and that's actually something included in #5473 (https://github.com/micropython/micropython/pull/5473/files#diff-b9499fc8ad5b9793822626f6befdb1b6 and https://github.com/micropython/micropython/pull/5473/files#diff-4c3d68ff23336da03f336fbc26571f7b). But that's not the end of the story...

Due to the esp32's 100hz clock tick moving the yield into MICROPY_EVENT_POLL_HOOK results in a 10ms granularity when a routine uses MICROPY_EVENT_POLL_HOOK. extmod/uasyncio_basic.py works around this by including code that checks "is the remaining sleep duration shorter than a 10ms clock tick? if yes, then busy-wait". However, poll_poll_internal doesn't (and really shouldn't since it's not port-specific). The next thing that happens is that in the test suite extmod/uasyncio_basic.py verifies that sleeping in uasyncio for 20ms and 40ms has the desired effect and it turns out it doesn't on the esp32, rather, the sleep times are often 30ms and 50ms. This over-sleeping happens because asyncio's IOQueue uses ipoll to sleep, which now gets 10ms long yields inserted and and mentioned above doesn't compensate for that. So long story short, fixing the not-yielding issue causes over-sleeping when using uasyncio.

IMHO the best fix is to increase the clock tick rate on the esp32 to 1kHz, which would also help reduce latency when waiting to receive a packet but I'm happy to learn about other alternatives!

CANDIDATE · ISSUE

uasyncio tests can fail on windows ports

closedby stinosopened 2022-02-14updated 2022-05-04

Since #8030 the dev variant yields 'random' test failures for uasyncio, probably depending on machine/version/...

For example on my machine the uasyncio_basic consistently prints took 30 50 0 as last line, instead of the expected took 20 40 0. Some builds of the mingw port also fail in Appveyor for me. The reason for this is mentioned in #7796 :

most likely all sleep/wait implementations on windows by default use a 16mSec (or close to that) resolution

The dev variant enables both uasyncio and the scheduler, and uasyncio calls poll_poll_internal and that uses MICROPY_EVENT_POLL_HOOK which in turn calls mp_hal_delay_us(500). That last one is the culprit.

Setting MICROPY_ENABLE_SCHEDULER to 0 leaves MICROPY_EVENT_POLL_HOOK undefined, so doesn't compile because moduselect.c uses that unconditionally. Just adding #define MICROPY_EVENT_POLL_HOOK fixes that. It also makes the uasyncio tests pass. But it also turns poll_poll_internal into a busy loop. Likewise for mp_hal_delay_ms because it's conditional on ifdef MICROPY_EVENT_POLL_HOOK which should argueably should be #if MICROPY_ENABLE_SCHEDULER.

Things also grew a bit messy over time with there being multiple ways to sleep on Windows: mp_hal_delay_ms calls SleepEx but mp_hal_delay_us uses an implementation which uses which uses a timer. Which I wrote, but I don't remember why: I don't think it's better/worse/very different from SleepEx. Could be that things used to be different back then. Anyway these 2 should be consolidated.

Then the question remains how to fix this

  • I don't hink having busy waits is ok, even though they will make everything work and do so fairly accurately.
  • by default there's just no accurate wait on windows. We could work with that, add a word of warning to the README, and change the tests so they pass
  • figure out a way to make the wait accurate. I know at least one but it's generally considered bad practice (because https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted/). There might be other ways though, not sure.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied