2025-12-01 22:55:42 +01:00

169 lines
5.0 KiB
C

/*******************************************************************
File: usage.c
Date: 9-September-2020
Author: Peter Spindler
Description: Functions to determine and show the cpu usage
*********************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "stm32f7xx_hal.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
//#define DEMCR (*(volatile uint32_t *)0xE000EDFC)
//#define DWT_CTRL (*(volatile uint32_t *)0xE0001000)
//#define DWT_CYCCNT (*(volatile uint32_t *)0xE0001004)
static uint32_t Usage_IdleTickStart, Usage_IdleTickEnd, Usage_IdleTickTotal = 0;
static uint32_t Usage_MeasTickStart, Usage_MeasTickEnd, Usage_MeasTickTotal = 0, Usage_MeasCnt = 0;
extern volatile void *pxCurrentTCB;
#define TASKSTATUS_SIZE 16
static TaskStatus_t Usage_TaskStatusArray[TASKSTATUS_SIZE];
static TaskStatus_t Usage_TaskStatusArrayPrev[TASKSTATUS_SIZE];
static TaskStatus_t *Usage_TaskStatusArraySort[TASKSTATUS_SIZE];
uint32_t Usage_TaskStatusTimePrev = 0;
static uint32_t Usage_SOL = 0;
uint32_t Usage_GetTicks( void )
{
return DWT->CYCCNT;
}
void Usage_TaskSwitchedIn( void )
{
if( pxCurrentTCB == xTaskGetIdleTaskHandle() ) {
Usage_IdleTickStart = Usage_GetTicks();
}
}
void Usage_TaskSwitchedOut( void )
{
if( pxCurrentTCB == xTaskGetIdleTaskHandle() ) {
Usage_IdleTickEnd = Usage_GetTicks();
Usage_IdleTickTotal += Usage_IdleTickEnd - Usage_IdleTickStart;
}
}
uint8_t Usage_GetUsage( void )
{
uint8_t Usage = 0;
Usage_MeasTickEnd = Usage_GetTicks();
Usage_MeasTickTotal = Usage_MeasTickEnd - Usage_MeasTickStart;
Usage_IdleTickTotal /= 1024; // Divide to prevent overflows by multiplication with 100
Usage_MeasTickTotal /= 1024; // Divide to prevent overflows by multiplication with 100
Usage = 100-(100*Usage_IdleTickTotal)/Usage_MeasTickTotal;
Usage_MeasTickStart = Usage_MeasTickEnd;
Usage_IdleTickTotal = 0;
if( Usage_MeasCnt < 0xff ) {
Usage_MeasCnt++;
}
// First measurement can be wrong!
if( Usage_MeasCnt > 1 ) {
return Usage;
} else {
return 0;
}
}
static int Usage_TaskStatusCompare (const void * a, const void * b)
{
TaskStatus_t *aa = *((TaskStatus_t**) a);
TaskStatus_t *bb = *((TaskStatus_t**) b);
return ((int)aa->xTaskNumber - (int)bb->xTaskNumber);
}
void Usage_PrintStats( void )
{
uint32_t TaskCnt, x, i;
uint8_t Ignore = 0;
int32_t DiffCounter;
TaskStatus_t *TS;
uint32_t TaskStatusTime, Usage, TotalTimeDiff;
uint32_t NonIdleCounter = 0;
TaskCnt = uxTaskGetNumberOfTasks();
if( TaskCnt > TASKSTATUS_SIZE ) {
TaskCnt = TASKSTATUS_SIZE;
}
TaskCnt = uxTaskGetSystemState( Usage_TaskStatusArray, TaskCnt, &TaskStatusTime );
// Note: uxTaskGetSystemState stores the task information in TaskStatusArray in an arbitrary sequence.
// Sort TaskStatusArray by the task number!
for(i=0;i<TaskCnt;i++) {
Usage_TaskStatusArraySort[i] = &Usage_TaskStatusArray[i];
}
qsort(Usage_TaskStatusArraySort,TaskCnt,sizeof(TaskStatus_t*),Usage_TaskStatusCompare);
// Get time without idle:
NonIdleCounter = 0;
for( x = 0; x < TaskCnt; x++ ) {
TS = Usage_TaskStatusArraySort[ x ];
for( i = 0; i < TaskCnt; i++ ) {
if( TS->xTaskNumber == Usage_TaskStatusArrayPrev[ i ].xTaskNumber ) {
if( Usage_TaskStatusArrayPrev[ i ].ulRunTimeCounter == 0 ) {
Ignore = 1;
}
if( TS->xHandle != xTaskGetIdleTaskHandle() ) {
NonIdleCounter += TS->ulRunTimeCounter-Usage_TaskStatusArrayPrev[ i ].ulRunTimeCounter;
}
}
}
}
TotalTimeDiff = TaskStatusTime - Usage_TaskStatusTimePrev;
TotalTimeDiff /= 100UL; // For percentage calculations.
if( TaskStatusTime > 0 && Usage_TaskStatusTimePrev != 0 && !Ignore ) {
printf("CPU usage without idle: %d%%, free RTOS heap: %d, SOL: %d\n\r", (int) (NonIdleCounter/TotalTimeDiff), xPortGetFreeHeapSize(), (int) Usage_SOL );
Usage_SOL++;
for( x = 0; x < TaskCnt; x++ ) {
TS = Usage_TaskStatusArraySort[ x ];
DiffCounter = -1;
for( i = 0; i < TaskCnt; i++ ) {
if( TS->xTaskNumber == Usage_TaskStatusArrayPrev[ i ].xTaskNumber ) {
DiffCounter = TS->ulRunTimeCounter-Usage_TaskStatusArrayPrev[ i ].ulRunTimeCounter;
break;
}
}
if( DiffCounter >= 0 ) {
Usage = (DiffCounter) / TotalTimeDiff;
if( Usage > 100 ) {
Usage = 100;
}
}
printf(" %2d: %-16s: CPU: %3u%%, free stack: %3u\n\r",
(int) TS->xTaskNumber, TS->pcTaskName, (int) Usage,
TS->usStackHighWaterMark );
}
}
memcpy(Usage_TaskStatusArrayPrev,Usage_TaskStatusArray,sizeof(Usage_TaskStatusArrayPrev));
Usage_TaskStatusTimePrev = TaskStatusTime;
}
void Usage_Init(void)
{
// Use core tick timer (implemented in the data watchpoint and trace unit, available in STM32F4 only!)
//DEMCR |= (1<<24);
//DWT_CTRL |= (1<<0);
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}