Skip to content

Zephyr port: async event loop implementation starves CPU #11837

Open
@bogdanm

Description

@bogdanm

When using asyncio in MicroPython, the event loop implementation (asyncio.run) ends up polling Python objects in a queue. The polling code does this (extmod/modselect.c:poll_poll_internal):

...
    mp_uint_t start_tick = mp_hal_ticks_ms();
    mp_uint_t n_ready;
    for (;;) {
        // poll the objects
        n_ready = poll_map_poll(&self->poll_map, NULL);
        if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) {
            break;
        }
        MICROPY_EVENT_POLL_HOOK
    }
...

The for(;;) loop above is a busy wait loop. In the Zephyr port, it consumes a lot of CPU time and it starves other threads. Even when MICROPY_EVENT_POOL_HOOK is set to k_yield (and thus the loop gives control back to the OS scheduler after each iteration) the code will still take most of the CPU time. Setting MICROPY_EVENT_POOL_HOOK to something like k_msleep(100) (which waits 100ms before running another iteration of the loop) fixes the starving issue, but it delays the Python thread for no good reason.

I have a possible solution for this, but please let me know first if there is interest to move this forward, since lately I got the impression that the Zephyr port isn't exactly a "fist class citizen" in the world of MicroPython ports.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementFeature requests, new feature implementationsport-zephyr

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions