[RT-Thread]CPU利用率统计

1.CPU利用率的基本概念
CPU使用率其实就是系统运行的程序占用的CPU资源,表示机器在某段时间程序运行的情况,如果这段时间中,程序一 直在占用CPU的使用权,那么可以认为CPU的利用率是100%。

CPU的利用率越高,说明机器在这个时间上运行了很多程序,反之较少。利用率的高低与CPU强弱有直接关系,就像一段一模一样的程序,如果使用运算速度很慢的CPU,它可能要运行1000ms,而使用很运算速度很快的CPU可能只需要10ms,那么在1000ms这段时间中,前者的CPU利用率就 是100%,而后者的CPU利用率只有1%,因为1000ms内前者都在使用CPU做运算,而后者只使用10ms的时间做运算, 剩下的时间CPU可以做其他事情。

RT-Thread是多线程操作系统,对 CPU 都是分时使用的:比如A进程占用10ms,然后B进程占用30ms,然后空闲60ms,再又是A进程占10ms,B进程占30ms,空闲60ms;如果在一段时间内都是如此,那么这段时间内的利用率为40%,因为整个系统中只有40%的时间是CPU处理数据的时间。

2. CPU利用率的作用
一个系统设计的好坏,可以使用CPU使用率来衡量,一个好的系统必然是能完美响应急需的处理,并且系统的资源不会过于浪费(性价比高)

作为产品的设计,既不能让资源过于浪费,也不能让资源过于紧迫, 这种设计才是完美的,在需要的时候能及时处理完突发事件,而且资源也不会过剩,性价比更高。

3. CPU利用率统计
RT-Thread给我们提供一个CPU统计的代码文件,该代码并非RT-Thread内核资源,只是利用RT-Thread中空闲线程来统计CPU的利用率,实现的算法原理很简单,在RT-Thread的空闲线程计算出在一段时间内处于空闲线程的时间,就知 道CPU在有效干活的时间,从而得到CPU的利用率。

4.代码实现
创建一个与cpuusage.c源码文件对应的头文件cpuusage.h,目的是为了声明cpuusage.c文件中对 外提供的函数接口,方便调用这些函数

#ifndef __CPUUSAGE_H__
#define __CPUUSAGE_H__

#include <rtthread.h>
#include <rthw.h>

/*获取CPU利用率*/
void cpu_usage_init(void);
void cpu_usage_get(rt_uint8_t *major, rt_uint8_t *minor);

#endif

使用cpuusage.c文件提供的函数来统计我们的CPU利用率了。

#include <rtthread.h>
#include <rthw.h>
#include "cpuusage.h"

#define CPU_USAGE_CALC_TICK   1000
#define CPU_USAGE_LOOP        100

static rt_uint8_t cpu_usage_major = 0, cpu_usage_minor = 0;
static rt_uint32_t total_count = 0;

static void cpu_usage_idle_hook()
{
    rt_tick_t tick;
    rt_uint32_t count;
    volatile rt_uint32_t loop;
    // 1.在第一次进入该函数的时候,total_count 为0,那么就在指定的时间段中CPU全速运算,
    // 看看能将total_count加一运算加到多大,并以total_count的值作为CPU利用率100%的运算标准。
    if(total_count == 0){
        /*get total count*/
        //2.进入临界段,不响应中断,CPU全速运行。
        rt_enter_critical();
        //3.获取当前时间tick,也就是作为运算起始的时间点。
        tick = rt_tick_get();
        while (rt_tick_get() - tick < CPU_USAGE_CALC_TICK){
            // 4.在一个相对时间 rt_tick_get() - tick < CPU_USAGE_CALC_TICK 里面,循环将total_count自加,
            // CPU_USAGE_CALC_TICK的大小由宏定义指定,用户可以修改其值,我们以1000个tick作为计算。
            // 时间到达之后,退出循环,我们也得到一个CPU全速运算的值total_count。
            total_count++;
            loop = 0;
        while (loop < CPU_USAGE_LOOP) loop++;
        }
    rt_exit_critical();
    }   

    count = 0;                                                          
    /*get CPU usage*/
    /* 5.获取当前时间tick,也就是作为运算起始的时间点,
       这个获取当前系统时间是为了计算在指定的CPU_USAGE_CALC_TICK相对时间内,计算空闲任务占到的相对时间。*/
    tick = rt_tick_get();
    while(rt_tick_get - tick < CPU_USAGE_CALC_TICK){
        /* 6.不进入临界段的count自加,可能count的运算会被系统其它任务或中断打断,这样子的运算我称之为空闲的CPU运算,只在空闲时间占用CPU,
         因为空闲线程是永远处于运行的,而空闲任务是可以被我们粗略认为是做无用功的,CPU没有被利用上。*/
        count++;
        loop = 0;
        while (loop < CPU_USAGE_LOOP) loop++;
    }

    /*calculate major and minor*/
    /*7.假设在CPU全速运行的时候,total_count自加到100,而在有线程运行的时候,空 闲线程是不能获得CPU的使用权,那么自然count也无法一直自加,所以count的值往往是比total_count要小的,
    假设某段时间count的值为80,那么我们可以认为空闲线程占了系统的80%CPU所使用权,
    其他线程占用了 20%,而这20%是有用的,所以可以看做CPU的利用率是20%,
    按照这个思想,将得到某个相对时间段中CPU的利 用率,CPU利用率的结果将保留两位小数,
    cpu_usage_major是CPU利用率的整数部分,cpu_usage_minor是 CPU利用率的小数部分。*/
    if (count < total_count) {
        count = total_count - count;
        cpu_usage_major = (count * 100) / total_count;
        cpu_usage_minor = ((count * 100)%total_count) * 100 / total_count;
    } else {
        /*8.如果count的值大于等于total_count的值,
        那么就说明了这段时间CPU没有处理 其他事情,基本都在空闲线程中做运算。*/
        total_count = count;
        /*no CPU usage*/
        cpu_usage_major = 0;
        cpu_usage_minor = 0;
    }
}

void cpu_usage_get(rt_uint8_t *major, rt_uint8_t *minor)
{
    RT_ASSERT(major != RT_NULL);
    RT_ASSERT(minor != RT_NULL);
    /*9.获取CPU利用率,并保存在传入的参数中。*/
    *major = cpu_usage_major;
    *minor = cpu_usage_minor;
}

void cpu_usage_init()
{
    /*设置空闲线程钩子函数*/
    /*10.CPU利用率统计的初始化函数,设置空闲线程钩子函数,让空闲线程能调用到空闲钩子 函数,从而能进行CPU利用率的统计。*/
    rt_thread_idle_sethook(cpu_usage_idle_hook);
}

CPU利用率实验是是在RT-Thread中创建了两个线程,其中一个线程是模拟占用CPU,另一个线程用于获取CPU利用率并 通过串口打印出来。

/*************************************************************************
*                             包含的头文件
*************************************************************************/
#include "board.h"
#include "rtthread.h"

/*************************************************************************
*                               变量
*************************************************************************/
/*定义线程控制块*/
static rt_thread_t led1_thread = RT_NULL;
static rt_thread_t get_cpu_use_thread = RT_NULL;


/*************************************************************************
*                             函数声明
*************************************************************************/
static void led1_thread_entry(void* parameter);
static void get_cpu_use_thread_entry(void* parameter);


/*************************************************************************
*                             main 函数
*************************************************************************/
int main(void)
{
    /*
    * 开发板硬件初始化,RTT系统初始化已经在main函数之前完成,
    * 即在component.c文件中的rtthread_startup()函数中完成了。
    * 所以在main函数中,只需要创建线程和启动线程即可。
    */
   rt_kprintf("这是一个[野火]-STM32全系列开发板-RTT-CPU利用率统计实验\r\n");

   led1_thread =        /* 线程控制块指针 */ 
                rt_thread_creat("led1", /* 线程名字 */
                                led1_thread_entry,/* 线程入口函数 */
                                RT_NULL, /* 线程入口函数参数 */
                                512,     /* 线程栈大小 */
                                3,       /* 线程的优先级 */
                                20);     /* 线程时间片 */
    /*启动线程,开启调度*/
    if(led1_thread != RT_NULL)
            rt_thread_startup(led1_thread);
    else
        return -1;

    get_cpu_use_thread =  /* 线程控制块指针 */
                        rt_thread_create("get_cpu_use",/* 线程名字 */
                                        get_cpu_use_thread_entry;/* 线程入口函数 */
                                        RT_NULL,/* 线程入口函数参数 */
                                        512,/* 线程栈大小 */
                                        5,/* 线程的优先级 */
                                        20);  /* 线程时间片 */
    /* 启动线程,开启调度 */
    if(get_cpu_use_thread != RT_NULL)
            rt_thread_startup(get_cpu_use_thread);
    else
        return -1;
}

/*************************************************************************
*                             线程定义
*************************************************************************/
static void led1_thread_entry(void * parameter)
{
    rt_uint16_t i;

    while(1){
        LED_TOGGLE;
    /* 模拟占用CPU资源,修改数值作为模拟测试 */
    for(i = 0; i < 10000; i++);
        rt_thread_delay(5);/* 延时5个tick */
    }
}


static void led1_thread_entry(void * parameter)
{
    rt_uint8_t major, minor;

    while(1){
      /* 获取CPU利用率数据 */
        cpu_usage_get(&major,&minor);
    /* 打印CPU利用率 */
        rt_kprintf("CPU利用率 = %d.%d%\r\n",major,minor);

        rt_thread_delay(1000);   /* 延时1000个tick */

    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值