Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add memory_type Support for Flexible Memory Allocation in WebSocket Client to permit other memory type caps to be used (IDFGH-13127) #586

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

filzek
Copy link

@filzek filzek commented Jun 3, 2024

Enable Usage of External or Specific Memory Types in WebSocket

Feature: Added a memory_type directive to esp_websocket_client_config_t to allow usage of various memory types in heap_caps_malloc and heap_caps_calloc.

Default Handling: If memory_type is not defined or is invalid, MALLOC_CAP_DEFAULT is used.
HTTP Auth Update: Updated http_auth_basic function to use the specified memory region.

All relevant functions have been updated to utilize the new memory_type configuration.

Now can set any memory CAPS region such as MALLOC_CAP_SPIRAM and others.

update esp_websocket_client_config_t with memory_type to be used in the allocation space, you can choose any avalible memory type in esp_heap_caps.h to be used with the heap_caps_calloc / heap_caps_malloc
Update to use heap_caps_malloc and heap_caps_calloc, with the memory_type defined in the esp_websocket_client_config_t struct, if the esp_websocket_client_config_t  memory_type is not set or it is invalid check it will uses the MALLOC_CAP_INTERNAL, otherwise will use the option set in it for any kind of memory allocation in websocket component.
missing memory_type
add example of memory usage
Use the correct default memory if not defined by user.
@erkia
Copy link
Contributor

erkia commented Jun 25, 2024

+1
Maybe allocate websocket task stack also from selected RAM by using xTaskCreateWithCaps?

@github-actions github-actions bot changed the title Add memory_type Support for Flexible Memory Allocation in WebSocket Client to permit other memory type caps to be used Add memory_type Support for Flexible Memory Allocation in WebSocket Client to permit other memory type caps to be used (IDFGH-13127) Jun 25, 2024
@gabsuren
Copy link
Contributor

gabsuren commented Jul 1, 2024

@filzek Thank you for your contribution.
However, the changes are causing compilation issues in our CI pipeline. Please refer to the details here:
https://github.com/espressif/esp-protocols/actions/runs/9708563633/job/26876119855?pr=586

adjusted the VALID_MEMORY_FLAGS macro by adding the header
#include "esp_heap_caps.h"  

also if a wrong memory is set to the websocket client the system will log an error and will return null.

the other memory info was moved to debug level.
@filzek
Copy link
Author

filzek commented Jul 4, 2024

@filzek Thank you for your contribution. However, the changes are causing compilation issues in our CI pipeline. Please refer to the details here: https://github.com/espressif/esp-protocols/actions/runs/9708563633/job/26876119855?pr=586

changes made to the original file as requested!

@filzek
Copy link
Author

filzek commented Jul 10, 2024

I will provide corrections for the SDK version to build the SDK. Some memory types are strictly dependent on the SDK version, such as MALLOC_CAP_TCM, which is only available after version 5.2. I will check all kinds of memory for each SDK version and provide #ifdef directives for those types.

@gabsuren
Copy link
Contributor

@filzek Thank you for the update. However, there are still breaking changes in the CI due to the modifications.

https://github.com/espressif/esp-protocols/actions/runs/9798927333/job/27229816060?pr=586

Add conditional inclusion of MALLOC_CAP_TCM based on ESP-IDF version

- Defined `VALID_MEMORY_FLAGS` macro to conditionally include `MALLOC_CAP_TCM` if the ESP-IDF version is 5.2.0 or higher.
- Ensured compatibility with earlier ESP-IDF versions by excluding `MALLOC_CAP_TCM` for versions lower than 5.2.0.
- Utilized `ESP_IDF_VERSION` and `ESP_IDF_VERSION_VAL` macros to implement version check.

This change addresses build issues caused by the undefined `MALLOC_CAP_TCM` macro in versions of ESP-IDF prior to 5.2.0.
@filzek
Copy link
Author

filzek commented Jul 24, 2024

@erkia

xTaskCreateWithCaps

We're currently testing the option to choose the core on which tasks will run, in addition to specifying the memory region. We believe this could enhance speed and consistency more effectively than just allocating the memory region, as the majority of memory consumption is in buffer processing rather than executable code. Therefore, our priority has been to select the core. However, we can provide an option that allows both core selection and memory region allocation if a specific flag is set.

@gabsuren and @euripedesrocha, here are my thoughts:

  1. I have implemented and am currently testing task creation with xTaskCreatePinnedToCore.
  2. I can add an option to enable the WebSocket Client to use xTaskCreateWithCaps.
  3. We can set a configuration flag to allow users to choose from three types of task creation:
    • xTaskCreatePinnedToCore
    • xTaskCreateWithCaps
    • A combination of both (with core selection and memory region allocation)

However, there is an issue with SDK versions prior to 5.1, which do not support xTaskCreatePinnedToCoreWithCaps. For these versions, we will need to use xTaskCreateStaticPinnedToCore and manually allocate the required memory size. Alternatively, we can use xTaskCreatePinnedToCoreWithCaps only if the SDK version is greater than 5.1. This approach ensures resource optimization and compatibility.

Any ideas or feedback on this?

Copy link
Author

@filzek filzek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Memory updated to SDK versions.

@filzek
Copy link
Author

filzek commented Jul 31, 2024

+1 Maybe allocate websocket task stack also from selected RAM by using xTaskCreateWithCaps?

if (!client->core) {
// No core affinity
if (!client->memory_type) {
// Default memory
if (xTaskCreate(esp_websocket_client_task,
client->config->task_name ? client->config->task_name : "websocket_task",
client->config->task_stack,
client, client->config->task_prio, &client->task_handle) != pdTRUE) {
ESP_LOGE(TAG, "Failed to create websocket task without core affinity using default memory");
return ESP_FAIL;
}
ESP_LOGD(TAG, "Websocket task created without core affinity using default memory");
} else {
// Specific memory type without core affinity
if (xTaskCreatePinnedToCoreWithCaps(esp_websocket_client_task,
client->config->task_name ? client->config->task_name : "websocket_task",
client->config->task_stack,
client,
client->config->task_prio,
&client->task_handle,
tskNO_AFFINITY,
client->memory_type) != pdTRUE) {
ESP_LOGE(TAG, "Failed to create websocket task without core affinity using specified memory type");
return ESP_FAIL;
}
ESP_LOGD(TAG, "Websocket task created without core affinity using specified memory type");
}
} else {
// With core affinity
if (!client->memory_type) {
// Default memory with core affinity
if (xTaskCreatePinnedToCoreWithCaps(esp_websocket_client_task,
client->config->task_name ? client->config->task_name : "websocket_task",
client->config->task_stack,
client,
client->config->task_prio,
&client->task_handle,
client->core,
MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT) != pdTRUE) {
ESP_LOGE(TAG, "Failed to create websocket task with core affinity using default memory (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)");
return ESP_FAIL;
}
ESP_LOGD(TAG, "Websocket task created with core affinity using default memory (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)");
} else {
// Specific memory type with core affinity
if (xTaskCreatePinnedToCoreWithCaps(esp_websocket_client_task,
client->config->task_name ? client->config->task_name : "websocket_task",
client->config->task_stack,
client,
client->config->task_prio,
&client->task_handle,
client->core,
client->memory_type) != pdTRUE) {
ESP_LOGE(TAG, "Failed to create websocket task with core affinity using specified memory type");
return ESP_FAIL;
}
ESP_LOGD(TAG, "Websocket task created with core affinity using specified memory type (%d)", client->memory_type);
}
}

Now it is working correct using the memory area, but we need to evaluate to tell that some internal heap memory will be used as the task function couldnt be placed in the external memory.

Added the Option to choose if the WebSocket will use a default memory or CAPS memory, if the memory_type is used it will use the CAPS also to create the task with a buffer allocated in this memory area.

The CPU Core affinity have been added to the WebSocket config with the option  "core", if not core is set it will use the tskNO_AFFINITY flag, otherwise will use the core option set.
add features added
add explanation to CORE and Task Memory creation if the MEMORY_TYPE is set.
@@ -1,5 +1,21 @@
# Changelog

## [1.x.x](https://github.com/espressif/esp-protocols/commits/websocket-v1.x.x)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to modify, in fact you should not, the Changelog.
As stated in the contribution guide, you only need to follow the conventional commits, and we take care of the release notes when releasing a new version of the component.

@@ -137,6 +153,8 @@ struct esp_websocket_client {
int payload_offset;
esp_transport_keep_alive_t keep_alive_cfg;
struct ifreq *if_name;
int memory_type;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not against making the selection in runtime but, in other components, we make this choice in compile time through Kconfig.
Do you have a use case to have it set in runtime?

ESP_WS_CLIENT_MEM_CHECK(TAG, client, return NULL);

if (config->core){
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer it to be introduced in a separated PR. Since we'll have to take into consideration portability among different IDF versions given the proposal of usage xTaskCreatePinnedToCoreWithCaps. Could you please move this to a second PR?

@euripedesrocha
Copy link
Collaborator

@filzek thank you for your contribution and diligent answer to our questions. I left a few comments that we have to address prior to merging.
You will need also to clean up the commit history, could you please install the pre-commit as suggested in our contributing guide and have the commit messages in the correct format?

@@ -127,6 +127,8 @@ typedef struct {
int network_timeout_ms; /*!< Abort network operation if it is not completed after this value, in milliseconds (defaults to 10s) */
size_t ping_interval_sec; /*!< Websocket ping interval, defaults to 10 seconds if not set */
struct ifreq *if_name; /*!< The name of interface for data to go through. Use the default interface without setting */
int memory_type; /*!< The name of memory region type to be used in the heap_caps_malloc / heap_caps_calloc */
esp_transport_handle_t ext_transport; /*!< External WebSocket tcp_transport handle to the client; or if null, the client will create its own transport handle. */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be some kind of leftover.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants