/****************************************************************************** * 作者:kerwincui * 时间:2021-06-08 * 邮箱:164770707@qq.com * 源码地址:https://gitee.com/kerwincui/wumei-smart * author: kerwincui * create: 2021-06-08 * email:164770707@qq.com * source:https://github.com/kerwincui/wumei-smart ******************************************************************************/ #include "statistic_free_rtos.h" 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 函数打印给定时间内任务的CPU使用情况 * * * @param xTicksToWait 统计测量周期 * * @return * - ESP_OK 成功 * - ESP_ERR_NO_MEM 内存不足,无法分配内部数组 * - ESP_ERR_INVALID_SIZE uxTaskGetSystemState的数组大小不足,尝试增加ARRAY_SIZE_OFFSET * - ESP_ERR_INVALID_STATE 延迟时间太短 */ 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; uint32_t start_run_time, end_run_time; esp_err_t ret; //分配数组存储当前的任务状态 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; } //获取当前任务状态 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); //分配数组以存储延迟后的任务状态 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; } //获取延迟后任务状态 end_array_size = uxTaskGetSystemState(end_array, end_array_size, &end_run_time); if (end_array_size == 0) { ret = ESP_ERR_INVALID_SIZE; goto exit; } //以运行时统计时钟周期为单位,计算合计已用时间 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"); //将开始数组和结束数组的每一个任务进行匹配 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; //通过覆盖他们的句柄来标记已匹配的任务 start_array[i].xHandle = NULL; end_array[j].xHandle = NULL; break; } } //检查是否找到匹配的任务 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 * portNUM_PROCESSORS); printf("| %s | %d | %d%%\n", start_array[i].pcTaskName, task_elapsed_time, percentage_time); } } //打印不匹配的任务 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: //公共返回路径 free(start_array); free(end_array); return ret; } static void spin_task(void *arg) { xSemaphoreTake(sync_spin_task, portMAX_DELAY); while (1) { //消耗CPU周期 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); //开始所有旋转任务 for (int i = 0; i < NUM_OF_SPIN_TASKS; i++) { xSemaphoreGive(sync_spin_task); } //定期打印实时统计信息 while (1) { printf("\n\nGetting real time stats over %d 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 free_rtos_start(void) { //允许其他核心完成初始化 vTaskDelay(pdMS_TO_TICKS(100)); //创建信号量以进行同步 sync_spin_task = xSemaphoreCreateCounting(NUM_OF_SPIN_TASKS, 0); sync_stats_task = xSemaphoreCreateBinary(); //创建旋转任务 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); } //创建并启动统计任务 xTaskCreatePinnedToCore(stats_task, "stats", 4096, NULL, STATS_TASK_PRIO, NULL, tskNO_AFFINITY); xSemaphoreGive(sync_stats_task); }