diff --git a/CMakeLists.txt b/CMakeLists.txt index 9964d85abd0..591b0b31568 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,6 +49,7 @@ set(CORE_SRCS cores/esp32/esp32-hal-uart.c cores/esp32/esp32-hal-rmt.c cores/esp32/Esp.cpp + cores/esp32/freertos_stats.cpp cores/esp32/FunctionalInterrupt.cpp cores/esp32/HardwareSerial.cpp cores/esp32/HEXBuilder.cpp diff --git a/cores/esp32/Arduino.h b/cores/esp32/Arduino.h index 2b115505cff..ab7e497dcf6 100644 --- a/cores/esp32/Arduino.h +++ b/cores/esp32/Arduino.h @@ -199,6 +199,7 @@ void shiftOut(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, uint8_t val); #include "Udp.h" #include "HardwareSerial.h" #include "Esp.h" +#include "freertos_stats.h" // Use float-compatible stl abs() and round(), we don't use Arduino macros to avoid issues with the C++ libraries using std::abs; diff --git a/cores/esp32/freertos_stats.cpp b/cores/esp32/freertos_stats.cpp new file mode 100644 index 00000000000..50a98bf502b --- /dev/null +++ b/cores/esp32/freertos_stats.cpp @@ -0,0 +1,111 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "freertos_stats.h" +#include "sdkconfig.h" + +#if CONFIG_FREERTOS_USE_TRACE_FACILITY +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/portable.h" +#endif /* CONFIG_FREERTOS_USE_TRACE_FACILITY */ + +void printRunningTasks(Print &printer) { +#if CONFIG_FREERTOS_USE_TRACE_FACILITY +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS +#define FREERTOS_TASK_NUMBER_MAX_NUM 256 // RunTime stats for how many Tasks to be stored + static configRUN_TIME_COUNTER_TYPE ulRunTimeCounters[FREERTOS_TASK_NUMBER_MAX_NUM]; + static configRUN_TIME_COUNTER_TYPE ulLastRunTime = 0; + configRUN_TIME_COUNTER_TYPE ulCurrentRunTime = 0, ulTaskRunTime = 0; +#endif + configRUN_TIME_COUNTER_TYPE ulTotalRunTime = 0; + TaskStatus_t *pxTaskStatusArray = NULL; + volatile UBaseType_t uxArraySize = 0, x = 0; + const char *taskStates[] = {"Running", "Ready", "Blocked", "Suspended", "Deleted", "Invalid"}; + + // Take a snapshot of the number of tasks in case it changes while this function is executing. + uxArraySize = uxTaskGetNumberOfTasks(); + + // Allocate a TaskStatus_t structure for each task. + pxTaskStatusArray = (TaskStatus_t *)pvPortMalloc(uxArraySize * sizeof(TaskStatus_t)); + + if (pxTaskStatusArray != NULL) { + // Generate raw status information about each task. + uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &ulTotalRunTime); + +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + ulCurrentRunTime = ulTotalRunTime - ulLastRunTime; + ulLastRunTime = ulTotalRunTime; +#endif + printer.printf( + "Tasks: %u" +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + ", Runtime: %lus, Period: %luus" +#endif + "\n", + uxArraySize +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + , + ulTotalRunTime / 1000000, ulCurrentRunTime +#endif + ); + printer.printf("Num\t Name" +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + "\tLoad" +#endif + "\tPrio\t Free" +#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID + "\tCore" +#endif + "\tState\r\n"); + for (x = 0; x < uxArraySize; x++) { +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + if (pxTaskStatusArray[x].xTaskNumber < FREERTOS_TASK_NUMBER_MAX_NUM) { + ulTaskRunTime = (pxTaskStatusArray[x].ulRunTimeCounter - ulRunTimeCounters[pxTaskStatusArray[x].xTaskNumber]); + ulRunTimeCounters[pxTaskStatusArray[x].xTaskNumber] = pxTaskStatusArray[x].ulRunTimeCounter; + ulTaskRunTime = (ulTaskRunTime * 100) / ulCurrentRunTime; // in percentage + } else { + ulTaskRunTime = 0; + } +#endif + printer.printf( + "%3u\t%16s" +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + "\t%3lu%%" +#endif + "\t%4u\t%5lu" +#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID + "\t%4c" +#endif + "\t%s\r\n", + pxTaskStatusArray[x].xTaskNumber, pxTaskStatusArray[x].pcTaskName, +#if CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS + ulTaskRunTime, +#endif + pxTaskStatusArray[x].uxCurrentPriority, pxTaskStatusArray[x].usStackHighWaterMark, +#if CONFIG_FREERTOS_VTASKLIST_INCLUDE_COREID + (pxTaskStatusArray[x].xCoreID == tskNO_AFFINITY) ? '*' : ('0' + pxTaskStatusArray[x].xCoreID), +#endif + taskStates[pxTaskStatusArray[x].eCurrentState] + ); + } + + // The array is no longer needed, free the memory it consumes. + vPortFree(pxTaskStatusArray); + printer.println(); + } +#else + printer.println("FreeRTOS trace facility is not enabled."); +#endif /* CONFIG_FREERTOS_USE_TRACE_FACILITY */ +} diff --git a/cores/esp32/freertos_stats.h b/cores/esp32/freertos_stats.h new file mode 100644 index 00000000000..ea9e1a55a21 --- /dev/null +++ b/cores/esp32/freertos_stats.h @@ -0,0 +1,28 @@ +// Copyright 2024 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#ifdef __cplusplus + +#include "Print.h" + +/* + * Executing this function will cause interrupts and + * the scheduler to be blocked for some time. + * Please use only for debugging purposes. + */ +void printRunningTasks(Print &printer); + +#endif