|
| 1 | +#include "task_monitor.h" |
| 2 | + |
| 3 | +#include <stdio.h> |
| 4 | + |
| 5 | +#include "freertos/FreeRTOS.h" |
| 6 | +#include "freertos/task.h" |
| 7 | + |
| 8 | +#include "esp_err.h" |
| 9 | +#include "esp_heap_caps.h" |
| 10 | +#include "esp_system.h" |
| 11 | +#include "esp_timer.h" |
| 12 | +#include "sdkconfig.h" |
| 13 | + |
| 14 | +#if !defined(CONFIG_FREERTOS_USE_TRACE_FACILITY) || !defined(CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS) |
| 15 | + #error "USE_TRACE_FACILITY and GENERATE_RUN_TIME_STATS must be defined!" |
| 16 | +#endif |
| 17 | + |
| 18 | +#define COLOR_BLACK "30" |
| 19 | +#define COLOR_RED "31" |
| 20 | +#define COLOR_GREEN "32" |
| 21 | +#define COLOR_YELLOW "33" |
| 22 | +#define COLOR_BLUE "34" |
| 23 | +#define COLOR_PURPLE "35" |
| 24 | +#define COLOR_CYAN "36" |
| 25 | +#define COLOR_WHITE "37" |
| 26 | + |
| 27 | +#define COLOR(COLOR) "\033[0;" COLOR "m" |
| 28 | +#define RESET_COLOR "\033[0m" |
| 29 | +#define UNDERLINE "\033[4m" // TODO: FIX. Does not work! |
| 30 | +#define BOLD "\033[1m" // TODO: FIX. Does not work! |
| 31 | + |
| 32 | +#define BLACK COLOR(COLOR_BLACK) |
| 33 | +#define RED COLOR(COLOR_RED) |
| 34 | +#define GREEN COLOR(COLOR_GREEN) |
| 35 | +#define YELLOW COLOR(COLOR_YELLOW) |
| 36 | +#define BLUE COLOR(COLOR_BLUE) |
| 37 | +#define PURPLE COLOR(COLOR_PURPLE) |
| 38 | +#define CYAN COLOR(COLOR_CYAN) |
| 39 | +#define WHITE COLOR(COLOR_WHITE) |
| 40 | + |
| 41 | +static uint32_t get_current_time_ms(void) |
| 42 | +{ |
| 43 | + return xTaskGetTickCount() * 1000 / configTICK_RATE_HZ; |
| 44 | +} |
| 45 | + |
| 46 | + |
| 47 | +static float get_current_heap_free_percent(void) |
| 48 | +{ |
| 49 | + size_t current_size = heap_caps_get_free_size(MALLOC_CAP_DEFAULT); |
| 50 | + size_t total_size = heap_caps_get_total_size(MALLOC_CAP_DEFAULT); |
| 51 | + return ((float) current_size / total_size) * 100.0; |
| 52 | +} |
| 53 | + |
| 54 | +static float get_minimum_heap_free_percent(void) |
| 55 | +{ |
| 56 | + size_t minimum_size = heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT); |
| 57 | + size_t total_size = heap_caps_get_total_size(MALLOC_CAP_DEFAULT); |
| 58 | + return ((float) minimum_size / total_size) * 100.0; |
| 59 | +} |
| 60 | + |
| 61 | +static const char* int_to_string(int number, char *string) |
| 62 | +{ |
| 63 | + sprintf(string, "%d", number); |
| 64 | + return string; |
| 65 | +} |
| 66 | + |
| 67 | +static const char* task_state_to_string(eTaskState state) { |
| 68 | + switch (state) { |
| 69 | + case eRunning: |
| 70 | + return "Running"; |
| 71 | + case eReady: |
| 72 | + return "Ready"; |
| 73 | + case eBlocked: |
| 74 | + return "Blocked"; |
| 75 | + case eSuspended: |
| 76 | + return "Suspended"; |
| 77 | + case eDeleted: |
| 78 | + return "Deleted"; |
| 79 | + case eInvalid: |
| 80 | + return "Invalid"; |
| 81 | + default: |
| 82 | + return "Unknown state"; |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +static void sort_tasks_by_runtime(TaskStatus_t *tasks_status_array, size_t number_of_tasks) |
| 87 | +{ |
| 88 | + for (size_t i = 0; i < number_of_tasks - 1; ++i) { |
| 89 | + for (size_t k = i + 1; k < number_of_tasks; ++k) { |
| 90 | + if (tasks_status_array[k].ulRunTimeCounter > tasks_status_array[i].ulRunTimeCounter) { |
| 91 | + TaskStatus_t temp = tasks_status_array[i]; |
| 92 | + tasks_status_array[i] = tasks_status_array[k]; |
| 93 | + tasks_status_array[k] = temp; |
| 94 | + } |
| 95 | + } |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +static void task_status_monitor_task(void *params) |
| 100 | +{ |
| 101 | + while (true) { |
| 102 | + UBaseType_t number_of_tasks = uxTaskGetNumberOfTasks(); |
| 103 | + TaskStatus_t *p_tasks_status_array = pvPortMalloc(number_of_tasks * sizeof(TaskStatus_t)); |
| 104 | + |
| 105 | + if (p_tasks_status_array != NULL) { |
| 106 | + uint32_t total_run_time; |
| 107 | + number_of_tasks = uxTaskGetSystemState(p_tasks_status_array, number_of_tasks, &total_run_time); |
| 108 | + |
| 109 | + if (total_run_time > 0) { // Avoid divide by zero error |
| 110 | + sort_tasks_by_runtime(p_tasks_status_array, number_of_tasks); |
| 111 | + |
| 112 | + printf("I (%lu) tm: " CYAN "%-18.16s %-11.10s %-7.6s %-8.7s %-11.10s %-12.10s %-15.15s %-s" |
| 113 | + RESET_COLOR, |
| 114 | + get_current_time_ms(), |
| 115 | + "TASK NAME:", |
| 116 | + "STATE:", |
| 117 | + "CORE:", |
| 118 | + "NUMBER:", |
| 119 | + "PRIORITY:", |
| 120 | + "STACK_MIN:", |
| 121 | + "RUNTIME, µs:", |
| 122 | + "RUNTIME, %:\n" |
| 123 | + ); |
| 124 | + |
| 125 | + for (size_t i = 0; i < number_of_tasks; ++i) { |
| 126 | + char string[10]; // 10 - maximum number of characters for int |
| 127 | + printf("I (%lu) tm: " YELLOW "%-18.16s %-11.10s %-7.6s %-8d %-11d %-12lu %-14lu %-10.3f\n" |
| 128 | + RESET_COLOR, |
| 129 | + get_current_time_ms(), |
| 130 | + p_tasks_status_array[i].pcTaskName, |
| 131 | + task_state_to_string(p_tasks_status_array[i].eCurrentState), |
| 132 | + |
| 133 | + xTaskGetAffinity(p_tasks_status_array[i].xHandle) == tskNO_AFFINITY ? |
| 134 | + "Any" : int_to_string((int)xTaskGetAffinity(p_tasks_status_array[i].xHandle), string), |
| 135 | + |
| 136 | + p_tasks_status_array[i].xTaskNumber, |
| 137 | + p_tasks_status_array[i].uxCurrentPriority, |
| 138 | + p_tasks_status_array[i].usStackHighWaterMark, |
| 139 | + p_tasks_status_array[i].ulRunTimeCounter, |
| 140 | + (p_tasks_status_array[i].ulRunTimeCounter * 100.0) / total_run_time); |
| 141 | + } |
| 142 | + |
| 143 | + printf("I (%lu) tm: " YELLOW "Total heap free size: " GREEN "%d" YELLOW " bytes\n" RESET_COLOR, |
| 144 | + get_current_time_ms(), heap_caps_get_total_size(MALLOC_CAP_DEFAULT)); |
| 145 | + |
| 146 | + printf("I (%lu) tm: " YELLOW "Current heap free size: " GREEN "%d" YELLOW " bytes (" GREEN "%.2f" |
| 147 | + YELLOW " %%)\n" RESET_COLOR, get_current_time_ms(), heap_caps_get_free_size(MALLOC_CAP_DEFAULT), |
| 148 | + get_current_heap_free_percent()); |
| 149 | + |
| 150 | + printf("I (%lu) tm: " YELLOW "Minimum heap free size: " GREEN "%d" YELLOW " bytes (" GREEN "%.2f" |
| 151 | + YELLOW " %%)\n" RESET_COLOR, get_current_time_ms(), |
| 152 | + heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT), get_minimum_heap_free_percent()); |
| 153 | + |
| 154 | + printf("I (%lu) tm: " YELLOW "Total RunTime: " GREEN "%lu" YELLOW " µs (" GREEN "%lu" YELLOW |
| 155 | + " seconds)\n" RESET_COLOR, get_current_time_ms(), total_run_time, total_run_time / 1000000); |
| 156 | + |
| 157 | + uint64_t current_time = esp_timer_get_time(); |
| 158 | + printf("I (%lu) tm: " YELLOW "System UpTime: " GREEN "%llu" YELLOW " µs (" GREEN "%llu" YELLOW |
| 159 | + " seconds)\n\n" RESET_COLOR, get_current_time_ms(), current_time, current_time / 1000000); |
| 160 | + } |
| 161 | + vPortFree(p_tasks_status_array); |
| 162 | + } else { |
| 163 | + printf("I (%lu) tm: " RED "Could not allocate required memory\n" RESET_COLOR, get_current_time_ms()); |
| 164 | + } |
| 165 | + vTaskDelay(pdMS_TO_TICKS(30 * 1000)); |
| 166 | + } |
| 167 | +} |
| 168 | + |
| 169 | +esp_err_t task_monitor(void) |
| 170 | +{ |
| 171 | + BaseType_t status = xTaskCreatePinnedToCore(task_status_monitor_task, "monitor_task", configMINIMAL_STACK_SIZE * 4, |
| 172 | + NULL, tskIDLE_PRIORITY + 1, NULL, tskNO_AFFINITY); |
| 173 | + if (status != pdPASS) { |
| 174 | + printf("I (%lu) tm: task_status_monitor_task(): Task was not created. Could not allocate required memory\n", |
| 175 | + get_current_time_ms()); |
| 176 | + return ESP_ERR_NO_MEM; |
| 177 | + } |
| 178 | + printf("I (%lu) tm: task_status_monitor_task() started successfully\n", get_current_time_ms()); |
| 179 | + return ESP_OK; |
| 180 | +} |
0 commit comments