FreeRTOS学习笔记(11)——CPU使用率统计
一、基本概念
CPU 使用率其实就是系统运行的程序占用的 CPU 资源,表示机器在某段时间程序运行的情况,如果这段时间中,程序一直在占用 CPU 的使用权,那么可以人为 CPU 的利用率是 100%。CPU 的利用率越高,说明机器在这个时间上运行了很多程序,反之较少。利用率的高低与 CPU 强弱有直接关系,就像一段一模一样的程序,如果使用运算速度很慢的 CPU,它可能要运行 1000ms,而使用很运算速度很快的 CPU 可能只需要 10ms,那么在 1000ms 这段时间中,前者的 CPU 利用率就是 100%,而后者的 CPU 利用率只有 1%,因为 1000ms 内前者都在使用 CPU 做运算,而后者只使用 10ms 的时间做运算,剩下的时间 CPU 可以做其他事情。
FreeRTOS 是多任务操作系统,对 CPU 都是分时使用的:比如 A 任务占用 10ms,然后 B 任务占用 30ms,然后空闲 60ms,再又是 A 任务占 10ms,B 任务占 30ms,空闲 60ms;
二、CPU利用率统计
在调试的时候很有必要得到当前系统的 CPU 利用率相关信息,但是在产品发布的时候,就可以把 CPU 利用率统计这个功能去掉,因为使用任何功能的时候,都是需要消耗系统资源的,FreeRTOS 是使用一个外部的变量进行统计时间的,并且消耗一个高精度的定时器,其用于定时的精度是系统时钟节拍的 10-20 倍,比如当前系统时钟节拍是 1000HZ,那么定时器的计数节拍就要是 10000-20000HZ。而且 FreeRTOS 进行 CPU 利用率统计的时候,也有一定缺陷,因为它没有对进行 CPU 利用率统计时间的变量做溢出保护,我们使用的是 32 位变量来系统运行的时间计数值,而按 20000HZ 的中断频率计算,每进入一中断就是 50us,变量加一,最大支持计数时间:2^32 * 50us / 3600s = 59.6 分钟,运行时间超过了 59.6 分钟后统计的结果将不准确,除此之外整个系统一直响应定时器 50us 一次的中断会比较影响系统的性能。
三、配置选项
在 FreeRTOSConfig.h
配置与系统运行时间和任务状态收集有关的配置选项,并且实现
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
与 portGET_RUN_TIME_COUNTER_VALUE()
这两个宏定义
/********************************************************************
FreeRTOS 与运行时间和任务状态收集有关的配置选项
**********************************************************************/
//启用运行时间统计功能
#define configGENERATE_RUN_TIME_STATS 1
//启用可视化跟踪调试
#define configUSE_TRACE_FACILITY 1
/* 与宏 configUSE_TRACE_FACILITY 同时为 1 时会编译下面 3 个函数
* prvWriteNameToBuffer()
* vTaskList(),
* vTaskGetRunTimeStats()
*/
#define configUSE_STATS_FORMATTING_FUNCTIONS 1extern volatile uint32_t CPU_RunTime; #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (CPU_RunTime = 0ul)
#define portGET_RUN_TIME_COUNTER_VALUE() CPU_RunTime
然后需要实现一个中断频率为 20000HZ 定时器,用于系统运行时间统计,其实很简单,只需将 CPU_RunTime 变量自加即可,这个变量是用于记录系统运行时间的,中断服务函数见下
/* 用于统计运行时间 */
volatile uint32_t CPU_RunTime = 0UL;void BASIC_TIM_IRQHandler (void)
{if(TIM_GetITStatus( BASIC_TIM, TIM_IT_Update) != RESET ) {CPU_RunTime++; TIM_ClearITPendingBit(BASIC_TIM , TIM_FLAG_Update);}
}
然后我们就可以在任务中调用 vTaskGetRunTimeStats()
和 vTaskList()
函数获得任务的相关信息与 CPU 使用率的相关信息,然后打印出来即可
memset(CPU_RunInfo,0,400); //信息缓冲区清零vTaskList((char *)&CPU_RunInfo); //获取任务运行时间信息 printf("---------------------------------------------\r\n");
printf("任务名 任务状态 优先级 剩余栈 任务序号\r\n");
printf("%s", CPU_RunInfo);
printf("---------------------------------------------\r\n");memset(CPU_RunInfo,0,400); //信息缓冲区清零vTaskGetRunTimeStats((char *)&CPU_RunInfo); printf("任务名 运行计数 使用率\r\n");
printf("%s", CPU_RunInfo);
printf("---------------------------------------------\r\n\n");
四、示例
/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"
/* 开发板硬件bsp头文件 */
#include "bsp_led.h"
#include "bsp_usart.h"
#include "bsp_TiMbase.h"
#include "string.h"/**************************** 任务句柄 ********************************/
/* * 任务句柄是一个指针,用于指向一个任务,当任务创建好之后,它就具有了一个任务句柄* 以后我们要想操作这个任务都需要通过这个任务句柄,如果是自身的任务操作自己,那么* 这个句柄可以为NULL。*//* 创建任务句柄 */
static TaskHandle_t AppTaskCreate_Handle = NULL;
/* LED任务句柄 */
static TaskHandle_t LED1_Task_Handle = NULL;
static TaskHandle_t LED2_Task_Handle = NULL;
static TaskHandle_t CPU_Task_Handle = NULL;/*
*************************************************************************
* 函数声明
*************************************************************************
*/
static void AppTaskCreate(void);/* 用于创建任务 */static void LED1_Task(void* pvParameters);/* LED1_Task任务实现 */
static void LED2_Task(void* pvParameters);/* LED2_Task任务实现 */
static void CPU_Task(void* pvParameters);/* CPU_Task任务实现 */
static void BSP_Init(void);/* 用于初始化板载相关资源 *//****************************************************************** @brief 主函数* @param 无* @retval 无* @note 第一步:开发板硬件初始化 第二步:创建APP应用任务第三步:启动FreeRTOS,开始多任务调度****************************************************************/
int main(void)
{ BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS *//* 开发板硬件初始化 */BSP_Init();/* 创建AppTaskCreate任务 */xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* 任务入口函数 */(const char* )"AppTaskCreate",/* 任务名字 */(uint16_t )512, /* 任务栈大小 */(void* )NULL,/* 任务入口函数参数 */(UBaseType_t )1, /* 任务的优先级 */(TaskHandle_t* )&AppTaskCreate_Handle);/* 任务控制块指针 */ /* 启动任务调度 */ if(pdPASS == xReturn){vTaskStartScheduler(); /* 启动任务,开启调度 */}else{return -1; }while(1); /* 正常不会执行到这里 */
}/************************************************************************ @ 函数名 : AppTaskCreate* @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面* @ 参数 : 无 * @ 返回值 : 无**********************************************************************/
static void AppTaskCreate(void)
{BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */taskENTER_CRITICAL(); //进入临界区/* 创建LED_Task任务 */xReturn = xTaskCreate((TaskFunction_t )LED1_Task, /* 任务入口函数 */(const char* )"LED1_Task",/* 任务名字 */(uint16_t )512, /* 任务栈大小 */(void* )NULL, /* 任务入口函数参数 */(UBaseType_t )2, /* 任务的优先级 */(TaskHandle_t* )&LED1_Task_Handle);/* 任务控制块指针 */if(pdPASS == xReturn){printf("创建LED1_Task任务成功!\r\n");}/* 创建LED_Task任务 */xReturn = xTaskCreate((TaskFunction_t )LED2_Task, /* 任务入口函数 */(const char* )"LED2_Task",/* 任务名字 */(uint16_t )512, /* 任务栈大小 */(void* )NULL, /* 任务入口函数参数 */(UBaseType_t )3, /* 任务的优先级 */(TaskHandle_t* )&LED2_Task_Handle);/* 任务控制块指针 */if(pdPASS == xReturn){printf("创建LED2_Task任务成功!\r\n");}/* 创建LED_Task任务 */xReturn = xTaskCreate((TaskFunction_t )CPU_Task, /* 任务入口函数 */(const char* )"CPU_Task",/* 任务名字 */(uint16_t )512, /* 任务栈大小 */(void* )NULL, /* 任务入口函数参数 */(UBaseType_t )4, /* 任务的优先级 */(TaskHandle_t* )&CPU_Task_Handle);/* 任务控制块指针 */if(pdPASS == xReturn){printf("创建CPU_Task任务成功!\r\n");}vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务taskEXIT_CRITICAL(); //退出临界区
}/*********************************************************************** @ 函数名 : LED_Task* @ 功能说明: LED_Task任务主体* @ 参数 : * @ 返回值 : 无********************************************************************/
static void LED1_Task(void* parameter)
{ while (1){LED1_ON;vTaskDelay(500); /* 延时500个tick */printf("LED1_Task Running,LED1_ON\r\n");LED1_OFF; vTaskDelay(500); /* 延时500个tick */ printf("LED1_Task Running,LED1_OFF\r\n");}
}static void LED2_Task(void* parameter)
{ while (1){LED2_ON;vTaskDelay(300); /* 延时500个tick */printf("LED2_Task Running,LED2_ON\r\n");LED2_OFF; vTaskDelay(300); /* 延时500个tick */ printf("LED2_Task Running,LED2_OFF\r\n");}
}static void CPU_Task(void* parameter)
{ uint8_t CPU_RunInfo[400]; //保存任务运行时间信息while (1){memset(CPU_RunInfo,0,400); //信息缓冲区清零vTaskList((char *)&CPU_RunInfo); //获取任务运行时间信息printf("---------------------------------------------\r\n");printf("任务名 任务状态 优先级 剩余栈 任务序号\r\n");printf("%s", CPU_RunInfo);printf("---------------------------------------------\r\n");memset(CPU_RunInfo,0,400); //信息缓冲区清零vTaskGetRunTimeStats((char *)&CPU_RunInfo);printf("任务名 运行计数 利用率\r\n");printf("%s", CPU_RunInfo);printf("---------------------------------------------\r\n\n");vTaskDelay(1000); /* 延时500个tick */ }
}/************************************************************************ @ 函数名 : BSP_Init* @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面* @ 参数 : * @ 返回值 : 无*********************************************************************/
static void BSP_Init(void)
{/** STM32中断优先级分组为4,即4bit都用来表示抢占优先级,范围为:0~15* 优先级分组只需要分组一次即可,以后如果有其他的任务需要用到中断,* 都统一用这个优先级分组,千万不要再分组,切忌。*/NVIC_PriorityGroupConfig( NVIC_PriorityGroup_4 );/* LED 初始化 */LED_GPIO_Config();/* 串口初始化 */USART_Config();/* 基本定时器初始化 */BASIC_TIM_Init();
}
• 由 Leung 写于 2021 年 1 月 5 日
• 参考:野火FreeRTOS视频与PDF教程
FreeRTOS学习笔记(11)——CPU使用率统计相关推荐
- freeRtos学习笔记 (9) 移植和CPU利用率统计
freeRtos学习笔记 (9) 移植和CPU利用率统计 使用官方固件移植 首先准备一个能跑的裸机工程 注意,freertos需要使用systick定时器,而stm32HAL库默认使用systick作 ...
- FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析
FreeRtos学习笔记(11)查找就绪任务中优先级最高任务原理刨析 怎么查找就绪任务中优先级最高的? tasks.c中声明了一个全局变量 uxTopReadyPriority,任务从其他状态进入就绪 ...
- 1、野火freertos学习笔记
野火freertos学习笔记 1.任务 1.1 栈 1.2 任务的切换 taskYIELD(); 1.3 临界段 2.空闲任务 3.任务优先级 4.任务延时的表现 5.时间片 5.1抢占式.协做式 6 ...
- FreeRTOS学习笔记
FreeRTOS学习笔记 (这是我自己学习FreeRTOS整理的笔记,仅供参考) 第一部分:实现FreeRTOS内核 变量名: 定义变量时往往会把变量的类型当作前缀加在变量上 变量类型 前缀 char ...
- FreeRTOS学习笔记20200526
FreeRTOS学习笔记-Day1-20200526 nFlag = TRUE; 先立个Flag,是时候点亮嵌入式实时操作系统这个技能了.座右铭:坚持.认真.沉静.笃行. FreeRTOS优势 总结F ...
- freeRtos学习笔记 (6)软件定时器
freeRtos学习笔记 freeRtos软件定时器 软件定时器需要注意事项 软件定时器的精度基于时钟节拍,例如系统时钟节拍为10ms, 软件定时器定时时间必须是10ms的整数倍,因此软件定时器一般用 ...
- Hadoop学习笔记—11.MapReduce中的排序和分组
Hadoop学习笔记-11.MapReduce中的排序和分组 一.写在之前的 1.1 回顾Map阶段四大步骤 首先,我们回顾一下在MapReduce中,排序和分组在哪里被执行: 从上图中可以清楚地看出 ...
- 点云学习笔记11——VoxelNet算法+代码运行
点云学习笔记11--VoxelNet算法+代码运行 一.算法分析 摘要 介绍 相关工作 1.2. 贡献 2.VoxelNet 2.1.特征学习网络 2.1.1 特征学习网络 二.代码复现 2.1.环境 ...
- SpringMVC:学习笔记(11)——依赖注入与@Autowired
SpringMVC:学习笔记(11)--依赖注入与@Autowired 使用@Autowired 从Spring2.5开始,它引入了一种全新的依赖注入方式,即通过@Autowired注解.这个注解允许 ...
- freeRtos学习笔记 (8) 任务通知
freeRtos学习笔记 freeRtos任务通知 任务通知的优缺点 freeRtos任务控制块中包含两个32位的变量,用于任务通知,在一些情况下,任务通知可以替代信号量和事件组,并且比信号量和事件组 ...
最新文章
- opencv-python之机器视觉
- C语言博客作业--嵌套循环
- Java Web 之Token+Cookie+Session
- php access allow,PHP标头不适用于Access-Control-Allow-Origin
- 微软游戏开发工具XNA 2.0[转自驱动之家]
- C语言课后习题(37)
- git clone 添加代理_用树莓派3搭建私有git代码仓库
- JavaScript之子类构建工具
- php onchange,将PHP变量传递给ONCHANGE事件上的javascript
- window10设置文件夹备注
- uniapp 发布网站遇到的问题(跨域,nginx代理失败,index无法打开,手机端无法访问等)
- python实现带头结点的单链表的就地逆置_带头结点的单链表就地逆置 (10 分)...
- FileNet小错误汇总
- 计算机控制系统在电厂的应用,计算机控制系统在电厂中的应用.doc
- code review流程规范
- Window取消快捷方式箭头(脚本方式)
- Qt QSetting 读写ini配置文件(简单明了,多图)
- python中用于绘制各种图形、标注文本_在python中的图形上绘制常量文本-问答-阿里云开发者社区-阿里云...
- 贪心——绝对值不等式——货仓选址
- 免费cocos2dx3.x视频教程