在Amazon FreeRTOS V10中使用运行时统计信息

  在MCU on Eclipse网站上看到Erich Styger在8月2日发的博文,一篇关于在Amazon FreeRTOS V10中使用运行时统计信息的文章,本人觉得很有启发,特将其翻译过来以备参考。原文网址:https://mcuoneclipse.com/2018/08/02/tutorial-using-runtime-statistics-with-amazon-freertos-v10/

  FreeRTOS包含一个很好的功能,可以向我提供有关每个任务在系统上运行的时间的信息:

FreeRTOS运行时信息

  本教程解释了FreeRTOS运行时统计功能以及如何打开和使用它。

?软件和工具

  在本文中,我使用以下内容:

  • MCUXpresso IDE 10.2.1
  • FRDM-K64F板
  • 来自MCUXpresso SDK 2.4.0的Amazon FreeRTOS V10.0.1

  但是当然可以使用任何其他工具/ IDE或FreeRTOS版本(FreeRTOS至少应该是9.0.0或更高版本)。

  使用以下步骤,还可以使用FreeRTOS任务运行时信息收集来更新现有项目。

?怎么运行的

  FreeRTOS使用用户/应用程序特定的计时器来测量任务执行时间。为此,RTOS中的每个任务描述符都有一个累积计数器,用于添加为该任务花费的计时器滴答。当任务获得CPU时间时,当前计时器滴答计数被记忆,当RTOS切换出该任务时,则记忆当前计时器滴答计数。然后将对应于任务执行时间的增量时间添加到任务执行时间计数器。

  我需要配置FreeRTOS,并将以下宏设置为1以执行运行时分析:

1 #define configGENERATE_RUN_TIME_STATS 1

另外,需要提供以下两个宏:

1 portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
2 portGET_RUN_TIME_COUNTER_VALUE()

  RTOS使用它来配置运行时计数器计时器并获取计时器值。

  运行时计数器在每个任务描述符中存储为32位值,这意味着对于每个任务,我对系统的RAM要求将增加4个字节:

FreeRTOS TCB中的ulRunTimeCounter

  假设计数器周期为10 kHz(0.1 ms),这意味着变量将在大约5天后溢出。

  此外,RTOS在task.c中维护额外的全局变量:

1 #if ( configGENERATE_RUN_TIME_STATS == 1 )
2
3     PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */
4
5     PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL;       /*< Holds the total amount of execution time as defined by the run time counter clock. */
6
7 #endif

  第一个变量用于记住任务切换的时间,第二个变量是系统的总运行时间。这是在任务切换时发生的事情(内核函数vTaskSwitchContext):

 1 /* Add the amount of time the task has been running to theaccumulated time so far.  The time the task started running wasstored in ulTaskSwitchedInTime.  Note that there is no overflowprotection here so count values are only valid until the timeroverflows.  The guard against negative values is to protectagainst suspect run time stat counter implementations - whichare provided by the application, not the kernel. */
 2
 3 if( ulTotalRunTime > ulTaskSwitchedInTime )
 4
 5 {
 6
 7     pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime );
 8
 9 }
10
11 else
12
13 {
14
15     mtCOVERAGE_TEST_MARKER();
16
17 }
18
19 ulTaskSwitchedInTime = ulTotalRunTime;

  通常,周期性定时器中断用于计算执行时间,并且定时器频率应该是嘀嗒中断频率的大约10倍(比如说“Hello”到“奈奎斯特 - 香农”采样定理)。这意味着如果我的滴答中断是1 kHz,我的运行时分析定时器频率应该是10 kHz。

  运行时统计信息通常带有两个数字:

  • 绝对(时间)数字
  • 百分比

  下面是一个文本任务列表,其中包含右侧的运行时信息:

TCB Static Handle     Name         State    Prio    Stack Beg  Stack End  Size    Stack Top            Unused  Runtime

1   no (0) 0x20000450 Shell        Running  (1,1)   0x20000440 0x20000060  1000 B 0x200001EC (  600 B)   392 B 0x00000000 ( <1%)

7   no (0) 0x20001E68 IDLE         Ready    (0,0)   0x20001E58 0x20001CD0   400 B 0x20001DFC (   96 B)   312 B 0x00007C35 ( 91%)

2   no (0) 0x20000740 Refl         Blocked  (4,4)   0x20000730 0x20000510   552 B 0x200006BC (  120 B)   384 B 0x00000C6E (  9%)

6   no (0) 0x20001C68 Main         Blocked  (1,1)   0x20001C58 0x20001A08   600 B 0x20001BDC (  128 B)   356 B 0x00000000 ( <1%)

3   no (0) 0x20001378 Radio        Blocked  (3,3)   0x20001368 0x20000F88  1000 B 0x200012F4 (  120 B)   680 B 0x00000001 ( <1%)

4   no (0) 0x20001658 Sumo         Blocked  (2,2)   0x20001648 0x20001458   504 B 0x200015C4 (  136 B)   360 B 0x00000000 ( <1%)

5   no (0) 0x20001948 Drive        Blocked  (3,3)   0x20001938 0x20001748   504 B 0x200018B4 (  136 B)   264 B 0x00000000 ( <1%)

  绝对数字是运行时间计时器滴答数(TCB中的ulRunTimeCounter)以及此计数器相对于总运行时间的百分比(task.c中的ulTotalRunTime)。

  对于IDLE任务,它显示了这一点:

TCB Static Handle Name State Prio Stack Beg Stack End Size Stack Top Unused Runtime

7 no (0) 0x20001E68 IDLE Ready (0,0) 0x20001E58 0x20001CD0 400 B 0x20001DFC ( 96 B) 312 B 0x00007C35 ( 91%)

  0x7C35是定时器计数器(在本例中使用0.1 ms定时器,因此它意味着IDLE任务运行约3秒(0x7C35 / 10 => 3179 ms)并使用91%的运行时间。

  问题可能是:中断花费的时间是多少?答案是RTOS不知道中断,它只知道任务使用了多少运行时间计时器。或者换句话说:FreeRTOS运行时计数器显示的运行时* includes*中断的时间。

?教程:使用FreeRTOS进行运行时分析

  在下一节中,我将展示如何使用FreeRTOS启用运行时分析。基本步骤是:

  • 创建一个新项目(如果尚未存在)
  • 更新FreeRTOSConfig.h
  • 初始化和配置计时器
  • 添加钩子/回调到应用程序

1、创建项目

  创建一个基于你的目标板的项目:

项目创建的目标板

  确保包含FreeRTOS:

项目的FreeRTOS选项

2、添加FreeRTOS任务

  接下来添加一个任务,例如:

 1 #include "FreeRTOS.h"
 2
 3 #include "task.h"
 4
 5
 6
 7 static void MyTask(void *pvParameters) {
 8
 9   for(;;) {
10
11     vTaskDelay(pdMS_TO_TICKS(100));
12
13   }
14
15 }

  在main()内部,创建一个任务并启动调度程序:

 1 /* create task */
 2
 3  if (xTaskCreate(MyTask, "MyTask", 500/sizeof(StackType_t), NULL, tskIDLE_PRIORITY+1, NULL) != pdPASS) {
 4
 5    for(;;){} /* error */
 6
 7  }
 8
 9  vTaskStartScheduler(); /* start RTOS */
10
11  for(;;) {
12
13      /* should not get here */
14
15  }

添加FreeRTOS任务

构建和调试该项目,只是为了确保一切正常。

调试FreeRTOS任务

  要在Debug视图中显示FreeRTOS线程,请参阅https://mcuoneclipse.com/2018/06/29/show-freertos-threads-in-eclipse-debug-view-with-segger-j-link-and-nxp-s32-design-studio/

  但是FreeRTOS任务列表(使用Menu FreeRTOS>任务列表来显示该视图)不显示任何运行时信息:

FreeRTOS任务列表,没有运行时信息

  这是我们将在接下来的步骤中添加的内容。

3、跟踪和运行时统计信息

  在FreeRTOSConfig.h中,确保将以下定义设置为1(打开):

1 #define configGENERATE_RUN_TIME_STATS 1 /* 1: generate runtime statistics; 0: no runtime statistics */
2
3 #define configUSE_TRACE_FACILITY      1 /* 1: include additional structure members and functions to assist with execution visualization and tracing, 0: no runtime stats/trace */

启用运行时统计信息和跟踪功能

  该configUSE_TRACE_FACILITY需要使用RTOS有在任务描述当前存储的运行时间计数器的附加数据元素,在configGENERATE_RUN_TIME_STATS自动关上,以创纪录的任务执行时间的功能。

4、配置定时器

  接下来,我们必须设置一个计时器来测量任务执行时间。该计时器的运行速度至少比RTOS Tick计时器快10倍。

  在我们的示例中,滴答率为1 kHz:

1 #define configTICK_RATE_HZ ((TickType_t)1000)

  这意味着我们的运行时间应至少以10 kHz运行。

  要配置这样的计时器,我可以使用MCUXpresso配置外设工具:

外围设备工具

  在外设工具中,我们选择了FTM0定时器(我们也可以使用任何其他定时器)。

添加FTM0

  定时器配置为10 kHz:

定时器输出频率

  我们将使用定时器中断来增加一个计数器,所以不要忘记打开中断:

定时器溢出中断使能

  然后单击按钮以更新项目源:

更新项目

  切换回开发人员视角。

5、定时器ISR

  接下来,我们将定时器中断代码添加到应用程序:

 1 #include "fsl_ftm.h"
 2
 3 static uint32_t RTOS_RunTimeCounter; /* runtime counter, used for configGENERATE_RUNTIME_STATS */
 4
 5
 6
 7 void FTM0_IRQHandler(void) {
 8
 9   /* Clear interrupt flag.*/
10
11   FTM_ClearStatusFlags(FTM0, kFTM_TimeOverflowFlag);
12
13   RTOS_RunTimeCounter++; /* increment runtime counter */
14
15 }

6、添加定时器驱动

  该项目尚未编译,因为必要的驱动程序尚未成为项目的一部分。要添加它们,请使用“管理SDK组件”按钮:

管理SDK组件按钮

  然后检查ftm驱动程序并按OK,将额外的驱动程序源添加到项目中。

FTM驱动程序

7、向FreeRTOS添加定时器:用于运行时统计的FreeRTOS定时器宏

  将以下行添加到FreeRTOSConfig.h:

1 extern void RTOS_AppConfigureTimerForRuntimeStats(void);
2
3 #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()   RTOS_AppConfigureTimerForRuntimeStats()
4
5 extern uint32_t RTOS_AppGetRuntimeCounterValueFromISR(void);
6
7 #define portGET_RUN_TIME_COUNTER_VALUE()           RTOS_AppGetRuntimeCounterValueFromISR()

  这告诉FreeRTOS它将用于初始化定时器的功能以及获取定时器值的功能。

向FreeRTOSConfig.h添加了运行时计数器设置

8FreeRTOS Callback for Timer

  现在我们需要添加我们配置FreeRTOS使用的两个回调。

 1 void RTOS_AppConfigureTimerForRuntimeStats(void) {
 2
 3   RTOS_RunTimeCounter = 0;
 4
 5   EnableIRQ(FTM0_IRQn);
 6
 7 }
 8
 9
10
11 uint32_t RTOS_AppGetRuntimeCounterValueFromISR(void) {
12
13   return RTOS_RunTimeCounter;
14
15 }

9、正在运行...

  构建和调试您的应用程序。如果您现在停止应用程序并检查任务列表,它现在显示运行时信息:

显示运行时信息

10、没有Eclipse?没问题!

  上面我使用了FreeRTOS的Eclipse Task List视图,这是NXP为他们的基于Eclipse的IDE(MCUXpresso IDE,S32DS for ARM和Kinetis Design Studio)所做的事情。但是可以直接从应用程序显示该信息,例如在终端LCD显示器上。McuOnEclipse上的FreeRTOS 包含一个使用它的shell /终端接口。

控制台上的任务运行时信息

  下面的代码片段显示了如何为每个任务打印信息:

 1 #if configGENERATE_RUN_TIME_STATS
 2
 3   ulTotalTime = portGET_RUN_TIME_COUNTER_VALUE(); /* get total time passed in system */
 4
 5   ulTotalTime /= 100UL; /* For percentage calculations. */
 6
 7 #endif
 8
 9 ...
10
11 #if configGENERATE_RUN_TIME_STATS && configUSE_TRACE_FACILITY
12
13       /* runtime */
14
15       UTIL1_strcpy(tmpBuf, sizeof(tmpBuf), (unsigned char*)"0x");
16
17       UTIL1_strcatNum32Hex(tmpBuf, sizeof(tmpBuf), taskStatus.ulRunTimeCounter);
18
19       if (ulTotalTime>0) { /* to avoid division by zero */
20
21         /* What percentage of the total run time has the task used?
22
23            This will always be rounded down to the nearest integer.
24
25            ulTotalRunTime has already been divided by 100. */
26
27         ulStatsAsPercentage = taskStatus.ulRunTimeCounter/ulTotalTime;
28
29         if (ulStatsAsPercentage>0) {
30
31           UTIL1_strcat(tmpBuf, sizeof(tmpBuf), (unsigned char*)" (");
32
33           UTIL1_strcatNum16uFormatted(tmpBuf, sizeof(tmpBuf), ulStatsAsPercentage, ‘ ‘, 3);
34
35           UTIL1_strcat(tmpBuf, sizeof(tmpBuf), (unsigned char*)"%)");
36
37         } else {
38
39           /* If the percentage is zero here then the task has consumed less than 1% of the total run time. */
40
41           UTIL1_strcat(tmpBuf, sizeof(tmpBuf), (unsigned char*)" ( <1%)");
42
43         }
44
45       }
46
47       buf[0] = ‘\0‘;
48
49       UTIL1_strcatPad(buf, sizeof(buf), tmpBuf, ‘ ‘, PAD_STAT_TASK_RUNTIME);
50
51       CLS1_SendStr(buf, io->stdOut);
52
53 #endif
54
55       CLS1_SendStr((unsigned char*)"\r\n", io->stdOut);

?概要

  FreeRTOS运行时统计是一个非常有用的功能:它显示每个任务使用了多少时间,包括其中断时间。我需要的只是设置一些FreeRTOS配置宏并设置周期性定时器中断。当然,这并不是免费提供额外的定时器中断以及该功能所需的RAM和FLASH,但如果需要,它可以很容易地关闭以供最终版本使用。

?链接

  • GitHub上的示例项目:https://github.com/ErichStyger/mcuoneclipse/tree/master/Examples/MCUXpresso/FRDM-K64F/FRDM-K64F_SDK_FreeRTOS
  • 使用FreeRTOS进行性能和运行时分析
  • MCUXpresso IDE网页:http://www.nxp.com/mcuxpresso/ide
  • MCUXpresso IDE社区:http://www.nxp.com/mcuxpresso/ide/forum
  • 在Eclipse中更好的FreeRTOS调试
  • McuOnEclipse库项目:https://github.com/ErichStyger/McuOnEclipseLibrary/tree/master/lib/FreeRTOS/Source
  • ARM Cortex-M循环计数器:https://mcuoneclipse.com/2017/01/30/cycle-counting-on-arm-cortex-m-with-dwt/
  • 更好的FreeRTOS调试:https://mcuoneclipse.com/2017/03/18/better-freertos-debugging-in-eclipse/
  • FreeRTOS RuntimeStats:https://www.freertos.org/rtos-run-time-stats.html

 欢迎关注:

原文地址:https://www.cnblogs.com/foxclever/p/9459691.html

时间: 2024-10-08 11:53:51

在Amazon FreeRTOS V10中使用运行时统计信息的相关文章

浏览器客户端智能自动化:如何取得页面中JavaScript运行时动态生成的URL?

浏览器客户端智能自动化:如何取得页面中JavaScript运行时动态生成的URL? 需求 "页面智能拼接"指的是通过启发式查询DOM树,判断出"下一页"链接,取出其href属性.Chromium的官方插件DOM Distiller完成类似的工作,主要目的就是为了将多页点击流程变成单页的Ajax连续阅读体验. 问题是,现在有些网站为了阻止浏览器客户端这么做,将href属性设置为"#"(或javascript:void()),然后在其onclick事

运行时类型信息RTTI

我们在写C++代码的时候经常碰到使用dynamic_cast进行类型转换的情况,也都知道经过dynamic_cast的转换更加安全,因为dynamic_cast进行了类型检查. 但是可能很多人不知道dynamic_cast是C++ 运行时类型信息(RTTI)机制链条上的一个节点. RTTI提供了两个操作符和一个类: dynamic_cast typeid type_info 整个RTTI, 作为一个整体,暴露给程序员的就是这三个元素.因此我们关注的焦点也就在它们身上了. 什么是RTTI 在C++

获取java程序运行时内存信息

由于最近想自己动手测试一下String和StringBuffer的效率问题,需要获取程序运行时的内存占中信息,于是上网查了一下,根据查到的资料写了个程序,发现结果有问题,才发现查到的资料是错误的.所以在这里跟大家分享一下获取内存占用的正确方法 错误的方法 //程序开始时:(先调用一下垃圾回收,但是不一定立即执行) Runtime.getRuntime().gc(); long initm=Runtime.getRuntime().freeMemory(); //程序结束时: Runtime.ge

C++MFC编程笔记day04 运行时类信息和窗口的动态、静态切分

运行时类信息 程序在运行时,获取对象类的信息及类的继承关系 实现: 1.定义类继承自CObject类. 2.类内声明宏DECLARE_DYNAMIC(),类外实现宏IMPLEMENT_DYNAMIC() 3.使用: BOOL IsKindOf(CRuntimeClass* pClass)//对象是否属于某个类 CRuntimeClass* GetRuntimeClass( );//获取对象运行时类信息,经常使用RUNTIME_CLASS(类名)代替. 示例: #include "stdafx.h

运行时类信息机制

// MFCDynimic.cpp : Defines the entry point for the console application.///*运行时类信息机制:在程序运行过程中,可以判断类对象的相关类的信息以及继承派生类.*/ #include "stdafx.h"#include "MFCDynimic.h" class CAnimal:public CObject{DECLARE_DYNAMIC(CAnimal);}; IMPLEMENT_DYNAMI

SQLSERVER读懂语句运行的统计信息

SQLSERVER读懂语句运行的统计信息 对于语句的运行,除了执行计划本身,还有一些其他因素要考虑,例如语句的编译时间.执行时间.做了多少次磁盘读等. 如果DBA能够把问题语句单独测试运行,可以在运行前打开下面这三个开关,收集语句运行的统计信息. 这些信息对分析问题很有价值. 1 SET STATISTICS TIME ON 2 SET STATISTICS IO ON 3 SET STATISTICS PROFILE ON SET STATISTICS TIME ON 请先来看看SET STA

遍历目录中所有文件并统计信息

遍历目录中所有文件,并且统计文件类型. #!/bin/bash #filename: filestat.sh #set -x if [ $# -ne 1 ]; then     echo $0 basepath;    echo fi path=$1 declare -A statarray; while read line; do   ftype=`file -b "$line"`   let statarray["$ftype"]++; done< <

Android中Activity运行时屏幕方向与显示方式详解

现在我们的手机一般都内置有方向感应器,手机屏幕会根据所处位置自动进行横竖屏切换(前提是未锁定屏幕方向).但有时我们的应用程序仅限在横屏或者竖屏状态下才可以运行,此时我们需要锁定该程序Activity运行时的屏幕方向.还有就是在我们用手机观看视频时,随意的进行横竖屏切换,但播放进度不会随着屏幕的转换而从头开始播放,为了实现这个功能,我们就需要在Activity转换时对当前数据进行保存. 现在根据以上两种需求,个人提出以下解决方案: 一.锁定Activity运行时屏幕方向,如下图(演示锁定横屏):

虚拟机中的运行时栈帧

每个人都知道,各种各样的动画视频,都是由一帧一帧图片连续切换结果的结果而产生的,其实虚拟机的运行和动画也类似,每个在虚拟机中运行的程序也是由许多的帧的切换产生的结果,只是这些帧里面存放的是方法的局部变量,操作数栈,动态链接,方法返回地址和一些额外的附加信息组成,在虚拟机中包含这些信息的帧称为"栈帧",每个方法的执行,在虚拟机中都是对应的栈帧在虚拟机栈中的入栈到出栈的过程.其中比较重要的一点时,如果虚拟机中同时有多个线程在执行,那么各个线程的栈帧都是相互独立,互不侵犯的,所以这也实现了局