From e2a6653680e3a8e2fa0d259ca428352c6f7b3662 Mon Sep 17 00:00:00 2001 From: Jimmy Wennlund Date: Sat, 23 Nov 2024 00:42:52 +0100 Subject: [PATCH] feat(esp_event): Allow an event carry more data without malloc This is both a feature and an optimization. Feature: Adjustable size of the internal storage in esp_event queue, currently used by ISR posting, as they wont be able to make a malloc. Optimization: When non-isr is posting an event, use the inernal storage in the struct instead of always allocating a new heap for the data. Most events in esp-idf only contains a few bytes event information, and we have that allocation payed for anyway. This solved in a big part our memory fragmentation issue, as events happens freqvently and used to create small memory allocations for just 4 bytes, and then in the event handler we usually allocated a bigger chunk of heap for our feature. When returning from the event handler, the 4 byte allocation was freed, leaving a hole in the heap. Merges: https://github.com/espressif/esp-idf/pull/17797 --- components/esp_event/Kconfig | 24 ++++++++++++++++++- components/esp_event/esp_event.c | 18 ++++++++++---- .../private_include/esp_event_internal.h | 6 ++++- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/components/esp_event/Kconfig b/components/esp_event/Kconfig index 0ad0f906551..955f7d04479 100644 --- a/components/esp_event/Kconfig +++ b/components/esp_event/Kconfig @@ -5,7 +5,7 @@ menu "Event Loop Library" default n help Enables collections of statistics in the event loop library such as the number of events posted - to/recieved by an event loop, number of callbacks involved, number of events dropped to to a full event + to/received by an event loop, number of callbacks involved, number of events dropped to to a full event loop queue, run time of event handlers, and number of times/run time of each event handler. config ESP_EVENT_POST_FROM_ISR @@ -14,6 +14,28 @@ menu "Event Loop Library" help Enable posting events from interrupt handlers. + config ESP_EVENT_POST_FROM_ISR_SIZE + int "Max size of data from events (bytes)" + default 4 + depends on ESP_EVENT_POST_FROM_ISR + range 4 256 + help + Maximum size (in bytes) of event data that will be kept in the inline event + storage. + + When ESP_EVENT_POST_FROM_ISR is enabled, event data with size less + than or equal to this value is copied into the fixed-size inline storage. + If event's data is larger than this limit, a heap allocation is performed + and the data is copied into the allocated buffer before posting. + + When ESP_EVENT_POST_FROM_ISR is disabled, event data is always + copied to a heap-allocated buffer to ensure the data remains valid until the + event is processed. + + Choose this value to trade static RAM footprint of the inline storage + against the frequency of heap allocations: smaller values reduce static + memory usage; larger values reduce heap allocations and fragmentation. + config ESP_EVENT_POST_FROM_IRAM_ISR bool "Support posting events from ISRs placed in IRAM" default y diff --git a/components/esp_event/esp_event.c b/components/esp_event/esp_event.c index 9358d910e23..f601dd6cba3 100644 --- a/components/esp_event/esp_event.c +++ b/components/esp_event/esp_event.c @@ -924,6 +924,19 @@ esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop, esp_event_base_t memset((void*)(&post), 0, sizeof(post)); if (event_data != NULL && event_data_size != 0) { +#if CONFIG_ESP_EVENT_POST_FROM_ISR + if (event_data_size > sizeof(post.data.val)) { + post.data.ptr = calloc(1, event_data_size); + if (post.data.ptr == NULL) { + return ESP_ERR_NO_MEM; + } + post.data_allocated = true; + memcpy(post.data.ptr, event_data, event_data_size); + } else { + memcpy((void*)(&(post.data.val)), event_data, event_data_size); + } + post.data_set = true; +#else // !CONFIG_ESP_EVENT_POST_FROM_ISR // Make persistent copy of event data on heap. void* event_data_copy = calloc(1, event_data_size); @@ -933,10 +946,7 @@ esp_err_t esp_event_post_to(esp_event_loop_handle_t event_loop, esp_event_base_t memcpy(event_data_copy, event_data, event_data_size); post.data.ptr = event_data_copy; -#if CONFIG_ESP_EVENT_POST_FROM_ISR - post.data_allocated = true; - post.data_set = true; -#endif +#endif // !CONFIG_ESP_EVENT_POST_FROM_ISR } post.base = event_base; post.id = event_id; diff --git a/components/esp_event/private_include/esp_event_internal.h b/components/esp_event/private_include/esp_event_internal.h index 76304c689ce..85d8b6d58fb 100644 --- a/components/esp_event/private_include/esp_event_internal.h +++ b/components/esp_event/private_include/esp_event_internal.h @@ -92,7 +92,11 @@ typedef struct esp_event_remove_handler_context_t { } esp_event_remove_handler_context_t; typedef union esp_event_post_data { - uint32_t val; +#if CONFIG_ESP_EVENT_POST_FROM_ISR_SIZE + uint8_t val[CONFIG_ESP_EVENT_POST_FROM_ISR_SIZE]; +#else + uint8_t val[4]; +#endif void *ptr; } esp_event_post_data_t;