esp32: Sleep in MICROPY_EVENT_POLL_HOOK to free up GIL and cycles for other threads#8351
esp32: Sleep in MICROPY_EVENT_POLL_HOOK to free up GIL and cycles for other threads#8351DvdGiessen wants to merge 1 commit into
Conversation
Considering that But an interesting question is whether |
If MicroPython threads are enabled, loops waiting for an incoming event should release the GIL and suspend, allowing other tasks to run while they wait. Signed-off-by: Daniël van de Giessen <[email protected]>
734b94c to
badb5ca
Compare
|
Yes, having looked at everywhere that macro is used that actually makes much more sense. It's only ever used in waiting loops, so sleeping should probably be the default behaviour if threads are enabled. In fact that is also the solution for another bug that was next on my list to look into (uselect using 100% CPU). :) Updated PR with this change. |
|
Fantastic! I tested this PR against the thread test suite and it still runs and passes. Merged in 665f0e2, with an update of the commit message to put most of the above explanation in it. Thank you very much! |
|
Not sure if was this new change or the combination of the new |
Dotclockframebuffer
Currently on the ESP32 the REPL holds the GIL while sleeping in wait for input, blocking other threads significantly.
This can easily be observed by running a thread that is both busy and regularly releases the GIL (for example a loop doing something then sleeping a few ms after each iteration). When the main task is at the REPL, the thread is significantly stalled. If the main task is manually made to release the GIL (for example, by calling
utime.sleep_ms(500)) the other thread can be seen immediately working at the expected speed again.This change releases the GIL while sleeping and waiting for a new character, thus allowing other threads to acquire the GIL in the meantime and resolving the issue.Note thatMICROPY_EVENT_POLL_HOOKalready releases and re-acquires the GIL. So an optional improvements might be using an alternative version of that hook here, so we don't have to release and acquire the lock twice. Left that out for now to keep the patch simple.EDIT:
Additionally, there are various instances in where blocking functions run
MICROPY_EVENT_POLL_HOOKin a loop while they wait for a certain event / condition. For example theuselectmethods poll objects to determine whether data is available, but uses 100% of CPU while it does, constantly callingMICROPY_EVENT_POLL_HOOKin the process.The
MICROPY_EVENT_POLL_HOOKmacro is only ever used in waiting loops, where (if threads are enabled) it makes sense to yield for at a single tick so that these loops do not consume all CPU cycles but instead other threads may execute. (In fact, the thing these loops wait for may even indirectly or directly depend on another task being able to run.)This change moves the sleep that was inside the REPL input function to inside the
MICROPY_EVENT_POLL_HOOKmacro, where the GIL is already being released, solving both the blocking REPL issue and the 100% CPU use issue at the same time.