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_STATS
,configUSE_STATS_FORMATTING_FUNCTIONS
和configSUPPORT_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 之間。
參考通過上文的 task
的 CPU
佔用率,適當修改 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 鏈接等情況。