1、前语
出于功能方面的考虑,有的时分,咱们期望知道CPU的运用率为多少,从而判别此CPU的负载状况和关于当时运转环境是否满足“担任”。本文将介绍一种核算CPU占有率的办法以及其完成原理。
2、移植算法
2.1 算法简介
此算法是根据操作体系的,理论上不限于任何操作体系,只需有使命调度就能够。本文将以FreeRTOST为例来介绍本算法的运用办法。
本文所介绍的算法出处为随Cube库一同供给的,它在cube库中的方位如下图所示:
本文将以STM32F4为例,测验环境为STM3240G-EVAL评价板。
2.2 、开端移植
本文以CubeF4内的示例代码工程STM32Cube_FW_F4_V1.10.0\Projects\STM324xG_EVAL\Applications\FreeRTOS\FreeRTOS_ThreadCreation为例,IDE运用IAR。
第一步:
运用IAR翻开FreeRTOS_ThreadCreation工程,将cpu_utils.c文件增加到工程,并在工程中增加对应头文件目录:
第二步:翻开FreeRTOST的装备头文件FreeRTOSConfig.h修正宏configUSE_IDLE_HOOK和configUSE_TICK_HOOK的值为1:
#defineconfigUSE_PREEMPTION 1
#defineconfigUSE_IDLE_HOOK 1 //修正此宏的值为1
#defineconfigUSE_TICK_HOOK 1 //修正此宏的值为1
#defineconfigCPU_CLOCK_HZ (SystemCoreClock )
#defineconfigT%&&&&&%K_RATE_HZ ( (TickType_t ) 1000 )
#define configMAX_PRIORITIES ( 8 )
#define configMINIMAL_STACK_SIZE (( uint16_t ) 128 )
第三步:持续在FreeRTOSConfig.h头文件的结尾处增加traceTASK_SWITCHED_IN与traceTASK_SWITCHED_OUT界说:
#definetraceTASK_SWITCHED_IN() extern voidStartIdleMonitor(void); \
StartIdleMonitor()
#define traceTASK_SWITCHED_OUT() extern voidEndIdleMonitor(void); \
EndIdleMonitor()
第四步:在main.h头文件中include“”cmsis_os.h“”
Main.h :
#include “stm32f4xx_hal.h”
#include “stm324xg_eval.h”
#include “cmsis_os.h” //增加包括此头文件
//…
第五步:修正工程特点,使编译进程不需求函数原型:
第六步:在工程中任何用户代码处都能够调用osGetCPUUsage()函数来获取当时CPU的运用率:
static void LED_Thread2(void const *argument)
{
uint32_t count;
uint16_t usage =0;
(void) argument;
for(;;)
{
count =osKernelSysTick() + 10000;
/* Toggle LED2 every500 ms for 10 s */
while (count >=osKernelSysTick())
{
BSP_LED_Toggle(LED2);
osDelay(500);
}
usage =osGetCPUUsage(); //获取当时CPU的运用率
/* Turn off LED2 */
BSP_LED_Off(LED2);
/* Resume Thread 1 */
osThreadResume(LEDThread1Handle);
/* Suspend Thread 2 */
osThreadSuspend(NULL);
}
}
第七步:编译并运转测验
在调试状态下运用Live Watch窗口监控悉数变量osCPU_Usage的值:
osCPU_Usage是在cpu_utils.c文件中界说的全局变量,表明当时CPU的运用率,是个动态值,由上图能够,CPU运用率的动态值为20%。实践在代码中是按第六步中调用osGetCPUUsage()函数来获取当时CPU的运用率的。
至此,算法运用办法介绍结束。
3 、算法完成原理剖析
操作体系运转时是不断在不同的使命间进行切换,而驱动这一调度进程是经过体系tick来驱动的,即每发生一次体系tick则检查一下当时正在运转的使命的环境判别是否需求切换使命,即调度,假如需求,则触发PendSV,经过在PendSV中止调用vTaskSwitchContext()函数来完成使命的调度。而本文所要叙述的CPU运用率算法是经过在必定时刻内(1000个时刻片内),核算闲暇使命所占用的时刻片总量,100减去闲暇使命所占百分比则为工作使命所占百分比,即CPU运用率。
void vApplicationIdleHook(void)
{
if( xIdleHandle == NULL )
{
/* Store the handle tothe idle task. */
xIdleHandle =xTaskGetCurrentTaskHandle(); //记载闲暇使命的句柄
}
}
此函数为闲暇使命钩子函数,每次当切换到闲暇使命时就会运转此钩子函数,它的效果便是记载当时闲暇使命的句柄并保存到全局变量xIdleHandle。
void vApplicationTickHook (void)
{
static int tick = 0;
if(tick ++ >CALCULATION_PERIOD) //每1000个tick,改写一次CPU运用率
{
tick = 0;
if(osCPU_TotalIdleTime> 1000)
{
osCPU_TotalIdleTime =1000;
}
osCPU_Usage = (100 -(osCPU_TotalIdleTime * 100) / CALCULATION_PERIOD); //这行代码便是CPU运用率的详细核算办法了
osCPU_TotalIdleTime =0;
}
}
此函数为操作体系的tick钩子函数,即每次发生体系tick中止都会进入到此钩子函数。此钩子函数实践上便是详细核算CPU运用率的算法了。osCPU_TotalIdleTime是一个全局变量,表明在1000个tick时刻内闲暇使命一共占用的时刻片,CALCULATION_PERIOD宏的值为1000,即每1000个tick时刻内从头核算一次CPU的运用率。
下面两个函数便是怎么核算osCPU_TotalIdleTime的:
void StartIdleMonitor(void)
{
if( xTaskGetCurrentTaskHandle() ==xIdleHandle ) //假如是切入到闲暇使命
{
osCPU_IdleStartTime =xTaskGetTickCountFromISR();//记载切入到闲暇使命的时刻点
}
}
void EndIdleMonitor(void)
{
if( xTaskGetCurrentTaskHandle() ==xIdleHandle ) //假如是从闲暇使命切出
{
/* Store the handle to the idle task. */
osCPU_IdleSpentTime =xTaskGetTickCountFromISR() – osCPU_IdleStartTime; //核算此次闲暇使命花费多长时刻
osCPU_TotalIdleTime += osCPU_IdleSpentTime;//闲暇使命所占时刻进行累加
}
}
这两个函数是调度器钩子函数,在调度器进行使命切进和切出时别离回调,StartIdleMonitor()函数记载切换到闲暇使命时的时刻点,EndIdleMonitor()则在推出闲暇使命时核算此次闲暇使命花费多长时刻,并累加到osCPU_TotalIdleTime,即闲暇使命一共占用的时刻片。
uint16_t osGetCPUUsage(void)
{
return (uint16_t)osCPU_Usage; //直接回来全局变量osCPU_Usage,即CPU运用率
}
全局变量osCPU_Usage保存的便是CPU的运用率,它是在操作体系的tick钩子函数中每隔1000个tick就被从头核算一次。
4 定论
经过此办法能够用来评价STM23 MCU的运转功能。