zoukankan      html  css  js  c++  java
  • 【STM32F429】第16章 ThreadX原装任务统计分析功能实现(含IAR的ThreadX插件使用)

    论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514

    第16章       ThreadX原装任务统计分析功能实现(含IAR的ThreadX插件使用)

    本章节为大家讲解ThreadX原装任务统计分析功能的实现,支持MDK,IAR和GCC。

    16.1 ThreadX的任务统计分析实现原理

    16.2 ThreadX的任务统计分析功能移植

    16.3 IAR的ThreadX插件实现

    16.4 实验例程说明

    16.5 总结

    16.1 ThreadX的任务统计分析实现原理

    对于Cortex-M内核,带有DWT时钟周期计数器,比如芯片主频是100MHz,那么DWT统计的时钟周期分辨率就是10ns。

    ThreadX就是借助此功能实现任务统计分析,使用简单,仅需使能就可以使用。M3,M4和M7内核都带这个功能,而M0内核不带,使用中要注意。

    16.2 ThreadX的任务统计分析功能移植

    这里以移植到MDK为例进行说明,其它IAR,GCC的移植方法是一样的。

    16.2.1        添加任务分析代码

    从ThreadX 内核V6.1.7版本开始,加入了任务统计分析功能,位于源码软件包的如下路径:

    ThreadXutilityexecution_profile_kit 。

     

    按照前面章节的移植方法,升级ThreadX内核的版本到V6.1.7后,添加此文件即可。

     

    别忘了添加相应路径:

     

    16.2.2        设置宏定义

    C文件要添加宏定义:TX_EXECUTION_PROFILE_ENABLE, TX_CORTEX_M_EPK

     

    汇编文件要添加宏定义:TX_EXECUTION_PROFILE_ENABLE,TX_ENABLE_EXECUTION_CHANGE_NOTIFY

     

    对于MDK AC5,Misc Controls加上 –cpreproc

    16.2.3        使能DWT时钟周期计时器

    默认情况下,ThreadX的移植文件tx_initialize_low_level.s带了DWT时钟周期计数器的使能:

        /* Enable the cycle count register.  */
    
        LDR     r0, =0xE0001000                         ; Build address of DWT register
        LDR     r1, [r0]                                ; Pickup the current value
        ORR     r1, r1, #1                              ; Set the CYCCNTENA bit
    STR     r1, [r0]                                ; Enable the cycle count register

    保险起见,在bsp.c文件也调用了函数bsp_InitDWT()做初始化。

    16.2.4        展示任务统计方法

    Threadx提供了三个64bit的全局变量统计时间信息,单位是系统时钟计数器,比如主频是100MHz,那么单位就是10ns。

    •   _tx_execution_thread_time_total

    统计从上电开始,所有任务总的运行时间。

    •   _tx_execution_idle_time_total

    统计从上电开始,总的空闲时间。

    •   _tx_execution_isr_time_total

    统计从上电开始,中断服务程序总的执行实现。

    为了方便统计CPU利用率,可以采用:

    _tx_execution_thread_time_total/(_tx_execution_thread_time_total + _tx_execution_idle_time_total + _tx_execution_isr_time_total)

    但这种统计不能反应CPU利用率瞬时变化,所以做了一个瞬时的统计方法,每200ms统计一次:

    /*
    *********************************************************************************************************
    *    函 数 名: AppTaskStart
    *    功能说明: 启动任务。
    *    形    参: thread_input 是在创建该任务时传递的形参
    *    返 回 值: 无
        优 先 级: 2
    *********************************************************************************************************
    */
    static  void  AppTaskStart (ULONG thread_input)
    {
        EXECUTION_TIME TolTime, IdleTime, deltaTolTime, deltaIdleTime;
        uint32_t uiCount = 0;
        (void)thread_input;
        
    
        /* 内核开启后,恢复HAL里的时间基准 */
        HAL_ResumeTick();
        
        /* 外设初始化 */
        bsp_Init();
        
        /* 创建任务 */
        AppTaskCreate(); 
    
        /* 创建任务间通信机制 */
        AppObjCreate();    
    
        /* 计算CPU利用率 */
        IdleTime = _tx_execution_idle_time_total;
        TolTime = _tx_execution_thread_time_total + _tx_execution_isr_time_total + _tx_execution_idle_time_total;
        while (1)
        {  
            /* 需要周期性处理的程序,对应裸机工程调用的SysTick_ISR */
            bsp_ProPer1ms();
            
            /* CPU利用率统计 */
            uiCount++;
            if(uiCount == 200)
            {
                uiCount = 0;
                deltaIdleTime = _tx_execution_idle_time_total - IdleTime;
                deltaTolTime = _tx_execution_thread_time_total + _tx_execution_isr_time_total + 
    _tx_execution_idle_time_total - TolTime;
                OSCPUUsage = (double)deltaIdleTime/deltaTolTime;
                OSCPUUsage = 100- OSCPUUsage*100;
                IdleTime = _tx_execution_idle_time_total;
                TolTime = _tx_execution_thread_time_total + _tx_execution_isr_time_total +
     _tx_execution_idle_time_total;
            }
            
            tx_thread_sleep(1);
        }
    }

    任务信息统一通过函数DispTaskInfo进行打印:

    /*
    *********************************************************************************************************
    *    函 数 名: DispTaskInfo
    *    功能说明: 将ThreadX任务信息通过串口打印出来
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void DispTaskInfo(void)
    {
        TX_THREAD      *p_tcb;            /* 定义一个任务控制块指针 */
    
        p_tcb = &AppTaskStartTCB;
        
        /* 打印标题 */
        App_Printf("===============================================================
    ");
        App_Printf("CPU利用率 = %5.2f%%
    ", OSCPUUsage);
        App_Printf("任务执行时间 = %.9fs
    ", (double)_tx_execution_thread_time_total/SystemCoreClock);
        App_Printf("空闲执行时间 = %.9fs
    ", (double)_tx_execution_idle_time_total/SystemCoreClock);
        App_Printf("中断执行时间 = %.9fs
    ", (double)_tx_execution_isr_time_total/SystemCoreClock);
        App_Printf("系统总执行时间 = %.9fs
    ", (double)(_tx_execution_thread_time_total + 
                                                           _tx_execution_idle_time_total +  
                                                           _tx_execution_isr_time_total)/SystemCoreClock);    
        App_Printf("===============================================================
    ");
        App_Printf(" 任务优先级 任务栈大小 当前使用栈  最大栈使用   任务名
    ");
        App_Printf("   Prio     StackSize   CurStack    MaxStack   Taskname
    ");
    
        /* 遍历任务控制列表TCB list),打印所有的任务的优先级和名称 */
        while (p_tcb != (TX_THREAD *)0) 
        {
            
            App_Printf("   %2d        %5d      %5d       %5d      %s
    ", 
                        p_tcb->tx_thread_priority,
                        p_tcb->tx_thread_stack_size,
                        (int)p_tcb->tx_thread_stack_end - (int)p_tcb->tx_thread_stack_ptr,
                        (int)p_tcb->tx_thread_stack_end - (int)p_tcb->tx_thread_stack_highest_ptr,
                        p_tcb->tx_thread_name);
    
    
            p_tcb = p_tcb->tx_thread_created_next;
    
            if(p_tcb == &AppTaskStartTCB) break;
        }
    }

    效果:

    16.3 IAR的ThreadX插件实现

    IAR和MDK的实现一样,移植了V6.1.7或者以上版本后,添加统计分析文件即可,剩下就是使能IAR的ThreadX插件:

    •   第1步,使能ThreadX插件:

     

    •   第2步,进入调试状态,添加ThreadX组件,大家可以更新需要选择展现那些信息:

     

    •   第3步,先全速运行,然后点击暂停才可以查看信息,效果如下:

    16.4 实验例程

    配套例子:

    V6-3011_ThreadX Task Statistics

    实验目的:

    1. ThreadX原装任务统计分析功能

    实验内容:

    1、共创建了如下几个任务,通过按下按键K1可以通过串口或者RTT打印任务堆栈使用情况                                   

    ========================================================

             CPU利用率 =  0.89%

             任务执行时间 = 0.586484645s

             空闲执行时间 = 85.504470575s

             中断执行时间 = 0.173225395s

             系统总执行时间 = 86.264180615s              

    =======================================================

            任务优先级 任务栈大小 当前使用栈  最大栈使用   任务名

              Prio     StackSize   CurStack    MaxStack   Taskname

              2         4092        303         459      App Task Start

              5         4092        167         167      App Msp Pro

              4         4092        167         167      App Task UserIF

               5         4092        167         167      App Task COM

               0         1020        191         191      System Timer Thread           

    串口软件可以使用SecureCRT或者H7-TOOL RTT查看打印信息。

    App Task Start任务  :启动任务,这里用作BSP驱动包处理。

    App Task MspPro任务 :消息处理,这里用作LED闪烁。

    App Task UserIF任务 :按键消息处理。

    App Task COM任务   :这里用作LED闪烁。

    System Timer Thread任务:系统定时器任务

    2、 (1) 凡是用到printf函数的全部通过函数App_Printf实现。

     (2) App_Printf函数做了信号量的互斥操作,解决资源共享问题。

    3、默认上电是通过串口打印信息,如果使用RTT打印信息

    (1)   MDK AC5,MDK AC6或IAR通过使能bsp.h文件中的宏定义为1即可

    #define Enable_RTTViewer  1

    (2)   Embedded Studio继续使用此宏定义为0, 因为Embedded Studio仅制作了调试状态RTT方式查看。

    串口打印信息方式(AC5,AC6和IAR):

    波特率 115200,数据位 8,奇偶校验位无,停止位 1

     

    RTT打印信息方式(AC5,AC6和IAR):

     

    Embedded Studio仅支持调试状态RTT打印:

     

    由于Embedded Studio不支持中文,所以中文部分显示乱码,不用管。

    程序执行框图:


    16.5 总结

    本章节主要为大家讲解了ThreadX原装的任务统计分析功能的实现,比较实用。

    微信公众号:armfly_com 安富莱论坛:www.armbbs.cn 安富莱淘宝:https://armfly.taobao.com
  • 相关阅读:
    如何在腾讯云上安装Cloud Foundry
    Chrome浏览器扩展程序的本地备份
    如何在Kubernetes里创建一个Nginx service
    如何在Kubernetes里创建一个Nginx应用
    在Mac里给Terminal终端自定义颜色
    linux sed命令详解
    跟我一起写Makefile--- 变量(嵌套变量+追加变量+overrid+多行变量+环境变量+目标变量+模式变量)
    makefile详解 嵌套执行make,定义命令包
    makefile学习笔记(多目录嵌套调用、变量使用)
    Makefile所有内嵌函数
  • 原文地址:https://www.cnblogs.com/armfly/p/14919503.html
Copyright © 2011-2022 走看看