1 /*
2  * SPDX-FileCopyrightText: 2018-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <freertos/FreeRTOS.h>
8 #include <freertos/task.h>
9 #include <multi_heap.h>
10 #include "multi_heap_internal.h"
11 #include "heap_private.h"
12 #include "esp_heap_task_info.h"
13 
14 #ifdef CONFIG_HEAP_TASK_TRACKING
15 
16 /*
17  * Return per-task heap allocation totals and lists of blocks.
18  *
19  * For each task that has allocated memory from the heap, return totals for
20  * allocations within regions matching one or more sets of capabilities.
21  *
22  * Optionally also return an array of structs providing details about each
23  * block allocated by one or more requested tasks, or by all tasks.
24  *
25  * Returns the number of block detail structs returned.
26  */
heap_caps_get_per_task_info(heap_task_info_params_t * params)27 size_t heap_caps_get_per_task_info(heap_task_info_params_t *params)
28 {
29     heap_t *reg;
30     heap_task_block_t *blocks = params->blocks;
31     size_t count = *params->num_totals;
32     size_t remaining = params->max_blocks;
33 
34     // Clear out totals for any prepopulated tasks.
35     if (params->totals) {
36         for (size_t i = 0; i < count; ++i) {
37             for (size_t type = 0; type < NUM_HEAP_TASK_CAPS; ++type) {
38                 params->totals[i].size[type] = 0;
39                 params->totals[i].count[type] = 0;
40             }
41         }
42     }
43 
44     SLIST_FOREACH(reg, &registered_heaps, next) {
45         multi_heap_handle_t heap = reg->heap;
46         if (heap == NULL) {
47             continue;
48         }
49 
50         // Find if the capabilities of this heap region match on of the desired
51         // sets of capabilities.
52         uint32_t caps = get_all_caps(reg);
53         uint32_t type;
54         for (type = 0; type < NUM_HEAP_TASK_CAPS; ++type) {
55             if ((caps & params->mask[type]) == params->caps[type]) {
56                 break;
57             }
58         }
59         if (type == NUM_HEAP_TASK_CAPS) {
60             continue;
61         }
62 
63         multi_heap_block_handle_t b = multi_heap_get_first_block(heap);
64         multi_heap_internal_lock(heap);
65         for ( ; b ; b = multi_heap_get_next_block(heap, b)) {
66             if (multi_heap_is_free(b)) {
67                 continue;
68             }
69             void *p = multi_heap_get_block_address(b);  // Safe, only arithmetic
70             size_t bsize = multi_heap_get_allocated_size(heap, p); // Validates
71             TaskHandle_t btask = (TaskHandle_t)multi_heap_get_block_owner(b);
72 
73             // Accumulate per-task allocation totals.
74             if (params->totals) {
75                 size_t i;
76                 for (i = 0; i < count; ++i) {
77                     if (params->totals[i].task == btask) {
78                         break;
79                     }
80                 }
81                 if (i < count) {
82                     params->totals[i].size[type] += bsize;
83                     params->totals[i].count[type] += 1;
84                 }
85                 else {
86                     if (count < params->max_totals) {
87                         params->totals[count].task = btask;
88                         params->totals[count].size[type] = bsize;
89                         params->totals[i].count[type] = 1;
90                         ++count;
91                     }
92                 }
93             }
94 
95             // Return details about allocated blocks for selected tasks.
96             if (blocks && remaining > 0) {
97                 if (params->tasks) {
98                     size_t i;
99                     for (i = 0; i < params->num_tasks; ++i) {
100                         if (btask == params->tasks[i]) {
101                             break;
102                         }
103                     }
104                     if (i == params->num_tasks) {
105                         continue;
106                     }
107                 }
108                 blocks->task = btask;
109                 blocks->address = p;
110                 blocks->size = bsize;
111                 ++blocks;
112                 --remaining;
113             }
114         }
115         multi_heap_internal_unlock(heap);
116     }
117     *params->num_totals = count;
118     return params->max_blocks - remaining;
119 }
120 
121 #endif // CONFIG_HEAP_TASK_TRACKING
122