你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】一种计算 CPU 使用率的方法及其实现原理

[复制链接]
STMCU小助手 发布时间:2022-3-5 10:00
1 前言
出于性能方面的考虑,有的时候,我们希望知道 CPU 的使用率为多少,进而判断此 CPU 的负载情况和对于当前运行环境是否足够“胜任”。本文将介绍一种计算 CPU 占有率的方法以及其实现原理。

2 移植算法
2.1 算法简介

此算法是基于操作系统的,理论上不限于任何操作系统,只要有任务调度就可以。本文将以 FreeRTOST 为例来介绍本算法的使用方法。
本文所介绍的算法出处为随 Cube 库一起提供的,它在 cube 库中的位置如下图所示:

TA`{%P{P33M{K43(760U)70.png

本文将以 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 文件添加到工程,并在工程中添加对应头文件目录:

8CTMGLB)ZFZ[%[~8%INEM}N.png

第二步:打开 FreeRTOST 的配置头文件 FreeRTOSConfig.h 修改宏 configUSE_IDLE_HOOK 和 configUSE_TICK_HOOK的值为 1:
  1. #define configUSE_PREEMPTION 1
  2. #define configUSE_IDLE_HOOK 1 //修改此宏的值为 1
  3. #define configUSE_TICK_HOOK 1 //修改此宏的值为 1
  4. #define configCPU_CLOCK_HZ ( SystemCoreClock )
  5. #define configTICK_RATE_HZ ( ( TickType_t ) 1000 )
  6. #define configMAX_PRIORITIES ( 8 )
  7. #define configMINIMAL_STACK_SIZE ( ( uint16_t ) 128 )
复制代码

第三步:继续在 FreeRTOSConfig.h 头文件的末尾处添加 traceTASK_SWITCHED_IN 与 traceTASK_SWITCHED_OUT 定义:
  1. #define traceTASK_SWITCHED_IN() extern void StartIdleMonitor(void);
  2. StartIdleMonitor()
  3. #define traceTASK_SWITCHED_OUT() extern void EndIdleMonitor(void);
  4. EndIdleMonitor()
复制代码

第四步:在 main.h 头文件中 include “”cmsis_os.h“”
Main.h :
  1. #include "stm32f4xx_hal.h"
  2. #include "stm324xg_eval.h"
  3. #include "cmsis_os.h" //添加包含此头文件
  4. //…
复制代码

第五步: 修改工程属性,使编译过程不需要函数原型:

ZEKC[Q]QPCG~3`B[U4FHS5P.png

第六步:在工程中任何用户代码处都可以调用 osGetCPUUsage()函数来获取当前 CPU 的使用率:
  1. static void LED_Thread2(void const *argument)
  2. {
  3. uint32_t count;
  4. uint16_t usage =0;
  5. (void) argument;

  6. for(;;)
  7. {
  8. count = osKernelSysTick() + 10000;

  9. /* Toggle LED2 every 500 ms for 10 s */
  10. while (count >= osKernelSysTick())
  11. {
  12. BSP_LED_Toggle(LED2);

  13. osDelay(500);
  14. }
  15. usage =osGetCPUUsage(); //获取当前 CPU 的使用率
  16. /* Turn off LED2 */
  17. BSP_LED_Off(LED2);

  18. /* Resume Thread 1 */
  19. osThreadResume(LEDThread1Handle);

  20. /* Suspend Thread 2 */
  21. osThreadSuspend(NULL);
  22. }
  23. }
复制代码

第七步:编译并运行测试
在调试状态下使用 Live Watch 窗口监控全部变量 osCPU_Usage 的值:

6DN{URB]Y3CT1UNS13]R{9B.png

osCPU_Usage 是在 cpu_utils.c 文件中定义的全局变量,表示当前 CPU 的使用率,是个动态值,由上图可以,CPU 使用率的动态值为 20%。实际在代码中是按第六步中调用 osGetCPUUsage()函数来获取当前 CPU 的使用率的。
至此,算法使用方法介绍完毕。

3 算法实现原理分析
操作系统运行时是不断在不同的任务间进行切换,而驱动这一调度过程是通过系统 tick 来驱动的,即每产生一次系统 tick 则检查一下当前正在运行的任务的环境判断是否需要切换任务,即调度,如果需要,则触发 PendSV,通过在 PendSV 中断调用vTaskSwitchContext()函数来实现任务的调度。而本文所要讲述的 CPU 使用率算法是通过在一定时间内(1000 个时间片内),计算空闲任务所占用的时间片总量,100 减去空闲任务所占百分比则为工作任务所占百分比,即 CPU 使用率。
  1. void vApplicationIdleHook(void)
  2. {
  3. if( xIdleHandle == NULL )
  4. {
  5. /* Store the handle to the idle task. */
  6. xIdleHandle = xTaskGetCurrentTaskHandle(); //记录空闲任务的句柄
  7. }
  8. }
复制代码

此函数为空闲任务钩子函数,每次当切换到空闲任务时就会运行此钩子函数,它的作用就是记录当前空闲任务的句柄并保存到全局变量 xIdleHandle。
  1. void vApplicationTickHook (void)
  2. {
  3. static int tick = 0;

  4. if(tick ++ > CALCULATION_PERIOD) //每 1000 个 tick,刷新一次 CPU 使用率
  5. {
  6. tick = 0;

  7. if(osCPU_TotalIdleTime > 1000)
  8. {
  9. osCPU_TotalIdleTime = 1000;
  10. }
  11. osCPU_Usage = (100 - (osCPU_TotalIdleTime * 100) / CALCULATION_PERIOD); //这行代码就是
  12. CPU 使用率的具体计算方法了
  13. osCPU_TotalIdleTime = 0;
  14. }
  15. }
复制代码

此函数为操作系统的 tick 钩子函数,即每次产生系统 tick 中断都会进入到此钩子函数。此钩子函数实际上就是具体计算 CPU使用率的算法了。osCPU_TotalIdleTime 是一个全局变量,表示在 1000 个 tick 时间内空闲任务总共占用的时间片,CALCULATION_PERIOD 宏的值为 1000,即每 1000 个 tick 时间内重新计算一次 CPU 的使用率。
下面两个函数就是如何计算 osCPU_TotalIdleTime 的:
  1. void StartIdleMonitor (void)
  2. {
  3. if( xTaskGetCurrentTaskHandle() == xIdleHandle ) //如果是切入到空闲任务
  4. {
  5. osCPU_IdleStartTime = xTaskGetTickCountFromISR();//记录切入到空闲任务的时间点
  6. }
  7. }
  8. void EndIdleMonitor (void)
  9. {
  10. if( xTaskGetCurrentTaskHandle() == xIdleHandle ) //如果是从空闲任务切出
  11. {
  12. /* Store the handle to the idle task. */
  13. osCPU_IdleSpentTime = xTaskGetTickCountFromISR() - osCPU_IdleStartTime; //计算此次空闲
  14. 任务花费多长时间
  15. osCPU_TotalIdleTime += osCPU_IdleSpentTime; //空闲任务所占时间进行累加
  16. }
  17. }
复制代码

这两个函数是调度器钩子函数,在调度器进行任务切进和切出时分别回调,StartIdleMonitor()函数记录切换到空闲任务时的时间点,EndIdleMonitor()则在推出空闲任务时计算此次空闲任务花费多长时间,并累加到 osCPU_TotalIdleTime,即空闲任务总共占用的时间片。
  1. uint16_t osGetCPUUsage (void)
  2. {
  3. return (uint16_t)osCPU_Usage; //直接返回全局变量 osCPU_Usage,即 CPU 使用率
  4. }
复制代码

全局变量 osCPU_Usage 保存的就是 CPU 的使用率,它是在操作系统的 tick 钩子函数中每隔 1000 个 tick 就被重新计算一次。


4 结论
通过此方法可以很好的用来评估 STM23 MCU 的运行性能。

收藏 评论0 发布时间:2022-3-5 10:00

举报

0个回答

所属标签

相似技术帖

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版