cancel
Showing results for 
Search instead for 
Did you mean: 

FreeRTOS Runtime percentage calculations

DreamOnDirac
Associate III

Hi

 

Using FreeRTOS V11.0.1 and Stm32Cubeide 1.14.1 I was trying to read out the percentage information into the debugger.  Unfortunately I don't get the expected behavior

DreamOnDirac_0-1706483264013.png

As all of my tasks are either below 1% or at 1%, it does not seem correct.

I have followed the instructions in stm32CubeIDE user guide and if I make a call to 

uxTaskGetSystemState

 from the FreeRTOS API, i can calculate values that make more sense as the IDLE task now takes up about 99% of the time under no load.

Are there any other settings that needs to be fulfilled for this to work or are there any more needed configurations in FreeRTOS?

Best regards

Martin

6 REPLIES 6
KnarfB
Principal III

How have you implemented portGET_RUN_TIME_COUNTER_VALUE and friends? A timer, is is running? What spped, what MCU?

I often use the cycle counter on M4 like so. In FreeRTOSConfig.h:

/* USER CODE BEGIN Includes */
/* Section where include file can be added */
#include "main.h"

#include "tracer.h"

#define configUSE_TRACE_FACILITY 1
#define configGENERATE_RUN_TIME_STATS 1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() \
do { \
  CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; \
  ITM->LAR = 0xC5ACCE55; \
  DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; \
} while(0)

#define portGET_RUN_TIME_COUNTER_VALUE() (DWT->CYCCNT)

#define configRECORD_STACK_HIGH_ADDRESS 1
/* USER CODE END Includes */

 hth

KnarfB

Hi KnarfB and thanks for the reply.

 

I will dig in to my implementation and what I got later today. But I tested your variant, which I prefer since I dont need to assign a normal timer and have a timer update event interrupt that executes.

When I run with your code instead get this:

DreamOnDirac_0-1706514415005.png

Which looks reasonable apart from the "CTR OVR" for the runtime.

 

Best regards

Martin

No idea, where the counter overflow comes from, maybe you have to add a

DWT->CYCCNT = 0;

in the init phase or the MCU clock is soo high (or tick rate so low)? Never seen that before.

Even if you use a timer, you don't have to implement an interrupt handler, but read pass the CNT counter register of a running timer for the "run time variable" (STM32CubeIDE user manual) directly, either at register level or wrapped by the __HAL_TIM_GET_COUNTER macro.

hth

KnarfB

I tested a bunch of ways forward. I failed to configure the CoreDebug clock so i went back to using TIM2 instead. My code currently looks like this.

 

In FreeRTOSconfig.h

#if configGENERATE_RUN_TIME_STATS == 1
#include "RuntimeStat.h"
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() 	RTOSSetupRuntimeCounter();
#define portGET_RUN_TIME_COUNTER_VALUE() 			RTOSGetRuntimeCounterValueFromISR()
#endif

 

Then in RuntimeStat.c

#define RUNTIME_STAT_USED_TIMER (TIM2)
void RTOSSetupRuntimeCounter() {
	LL_TIM_InitTypeDef TIM_InitStruct = {0};
	uint32_t timer_prescaler = 1u;
	uTimerEnableBlockClock(RUNTIME_STAT_USED_TIMER, true);

	uint32_t timer_block_frequency = uTimerGetBlockClock(RUNTIME_STAT_USED_TIMER);
	timer_prescaler = __LL_TIM_CALC_PSC(timer_block_frequency, (10u * 1000u));

	TIM_InitStruct.Prescaler = (uint16_t)(timer_prescaler);
	TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
	TIM_InitStruct.Autoreload = 0xFFFFFFFFu;
	TIM_InitStruct.ClockDivision = LL_TIM_CLOCKDIVISION_DIV1;
	LL_TIM_Init(RUNTIME_STAT_USED_TIMER, &TIM_InitStruct);
	LL_TIM_EnableARRPreload(RUNTIME_STAT_USED_TIMER);


	vEnableIrq(TIM2_IRQn, PRIORITY_TIM2_FREERTOS_RUNTIME_STAT);

	// RTOS_RunTimeCounter = 0u;
	LL_TIM_SetCounter(RUNTIME_STAT_USED_TIMER, 0u);
	LL_TIM_EnableCounter(RUNTIME_STAT_USED_TIMER);
}

uint32_t RTOSGetRuntimeCounterValueFromISR(void) {
	return RUNTIME_STAT_USED_TIMER->CNT;
}

Finally i have a custom debug terminal where i can print stuff From it I do this

 

uxArraySize = uxTaskGetNumberOfTasks();
if (uxArraySize > 0u) {
	pxTaskStatusArray = pvPortMalloc(uxArraySize * sizeof(TaskStatus_t));
	vTerminalPrintf("FreeRTOS Free/Total heap: %lu / %lu\r\n", xPortGetFreeHeapSize(), configTOTAL_HEAP_SIZE );
	if (pxTaskStatusArray != NULL) {
		// Generate raw status information about each task.
		uint32_t total_runtime = 0u;
		uxArraySize = uxTaskGetSystemState(pxTaskStatusArray, uxArraySize, &total_runtime);
		vTerminalPrintf("%-15s\%-10s%-10s%-10s\r\n", "Taskname", "Stacksize", "Watermark", "PPM use");
		for (uint8_t x = 0u; x < uxArraySize; x++) {
			uint32_t runtime_promille = unsigned_divide_rounder((pxTaskStatusArray[x].ulRunTimeCounter * 1000u), total_runtime);
			vTerminalPrintf("%-15s\%-10lu%-10lu%-10lu\r\n",
						pxTaskStatusArray[x].pcTaskName,
						uxTaskGetStackSize(pxTaskStatusArray[x].xHandle),
						uxTaskGetStackHighWaterMark(pxTaskStatusArray[x].xHandle),
						runtime_promille);
		} // end for
		vPortFree(pxTaskStatusArray);
	}
} // end if there are any tasks at all.. there will always be tasks
// Now lets estimate the factor between the statistics timer and the freeRTOS tick

uint32_t stats = RTOSGetRuntimeCounterValueFromISR();
uint32_t tics = xTaskGetTickCount();

if (stats > tics) {
	// as expected
	vTerminalPrintf("Stats is %u, Tics %u. Stats is %u times faster\r\n",stats, tics, ((stats * 100u)/tics)/100u);
}
else {
	vTerminalPrintf("Tics is %u, stats %u. Tics is %u times faster\r\n",tics, stats, ((tics * 100u)/stats)/100u);
}

 

When i then call this code after a few seconds of execution, i get this

FreeRTOS Free/Total heap: 4448 / 36864
Taskname       Stacksize Watermark PPM use   
Terminal       164       49        1         
IDLE           12        19        995       
Modbus         334       267       0         
TaskTimer      164       133       0         
Regul          186       169       1         
Mounter        148       139       0         
Logger         180       175       0         
Flasher        3248      3233      1         
Reson          124       117       1         
Stats is 38515, Tics 3851. Stats is 10 times faster

(Something is off with the stack and high watermark values, I know.)

Nevertheless, the debugger still shows

DreamOnDirac_0-1706557301442.png

This seems to be more of an stm32cubeide issue than a FreeRTOS issue.

DreamOnDirac
Associate III

Does @mattias norlander or @B.Montanari have any input on this?

 

// Martin

jmalmari
Associate

This was broken by multicore support in FreeRTOS kernel, commit https://github.com/FreeRTOS/FreeRTOS-Kernel/commit/ae3a498e435cecdb25b889f2740ea99027dd0cb1.

Since data from uxTaskGetSystemState looks correct, most likely Cube IDE needs to adapt.