Select one of the symbols to view example projects that use it.
 
Outline
#include "sdkconfig.h"
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_err.h"
#define NUM_OF_SPIN_TASKS
#define SPIN_ITER
#define SPIN_TASK_PRIO
#define STATS_TASK_PRIO
#define STATS_TICKS
#define ARRAY_SIZE_OFFSET
task_names
sync_spin_task
sync_stats_task
print_real_time_stats(TickType_t)
spin_task(void *)
stats_task(void *)
app_main()
Files
loading...
SourceVuESP-IDF Framework and Examplesreal_time_stats samplemain/real_time_stats_example_main.c
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
/* FreeRTOS Real Time Stats 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 "sdkconfig.h" #include <stdio.h> #include <stdlib.h> #include <inttypes.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" #include "esp_err.h"8 includes #define NUM_OF_SPIN_TASKS 6 #define SPIN_ITER 500000 //Actual CPU cycles used will depend on compiler optimization #define SPIN_TASK_PRIO 2 #define STATS_TASK_PRIO 3 #define STATS_TICKS pdMS_TO_TICKS(1000) #define ARRAY_SIZE_OFFSET 5 //Increase this if print_real_time_stats returns ESP_ERR_INVALID_SIZE6 defines static char task_names[NUM_OF_SPIN_TASKS][configMAX_TASK_NAME_LEN]; static SemaphoreHandle_t sync_spin_task; static SemaphoreHandle_t sync_stats_task; /** * @brief Function to print the CPU usage of tasks over a given duration. * * This function will measure and print the CPU usage of tasks over a specified * number of ticks (i.e. real time stats). This is implemented by simply calling * uxTaskGetSystemState() twice separated by a delay, then calculating the * differences of task run times before and after the delay. * * @note If any tasks are added or removed during the delay, the stats of * those tasks will not be printed. * @note This function should be called from a high priority task to minimize * inaccuracies with delays. * @note When running in dual core mode, each core will correspond to 50% of * the run time. * * @param xTicksToWait Period of stats measurement * * @return * - ESP_OK Success * - ESP_ERR_NO_MEM Insufficient memory to allocated internal arrays * - ESP_ERR_INVALID_SIZE Insufficient array size for uxTaskGetSystemState. Trying increasing ARRAY_SIZE_OFFSET * - ESP_ERR_INVALID_STATE Delay duration too short *//* ... */ static esp_err_t print_real_time_stats(TickType_t xTicksToWait) { TaskStatus_t *start_array = NULL, *end_array = NULL; UBaseType_t start_array_size, end_array_size; configRUN_TIME_COUNTER_TYPE start_run_time, end_run_time; esp_err_t ret; //Allocate array to store current task states start_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET; start_array = malloc(sizeof(TaskStatus_t) * start_array_size); if (start_array == NULL) { ret = ESP_ERR_NO_MEM; goto exit; }{...} //Get current task states start_array_size = uxTaskGetSystemState(start_array, start_array_size, &start_run_time); if (start_array_size == 0) { ret = ESP_ERR_INVALID_SIZE; goto exit; }{...} vTaskDelay(xTicksToWait); //Allocate array to store tasks states post delay end_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET; end_array = malloc(sizeof(TaskStatus_t) * end_array_size); if (end_array == NULL) { ret = ESP_ERR_NO_MEM; goto exit; }{...} //Get post delay task states end_array_size = uxTaskGetSystemState(end_array, end_array_size, &end_run_time); if (end_array_size == 0) { ret = ESP_ERR_INVALID_SIZE; goto exit; }{...} //Calculate total_elapsed_time in units of run time stats clock period. uint32_t total_elapsed_time = (end_run_time - start_run_time); if (total_elapsed_time == 0) { ret = ESP_ERR_INVALID_STATE; goto exit; }{...} printf("| Task | Run Time | Percentage\n"); //Match each task in start_array to those in the end_array for (int i = 0; i < start_array_size; i++) { int k = -1; for (int j = 0; j < end_array_size; j++) { if (start_array[i].xHandle == end_array[j].xHandle) { k = j; //Mark that task have been matched by overwriting their handles start_array[i].xHandle = NULL; end_array[j].xHandle = NULL; break; }{...} }{...} //Check if matching task found if (k >= 0) { uint32_t task_elapsed_time = end_array[k].ulRunTimeCounter - start_array[i].ulRunTimeCounter; uint32_t percentage_time = (task_elapsed_time * 100UL) / (total_elapsed_time * CONFIG_FREERTOS_NUMBER_OF_CORES); printf("| %s | %"PRIu32" | %"PRIu32"%%\n", start_array[i].pcTaskName, task_elapsed_time, percentage_time); }{...} }{...} //Print unmatched tasks for (int i = 0; i < start_array_size; i++) { if (start_array[i].xHandle != NULL) { printf("| %s | Deleted\n", start_array[i].pcTaskName); }{...} }{...} for (int i = 0; i < end_array_size; i++) { if (end_array[i].xHandle != NULL) { printf("| %s | Created\n", end_array[i].pcTaskName); }{...} }{...} ret = ESP_OK; exit: //Common return path free(start_array); free(end_array); return ret; }{ ... } static void spin_task(void *arg) { xSemaphoreTake(sync_spin_task, portMAX_DELAY); while (1) { //Consume CPU cycles for (int i = 0; i < SPIN_ITER; i++) { __asm__ __volatile__("NOP"); }{...} vTaskDelay(pdMS_TO_TICKS(100)); }{...} }{ ... } static void stats_task(void *arg) { xSemaphoreTake(sync_stats_task, portMAX_DELAY); //Start all the spin tasks for (int i = 0; i < NUM_OF_SPIN_TASKS; i++) { xSemaphoreGive(sync_spin_task); }{...} //Print real time stats periodically while (1) { printf("\n\nGetting real time stats over %"PRIu32" ticks\n", STATS_TICKS); if (print_real_time_stats(STATS_TICKS) == ESP_OK) { printf("Real time stats obtained\n"); }{...} else { printf("Error getting real time stats\n"); }{...} vTaskDelay(pdMS_TO_TICKS(1000)); }{...} }{ ... } void app_main(void) { //Allow other core to finish initialization vTaskDelay(pdMS_TO_TICKS(100)); //Create semaphores to synchronize sync_spin_task = xSemaphoreCreateCounting(NUM_OF_SPIN_TASKS, 0); sync_stats_task = xSemaphoreCreateBinary(); //Create spin tasks for (int i = 0; i < NUM_OF_SPIN_TASKS; i++) { snprintf(task_names[i], configMAX_TASK_NAME_LEN, "spin%d", i); xTaskCreatePinnedToCore(spin_task, task_names[i], 1024, NULL, SPIN_TASK_PRIO, NULL, tskNO_AFFINITY); }{...} //Create and start stats task xTaskCreatePinnedToCore(stats_task, "stats", 4096, NULL, STATS_TASK_PRIO, NULL, tskNO_AFFINITY); xSemaphoreGive(sync_stats_task); }{ ... }
Details