forked from espressif/esp-idf
feat(examples): Update heap task tracking examples
update example to showcasee the new API of heap task tracking - Add basic heap task traacking example - Add advanced example for task tracking
This commit is contained in:
@@ -4,10 +4,11 @@
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <multi_heap.h>
|
||||
#include <string.h>
|
||||
#include "multi_heap_internal.h"
|
||||
#include "heap_private.h"
|
||||
#include "esp_heap_task_info.h"
|
||||
@@ -619,11 +620,15 @@ esp_err_t heap_caps_get_single_task_stat(heap_single_task_stat_t *task_stat, Tas
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void heap_caps_print_task_info(task_info_t *task_info, bool is_last_task_info)
|
||||
static void heap_caps_print_task_info(FILE *stream, task_info_t *task_info, bool is_last_task_info)
|
||||
{
|
||||
if (stream == NULL) {
|
||||
stream = stdout;
|
||||
}
|
||||
|
||||
const char *task_info_visual = is_last_task_info ? " " : "│";
|
||||
const char *task_info_visual_start = is_last_task_info ? "└" : "├";
|
||||
esp_rom_printf("%s %s: %s, CURRENT MEMORY USAGE %d, PEAK MEMORY USAGE %d, TOTAL HEAP USED %d:\n", task_info_visual_start,
|
||||
fprintf(stream, "%s %s: %s, CURRENT MEMORY USAGE %d, PEAK MEMORY USAGE %d, TOTAL HEAP USED %d:\n", task_info_visual_start,
|
||||
task_info->task_stat.is_alive ? "ALIVE" : "DELETED",
|
||||
task_info->task_stat.name,
|
||||
task_info->task_stat.overall_current_usage,
|
||||
@@ -634,7 +639,7 @@ static void heap_caps_print_task_info(task_info_t *task_info, bool is_last_task_
|
||||
STAILQ_FOREACH(heap_info, &task_info->heaps_stats, next_heap_stat) {
|
||||
char *next_heap_visual = !STAILQ_NEXT(heap_info, next_heap_stat) ? " " : "│";
|
||||
char *next_heap_visual_start = !STAILQ_NEXT(heap_info, next_heap_stat) ? "└" : "├";
|
||||
esp_rom_printf("%s %s HEAP: %s, CAPS: 0x%08lx, SIZE: %d, USAGE: CURRENT %d (%d%%), PEAK %d (%d%%), ALLOC COUNT: %d\n",
|
||||
fprintf(stream, "%s %s HEAP: %s, CAPS: 0x%08lx, SIZE: %d, USAGE: CURRENT %d (%d%%), PEAK %d (%d%%), ALLOC COUNT: %d\n",
|
||||
task_info_visual,
|
||||
next_heap_visual_start,
|
||||
heap_info->heap_stat.name,
|
||||
@@ -648,7 +653,7 @@ static void heap_caps_print_task_info(task_info_t *task_info, bool is_last_task_
|
||||
|
||||
alloc_stats_t *alloc_stats = NULL;
|
||||
STAILQ_FOREACH(alloc_stats, &heap_info->allocs_stats, next_alloc_stat) {
|
||||
esp_rom_printf("%s %s ├ ALLOC %p, SIZE %d\n", task_info_visual,
|
||||
fprintf(stream, "%s %s ├ ALLOC %p, SIZE %" PRIu32 "\n", task_info_visual,
|
||||
next_heap_visual,
|
||||
alloc_stats->alloc_stat.address,
|
||||
alloc_stats->alloc_stat.size);
|
||||
@@ -656,16 +661,20 @@ static void heap_caps_print_task_info(task_info_t *task_info, bool is_last_task_
|
||||
}
|
||||
}
|
||||
|
||||
static void heap_caps_print_task_overview(task_info_t *task_info, bool is_first_task_info, bool is_last_task_info)
|
||||
static void heap_caps_print_task_overview(FILE *stream, task_info_t *task_info, bool is_first_task_info, bool is_last_task_info)
|
||||
{
|
||||
if (stream == NULL) {
|
||||
stream = stdout;
|
||||
}
|
||||
|
||||
if (is_first_task_info) {
|
||||
esp_rom_printf("┌────────────────────┬─────────┬──────────────────────┬───────────────────┬─────────────────┐\n");
|
||||
esp_rom_printf("│ TASK │ STATUS │ CURRENT MEMORY USAGE │ PEAK MEMORY USAGE │ TOTAL HEAP USED │\n");
|
||||
esp_rom_printf("├────────────────────┼─────────┼──────────────────────┼───────────────────┼─────────────────┤\n");
|
||||
fprintf(stream, "┌────────────────────┬─────────┬──────────────────────┬───────────────────┬─────────────────┐\n");
|
||||
fprintf(stream, "│ TASK │ STATUS │ CURRENT MEMORY USAGE │ PEAK MEMORY USAGE │ TOTAL HEAP USED │\n");
|
||||
fprintf(stream, "├────────────────────┼─────────┼──────────────────────┼───────────────────┼─────────────────┤\n");
|
||||
}
|
||||
|
||||
task_stat_t task_stat = task_info->task_stat;
|
||||
esp_rom_printf("│ %18s │ %7s │ %20d │ %17d │ %15d │\n",
|
||||
fprintf(stream, "│ %18s │ %7s │ %20d │ %17d │ %15d │\n",
|
||||
task_stat.name,
|
||||
task_stat.is_alive ? "ALIVE " : "DELETED",
|
||||
task_stat.overall_current_usage,
|
||||
@@ -673,11 +682,11 @@ static void heap_caps_print_task_overview(task_info_t *task_info, bool is_first_
|
||||
task_stat.heap_count);
|
||||
|
||||
if (is_last_task_info) {
|
||||
esp_rom_printf("└────────────────────┴─────────┴──────────────────────┴───────────────────┴─────────────────┘\n");
|
||||
fprintf(stream, "└────────────────────┴─────────┴──────────────────────┴───────────────────┴─────────────────┘\n");
|
||||
}
|
||||
}
|
||||
|
||||
void heap_caps_print_single_task_stat(TaskHandle_t task_handle)
|
||||
void heap_caps_print_single_task_stat(FILE *stream, TaskHandle_t task_handle)
|
||||
{
|
||||
if (task_handle == NULL) {
|
||||
task_handle = xTaskGetCurrentTaskHandle();
|
||||
@@ -697,7 +706,7 @@ void heap_caps_print_single_task_stat(TaskHandle_t task_handle)
|
||||
xSemaphoreGive(s_task_tracking_mutex);
|
||||
}
|
||||
|
||||
void heap_caps_print_all_task_stat(void)
|
||||
void heap_caps_print_all_task_stat(FILE *stream)
|
||||
{
|
||||
task_info_t *task_info = NULL;
|
||||
|
||||
@@ -709,7 +718,7 @@ void heap_caps_print_all_task_stat(void)
|
||||
xSemaphoreGive(s_task_tracking_mutex);
|
||||
}
|
||||
|
||||
void heap_caps_print_single_task_stat_overview(TaskHandle_t task_handle)
|
||||
void heap_caps_print_single_task_stat_overview(FILE *stream, TaskHandle_t task_handle)
|
||||
{
|
||||
if (task_handle == NULL) {
|
||||
task_handle = xTaskGetCurrentTaskHandle();
|
||||
@@ -729,7 +738,7 @@ void heap_caps_print_single_task_stat_overview(TaskHandle_t task_handle)
|
||||
xSemaphoreGive(s_task_tracking_mutex);
|
||||
}
|
||||
|
||||
void heap_caps_print_all_task_stat_overview(void)
|
||||
void heap_caps_print_all_task_stat_overview(FILE *stream)
|
||||
{
|
||||
task_info_t *task_info = NULL;
|
||||
bool is_first_task_info = true;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#ifdef CONFIG_HEAP_TASK_TRACKING
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
@@ -167,16 +168,20 @@ esp_err_t heap_caps_get_single_task_stat(heap_single_task_stat_t *task_stat, Tas
|
||||
*
|
||||
* @note This function is an alternative to heap_caps_get_all_task_stat if the goal is just to print information
|
||||
* and not manipulate them.
|
||||
*
|
||||
* @param steam The stream to dump to, if NULL then stdout is used
|
||||
*/
|
||||
void heap_caps_print_all_task_stat(void);
|
||||
void heap_caps_print_all_task_stat(FILE *stream);
|
||||
|
||||
/**
|
||||
* @brief Print summary information of all tasks
|
||||
*
|
||||
* @note The information printed by this function is an array formatted log of task_stat_t content for each running
|
||||
* task (and deleted ones if HEAP_TRACK_DELETED_TASKS is enabled)
|
||||
*
|
||||
* @param steam The stream to dump to, if NULL then stdout is used
|
||||
*/
|
||||
void heap_caps_print_all_task_stat_overview(void);
|
||||
void heap_caps_print_all_task_stat_overview(FILE *stream);
|
||||
|
||||
/**
|
||||
* @brief Print heap memory usage and associated allocation information on each heap for a given task.
|
||||
@@ -184,9 +189,10 @@ void heap_caps_print_all_task_stat_overview(void);
|
||||
* @note This function is an alternative to heap_caps_get_single_task_stat if the goal is just to print information
|
||||
* and not manipulate them.
|
||||
*
|
||||
* @param steam The stream to dump to, if NULL then stdout is used
|
||||
* @param task_handle The task handle of the task to get memory usage and associated allocation information from.
|
||||
*/
|
||||
void heap_caps_print_single_task_stat(TaskHandle_t task_handle);
|
||||
void heap_caps_print_single_task_stat(FILE *stream, TaskHandle_t task_handle);
|
||||
|
||||
/**
|
||||
* @brief Print summary information of a given task
|
||||
@@ -195,9 +201,10 @@ void heap_caps_print_single_task_stat(TaskHandle_t task_handle);
|
||||
* task. This function will not print the task summary information if the given task is deleted and
|
||||
* HEAP_TRACK_DELETED_TASKS is disabled.
|
||||
*
|
||||
* @param steam The stream to dump to, if NULL then stdout is used
|
||||
* @param task_handle The task handle of the task to get memory usage and associated allocation information from.
|
||||
*/
|
||||
void heap_caps_print_single_task_stat_overview(TaskHandle_t task_handle);
|
||||
void heap_caps_print_single_task_stat_overview(FILE *stream, TaskHandle_t task_handle);
|
||||
|
||||
/**
|
||||
* @brief Allocate the memory used to store the heap and alloc statistics and fill task_stat
|
||||
|
@@ -202,7 +202,7 @@ Heap Task Tracking
|
||||
|
||||
Heap Task Tracking can be used to get per-task info for heap memory allocation. The application has to specify the heap capabilities for which the heap allocation is to be tracked.
|
||||
|
||||
Example code is provided in :example:`system/heap_task_tracking`.
|
||||
Example applications are provided in :example:`system/heap_task_tracking/basic` and :example:`system/heap_task_tracking/advanced`.
|
||||
|
||||
|
||||
.. _heap-tracing:
|
||||
@@ -629,7 +629,8 @@ One way to differentiate between "real" and "false positive" memory leaks is to
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
- :example:`system/heap_task_tracking` demonstrates the use of the heap task tracking feature to track heap memory allocated on a per-task basis.
|
||||
- :example:`system/heap_task_tracking/basic` demonstrates the use of the overview feature of the heap task tracking, dumping per-task summary statistics on heap memory usage.
|
||||
- :example:`system/heap_task_tracking/advanced` demonstrates the use of the statistics getter functions of the heap task tracking, accessing per-task complete statistic on the heap memory usage.
|
||||
|
||||
API Reference - Heap Tracing
|
||||
----------------------------
|
||||
|
@@ -1,39 +0,0 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- |
|
||||
|
||||
# Heap Task Tracking Example
|
||||
|
||||
## Overview
|
||||
|
||||
The example creates a task which allocates random amount of memory in each iteration and demonstrates use of internal API to get heap info on per task basis running in a system.
|
||||
|
||||
Heap task tracking feature has dependency on some of the internal heap debugging features (e.g. heap poisoning) which allows to store task control block in metadata of each heap block.
|
||||
|
||||
This adds small memory overhead on per heap block and hence this feature should be used for debugging purpose only.
|
||||
|
||||
### Configure the project
|
||||
|
||||
To change the `Heap Corruption Detection level`, open the project configuration menu (`idf.py menuconfig`).
|
||||
|
||||
Navigate to `Component config -> Heap memory debugging` menu. In `Heap corruption detection` menu select either "Light Impact" or "Comprehensive".
|
||||
|
||||
**Note:** Enabling “Comprehensive” detection has a substantial runtime performance impact.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build and flash the project..
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
Task: Pre-Scheduler allocs -> CAP_8BIT: 5360 CAP_32BIT: 0
|
||||
Task: esp_timer -> CAP_8BIT: 1724 CAP_32BIT: 0
|
||||
Task: ipc0 -> CAP_8BIT: 8316 CAP_32BIT: 0
|
||||
Task: main -> CAP_8BIT: 3480 CAP_32BIT: 0
|
||||
Task: ipc1 -> CAP_8BIT: 12 CAP_32BIT: 0
|
||||
Task: example_task -> CAP_8BIT: 696 CAP_32BIT: 0
|
||||
```
|
@@ -0,0 +1,6 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(advanced)
|
141
examples/system/heap_task_tracking/advanced/README.md
Normal file
141
examples/system/heap_task_tracking/advanced/README.md
Normal file
@@ -0,0 +1,141 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- |
|
||||
|
||||
# Heap Task Tracking Basic Example
|
||||
|
||||
## Overview
|
||||
|
||||
The example creates a task which allocates random amount of memory and frees it and another task that allocates random amount of memory but never frees it.
|
||||
The main then goes into a loop calling functions retrieving statistics for the "no leak" task, the "leaking" tasks and all tasks and printing them.
|
||||
For each tasks, the following information is retrieved and printed:
|
||||
- the task name
|
||||
- the task status (running or deleted)
|
||||
- the overall peak memory usage of the task
|
||||
- the overall current memory usage of the task
|
||||
For each heap used by a given task, the following information is printed:
|
||||
- the heap name
|
||||
- the heap caps
|
||||
- the heap size
|
||||
- the heap current memory usage by the task
|
||||
- the heap peak memory usage by the task
|
||||
- the number of blocks currently allocated in the heap by the task
|
||||
For each block of memory allocated in a given heap by a given task, the following information is printed:
|
||||
- the allocation address
|
||||
- the allocation size
|
||||
|
||||
Because the heap task tracking feature requires additional metadata to be allocated for each memory allocations, the overall heap usage of the application is
|
||||
greater than when the feature is disabled. For this reason, it is highly recommended to use the task tracking for debugging purpose only.
|
||||
|
||||
### Configure the project
|
||||
|
||||
- Enable thee option `Enable heap task tracking` by opening the project configuration menu (`idf.py menuconfig`) and navigate to `Component config -> Heap memory debugging` menu.
|
||||
- (optional) Enable the option `Keep information about the memory usage on deleted tasks` if you wish to keep track of the information of a task after it has been deleted.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build and flash the project..
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
--------------------------------------------------------------------------------
|
||||
PRINTING SINGLE TASK INFO
|
||||
--------------------------------------------------------------------------------
|
||||
no_leak_task: ALIVE : Peak Usage 10128, Current Usage 0
|
||||
RAM: Caps: 1071118. Size 22308, Current Usage 0, Peak Usage 10128, alloc count 0
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
PRINTING SINGLE TASK INFO
|
||||
--------------------------------------------------------------------------------
|
||||
leaking_task: ALIVE : Peak Usage 7232, Current Usage 6656
|
||||
RAM: Caps: 1071118. Size 22308, Current Usage 6656, Peak Usage 7232, alloc count 1
|
||||
0x3fceb878: Size: 6656
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
PRINTING SINGLE TASK INFO
|
||||
--------------------------------------------------------------------------------
|
||||
no_leak_task: ALIVE : Peak Usage 10128, Current Usage 0
|
||||
RAM: Caps: 1071118. Size 22308, Current Usage 0, Peak Usage 10128, alloc count 0
|
||||
RAM: Caps: 1071118. Size 14832, Current Usage 0, Peak Usage 8960, alloc count 0
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
PRINTING SINGLE TASK INFO
|
||||
--------------------------------------------------------------------------------
|
||||
leaking_task: ALIVE : Peak Usage 15040, Current Usage 9664
|
||||
RAM: Caps: 1071118. Size 22308, Current Usage 6656, Peak Usage 12032, alloc count 1
|
||||
0x3fceb878: Size: 6656
|
||||
RAM: Caps: 1071118. Size 14832, Current Usage 3008, Peak Usage 3008, alloc count 1
|
||||
0x3fc9a0e4: Size: 3008
|
||||
|
||||
[...]
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
PRINTING ALL TASKS INFO
|
||||
--------------------------------------------------------------------------------
|
||||
leaking_task: DELETED: Peak Usage 19248, Current Usage 13616
|
||||
RAM: Caps: 1071118. Size 22308, Current Usage 10608, Peak Usage 13296, alloc count 3
|
||||
0x3fceb878: Size: 6656
|
||||
0x3fceb634: Size: 368
|
||||
0x3fcedd00: Size: 3584
|
||||
RAM: Caps: 1071118. Size 14832, Current Usage 3008, Peak Usage 12224, alloc count 1
|
||||
0x3fc9a0e4: Size: 3008
|
||||
no_leak_task: DELETED: Peak Usage 10128, Current Usage 0
|
||||
RAM: Caps: 1071118. Size 22308, Current Usage 0, Peak Usage 10128, alloc count 0
|
||||
RAM: Caps: 1071118. Size 14832, Current Usage 0, Peak Usage 9728, alloc count 0
|
||||
main: ALIVE : Peak Usage 7456, Current Usage 352
|
||||
RAM: Caps: 1071118. Size 14832, Current Usage 264, Peak Usage 264, alloc count 3
|
||||
0x3fc99cf4: Size: 88
|
||||
0x3fc99e1c: Size: 88
|
||||
0x3fc99e78: Size: 88
|
||||
RAM: Caps: 1071118. Size 22308, Current Usage 88, Peak Usage 7192, alloc count 5
|
||||
0x3fce99f8: Size: 20
|
||||
0x3fce9a10: Size: 12
|
||||
0x3fce9a20: Size: 16
|
||||
0x3fce9a34: Size: 20
|
||||
0x3fce9a4c: Size: 20
|
||||
ipc1: ALIVE : Peak Usage 44, Current Usage 32
|
||||
RAM: Caps: 1071118. Size 14832, Current Usage 32, Peak Usage 44, alloc count 2
|
||||
0x3fc99dcc: Size: 16
|
||||
0x3fc99df4: Size: 16
|
||||
ipc0: ALIVE : Peak Usage 10092, Current Usage 10080
|
||||
RAM: Caps: 1071118. Size 14832, Current Usage 10080, Peak Usage 10092, alloc count 10
|
||||
0x3fc973b0: Size: 1312
|
||||
0x3fc97950: Size: 344
|
||||
0x3fc97ae4: Size: 16
|
||||
0x3fc97b0c: Size: 4224
|
||||
0x3fc98b90: Size: 344
|
||||
0x3fc98d00: Size: 1568
|
||||
0x3fc99338: Size: 344
|
||||
0x3fc994a8: Size: 1568
|
||||
0x3fc99ae0: Size: 344
|
||||
0x3fc99c64: Size: 16
|
||||
Pre-scheduler: ALIVE : Peak Usage 3364, Current Usage 3364
|
||||
RAM: Caps: 1071118. Size 14832, Current Usage 3364, Peak Usage 3364, alloc count 22
|
||||
0x3fc96410: Size: 164
|
||||
0x3fc96538: Size: 12
|
||||
0x3fc9655c: Size: 12
|
||||
0x3fc96580: Size: 16
|
||||
0x3fc965a8: Size: 24
|
||||
0x3fc965d8: Size: 36
|
||||
0x3fc96614: Size: 40
|
||||
0x3fc96654: Size: 36
|
||||
0x3fc96690: Size: 40
|
||||
0x3fc966d0: Size: 88
|
||||
0x3fc96740: Size: 88
|
||||
0x3fc967b0: Size: 88
|
||||
0x3fc96820: Size: 432
|
||||
0x3fc969e8: Size: 88
|
||||
0x3fc96a58: Size: 88
|
||||
0x3fc96ac8: Size: 88
|
||||
0x3fc96b38: Size: 132
|
||||
0x3fc96bd4: Size: 132
|
||||
0x3fc96c70: Size: 88
|
||||
0x3fc96ce0: Size: 16
|
||||
0x3fc96d08: Size: 1312
|
||||
0x3fc97240: Size: 344
|
||||
I (4504) main_task: Returned from app_main()
|
||||
```
|
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "heap_task_tracking_advanced_main.c"
|
||||
INCLUDE_DIRS "")
|
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
/* Heap Task Tracking Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_heap_task_info.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_random.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static void print_single_task_info(TaskHandle_t task_hdl)
|
||||
{
|
||||
heap_single_task_stat_t task_stat;
|
||||
/* call API to dynamically allocate the memory necessary to store the
|
||||
* information collected while calling heap_caps_get_single_task_stat */
|
||||
const esp_err_t ret_val = heap_caps_alloc_single_task_stat_arrays(&task_stat, task_hdl);
|
||||
assert(ret_val == ESP_OK);
|
||||
|
||||
/* collect the information */
|
||||
heap_caps_get_single_task_stat(&task_stat, task_hdl);
|
||||
|
||||
/* process the information retrieved */
|
||||
printf("\n--------------------------------------------------------------------------------\n");
|
||||
printf("PRINTING SINGLE TASK INFO\n");
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
printf("%s: %s: Peak Usage %"PRIu16", Current Usage %"PRIu16"\n", task_stat.stat.name,
|
||||
task_stat.stat.is_alive ? "ALIVE " : "DELETED",
|
||||
task_stat.stat.overall_peak_usage,
|
||||
task_stat.stat.overall_current_usage);
|
||||
|
||||
for (size_t heap_idx = 0; heap_idx < task_stat.heap_count; heap_idx++) {
|
||||
heap_stat_t heap_stat = task_stat.heap_stat_start[heap_idx];
|
||||
printf(" %s: Caps: %"PRIu32". Size %"PRIu16", Current Usage %"PRIu16", Peak Usage %"PRIu16", alloc count %"PRIu16"\n", heap_stat.name,
|
||||
heap_stat.caps,
|
||||
heap_stat.size,
|
||||
heap_stat.current_usage,
|
||||
heap_stat.peak_usage,
|
||||
heap_stat.alloc_count);
|
||||
|
||||
for (size_t alloc_idx = 0; alloc_idx < heap_stat.alloc_count; alloc_idx++) {
|
||||
heap_task_block_t alloc_stat = heap_stat.alloc_stat[alloc_idx];
|
||||
printf(" %p: Size: %"PRIu32"\n", alloc_stat.address, alloc_stat.size);
|
||||
}
|
||||
}
|
||||
|
||||
/* delete the memory dynamically allocated while calling heap_caps_alloc_all_task_stat_arrays */
|
||||
heap_caps_free_single_task_stat_arrays(&task_stat);
|
||||
}
|
||||
|
||||
static void print_all_tasks_info(void)
|
||||
{
|
||||
heap_all_tasks_stat_t tasks_stat;
|
||||
/* call API to dynamically allocate the memory necessary to store the
|
||||
* information collected while calling heap_caps_get_all_task_stat */
|
||||
const esp_err_t ret_val = heap_caps_alloc_all_task_stat_arrays(&tasks_stat);
|
||||
assert(ret_val == ESP_OK);
|
||||
|
||||
/* collect the information */
|
||||
heap_caps_get_all_task_stat(&tasks_stat);
|
||||
|
||||
/* process the information retrieved */
|
||||
printf("\n--------------------------------------------------------------------------------\n");
|
||||
printf("PRINTING ALL TASKS INFO\n");
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
for (size_t task_idx = 0; task_idx < tasks_stat.task_count; task_idx++) {
|
||||
task_stat_t task_stat = tasks_stat.stat_arr[task_idx];
|
||||
printf("%s: %s: Peak Usage %"PRIu16", Current Usage %"PRIu16"\n", task_stat.name,
|
||||
task_stat.is_alive ? "ALIVE " : "DELETED",
|
||||
task_stat.overall_peak_usage,
|
||||
task_stat.overall_current_usage);
|
||||
|
||||
for (size_t heap_idx = 0; heap_idx < task_stat.heap_count; heap_idx++) {
|
||||
heap_stat_t heap_stat = task_stat.heap_stat[heap_idx];
|
||||
printf(" %s: Caps: %"PRIu32". Size %"PRIu16", Current Usage %"PRIu16", Peak Usage %"PRIu16", alloc count %"PRIu16"\n", heap_stat.name,
|
||||
heap_stat.caps,
|
||||
heap_stat.size,
|
||||
heap_stat.current_usage,
|
||||
heap_stat.peak_usage,
|
||||
heap_stat.alloc_count);
|
||||
|
||||
for (size_t alloc_idx = 0; alloc_idx < heap_stat.alloc_count; alloc_idx++) {
|
||||
heap_task_block_t alloc_stat = heap_stat.alloc_stat[alloc_idx];
|
||||
printf(" %p: Size: %"PRIu32"\n", alloc_stat.address, alloc_stat.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* delete the memory dynamically allocated while calling heap_caps_alloc_all_task_stat_arrays */
|
||||
heap_caps_free_all_task_stat_arrays(&tasks_stat);
|
||||
}
|
||||
|
||||
static void no_leak_task(void *args)
|
||||
{
|
||||
size_t size_a = 0;
|
||||
size_t size_b = 0;
|
||||
char *task_name = pcTaskGetName(*((TaskHandle_t*)args));
|
||||
|
||||
while(1) {
|
||||
/* Allocate random amount of memory for demonstration */
|
||||
size_a = (esp_random() % 10000) + 1;
|
||||
size_b = (esp_random() % (10000 - size_a)) + 1;
|
||||
|
||||
void *ptr_a = heap_caps_malloc(size_a, MALLOC_CAP_DEFAULT);
|
||||
void *ptr_b = heap_caps_malloc(size_b, MALLOC_CAP_DEFAULT);
|
||||
if (ptr_a == NULL || ptr_b == NULL) {
|
||||
ESP_LOGE(task_name, "Could not allocate heap memory");
|
||||
abort();
|
||||
}
|
||||
|
||||
heap_caps_free(ptr_a);
|
||||
heap_caps_free(ptr_b);
|
||||
|
||||
// print the task statistics (passing NULL will print info for
|
||||
// the currently running task)
|
||||
print_single_task_info(NULL);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
static void leaking_task(void *args)
|
||||
{
|
||||
size_t size_a = 0;
|
||||
size_t size_b = 0;
|
||||
char *task_name = pcTaskGetName(*((TaskHandle_t*)args));
|
||||
|
||||
while(1) {
|
||||
/* Allocate random amount of memory for demonstration */
|
||||
size_a = (esp_random() % 10000) + 1;
|
||||
size_b = (esp_random() % (10000 - size_a)) + 1;
|
||||
|
||||
void *ptr_a = heap_caps_malloc(size_a, MALLOC_CAP_DEFAULT);
|
||||
void *ptr_b = heap_caps_malloc(size_b, MALLOC_CAP_DEFAULT);
|
||||
if (ptr_a == NULL || ptr_b == NULL) {
|
||||
ESP_LOGE(task_name, "Could not allocate heap memory");
|
||||
abort();
|
||||
}
|
||||
|
||||
heap_caps_free(ptr_a);
|
||||
|
||||
// don't free ptr_b on purpose to create unfreed memory for the task info to print
|
||||
// heap_caps_free(ptr_b);
|
||||
|
||||
// print the task statistics (passing NULL will print info for
|
||||
// the currently running task)
|
||||
print_single_task_info(NULL);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
TaskHandle_t no_leak_task_hdl, leaking_task_hdl;
|
||||
|
||||
/* Create example task to demonstrate heap_task_tracking */
|
||||
xTaskCreate(&no_leak_task, "no_leak_task", 3072, &no_leak_task_hdl, 0, &no_leak_task_hdl);
|
||||
xTaskCreate(&leaking_task, "leaking_task", 3072, &leaking_task_hdl, 0, &leaking_task_hdl);
|
||||
|
||||
size_t counter = 4;
|
||||
while(counter != 0) {
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
counter--;
|
||||
}
|
||||
|
||||
vTaskDelete(leaking_task_hdl);
|
||||
vTaskDelete(no_leak_task_hdl);
|
||||
|
||||
print_all_tasks_info();
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
# enable the task tracking feature
|
||||
CONFIG_HEAP_TASK_TRACKING=y
|
||||
|
||||
# keep task tracking information after the task is deleted
|
||||
CONFIG_HEAP_TRACK_DELETED_TASKS=y
|
@@ -5,4 +5,4 @@ cmake_minimum_required(VERSION 3.16)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
# "Trim" the build. Include the minimal set of components, main, and anything it depends on.
|
||||
idf_build_set_property(MINIMAL_BUILD ON)
|
||||
project(heap_task_tracking)
|
||||
project(basic)
|
156
examples/system/heap_task_tracking/basic/README.md
Normal file
156
examples/system/heap_task_tracking/basic/README.md
Normal file
@@ -0,0 +1,156 @@
|
||||
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C5 | ESP32-C6 | ESP32-C61 | ESP32-H2 | ESP32-H21 | ESP32-P4 | ESP32-S2 | ESP32-S3 |
|
||||
| ----------------- | ----- | -------- | -------- | -------- | -------- | --------- | -------- | --------- | -------- | -------- | -------- |
|
||||
|
||||
# Heap Task Tracking Basic Example
|
||||
|
||||
## Overview
|
||||
|
||||
The example creates a task which allocates random amount of memory and frees it and another task that allocates random amount of memory but never frees it.
|
||||
The main then goes into a loop printing the overview information of each task that allocated memory dynamically.
|
||||
The information include:
|
||||
- The task name
|
||||
- The task status
|
||||
- The current memory usage
|
||||
- The peak memory usage
|
||||
- The number of heaps currently used by the task
|
||||
|
||||
Because the heap task tracking feature requires additional metadata to be allocated for each memory allocations, the overall heap usage of the application is
|
||||
greater than when the feature is disabled. For this reason, it is highly recommended to use the task tracking for debugging purpose only.
|
||||
|
||||
### Configure the project
|
||||
|
||||
- Enable thee option `Enable heap task tracking` by opening the project configuration menu (`idf.py menuconfig`) and navigate to `Component config -> Heap memory debugging` menu.
|
||||
- (optional) Enable the option `Keep information about the memory usage on deleted tasks` if you wish to keep track of the information of a task after it has been deleted.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Run `idf.py -p PORT flash monitor` to build and flash the project..
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
Starting task: no_leak_task
|
||||
Starting task: leaking_task
|
||||
|
||||
PRINTING OVERVIEW STATISTICS OF EACH TASK
|
||||
┌────────────────────┬─────────┬──────────────────────┬───────────────────┬─────────────────┐
|
||||
│ TASK │ STATUS │ CURRENT MEMORY USAGE │ PEAK MEMORY USAGE │ TOTAL HEAP USED │
|
||||
├────────────────────┼─────────┼──────────────────────┼───────────────────┼─────────────────┤
|
||||
│ leaking_task │ ALIVE │ 6656 │ 8064 │ 1 │
|
||||
│ no_leak_task │ ALIVE │ 0 │ 7152 │ 1 │
|
||||
│ main │ ALIVE │ 7412 │ 7412 │ 2 │
|
||||
│ ipc1 │ ALIVE │ 32 │ 44 │ 1 │
|
||||
│ ipc0 │ ALIVE │ 10080 │ 10092 │ 1 │
|
||||
│ Pre-scheduler │ ALIVE │ 2236 │ 2236 │ 1 │
|
||||
└────────────────────┴─────────┴──────────────────────┴───────────────────┴─────────────────┘
|
||||
|
||||
PRINTING OVERVIEW STATISTICS OF NO LEAK TASK
|
||||
┌────────────────────┬─────────┬──────────────────────┬───────────────────┬─────────────────┐
|
||||
│ TASK │ STATUS │ CURRENT MEMORY USAGE │ PEAK MEMORY USAGE │ TOTAL HEAP USED │
|
||||
├────────────────────┼─────────┼──────────────────────┼───────────────────┼─────────────────┤
|
||||
│ no_leak_task │ ALIVE │ 0 │ 7152 │ 1 │
|
||||
└────────────────────┴─────────┴──────────────────────┴───────────────────┴─────────────────┘
|
||||
|
||||
PRINTING OVERVIEW STATISTICS OF LEAKING TASK
|
||||
┌────────────────────┬─────────┬──────────────────────┬───────────────────┬─────────────────┐
|
||||
│ TASK │ STATUS │ CURRENT MEMORY USAGE │ PEAK MEMORY USAGE │ TOTAL HEAP USED │
|
||||
├────────────────────┼─────────┼──────────────────────┼───────────────────┼─────────────────┤
|
||||
│ leaking_task │ ALIVE │ 6656 │ 8064 │ 1 │
|
||||
└────────────────────┴─────────┴──────────────────────┴───────────────────┴─────────────────┘
|
||||
|
||||
[...]
|
||||
Deleting task: leaking_task
|
||||
|
||||
PRINTING OVERVIEW STATISTICS OF EACH TASK
|
||||
┌────────────────────┬─────────┬──────────────────────┬───────────────────┬─────────────────┐
|
||||
│ TASK │ STATUS │ CURRENT MEMORY USAGE │ PEAK MEMORY USAGE │ TOTAL HEAP USED │
|
||||
├────────────────────┼─────────┼──────────────────────┼───────────────────┼─────────────────┤
|
||||
│ leaking_task │ DELETED │ 11392 │ 11616 │ 1 │
|
||||
│ no_leak_task │ ALIVE │ 0 │ 9408 │ 2 │
|
||||
│ main │ ALIVE │ 3860 │ 7412 │ 2 │
|
||||
│ ipc1 │ ALIVE │ 32 │ 44 │ 1 │
|
||||
│ ipc0 │ ALIVE │ 10080 │ 10092 │ 1 │
|
||||
│ Pre-scheduler │ ALIVE │ 2236 │ 2236 │ 1 │
|
||||
└────────────────────┴─────────┴──────────────────────┴───────────────────┴─────────────────┘
|
||||
|
||||
PRINTING OVERVIEW STATISTICS OF NO LEAK TASK
|
||||
┌────────────────────┬─────────┬──────────────────────┬───────────────────┬─────────────────┐
|
||||
│ TASK │ STATUS │ CURRENT MEMORY USAGE │ PEAK MEMORY USAGE │ TOTAL HEAP USED │
|
||||
├────────────────────┼─────────┼──────────────────────┼───────────────────┼─────────────────┤
|
||||
│ no_leak_task │ ALIVE │ 0 │ 9408 │ 2 │
|
||||
└────────────────────┴─────────┴──────────────────────┴───────────────────┴─────────────────┘
|
||||
|
||||
PRINTING OVERVIEW STATISTICS OF LEAKING TASK
|
||||
┌────────────────────┬─────────┬──────────────────────┬───────────────────┬─────────────────┐
|
||||
│ TASK │ STATUS │ CURRENT MEMORY USAGE │ PEAK MEMORY USAGE │ TOTAL HEAP USED │
|
||||
├────────────────────┼─────────┼──────────────────────┼───────────────────┼─────────────────┤
|
||||
│ leaking_task │ DELETED │ 11392 │ 11616 │ 1 │
|
||||
└────────────────────┴─────────┴──────────────────────┴───────────────────┴─────────────────┘
|
||||
Deleting task: no_leak_task
|
||||
|
||||
PRINTING OVERVIEW STATISTICS OF EACH TASK
|
||||
┌────────────────────┬─────────┬──────────────────────┬───────────────────┬─────────────────┐
|
||||
│ TASK │ STATUS │ CURRENT MEMORY USAGE │ PEAK MEMORY USAGE │ TOTAL HEAP USED │
|
||||
├────────────────────┼─────────┼──────────────────────┼───────────────────┼─────────────────┤
|
||||
│ leaking_task │ DELETED │ 11392 │ 11616 │ 1 │
|
||||
│ no_leak_task │ DELETED │ 0 │ 9408 │ 2 │
|
||||
│ main │ ALIVE │ 308 │ 7412 │ 2 │
|
||||
│ ipc1 │ ALIVE │ 32 │ 44 │ 1 │
|
||||
│ ipc0 │ ALIVE │ 10080 │ 10092 │ 1 │
|
||||
│ Pre-scheduler │ ALIVE │ 2236 │ 2236 │ 1 │
|
||||
└────────────────────┴─────────┴──────────────────────┴───────────────────┴─────────────────┘
|
||||
|
||||
PRINTING DETAILED STATISTICS OF EACH TASK
|
||||
├ DELETED: leaking_task, CURRENT MEMORY USAGE 11392, PEAK MEMORY USAGE 11616, TOTAL HEAP USED 1:
|
||||
│ └ HEAP: RAM, CAPS: 0x0010580e, SIZE: 22308, USAGE: CURRENT 11392 (51%), PEAK 11616 (52%), ALLOC COUNT: 3
|
||||
│ ├ ALLOC 0x3fcebbb8, SIZE 6656
|
||||
│ ├ ALLOC 0x3fced5bc, SIZE 3584
|
||||
│ ├ ALLOC 0x3fceb718, SIZE 1152
|
||||
├ DELETED: no_leak_task, CURRENT MEMORY USAGE 0, PEAK MEMORY USAGE 9408, TOTAL HEAP USED 2:
|
||||
│ ├ HEAP: RAM, CAPS: 0x0010580e, SIZE: 22308, USAGE: CURRENT 0 (0%), PEAK 7152 (32%), ALLOC COUNT: 0
|
||||
│ └ HEAP: RAM, CAPS: 0x0010580e, SIZE: 344400, USAGE: CURRENT 0 (0%), PEAK 9216 (2%), ALLOC COUNT: 0
|
||||
├ ALIVE: main, CURRENT MEMORY USAGE 308, PEAK MEMORY USAGE 7412, TOTAL HEAP USED 2:
|
||||
│ ├ HEAP: RAM, CAPS: 0x0010580e, SIZE: 344400, USAGE: CURRENT 220 (0%), PEAK 220 (0%), ALLOC COUNT: 2
|
||||
│ │ ├ ALLOC 0x3fc99024, SIZE 88
|
||||
│ │ ├ ALLOC 0x3fc99124, SIZE 132
|
||||
│ └ HEAP: RAM, CAPS: 0x0010580e, SIZE: 22308, USAGE: CURRENT 88 (0%), PEAK 7192 (32%), ALLOC COUNT: 5
|
||||
│ ├ ALLOC 0x3fce99f8, SIZE 20
|
||||
│ ├ ALLOC 0x3fce9a10, SIZE 12
|
||||
│ ├ ALLOC 0x3fce9a20, SIZE 16
|
||||
│ ├ ALLOC 0x3fce9a34, SIZE 20
|
||||
│ ├ ALLOC 0x3fce9a4c, SIZE 20
|
||||
├ ALIVE: ipc1, CURRENT MEMORY USAGE 32, PEAK MEMORY USAGE 44, TOTAL HEAP USED 1:
|
||||
│ └ HEAP: RAM, CAPS: 0x0010580e, SIZE: 344400, USAGE: CURRENT 32 (0%), PEAK 44 (0%), ALLOC COUNT: 2
|
||||
│ ├ ALLOC 0x3fc990fc, SIZE 16
|
||||
│ ├ ALLOC 0x3fc991c0, SIZE 16
|
||||
├ ALIVE: ipc0, CURRENT MEMORY USAGE 10080, PEAK MEMORY USAGE 10092, TOTAL HEAP USED 1:
|
||||
│ └ HEAP: RAM, CAPS: 0x0010580e, SIZE: 344400, USAGE: CURRENT 10080 (2%), PEAK 10092 (2%), ALLOC COUNT: 10
|
||||
│ ├ ALLOC 0x3fc966e0, SIZE 1312
|
||||
│ ├ ALLOC 0x3fc96c80, SIZE 344
|
||||
│ ├ ALLOC 0x3fc96e14, SIZE 16
|
||||
│ ├ ALLOC 0x3fc96e3c, SIZE 4224
|
||||
│ ├ ALLOC 0x3fc97ec0, SIZE 344
|
||||
│ ├ ALLOC 0x3fc98030, SIZE 1568
|
||||
│ ├ ALLOC 0x3fc98668, SIZE 344
|
||||
│ ├ ALLOC 0x3fc987d8, SIZE 1568
|
||||
│ ├ ALLOC 0x3fc98e10, SIZE 344
|
||||
│ ├ ALLOC 0x3fc98f94, SIZE 16
|
||||
└ ALIVE: Pre-scheduler, CURRENT MEMORY USAGE 2236, PEAK MEMORY USAGE 2236, TOTAL HEAP USED 1:
|
||||
└ HEAP: RAM, CAPS: 0x0010580e, SIZE: 344400, USAGE: CURRENT 2236 (0%), PEAK 2236 (0%), ALLOC COUNT: 11
|
||||
├ ALLOC 0x3fc95cb0, SIZE 164
|
||||
├ ALLOC 0x3fc95dd8, SIZE 12
|
||||
├ ALLOC 0x3fc95dfc, SIZE 12
|
||||
├ ALLOC 0x3fc95e20, SIZE 16
|
||||
├ ALLOC 0x3fc95e48, SIZE 24
|
||||
├ ALLOC 0x3fc95e78, SIZE 88
|
||||
├ ALLOC 0x3fc95ee8, SIZE 88
|
||||
├ ALLOC 0x3fc95f58, SIZE 88
|
||||
├ ALLOC 0x3fc95fc8, SIZE 88
|
||||
├ ALLOC 0x3fc96038, SIZE 1312
|
||||
├ ALLOC 0x3fc96570, SIZE 344
|
||||
I (5949) main_task: Returned from app_main()
|
||||
```
|
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Unlicense OR CC0-1.0
|
||||
*/
|
||||
/* Heap Task Tracking Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_heap_task_info.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_random.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static void no_leak_task(void *args)
|
||||
{
|
||||
size_t size_a = 0;
|
||||
size_t size_b = 0;
|
||||
char *task_name = pcTaskGetName(*((TaskHandle_t*)args));
|
||||
printf("Starting task: %s\n", task_name);
|
||||
|
||||
while(1) {
|
||||
/* Allocate random amount of memory for demonstration */
|
||||
size_a = (esp_random() % 10000) + 1;
|
||||
size_b = (esp_random() % (10000 - size_a)) + 1;
|
||||
|
||||
void *ptr_a = heap_caps_malloc(size_a, MALLOC_CAP_DEFAULT);
|
||||
void *ptr_b = heap_caps_malloc(size_b, MALLOC_CAP_DEFAULT);
|
||||
if (ptr_a == NULL || ptr_b == NULL) {
|
||||
ESP_LOGE(task_name, "Could not allocate heap memory");
|
||||
abort();
|
||||
}
|
||||
|
||||
heap_caps_free(ptr_a);
|
||||
heap_caps_free(ptr_b);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
static void leaking_task(void *args)
|
||||
{
|
||||
size_t size_a = 0;
|
||||
size_t size_b = 0;
|
||||
char *task_name = pcTaskGetName(*((TaskHandle_t*)args));
|
||||
printf("Starting task: %s\n", task_name);
|
||||
|
||||
while(1) {
|
||||
/* Allocate random amount of memory for demonstration */
|
||||
size_a = (esp_random() % 10000) + 1;
|
||||
size_b = (esp_random() % (10000 - size_a)) + 1;
|
||||
|
||||
void *ptr_a = heap_caps_malloc(size_a, MALLOC_CAP_DEFAULT);
|
||||
void *ptr_b = heap_caps_malloc(size_b, MALLOC_CAP_DEFAULT);
|
||||
if (ptr_a == NULL || ptr_b == NULL) {
|
||||
ESP_LOGE(task_name, "Could not allocate heap memory");
|
||||
abort();
|
||||
}
|
||||
|
||||
heap_caps_free(ptr_a);
|
||||
// heap_caps_free(ptr_b);
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
TaskHandle_t no_leak_task_hdl, leaking_task_hdl;
|
||||
|
||||
/* Create example task to demonstrate heap_task_tracking */
|
||||
xTaskCreate(&no_leak_task, "no_leak_task", 3072, &no_leak_task_hdl, 5, &no_leak_task_hdl);
|
||||
xTaskCreate(&leaking_task, "leaking_task", 3072, &leaking_task_hdl, 5, &leaking_task_hdl);
|
||||
|
||||
/* print task statistic periodically */
|
||||
for(size_t counter = 0; counter < 4; counter++) {
|
||||
/* print the overview stats of every task */
|
||||
printf("\n PRINTING OVERVIEW STATISTICS OF EACH TASK\n");
|
||||
heap_caps_print_all_task_stat_overview(stdout);
|
||||
|
||||
/* print the overview statistics of the no leak task */
|
||||
printf("\n PRINTING OVERVIEW STATISTICS OF NO LEAK TASK\n");
|
||||
heap_caps_print_single_task_stat_overview(stdout, no_leak_task_hdl);
|
||||
|
||||
/* print the overview statistics of the leaking task */
|
||||
printf("\n PRINTING OVERVIEW STATISTICS OF LEAKING TASK\n");
|
||||
heap_caps_print_single_task_stat_overview(stdout, leaking_task_hdl);
|
||||
|
||||
if (counter == 2) {
|
||||
/* delete the leaking task and let the no leak task run
|
||||
* for some more time */
|
||||
printf("Deleting task: %s\n", pcTaskGetName(leaking_task_hdl));
|
||||
vTaskDelete(leaking_task_hdl);
|
||||
}
|
||||
|
||||
/* wait for a second before running the loop again*/
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
/* Delete the no leak task */
|
||||
printf("Deleting task: %s\n", pcTaskGetName(no_leak_task_hdl));
|
||||
vTaskDelete(no_leak_task_hdl);
|
||||
|
||||
/* print overview information of every task */
|
||||
printf("\n PRINTING OVERVIEW STATISTICS OF EACH TASK\n");
|
||||
heap_caps_print_all_task_stat_overview(stdout);
|
||||
|
||||
/* print detailed statistics for every task */
|
||||
printf("\n PRINTING DETAILED STATISTICS OF EACH TASK\n");
|
||||
heap_caps_print_all_task_stat(stdout);
|
||||
}
|
@@ -0,0 +1,5 @@
|
||||
# enable the task tracking feature
|
||||
CONFIG_HEAP_TASK_TRACKING=y
|
||||
|
||||
# keep task tracking information after the task is deleted
|
||||
CONFIG_HEAP_TRACK_DELETED_TASKS=y
|
@@ -1,78 +0,0 @@
|
||||
/* Heap Task Tracking Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_heap_task_info.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_random.h"
|
||||
|
||||
|
||||
#define MAX_TASK_NUM 20 // Max number of per tasks info that it can store
|
||||
#define MAX_BLOCK_NUM 20 // Max number of per block info that it can store
|
||||
|
||||
static size_t s_prepopulated_num = 0;
|
||||
static heap_task_totals_t s_totals_arr[MAX_TASK_NUM];
|
||||
static heap_task_block_t s_block_arr[MAX_BLOCK_NUM];
|
||||
|
||||
static void esp_dump_per_task_heap_info(void)
|
||||
{
|
||||
heap_task_info_params_t heap_info = {0};
|
||||
heap_info.caps[0] = MALLOC_CAP_8BIT; // Gets heap with CAP_8BIT capabilities
|
||||
heap_info.mask[0] = MALLOC_CAP_8BIT;
|
||||
heap_info.caps[1] = MALLOC_CAP_32BIT; // Gets heap info with CAP_32BIT capabilities
|
||||
heap_info.mask[1] = MALLOC_CAP_32BIT;
|
||||
heap_info.tasks = NULL; // Passing NULL captures heap info for all tasks
|
||||
heap_info.num_tasks = 0;
|
||||
heap_info.totals = s_totals_arr; // Gets task wise allocation details
|
||||
heap_info.num_totals = &s_prepopulated_num;
|
||||
heap_info.max_totals = MAX_TASK_NUM; // Maximum length of "s_totals_arr"
|
||||
heap_info.blocks = s_block_arr; // Gets block wise allocation details. For each block, gets owner task, address and size
|
||||
heap_info.max_blocks = MAX_BLOCK_NUM; // Maximum length of "s_block_arr"
|
||||
|
||||
heap_caps_get_per_task_info(&heap_info);
|
||||
|
||||
for (int i = 0 ; i < *heap_info.num_totals; i++) {
|
||||
printf("Task: %s -> CAP_8BIT: %d CAP_32BIT: %d\n",
|
||||
heap_info.totals[i].task ? pcTaskGetName(heap_info.totals[i].task) : "Pre-Scheduler allocs" ,
|
||||
heap_info.totals[i].size[0], // Heap size with CAP_8BIT capabilities
|
||||
heap_info.totals[i].size[1]); // Heap size with CAP32_BIT capabilities
|
||||
}
|
||||
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
static void example_task(void *args)
|
||||
{
|
||||
uint32_t size = 0;
|
||||
const char *TAG = "example_task";
|
||||
while (1) {
|
||||
/*
|
||||
* Allocate random amount of memory for demonstration
|
||||
*/
|
||||
size = (esp_random() % 1000);
|
||||
void *ptr = malloc(size);
|
||||
if (ptr == NULL) {
|
||||
ESP_LOGE(TAG, "Could not allocate heap memory");
|
||||
abort();
|
||||
}
|
||||
esp_dump_per_task_heap_info();
|
||||
free(ptr);
|
||||
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/*
|
||||
* Create example task to demonstrate heap_task_tracking
|
||||
*/
|
||||
xTaskCreate(&example_task, "example_task", 3072, NULL, 5, NULL);
|
||||
}
|
@@ -1 +0,0 @@
|
||||
CONFIG_HEAP_TASK_TRACKING=y
|
Reference in New Issue
Block a user