在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以执行运行时分析:
#define configGENERATE_RUN_TIME_STATS 1
另外,需要提供以下两个宏:
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
portGET_RUN_TIME_COUNTER_VALUE()
RTOS使用它来配置运行时计数器计时器并获取计时器值。
运行时计数器在每个任务描述符中存储为32位值,这意味着对于每个任务,我对系统的RAM要求将增加4个字节:
FreeRTOS TCB中的ulRunTimeCounter
假设计数器周期为10 kHz(0.1 ms),这意味着变量将在大约5天后溢出。
此外,RTOS在task.c中维护额外的全局变量:
#if ( configGENERATE_RUN_TIME_STATS == 1 ) PRIVILEGED_DATA static uint32_t ulTaskSwitchedInTime = 0UL; /*< Holds the value of a timer/counter the last time a task was switched in. */ PRIVILEGED_DATA static uint32_t ulTotalRunTime = 0UL; /*< Holds the total amount of execution time as defined by the run time counter clock. */ #endif
第一个变量用于记住任务切换的时间,第二个变量是系统的总运行时间。这是在任务切换时发生的事情(内核函数vTaskSwitchContext):
/* 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. */ if( ulTotalRunTime > ulTaskSwitchedInTime ) { pxCurrentTCB->ulRunTimeCounter += ( ulTotalRunTime - ulTaskSwitchedInTime ); } else { mtCOVERAGE_TEST_MARKER(); } 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任务
接下来添加一个任务,例如:
#include "FreeRTOS.h" #include "task.h" static void MyTask(void *pvParameters) { for(;;) { vTaskDelay(pdMS_TO_TICKS()); } }
在main()内部,创建一个任务并启动调度程序:
/* create task */ if (xTaskCreate(MyTask, "MyTask", /sizeof(StackType_t), NULL, tskIDLE_PRIORITY+, NULL) != pdPASS) { for(;;){} /* error */ } vTaskStartScheduler(); /* start RTOS */ for(;;) { /* should not get here */ }
添加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(打开):
#define configGENERATE_RUN_TIME_STATS 1 /* 1: generate runtime statistics; 0: no runtime statistics */ #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:
#define configTICK_RATE_HZ ((TickType_t)1000)
这意味着我们的运行时间应至少以10 kHz运行。
要配置这样的计时器,我可以使用MCUXpresso配置外设工具:
外围设备工具
在外设工具中,我们选择了FTM0定时器(我们也可以使用任何其他定时器)。
添加FTM0
定时器配置为10 kHz:
定时器输出频率
我们将使用定时器中断来增加一个计数器,所以不要忘记打开中断:
定时器溢出中断使能
然后单击按钮以更新项目源:
更新项目
切换回开发人员视角。
5、定时器ISR
接下来,我们将定时器中断代码添加到应用程序:
#include "fsl_ftm.h" static uint32_t RTOS_RunTimeCounter; /* runtime counter, used for configGENERATE_RUNTIME_STATS */ void FTM0_IRQHandler(void) { /* Clear interrupt flag.*/ FTM_ClearStatusFlags(FTM0, kFTM_TimeOverflowFlag); RTOS_RunTimeCounter++; /* increment runtime counter */ }
6、添加定时器驱动
该项目尚未编译,因为必要的驱动程序尚未成为项目的一部分。要添加它们,请使用“管理SDK组件”按钮:
管理SDK组件按钮
然后检查ftm驱动程序并按OK,将额外的驱动程序源添加到项目中。
FTM驱动程序
7、向FreeRTOS添加定时器:用于运行时统计的FreeRTOS定时器宏
将以下行添加到FreeRTOSConfig.h:
extern void RTOS_AppConfigureTimerForRuntimeStats(void); #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() RTOS_AppConfigureTimerForRuntimeStats() extern uint32_t RTOS_AppGetRuntimeCounterValueFromISR(void); #define portGET_RUN_TIME_COUNTER_VALUE() RTOS_AppGetRuntimeCounterValueFromISR()
这告诉FreeRTOS它将用于初始化定时器的功能以及获取定时器值的功能。
向FreeRTOSConfig.h添加了运行时计数器设置
8、FreeRTOS Callback for Timer
现在我们需要添加我们配置FreeRTOS使用的两个回调。
void RTOS_AppConfigureTimerForRuntimeStats(void) { RTOS_RunTimeCounter = ; EnableIRQ(FTM0_IRQn); } uint32_t RTOS_AppGetRuntimeCounterValueFromISR(void) { return RTOS_RunTimeCounter; }
9、正在运行...。
构建和调试您的应用程序。如果您现在停止应用程序并检查任务列表,它现在显示运行时信息:
显示运行时信息
10、没有Eclipse?没问题!
上面我使用了FreeRTOS的Eclipse Task List视图,这是NXP为他们的基于Eclipse的IDE(MCUXpresso IDE,S32DS for ARM和Kinetis Design Studio)所做的事情。但是可以直接从应用程序显示该信息,例如在终端LCD显示器上。McuOnEclipse上的FreeRTOS 包含一个使用它的shell /终端接口。
控制台上的任务运行时信息
下面的代码片段显示了如何为每个任务打印信息:
#if configGENERATE_RUN_TIME_STATS ulTotalTime = portGET_RUN_TIME_COUNTER_VALUE(); /* get total time passed in system */ ulTotalTime /= 100UL; /* For percentage calculations. */ #endif ... #if configGENERATE_RUN_TIME_STATS && configUSE_TRACE_FACILITY /* runtime */ UTIL1_strcpy(tmpBuf, sizeof(tmpBuf), (unsigned char*)"0x"); UTIL1_strcatNum32Hex(tmpBuf, sizeof(tmpBuf), taskStatus.ulRunTimeCounter); if (ulTotalTime>) { /* to avoid division by zero */ /* What percentage of the total run time has the task used? This will always be rounded down to the nearest integer. ulTotalRunTime has already been divided by 100. */ ulStatsAsPercentage = taskStatus.ulRunTimeCounter/ulTotalTime; if (ulStatsAsPercentage>) { UTIL1_strcat(tmpBuf, sizeof(tmpBuf), (unsigned char*)" ("); UTIL1_strcatNum16uFormatted(tmpBuf, sizeof(tmpBuf), ulStatsAsPercentage, ' ', ); UTIL1_strcat(tmpBuf, sizeof(tmpBuf), (unsigned char*)"%)"); } else { /* If the percentage is zero here then the task has consumed less than 1% of the total run time. */ UTIL1_strcat(tmpBuf, sizeof(tmpBuf), (unsigned char*)" ( <1%)"); } } buf[] = '\0'; UTIL1_strcatPad(buf, sizeof(buf), tmpBuf, ' ', PAD_STAT_TASK_RUNTIME); CLS1_SendStr(buf, io->stdOut); #endif 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
欢迎关注:
在Amazon FreeRTOS V10中使用运行时统计信息的更多相关文章
- MFC中关于运行时类信息及动态创建对象的两个宏的意义(转)
http://blog.csdn.net/ligand/article/details/49839507 MFC运行时类信息 用途: 程序在运行时,获取对象类的信息及类的继承关系 实现: 1.定义的类 ...
- [C++]C++中的运行时类型检测
Date:2014-1-3 Summary: 使用C++中的运行时类型检测.(文章重点在于记录本人的使用情况,并非深层讨论RTTI) Contents:写习惯C#的我,在C++依然存在哪些.NET的惯 ...
- 翻译:JVM虚拟机规范1.7中的运行时常量池部分(二)
本篇为JVM虚拟机规范1.7中的运行时常量池部分系列的第二篇. 4.4.4. The CONSTANT_Integer_info and CONSTANT_Float_info Structures ...
- Visual C++中对运行时库的支持
原文地址:http://blog.csdn.net/wqvbjhc/article/details/6612099 一.什么是C运行时库 1)C运行时库就是 C run-time library,是 ...
- 是否含有RTTI(运行时类型信息)是动态语言与静态语言的主要区别
运行时类型信息代表类型信息和对内存的操作能力. 运行时类型信息是运行时系统的基础. 类型信息分为编译时类型信息和运行时类型信息两种: 静态语言的类型信息只在编译时使用和保留,在可执行文件中没有类型信息 ...
- 【JavaSE】运行时类型信息(RTTI、反射)
运行时类型信息使得你可以在程序运行时发现和使用类型信息.--<Think in java 4th> **** 通常我们在面向对象的程序设计中我们经常使用多态特性使得大部分代码尽可能地少了解 ...
- SQL Server读懂语句运行的统计信息 SET STATISTICS TIME IO PROFILE ON
对于语句的运行,除了执行计划本身,还有一些其他因素要考虑,例如语句的编译时间.执行时间.做了多少次磁盘读等. 如果DBA能够把问题语句单独测试运行,可以在运行前打开下面这三个开关,收集语句运行的统计信 ...
- SQLSERVER读懂语句运行的统计信息
SQLSERVER读懂语句运行的统计信息 对于语句的运行,除了执行计划本身,还有一些其他因素要考虑,例如语句的编译时间.执行时间.做了多少次磁盘读等. 如果DBA能够把问题语句单独测试运行,可以在运行 ...
- Android中Activity运行时屏幕方向与显示方式详解
现在我们的手机一般都内置有方向感应器,手机屏幕会根据所处位置自动进行横竖屏切换(前提是未锁定屏幕方向).但有时我们的应用程序仅限在横屏或者竖屏状态下才可以运行,此时我们需要锁定该程序Activity运 ...
随机推荐
- springboot 02-PropertiesFile 自定义配置属性,多环境配置
application.properties: # 自定义配置 test.hello.world = HelloWorld test.person.name = 哈哈 test.person.sex ...
- file图片上传之前先预览
链接:https://www.cnblogs.com/tandaxia/p/5125275.html 记得以前做网站时,曾经需要实现一个图片上传到服务器前,先预览的功能.当时用html的<inp ...
- Git学习之连接GitHub远程仓库
在看此教程之前电脑上应该已安装好git,并且配置好基本信息,Git新手请从头开始. 第1步:创建SSH Key 在用户主目录下(Mac系统是在用户主目录下,可通过命令ll -a查看,Windows下自 ...
- CMFCToolBar、CMFCStatusBar
首先删除注册表HKEY_CURRENT_USER\Software\应用程序向导生成的本地应用程序之下你这铬软件的配置 CMFCToolBar m_myToolBar; CMFCToolBarImag ...
- MySql 在cmd下的学习笔记 —— 有关游标的操作(cursor)
---恢复内容开始--- cursor 指在1条sql,对应N条资源,取出资源的接口/句柄,就是游标 沿着游标,可以一次取出一行 对于游标,必须要先声明一下 fetch 会读取每一条记录,当没有时,会 ...
- 6034 Balala Power! (17多校)
题目大意:给出的字符串,每个字符建立一种与0-25的对应关系.然后每个字符串看成是一个26进制的数.问能获得的数的总和的最大值.(最后对1e9+7取模). 题目思考:把每个字符的贡献值看做一个26进制 ...
- 20165237 预备作业3 Linux安装及学习
Linux安装及学习 安装 对操作系统略知一二的我,按照老师发的基于VirtualBox虚拟机安装Ubuntu图文教程慢慢一步步往下做,虽然中间有些小困难,但最终都得以解决,安装成功. 遇到的小困难: ...
- SpringBoot单元测试示例
⒈控制器Action示例 package cn.coreqi.controller; import org.junit.Test; import org.junit.runner.RunWith; i ...
- 2018 Multi-University Training Contest 1 杭电多校第一场
抱着可能杭电的多校1比牛客的多校1更恐怖的想法 看到三道签到题 幸福的都快哭出来了好吗 1001 Maximum Multiple(hdoj 6298) 链接:http://acm.hdu.edu. ...
- tomcat目录映射
环境:CentOS 6 + tomcat 7 + jdk 7 目前使用2种方法: 1.tomcat/conf/server.xml <Host name="localhost" ...