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