FreeRTOS 接口: vTaskGetRunTimeStats() - 可解決 task watchdog 和調優 task 優先級

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 鏈接等情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章