mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'feature/freeRTOS_make_debug_functions_configurable' into 'master'
FreeRTOS/make Queue Registry and Run Time Stats configurable See merge request !1480
This commit is contained in:
commit
3c33807689
@ -275,6 +275,16 @@ config TIMER_QUEUE_LENGTH
|
||||
|
||||
For most uses the default value of 10 is OK.
|
||||
|
||||
config FREERTOS_QUEUE_REGISTRY_SIZE
|
||||
int "FreeRTOS queue registry size"
|
||||
range 0 20
|
||||
default 0
|
||||
help
|
||||
FreeRTOS uses the queue registry as a means for kernel aware debuggers to locate queues, semaphores,
|
||||
and mutexes. The registry allows for a textual name to be associated with a queue for easy identification
|
||||
within a debugging GUI. A value of 0 will disable queue registry functionality, and a value larger than 0
|
||||
will specify the number of queues/semaphores/mutexes that the registry can hold.
|
||||
|
||||
config FREERTOS_USE_TRACE_FACILITY
|
||||
bool "Enable FreeRTOS trace facility"
|
||||
default n
|
||||
@ -285,13 +295,63 @@ config FREERTOS_USE_TRACE_FACILITY
|
||||
|
||||
config FREERTOS_USE_STATS_FORMATTING_FUNCTIONS
|
||||
bool "Enable FreeRTOS stats formatting functions"
|
||||
depends on FREERTOS_USE_TRACE_FACILITY
|
||||
depends on FREERTOS_USE_TRACE_FACILITY || FREERTOS_GENERATE_RUN_TIME_STATS
|
||||
default n
|
||||
help
|
||||
If enabled, configUSE_STATS_FORMATTING_FUNCTIONS will be defined as 1 in
|
||||
FreeRTOS. This will allow the usage of stats formatting functions such
|
||||
as vTaskList().
|
||||
|
||||
config FREERTOS_GENERATE_RUN_TIME_STATS
|
||||
bool "Enable FreeRTOS to collect run time stats"
|
||||
default n
|
||||
help
|
||||
If enabled, configGENERATE_RUN_TIME_STATS will be defined as 1 in
|
||||
FreeRTOS. This will allow FreeRTOS to collect information regarding the
|
||||
usage of processor time amongst FreeRTOS tasks. Run time stats are
|
||||
generated using either the ESP Timer or the CPU Clock as the clock
|
||||
source (Note that run time stats are only valid until the clock source
|
||||
overflows). The function vTaskGetRunTimeStats() will also be available
|
||||
if FREERTOS_USE_STATS_FORMATTING_FUNCTIONS and
|
||||
FREERTOS_USE_TRACE_FACILITY are enabled. vTaskGetRunTimeStats() will
|
||||
display the run time of each task as a % of the total run time of all
|
||||
CPUs (task run time / no of CPUs) / (total run time / 100 )
|
||||
|
||||
|
||||
choice FREERTOS_RUN_TIME_STATS_CLK
|
||||
prompt "Choose the clock source for run time stats"
|
||||
depends on FREERTOS_GENERATE_RUN_TIME_STATS
|
||||
default FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER
|
||||
help
|
||||
Choose the clock source for FreeRTOS run time stats. Options are CPU0's
|
||||
CPU Clock or the ESP Timer. Both clock sources are 32 bits. The CPU
|
||||
Clock can run at a higher frequency hence provide a finer resolution
|
||||
but will overflow much quicker. Note that run time stats are only valid
|
||||
until the clock source overflows.
|
||||
|
||||
config FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER
|
||||
bool "Use ESP TIMER for run time stats"
|
||||
help
|
||||
ESP Timer will be used as the clock source for FreeRTOS run time stats.
|
||||
The ESP Timer runs at a frequency of 1MHz regardless of Dynamic
|
||||
Frequency Scaling. Therefore the ESP Timer will overflow in
|
||||
approximately 4290 seconds.
|
||||
|
||||
config FREERTOS_RUN_TIME_STATS_USING_CPU_CLK
|
||||
bool "Use CPU Clock for run time stats"
|
||||
help
|
||||
CPU Clock will be used as the clock source for the generation of run
|
||||
time stats. The CPU Clock has a frequency dependent on
|
||||
ESP32_DEFAULT_CPU_FREQ_MHZ and Dynamic Frequency Scaling (DFS).
|
||||
Therefore the CPU Clock frequency can fluctuate between 80 to 240MHz.
|
||||
Run time stats generated using the CPU Clock represents the number of
|
||||
CPU cycles each task is allocated and DOES NOT reflect the amount of
|
||||
time each task runs for (as CPU clock frequency can change). If the CPU
|
||||
clock consistently runs at the maximum frequency of 240MHz, it will
|
||||
overflow in approximately 17 seconds.
|
||||
|
||||
endchoice
|
||||
|
||||
menuconfig FREERTOS_DEBUG_INTERNALS
|
||||
bool "Debug FreeRTOS internals"
|
||||
default n
|
||||
|
@ -219,7 +219,7 @@ int xt_clock_freq(void) __attribute__((deprecated));
|
||||
#define configBENCHMARK 0 /* Provided by Xtensa port patch */
|
||||
#define configUSE_16_BIT_TICKS 0
|
||||
#define configIDLE_SHOULD_YIELD 0
|
||||
#define configQUEUE_REGISTRY_SIZE 0
|
||||
#define configQUEUE_REGISTRY_SIZE CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE
|
||||
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configUSE_RECURSIVE_MUTEXES 1
|
||||
|
@ -80,6 +80,7 @@ extern "C" {
|
||||
#include <xtensa/config/system.h> /* required for XSHAL_CLIB */
|
||||
#include <xtensa/xtruntime.h>
|
||||
#include "esp_crosscore_int.h"
|
||||
#include "esp_timer.h" /* required for FreeRTOS run time stats */
|
||||
|
||||
|
||||
#include <esp_heap_caps.h>
|
||||
@ -299,6 +300,15 @@ static inline void uxPortCompareSet(volatile uint32_t *addr, uint32_t compare, u
|
||||
|
||||
/* Fine resolution time */
|
||||
#define portGET_RUN_TIME_COUNTER_VALUE() xthal_get_ccount()
|
||||
//ccount or esp_timer are initialized elsewhere
|
||||
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
|
||||
|
||||
#ifdef CONFIG_FREERTOS_RUN_TIME_STATS_USING_ESP_TIMER
|
||||
/* Coarse resolution time (us) */
|
||||
#define portALT_GET_RUN_TIME_COUNTER_VALUE(x) x = (uint32_t)esp_timer_get_time()
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Kernel utilities. */
|
||||
void vPortYield( void );
|
||||
|
@ -1627,6 +1627,23 @@ BaseType_t xQueueGiveMutexRecursive( QueueHandle_t pxMutex ) PRIVILEGED_FUNCTION
|
||||
void vQueueUnregisterQueue( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* @note This function has been back ported from FreeRTOS v9.0.0
|
||||
*
|
||||
* The queue registry is provided as a means for kernel aware debuggers to
|
||||
* locate queues, semaphores and mutexes. Call pcQueueGetName() to look
|
||||
* up and return the name of a queue in the queue registry from the queue's
|
||||
* handle.
|
||||
*
|
||||
* @param xQueue The handle of the queue the name of which will be returned.
|
||||
* @return If the queue is in the registry then a pointer to the name of the
|
||||
* queue is returned. If the queue is not in the registry then NULL is
|
||||
* returned.
|
||||
*/
|
||||
#if( configQUEUE_REGISTRY_SIZE > 0 )
|
||||
const char *pcQueueGetName( QueueHandle_t xQueue ) PRIVILEGED_FUNCTION; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Generic version of the function used to creaet a queue using dynamic memory
|
||||
* allocation. This is called by other functions and macros that create other
|
||||
|
@ -205,6 +205,9 @@ _Static_assert(sizeof(StaticQueue_t) == sizeof(Queue_t), "StaticQueue_t != Queue
|
||||
array position being vacant. */
|
||||
QueueRegistryItem_t xQueueRegistry[ configQUEUE_REGISTRY_SIZE ];
|
||||
|
||||
//Need to add queue registry mutex to protect against simultaneous access
|
||||
static portMUX_TYPE queue_registry_spinlock = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
#endif /* configQUEUE_REGISTRY_SIZE */
|
||||
|
||||
|
||||
@ -2316,7 +2319,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||
{
|
||||
UBaseType_t ux;
|
||||
|
||||
UNTESTED_FUNCTION();
|
||||
portENTER_CRITICAL(&queue_registry_spinlock);
|
||||
/* See if there is an empty space in the registry. A NULL name denotes
|
||||
a free slot. */
|
||||
for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ )
|
||||
@ -2335,6 +2338,38 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&queue_registry_spinlock);
|
||||
}
|
||||
|
||||
#endif /* configQUEUE_REGISTRY_SIZE */
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( configQUEUE_REGISTRY_SIZE > 0 )
|
||||
|
||||
//This function is backported from FreeRTOS v9.0.0
|
||||
const char *pcQueueGetName( QueueHandle_t xQueue ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
{
|
||||
UBaseType_t ux;
|
||||
const char *pcReturn = NULL; /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
|
||||
|
||||
portENTER_CRITICAL(&queue_registry_spinlock);
|
||||
/* Note there is nothing here to protect against another task adding or
|
||||
removing entries from the registry while it is being searched. */
|
||||
for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ )
|
||||
{
|
||||
if( xQueueRegistry[ ux ].xHandle == xQueue )
|
||||
{
|
||||
pcReturn = xQueueRegistry[ ux ].pcQueueName;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&queue_registry_spinlock);
|
||||
|
||||
return pcReturn;
|
||||
}
|
||||
|
||||
#endif /* configQUEUE_REGISTRY_SIZE */
|
||||
@ -2346,6 +2381,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||
{
|
||||
UBaseType_t ux;
|
||||
|
||||
portENTER_CRITICAL(&queue_registry_spinlock);
|
||||
/* See if the handle of the queue being unregistered in actually in the
|
||||
registry. */
|
||||
for( ux = ( UBaseType_t ) 0U; ux < ( UBaseType_t ) configQUEUE_REGISTRY_SIZE; ux++ )
|
||||
@ -2361,6 +2397,7 @@ Queue_t * const pxQueue = ( Queue_t * ) xQueue;
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&queue_registry_spinlock);
|
||||
|
||||
} /*lint !e818 xQueue could not be pointer to const because it is a typedef. */
|
||||
|
||||
|
@ -309,7 +309,7 @@ PRIVILEGED_DATA static portMUX_TYPE xTickCountMutex = portMUX_INITIALIZER_UNLOCK
|
||||
|
||||
#if ( configGENERATE_RUN_TIME_STATS == 1 )
|
||||
|
||||
PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
|
||||
PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime[portNUM_PROCESSORS] = {0U}; /*< Holds the value of a timer/counter the last time a task was switched in on a particular core. */
|
||||
PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */
|
||||
|
||||
#endif
|
||||
@ -2729,16 +2729,16 @@ void vTaskSwitchContext( void )
|
||||
against suspect run time stat counter implementations - which
|
||||
are provided by the application, not the kernel. */
|
||||
taskENTER_CRITICAL_ISR(&xTaskQueueMutex);
|
||||
if( ulTotalRunTime > ulTaskSwitchedInTime )
|
||||
if( ulTotalRunTime > ulTaskSwitchedInTime[ xPortGetCoreID() ] )
|
||||
{
|
||||
pxCurrentTCB[ xPortGetCoreID() ]->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
|
||||
pxCurrentTCB[ xPortGetCoreID() ]->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime[ xPortGetCoreID() ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
mtCOVERAGE_TEST_MARKER();
|
||||
}
|
||||
taskEXIT_CRITICAL_ISR(&xTaskQueueMutex);
|
||||
ulTaskSwitchedInTime = ulTotalRunTime;
|
||||
ulTaskSwitchedInTime[ xPortGetCoreID() ] = ulTotalRunTime;
|
||||
}
|
||||
#endif /* configGENERATE_RUN_TIME_STATS */
|
||||
|
||||
@ -4372,7 +4372,6 @@ For ESP32 FreeRTOS, vTaskExitCritical implements both portEXIT_CRITICAL and port
|
||||
volatile UBaseType_t uxArraySize, x;
|
||||
uint32_t ulTotalTime, ulStatsAsPercentage;
|
||||
|
||||
UNTESTED_FUNCTION();
|
||||
#if( configUSE_TRACE_FACILITY != 1 )
|
||||
{
|
||||
#error configUSE_TRACE_FACILITY must also be set to 1 in FreeRTOSConfig.h to use vTaskGetRunTimeStats().
|
||||
@ -4433,7 +4432,8 @@ For ESP32 FreeRTOS, vTaskExitCritical implements both portEXIT_CRITICAL and port
|
||||
/* What percentage of the total run time has the task used?
|
||||
This will always be rounded down to the nearest integer.
|
||||
ulTotalRunTimeDiv100 has already been divided by 100. */
|
||||
ulStatsAsPercentage = pxTaskStatusArray[ x ].ulRunTimeCounter / ulTotalTime;
|
||||
/* Also need to consider total run time of all */
|
||||
ulStatsAsPercentage = (pxTaskStatusArray[ x ].ulRunTimeCounter/portNUM_PROCESSORS)/ ulTotalTime;
|
||||
|
||||
/* Write the task name to the string, padding with
|
||||
spaces so it can be printed in tabular form more
|
||||
|
100
components/freertos/test/test_freertos_debug_functions.c
Normal file
100
components/freertos/test/test_freertos_debug_functions.c
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Test FreeRTOS debug functions and utilities.
|
||||
* - Queue registry functions vQueueAddToRegistry(), vQueueUnregisterQueue(),
|
||||
* and pcQueueGetName(backported)
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "unity.h"
|
||||
|
||||
#if (CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE > 0)
|
||||
#define NO_OF_QUEUES_PER_CORE ((int)((CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE - 3)/portNUM_PROCESSORS)) //Save space for some preallocated tasks
|
||||
#define NO_OF_QUEUES_TOTAL (NO_OF_QUEUES_PER_CORE * portNUM_PROCESSORS)
|
||||
#define QUEUE_NAME_MAX_LENGTH 10
|
||||
|
||||
static SemaphoreHandle_t start_sem = NULL;
|
||||
static SemaphoreHandle_t done_sem = NULL;
|
||||
static char *names[NO_OF_QUEUES_TOTAL];
|
||||
static QueueHandle_t handles[NO_OF_QUEUES_TOTAL];
|
||||
|
||||
void test_queue_registry_task(void *arg)
|
||||
{
|
||||
int core = xPortGetCoreID();
|
||||
int offset = core * NO_OF_QUEUES_PER_CORE;
|
||||
//Create queues and accompanying queue names
|
||||
for(int i = 0; i < NO_OF_QUEUES_PER_CORE; i++){
|
||||
handles[i + offset] = xQueueCreate(1,1); //Create queues
|
||||
names[i + offset] = calloc(QUEUE_NAME_MAX_LENGTH, sizeof(char));
|
||||
sprintf(names[i + offset], "Queue%d%d", core, i);
|
||||
}
|
||||
|
||||
xSemaphoreTake(start_sem, portMAX_DELAY); //Wait for start vQueueAddToRegistry()
|
||||
for(int i = 0; i < NO_OF_QUEUES_PER_CORE; i++){
|
||||
vQueueAddToRegistry(handles[i + offset] , names[i + offset]); //Register queues to queue registry
|
||||
}
|
||||
xSemaphoreGive(done_sem); //Signal that vQueueAddToRegistry() has completed
|
||||
|
||||
vTaskDelay(1);
|
||||
|
||||
xSemaphoreTake(start_sem, portMAX_DELAY); //Wait to start vQueueUnregisterQueue()
|
||||
for(int i = 0; i < NO_OF_QUEUES_PER_CORE; i++){
|
||||
vQueueDelete(handles[i + offset]); //Internally calls vQueueUnregisterQueue
|
||||
}
|
||||
xSemaphoreGive(done_sem); //Signal done
|
||||
|
||||
vTaskDelete(NULL); //Delete self
|
||||
}
|
||||
|
||||
TEST_CASE("Test FreeRTOS Queue Registry", "[freertos]")
|
||||
{
|
||||
//Create synchronization semaphores
|
||||
start_sem = xSemaphoreCreateCounting(portNUM_PROCESSORS, 0);
|
||||
done_sem = xSemaphoreCreateCounting(portNUM_PROCESSORS, 0);
|
||||
for(int i = 0; i < portNUM_PROCESSORS; i++){ //Create tasks to test queue registry
|
||||
xTaskCreatePinnedToCore(test_queue_registry_task, "testing task", 4096, NULL, UNITY_FREERTOS_PRIORITY+1, NULL, i);
|
||||
}
|
||||
|
||||
portDISABLE_INTERRUPTS();
|
||||
for(int i = 0; i < portNUM_PROCESSORS; i++){
|
||||
xSemaphoreGive(start_sem); //Trigger start
|
||||
}
|
||||
portENABLE_INTERRUPTS();
|
||||
for(int i = 0; i < portNUM_PROCESSORS; i++){
|
||||
xSemaphoreTake(done_sem, portMAX_DELAY); //Wait for tasks to complete vQueueAddToRegistry
|
||||
}
|
||||
for(int i = 0; i < NO_OF_QUEUES_TOTAL; i++){
|
||||
const char *addr = pcQueueGetName(handles[i]);
|
||||
TEST_ASSERT(addr == names[i]) //Check vQueueAddToRegistry was successful
|
||||
}
|
||||
|
||||
portDISABLE_INTERRUPTS();
|
||||
for(int i = 0; i < portNUM_PROCESSORS; i++){
|
||||
xSemaphoreGive(start_sem); //Trigger start
|
||||
}
|
||||
portENABLE_INTERRUPTS();
|
||||
for(int i = 0; i < portNUM_PROCESSORS; i++){
|
||||
xSemaphoreTake(done_sem, portMAX_DELAY); //Wait for tasks to complete vQueueUnregisterQueue
|
||||
}
|
||||
for(int i = 0; i < NO_OF_QUEUES_TOTAL; i++){
|
||||
const char *addr = pcQueueGetName(handles[i]);
|
||||
TEST_ASSERT(addr == NULL) //Check vQueueUnregisterQueue was successful
|
||||
handles[i] = NULL;
|
||||
}
|
||||
|
||||
//Cleanup
|
||||
for(int i = 0; i < NO_OF_QUEUES_TOTAL; i++){
|
||||
free(names[i]);
|
||||
names[i] = NULL;
|
||||
}
|
||||
vSemaphoreDelete(start_sem);
|
||||
start_sem = NULL;
|
||||
vSemaphoreDelete(done_sem);
|
||||
done_sem = NULL;
|
||||
}
|
||||
#endif //(CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE > 0)
|
@ -20,3 +20,4 @@ CONFIG_SPI_FLASH_ENABLE_COUNTERS=y
|
||||
CONFIG_ULP_COPROC_ENABLED=y
|
||||
CONFIG_TASK_WDT=n
|
||||
CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS=y
|
||||
CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=7
|
||||
|
Loading…
Reference in New Issue
Block a user