vTaskGetRunTimeStats() 介绍

使用 ESP32/ESP8266 进行开发时,读者可通过 vTaskGetRunTimeStats() 来协助分析操作系统当前 task CPU 占用状态,以帮助优化 task 优先级,帮助定位 task watchdog 问题,帮助理解和学习操作系统原理相关知识。

读者若想深入了解 vTaskGetRunTimeStats(), 可参考 vTaskGetRunTimeStats() 英文原版介绍 相关文档。


vTaskGetRunTimeStats() 使用

注意:
使用 vTaskGetRunTimeStats() 前需使能:

  • make menuconfig -> Component config -> FreeRTOS -> Enable FreeRTOS trace facility
  • make menuconfig -> Component config -> FreeRTOS -> Enable FreeRTOS trace facility -> Enable FreeRTOS stats formatting functions
  • make menuconfig -> Component config -> FreeRTOS -> Enable FreeRTOS to collect run time stats

通过上面配置,等同于使能 FreeRTOSConfig.h 中如下三个宏:
configGENERATE_RUN_TIME_STATSconfigUSE_STATS_FORMATTING_FUNCTIONSconfigSUPPORT_DYNAMIC_ALLOCATION

参考代码

#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"

void esp_print_tasks(void)
{
    char *pbuffer = (char *)calloc(1, 2048);
    printf("--------------- heap:%u ---------------------\r\n", esp_get_free_heap_size());
    vTaskGetRunTimeStats(pbuffer);
    printf("%s", pbuffer);
    printf("----------------------------------------------\r\n");
    free(pbuffer);
}

void test_task(void *param)
{
    while(1) {
        esp_print_tasks();
        vTaskDelay(3000 / portTICK_RATE_MS);
    }
}

打印一次 task CPU 占用情况可调用:
esp_print_tasks();

循环打印 task CPU 占用情况可调用:
xTaskCreate(test_task, "test_task", 2048, NULL, 5, NULL);


vTaskGetRunTimeStats() 结果

读者可以去 task.c 中查看 vTaskGetRunTimeStats() 相关实现逻辑,或更有助于读者理解。

例如: 基于 ESP8266, release/v3.3, commit:4c38ff31, 在 app_main() 中调用 vTaskGetRunTimeStats() 结果如下:
在这里插入图片描述

  • 第一列: task name
    xTaskCreate 创建该 task 时第二个参数。
    如果名称过长,会根据 configMAX_TASK_NAME_LEN 截断。

  • 第二列: task 占用 CPU 时间值
    默认单位是微秒(us), 即从上电开始,该 task 得到调度执行的时间。
    该值通过硬件计数, 参考 #define WDEV_COUNT_REG (0x3ff20c00)

    由于采用四字节微秒计数,该值理论上会在约 1.19 小时后溢出。

  • 第三列: task 占用 CPU 百分比
    即第二列时间值除以上电总时间。

笔记一: task watchdog 定位和解决

通过参考代码,添加 task 占用 CPU 时间代码,分析结果,例如:
在这里插入图片描述
分析:
由于 test_task CPU 占用率较高,导致 IDLE task 无法得到运行,
从而无法喂狗,当超过配置的 watchdog 超时时间,即触发 task watchdog

解决办法:

  • 查看占用率较高的 task 代码逻辑,是否有 delay 代码,如果没有,建议加上 vTaskDelay() 来让该 task 休息片刻

  • 如果该 task 某个过程,期望时间很短(用户体验考虑),例如 TLS 握手中非对称加解密过程。
    那么读者可在该过程中:
    A: 考虑添加 esp_task_wdt_reset() 手动喂狗。

    B: 考虑提高 CPU 默认频率来加速此过程。
    参考代码:

     #include "platform/ssl_port.h"
     ssl_speed_up_enter();  // speed up to 160MHz
     // user code to speed up
     ssl_speed_up_exit();  // back to 80MHz, it is necessary for system stability
    

笔记二:调优 task 优先级

通常建议客户创建的 task 优先级在 1-9 之间。

参考通过上文的 taskCPU 占用率,适当修改 task 优先级以符合预期。

例如一:
MQTT task 优先级可以适当高于 OTA task 优先级。

这是由于 OTA task 通常有长时间的擦写 flash 过程,如果 OTA task 优先级过高,将可能导致 MQTT task 长时间得不到运行,触发 MQTT PING 超时,或者触发和服务器链接中断。如果优先级设置合理,则 MQTT 链接不会断开,同时可以完成 OTA 过程。

例如二:
需长时间占用 CPU 的 task 优先级可以适当降低

如果长时间占用 CPU, 可能导致系统内部 ppT task 处理 WiFi 包不及时,造成 bcn timeout 而断开 WiFi 链接等情况。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐