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
This commit is contained in:
Jimmy Wennlund
2024-11-23 00:42:52 +01:00
committed by Konstantin Kondrashov
parent d1b91b79b5
commit e2a6653680
3 changed files with 42 additions and 6 deletions

View File

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

View File

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

View File

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