zoukankan      html  css  js  c++  java
  • 统计任务的真正运行原理《转载》

    在百度里看到张连聘文章,对ucos的两个系统任务分析的很恰当,就是最后边一段观点我不太认同,在此非常感谢张连聘。

    先把ucosii中的原文写在这,然后再说一下我的具体理解(下面有我的理解部分)。

    我觉得这篇文章对ucos的两个系统任务分析的很恰当,就是最后边一段观点我不太认同,在此非常感谢张连聘。

    先把ucosii中的原文写在这,然后再说一下我的具体理解。

    μC/OS-Ⅱ有一个提供运行时间统计的任务。这个任务叫做OS_TaskStat(),如果用户将系统定义常数OS_TASK_STAT_EN(见文件OS_CFG.H)设为1,这个任务就会建立。一旦得到了允许,OS_TaskStat()每秒钟运行一次(见文件OS_CORE.C),计算当前的CPU利用率。换句话说,OS_TaskStat()告诉用户应用程序使用了多少CPU时间,用百分比表示,这个值放在一个有符号8位整数OSCPUsage中,精读度是1个百分点。

     如果用户应用程序打算使用统计任务,用户必须在初始化时建立一个唯一的任务,在这个任务中调用OSStatInit()。换句话说,在调用系统启动函数OSStart()之前,用户初始代码必须先建立一个任务,在这个任务中调用系统统计初始化函数OSStatInit(),然后再建立应用程序中的其它任务。程序清单L3.12是统计任务的示意性代码。

    程序清单 L3.12 初始化统计任务.

       

    Void main (void)

     {

        OSInit();

        OSStart();

      }

       Void TaskStart (void *pdata)

       {

        OSStatInit();

        for (;;) {

       }

     }

     因为用户的应用程序必须先建立一个起始任务[TaskStart()],当主程序main()调用系统启动函数OSInit()的时候,μC/OS-Ⅱ只有3个要管理的任务:TaskStart()、OSTaskIdle()和OS_TaskStat()。请注意,任务TaskStart()的名称是无所谓的,叫什么名字都可以。因为μC/OS-Ⅱ已经将空闲任务的优先级设为最低,即OS_LOWEST_PR10,统计任务的优先级设为次低,OS_LOWEST_PR10减1。启动任务TaskStart()总是优先级最高的任务。

     图F3.4解释初始化统计任务时的流程。用户必须首先调用的是μC/OS-Ⅱ中的系统初始化函数OSInit(),该函数初始化μC/OS-Ⅱ[图F3.4(2)]。有的处理器(例如Motorola的MC68HC11),不需要“设置”中断向量,中断向量已经在ROM中有了。用户必须调用OSTaskCreat()或者OSTaskCreatExt()以建立TaskStart()[图F3.4(3)]。进入多任务的条件准备好了以后,调用系统启动函数OSStart()。这个函数将使TaskStart()开始执行,因为TaskStart()是优先级最高的任务[图F3.4(4)]]。

    TaskStart()负责初始化和启动时钟节拍[图F3.4(5)]。在这里启动时钟节拍是必要的,因为用户不会希望在多任务还没有开始时就接收到时钟节拍中断。接下去TaskStart()调用统计初始化函数OSStatInit()[图F3.4(6)]。统计初始化函数OSStatInit()决定在没有其它应用任务运行时,空闲计数器(OSIdleCtr)的计数有多快。奔腾II微处理器以333MHz运行时,加1操作可以使该计数器的值达到每秒15,000,000次。OSIdleCtr的值离32位计数器的溢出极限值4,294,967,296还差得远。微处理器越来越快,用户要注意这里可能会是将来的一个潜在问题。

     系统统计初始化任务函数OSStatInit()调用延迟函数OSTimeDly()将自身延时2个时钟节拍以停止自身的运行[图F3.4(7)]。这是为了使OSStatInit()与时钟节拍同步。μC/OS-Ⅱ然后选下一个优先级最高的进入就绪态的任务运行,这恰好是统计任务OSTaskStat()。读者会在后面读到OSTaskStat()的代码,但粗看一下,OSTaskStat()所要做的第一件事就是查看统计任务就绪标志是否为“假”,如果是的话,也要延时两个时钟节拍[图F3.4(8)]。一定会是这样,因为标志OSStatRdy已被OSInit()函数初始化为“假”,所以实际上DSTaskStat也将自己推入休眠态(Sleep)两个时钟节拍[图F3.4(9)]。于是任务切换到空闲任务,OSTaskIdle()开始运行,这是唯一一个就绪态任务了。CPU处在空闲任务OSTaskIdle中,直到TaskStart()的延迟两个时钟节拍完成[图3.4(10)]。两个时钟节拍之后,TaskStart()恢复运行[图F3.4(11)]。 在执行OSStartInit()时,空闲计数器OSIdleCtr被清零[图F3.4(12)]。然后,OSStatInit()将自身延时整整一秒[图F3.4(13)]。因为没有其它进入就绪态的任务,OSTaskIdle()又获得了CPU的控制权[图F3.4(14)]。一秒钟以后,TaskStart()继续运行,还是在OSStatInit()中,空闲计数器将1秒钟内计数的值存入空闲计数器最大值OSIdleCtrMax中[图F3.4(15)]。

    OSStarInit()将统计任务就绪标志OSStatRdy设为“真”[图F3.4(16)],以此来允许两个时钟节拍以后OSTaskStat()开始计算CPU的利用率。

    统计任务的初始化函数OSStatInit()的代码如程序清单 L3.13所示。

     程序清单 L3.13 统计任务的初始化.

    void OSStatInit (void)

      {

       

         OSTimeDly(2);

        OS_ENTER_CRITICAL();

        OSIdleCtr = 0L;

        OS_EXIT_CRITICAL();

        OSTimeDly(OS_TICKS_PER_SEC);

        OS_ENTER_CRITICAL();

        OSIdleCtrMax = OSIdleCtr;

        OSStatRdy = TRUE;

        OS_EXIT_CRITICAL();

      }

       

    统计任务OSStat()的代码程序清单L3.14所示。在前面一段中,已经讨论了为什么要等待统计任务就绪标志OSStatRdy[L3.14(1)]。这个任务每秒执行一次,以确定所有应用程序中的任务消耗了多少CPU时间。当用户的应用程序代码加入以后,运行空闲任务的CPU时间就少了,OSIdleCtr就不会像原来什么任务都不运行时有那么多计数。要知道,OSIdleCtr的最大计数值是OSStatInit()在初始化时保存在计数器最大值OSIdleCtrMax中的。CPU利用率(表达式[3.1])是保存在变量OSCPUsage[L3.14(2)]中的:

    [3.1]表达式Need to typeset the equation.

    一旦上述计算完成,OSTaskStat()调用任务统计外界接入函数OSTaskStatHook() [L3.14(3)],这是一个用户可定义的函数,这个函数能使统计任务得到扩展。这样,用户可以计算并显示所有任务总的执行时间,每个任务执行时间的百分比以及其它信息(参见1.09节例3)。

     程序清单 L3.14 统计任务

       

    void OSTaskStat (void *pdata)

       {

        INT32U run;

        INT8S usage;

       pdata = pdata;

        while (OSStatRdy == FALSE) { (1)

        OSTimeDly(2 * OS_TICKS_PER_SEC);

        }

     for (;;) {

        OS_ENTER_CRITICAL();

        OSIdleCtrRun = OSIdleCtr;

        run = OSIdleCtr;

       OSIdleCtr = 0L;

        OS_EXIT_CRITICAL();

        if (OSIdleCtrMax > 0L) {

       usage = (INT8S)(100L - 100L * run / OSIdleCtrMax); (2)

        if (usage > 100) {

        OSCPUUsage = 100;

        } else if (usage < 0) {

        OSCPUUsage = 0;

       } else {

        OSCPUUsage = usage;

        }

     } else {

     OSCPUUsage = 0;

       }

        OSTaskStatHook(); (3)

        OSTimeDly(OS_TICKS_PER_SEC);

        }

       }

       

    还是先仔细看看源码,这样有利于你搞明白统计任务的实现原理和应用方法。

    下面我说一下我个人的理解:

    统计任务的实现原理大致上是这样的,一开始统计任务要初始化,主要是保证μC/OS-Ⅱ的空闲任务准时运行1s的时间。我们看看这个任务都干些什么。

    void OSTaskIdle (void *pdata)

       {

        pdata = pdata;

        for (;;) {

        OS_ENTER_CRITICAL();

        OSIdleCtr++;

        OS_EXIT_CRITICAL();

        }

       }

    这个任务其实就是给一个OSIdleCtr这个变量加一。这样在保证空闲任务运行1s的时间内,就把1s内空闲任务中OSIdleCtr变量达到此次开机的最大值。而且在初始化统计任务中把这个变量的值赋给了OSIdleCtrMax 这个变量。如果不重启的话,这个值是不变的。用这个值来算以后有了其他任务时cpu的利用率。具体怎么实现的计算和怎么实现的一开始让空闲任务运行1s的。可以看上面的源码。其中,我用红色字体标出的,我认为应该是2分钟。看源码就会知道。

    至于,启动多任务之后,统计任务如何计算cpu利用率的,关于书上说的统计任务每秒执行一次的问题,我认为这种说法不对,统计任务并不是每秒运行一次,大家可以想一想,统计任务执行到最后时是OSTimeDly(OS_TICKS_PER_SEC);这样一个函数。表示延迟一分钟。而只有统计任务延时时空闲任务才有可能运行,所以每当统计任务运行时OSIdleCtr的值都是在可能的1s内记的数。因为在统计任务在赋完值之后清零了。所以说,统计任务不是1s运行一次,只不过统计任务运行时用到的变量都是在1s内的数据。所以,用统计任务可以统计cpu利用率。

  • 相关阅读:
    Linux 下的类似Windows下Everything的搜索工具
    windows和linux环境下制作U盘启动盘
    程序调试手段之gdb, vxworks shell
    LeetCode 1021. Remove Outermost Parentheses (删除最外层的括号)
    LeetCode 1047. Remove All Adjacent Duplicates In String (删除字符串中的所有相邻重复项)
    LeetCode 844. Backspace String Compare (比较含退格的字符串)
    LeetCode 860. Lemonade Change (柠檬水找零)
    LeetCode 1221. Split a String in Balanced Strings (分割平衡字符串)
    LeetCode 1046. Last Stone Weight (最后一块石头的重量 )
    LeetCode 746. Min Cost Climbing Stairs (使用最小花费爬楼梯)
  • 原文地址:https://www.cnblogs.com/locean/p/5424992.html
Copyright © 2011-2022 走看看