打印
[应用相关]

一种计算 CPU 使用率的方法及其实现原理

[复制链接]
2088|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1 前言
出于性能方面的考虑,有的时候,我们希望知道 CPU 的使用率为多少, 进而判断此 CPU 的负载情况和对于当前运行环境是
否足够“ 胜任” 。本文将介绍一种计算 CPU 占有率的方法以及其实现原理。  

使用特权

评论回复
沙发
我想看大海|  楼主 | 2021-11-9 10:22 | 只看该作者
2 移植算法
2.1 算法简介
此算法是基于操作系统的, 理论上不限于任何操作系统,只要有任务调度就可以。 本文将以 FreeRTOST 为例来介绍本算法的
使用方法。
本文所介绍的算法出处为随 Cube 库一起提供的, 它在 cube 库中的位置如下图所示:  


本文将以 STM32F4 为例, 测试环境为 STM3240G-EVAL 评估板。


使用特权

评论回复
板凳
我想看大海|  楼主 | 2021-11-9 10:25 | 只看该作者
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:

第三步: 继续在 FreeRTOSConfig.h 头文件的末尾处添加 traceTASK_SWITCHED_IN 与 traceTASK_SWITCHED_OUT 定义:

第四步: 在 main.h 头文件中 include “”cmsis_os.h“”
Main.h :

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

第六步:在工程中任何用户代码处都可以调用 osGetCPUUsage()函数来获取当前 CPU 的使用率:

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

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


使用特权

评论回复
地板
我想看大海|  楼主 | 2021-11-9 10:27 | 只看该作者
3 算法实现原理分析
操作系统运行时是不断在不同的任务间进行切换, 而驱动这一调度过程是通过系统 tick 来驱动的,即每产生一次系统 tick 则检
查一下当前正在运行的任务的环境判断是否需要切换任务,即调度, 如果需要,则触发 PendSV,通过在 PendSV 中断调用
vTaskSwitchContext()函数来实现任务的调度。 而本文所要讲述的 CPU 使用率算法是通过在一定时间内( 1000 个时间片内) ,
计算空闲任务所占用的时间片总量, 100 减去空闲任务所占百分比则为工作任务所占百分比,即 CPU 使用率。  


此函数为空闲任务钩子函数, 每次当切换到空闲任务时就会运行此钩子函数, 它的作用就是记录当前空闲任务的句柄并保存
到全局变量 xIdleHandle。

此函数为操作系统的 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 就被重新计算一次。


使用特权

评论回复
5
我想看大海|  楼主 | 2021-11-9 10:28 | 只看该作者
4 结论
通过此方法可以很好的用来评估 STM23 MCU 的运行性能。

使用特权

评论回复
6
sadicy| | 2021-11-11 10:00 | 只看该作者
mark
学习了,回头试试。

使用特权

评论回复
7
q1d0mnx| | 2021-11-11 12:14 | 只看该作者
步骤很详细,研究研究

使用特权

评论回复
8
renzheshengui| | 2021-12-6 11:26 | 只看该作者
这个非常实用啊

使用特权

评论回复
9
keaibukelian| | 2021-12-6 11:28 | 只看该作者
考虑的非常周全啊

使用特权

评论回复
10
labasi| | 2021-12-6 11:31 | 只看该作者
和实际的相符吗

使用特权

评论回复
11
paotangsan| | 2021-12-6 11:37 | 只看该作者
这个函数是自己写的还是库函数啊

使用特权

评论回复
12
tpgf| | 2021-12-6 11:52 | 只看该作者
非常简便的方法

使用特权

评论回复
13
wakayi| | 2021-12-6 11:55 | 只看该作者
如果占用率很大 就跑不起来吧

使用特权

评论回复
14
moticsoft| | 2021-12-6 22:12 | 只看该作者
有机会试试

使用特权

评论回复
15
xxxt| | 2022-3-4 16:19 | 只看该作者
Mark!

使用特权

评论回复
16
AloneKaven| | 2022-10-7 20:22 | 只看该作者
得到的数据准确吗

使用特权

评论回复
17
Pulitzer| | 2022-10-9 08:05 | 只看该作者

一种了解状态变化的简单方法

使用特权

评论回复
18
Uriah| | 2022-10-9 15:06 | 只看该作者

多次检查也会给单片机带来负荷,对功耗不利

使用特权

评论回复
19
Bblythe| | 2022-10-9 18:05 | 只看该作者

在掌握对象的变化频度时是有效的

使用特权

评论回复
20
SantaBunny| | 2023-2-13 16:25 | 只看该作者
占用率很大 就跑不起来的吧

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

36

主题

282

帖子

0

粉丝