FreeRTOS 接口: vTaskList() - 可优化内存和 task 栈溢出定位

vTaskList() 介绍

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

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


vTaskList() 使用

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

  • make menuconfig -> Component config -> FreeRTOS -> Enable FreeRTOS trace facility
  • make menuconfig -> Component config -> FreeRTOS -> Enable FreeRTOS trace facility -> Enable FreeRTOS stats formatting functions

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

参考代码

#include 
#include 
#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());
    vTaskList(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 情况可调用:
esp_print_tasks();

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


vTaskList() 结果和高能预警

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

例如: 基于 ESP8266, release/v3.3, commit:4c38ff31, 在 app_main() 中调用 vTaskList() 结果如下:
FreeRTOS 接口: vTaskList() - 可优化内存和 task 栈溢出定位_第1张图片

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

  • 第二列: task 当前状态

    • X: running
    • B: blocked
    • R: ready
    • D: deleted
    • S: suspended
  • 第三列: task 优先级
    xTaskCreate 创建该 task 时第四个参数。
    数字越大,优先级越高,建议客户设置 task 优先级在 1-9 之间,慎行!

  • 第四列: 最小剩余 task 栈空间,字节为单位
    xTaskCreate 创建 task 时,给定的第三个参数值代表该 task 调度和运行过程中,最大可用 task 栈空间,以字节为单位(读者可以修改 portSTACK_TYPE 宏来决定是否以字节还是4字节为单位);
    Task 如果 API 调用比较深,则使用的栈空间越大,也就意味着最小剩余 task 栈空间越小。

    高能预警,做好笔记,熟读三遍:
    A: 当某个 task 最小剩余 task 栈空间比较大时,适当减小 xTaskCreate 创建该 task 时给定的第三个参数值,可节约 DRAM,以优化系统内存

    B: 当某个 task 最小剩余 task 栈空间比较小时,适当增大 xTaskCreate 创建该 task 时给定的第三个参数值,可降低 task 栈溢出风险

    C: 如果对 SDK 没有深入了解,不要修改 系统 task 优先级和分配的最大可用栈空间。

    D: 不要在系统 task 的 callback 函数里,添加过多代码,不要添加阻塞操作
    因为系统 task 通常都是经过优化配置的,如果代码深度较大,容易造成 task 栈溢出;
    如果有阻塞操作,将导致该系统 task 接下来逻辑无法执行,甚至有死锁的可能。
    例如:
    sniffer 的 callback 函数: wifi_promiscuous_cb_t cb
    WiFi callback 函数: system_event_cb_t cb

    E: 减少应用代码 task 的个数,以优化内存。
    例如:
    多个 socket 数据流,可以通过 select() 放在同一个 task 里处理;
    而不是一个 socket 数据流,一个 task;
    更不要一个 socket 数据流,居然三个 task (接收 task, 发送 task, 处理 task), it is amazing!

    F: 占用空间较大的变量,尽可能通过 malloc/calloc 等动态申请释放,以提高栈空间利用率。

  • 第五列: task 创建顺序

你可能感兴趣的:(操作系统(FreeRTOS),vTaskList,freertos,esp8266,esp32,内存)