基于TI-RTOS的CC2650DK开发(21)---检测

第9章 检测
本章描述用于检测目的的模块和其它工具。

9.1  仪器概览
很多可用于SYS/BIOS应用程序的检测工具都是由XDCtools模块和APIs提供的。参阅CDOC在线参考文档获取Assert、Diags和Error模块的详细信息。

9.2  Load模块
ti.sysbios.utils.Load模块报告系统线程的执行时间和负载信息。

SYS/BIOS管理了四个不同层级的执行线程:硬件中断服务程序、软件中断服务程序、tasks和后台idle函数。Load模块在每个task基础上报告执行时间和负载信息,还为硬件中断服务程序、软件中断服务程序和idle函数(以idle task的形式)提供全局信息。它还可以报告全局CPU负载评估值,也就是用于测量窗而非idle loop的时间百分比的计算。更具体地说,load使用如下公式计算:
global CPU load =  100 * ( 1 - ((x * t) / w) )
其中:
  • 'x'是在测量窗期间,idle loop被执行的时间。
  • 't'是执行idle loop一遍的最小时间,也就是在没有工作要做的情况下,完成idle loop所需的时间。
  • 'w'是测量窗的时间长度。
任何在idle loop中所完成的工作都包含在CPU负载内。换句话说,idle loop最短行程之外的任何工作都计算在non-idle时间。Load模块使用“update”函数来计算自上次“update”被调用以来的负载和执行时间。当Loadd.updateInIdle被设置为true(默认值)时,“update”在ti.sysbios.knl.Idle函数中按Load.windowInMs(默认为500ms)所指定的周期进行自动调用。基准时间窗口是两个“update”调用之间的时间长度。

执行时间使用xdc.runtime.Timestamp数量为单位进行报告,load以百分数进行报告。

默认情况下,load收集所有线程的数据。你可以使用配置参数Load.hwiEnabled、Load.swiEnabled和Load.taskEnabled来选择监控哪个类型的线程。

9.2.1  Load模块配置
Load被设置为提供尽可能少的配置数据。使用默认配置,load每隔大约500ms收集并记录所有线程的数据。

以下代码将Load模块配置为将负载统计写入到一个LoggerBuf实例:
var LoggerBuf = xdc.useModule( 'xdc.runtime.LoggerBuf');
var Load = xdc.useModule( 'ti.sysbios.utils.Load');
var Diags = xdc.useModule( 'xdc.runtime.Diags');
var loggerBuf = LoggerBuf.create();
Load.common$.logger = loggerBuf;
Load.common$.diags_USER4 = Diags.ALWAYS_ON;
有关Load模块的高级配置和附加说明信息,请查阅在线参考文档。

9.2.2  获取负载统计
可通过以下两个途径获取Load模块的负载统计报告:
  • Load module logger:如果你将Load模块配置为logger并打开diags_USER4,Load模块的统计数据将收集到load模块的logger实例。你可以使用RTOS分析工具将这些基于日志记录的负载可视化。参阅System Analyzer User’s Guide(SPRUH43)和System Analyzer wiki page获取更多信息。

或者,你也可以将logger配置为在控制台上打印日志。全局CPU负载日志打印一个百分数,如:
LS_cpuLoad:  10
全局Swi和Hwi负载日志打印两个数字:线程使用时间和测量窗长度,如:
LS_hwiLoad:  13845300, 158370213
LS_swiLoad:  11963546, 158370213
此负载评估值为8.7%和7.6%。

Task负载日志使用相同格式,它将Task句柄地址作为第一个参数,如:
LS_taskLoad: 0x11802830, 56553702, 158370213
此负载评估值为35.7%。

  • Runtime APIs:你也可以选择调用 Load_getTaskLoad()、Load_getGlobalSwiLoad()、Load_getGlobalHwiLoad()或Load_getCPULoad()在运行时的任意时间获取统计数据。

Load_getCPULoad() API返回负载的实际百分比,而Load_getTaskLoad()、
Load_getGlobalSwiLoad()和Load_getGlobalHwiLoad()则返回一个Load_Stat结构体。此结构体包含两个字段:线程时间找度和测量窗时间长度。负载百分比可以通过这两个数字相除并乘上100%而获得。尽管如此,Load模块还是提供了一个便利函数Load_calculateLoad()来实现此目的。例如,以下代码取回Hwi负载
Load_Stat stat;
UInt32 hwiLoad;
Load_getGlobalHwiLoad(&stat);
hwiLoad = Load_calculateLoad(&stat);

9.3  错误(Error)处理
很多SYS/BIOS APIs — 特别是那些创建对象和分配内存的函数 — 都有一个Error_Block类型参数。此类型由XDCtools所提供的xdc.runtime.Error模块定义。下例以推荐的方式在创建Swi时声明和使用error块:
#include <xdc/std.h>
#include <xdc/runtime/Error.h>
#include <xdc/runtime/System.h>
#include <ti/sysbios/BIOS.h>
#include <ti/sysbios/knl/Swi.h>
Swi_Handle swi0;
Swi_Params swiParams;
Error_Block eb;
Error_init(&eb);
Swi_Params_init(&swiParams);
swi0 = Swi_create(swiFunc, &swiParams, &eb);
if (swi0 ==  NULL)
{
    System_abort( "Swi create failed");
}
注意在此例中,检测Swi_create()的返回值是否为NULL,然后决定是否调用System_abort():
if (swi0 ==  NULL)
{
    System_abort( "Swi create failed");
}
大多数SYS/BIOS APIs的错误块还返回一个创建对象的句柄或分配的内存。为此,它是最简单的,并提供最好的性能来检查这些API返回的值。

对于那些传递了Error_Block但没有返回句柄或其它状态值的APIs,你可以使用Error_check()函数来检测Error_Block。下例通过调用Timer_reconfig()来重新配置静态创建的定时器对象:
Timer_reconfig(myTimer, tickFxn, &timerParams, &eb);
if (Error_check(&eb))
{
    System_abort( "Timer reconfigure failed");
}

你可能会在其它文档中看到使用NULL来代替Error_Block参数。在创建对象或分配内存时使用NULL代替Error_Block作为参数传递,如果此时发生了错误,应用程序将中止,错误原因会通过System_printf()打印输出。在任何错误都是致命的系统中,这是最好的行为方式,你不再需要任何错误检查。

传递和检测Error_Block的优势是你可以控制程序何时中止。例如,当内存无法分配时你不希望中止,而是希望释放内存并再次尝试或切换到一个拥有更多内存的模式。

注意System_abort()函数从它的System.SupportProxy模块调用一个hook函数(如xdc.runtime.SysStd)。你可能希望使用不同的abort() hook函数来执行一个重启并重新开始应用程序。

9.4  Code Composer Studio检测工具
当你在调试应用程序是地,在 Tools菜单下有几个特别有用的项目可以调试SYS/BIOS应用程序。

Tools > RTOS Object View (ROV)对TI-RTOS是一个可停止模式调试工具。获取更多信息,请参考7.5.3节的 ROV for System Stacks and Task Stacks,或者ROV的wiki页: http://rtsc.eclipse.org/docs-tip/RTSC_Object_Viewer

Tools > RTOS Analyzer提供了几个工具用于检测SYS/BIOS线程的执行顺序、CPU负载分析、信息和错误日志以及task行为。为了使用这些命令,你的应用程序必须将UIA模块 LoggingSetup设为可用。一旦UIA包可用,SYS/BIOS线程的执行和负载在默认情况下将被检测。参考 System Analyzer  User's Guide(SPRUH43)获取有关RTOS分析工具使用的信息。
基于TI-RTOS的CC2650DK开发(21)---检测 - 阿巴睇 - 阿巴睇的博客
 
Tools > System Analyzer让你可以访问带附加图表检测的分析工具。这些工具需要使用UIA C/C++ APIs额外代码。如果你需添加额外UIA事件的基准代码和收集额外数据,可以使用这些分析工具。它还提供了多核数据相关。关于系统分析的详细使用方法,参见 System Analyzer User’s Guide (SPRUH43)
基于TI-RTOS的CC2650DK开发(21)---检测 - 阿巴睇 - 阿巴睇的博客
 
如果你已经安装了TI-RTOS,则在应用程序中,UIA是可用的。默认情况下,SYS/BIOS示例中未使用UIA,但你可通过在XGCONF配置编辑器中加入LoggingSetup模块,并选中多选框来激活UIA。

如果你安装了SYS/BIOS和独立的UIA产品(没有安装TI-RTOS),可以通过以下方式激活UIA:
  1. 在CCS的Project Explorer面板右键单击项目,并选择Properties
  2. 在Properties对话框选择General类别,然后选中RTSC标签。
  3. 在Products and Repositories区域,选中System Analyzer (UIA Target)项,并确保所选的是最新版本。这让你的应用程序可链接至UIA的必要部分,并让UIA在XGCONF模块中可用。(如果你看见TI-RTOS项被选中,则UIA已经在你的项目中可用了)
  4. 单击OK
基于TI-RTOS的CC2650DK开发(21)---检测 - 阿巴睇 - 阿巴睇的博客
 
任何拥有NDK驱动的目标可通过以太网采集UIA运行时数据。所有C64x+和C66x目标也可通过JTAG采集运行时数据。针对UIA发布说明里罗列的额外目标也提供了停止模式数据采集。

9.5  性能优化
本节为SYS/BIOS应用程序的性能优先提供建议。它是以两种方式完成的:使用编译器和链接优化,优化SYS/BIOS配置。

9.5.1  配置日志
日志可以显著地影响系统性能。通过优化配置可以减少日志的影响。有两个主要途径优化日志在应用程序中的使用:
  • 无日志:在SYS/BIOS中,默认情况下日志不可用。
  • 优化日志:如果需要在应用程序中使用日志,选择某些配置可优化性能。以下子节分别进行讨论。

9.5.1.1  Diags设置
针对每个诊断等级有四个诊断设置:RUNTIME_OFF、RUNTIME_ON、ALWAYS_OFF和ALWAYS_ON。

两个运行时设置(RUNTIME_OFF和RUNTIME_ON)让你在运行时使用和禁用特定诊断等级。但是必须执行检查,以确定每次记录事件是否启用或禁用日志记录。

如果使用的是ALWAYS_OFF或ALWAYS_ON,则无法在运行时改变设置。要不直接记录入日志(ALWAYS_ON),要不被优先出代码(ALWAYS_OFF)。
var Defaults = xdc.useModule( 'xdc.runtime.Defaults');
var Diags = xdc.useModule( 'xdc.runtime.Diags');

/* 'RUNTIME' settings allow you to turn it off or on at runtime,
* but require a check at runtime. */

Defaults.common$.diags_USER1 = Diags.RUNTIME_ON;
Defaults.common$.diags_USER2 = Diags.RUNTIME_OFF;

/* These settings cannot be changed at runtime, but optimize out
* the check for better performance. */

Defaults.common$.diags_USER3 = Diags.ALWAYS_OFF;
Defaults.common$.diags_USER4 = Diags.ALWAYS_ON;

9.5.1.2  选择诊断等级
SYS/BIOS模块只记录两个等级:USER1和USER2。根据惯例,USER1是基本事件,USER2更为详细。

为提供性能,你可以仅打开USER1,或仅为特定模块打开USER2。

参阅每个模块的文档以查看哪些事件记录为USER1,哪些事件记录为USER2。

9.5.1.3  选择使用日志的模块
为了优化日志,只允许对有兴趣调试的模块进行日志记录。

例如,由于硬件中断频率方面的原因,Hwi日志往往在性能方面最为昂贵。当时钟计时器到期,每个时钟tick往往记录两个Hwi事件。

9.5.2  配置诊断
默认情况下,断言对所有模块启用。SYS/BIOS使用断言检查普通用户错误,如使用无效的参数或从不支持的上下文调用API。断言对于捕获代码错误非常有用的,否则可能会导致混乱的bugs。

在你做完API调用的基础调试后,为优化性能,可在配置文件中禁用断言:
var Defaults = xdc.useModule( 'xdc.runtime.Defaults');
var Diags = xdc.useModule( 'xdc.runtime.Diags');

/* Disable asserts in all modules. */
Defaults.common$.diags_ASSERT = Diags.ALWAYS_OFF;

9.5.3  选择一个Heap管理器
SYS/BIOS提供了几个不同的heap管理器实现。每个在分配和释放内存方面都有不同的性能权衡。参考7.8节获取有关每个模块权衡的讨论。

HeapMem可以分配任意尺寸的块,但却是三个中最慢的。HeapBuf仅可以分配固定尺寸的块,但却非常快。HeapMultiBuf管理一个HeapBuf实例池,并平衡了其它两个的优势。HeapMultiBuf比HeapMem快,但比HeapBuf慢。HeapMin使用最小内存,但不能释放内存。

但还是要考虑使用不同的heap实现不同的作用。例如,HeapBuf完美适合频繁创建和删除的固定尺寸对象。如果您正在分配和释放许多固定尺寸的数据缓冲区,则可以创建一个HeapBuf实例来分配这些数据缓冲。

9.5.4  Hwi配置
硬件中断调度器默认提供了一些中断延迟的功能。如果你的应用程序不需要这些功能,可以禁用它们以减少中断延迟。
  • dispatcherAutoNestingSupport:如果不需要在执行Hwi函数期间禁用中断,则可以禁用此项功能。
  • dispatcherSwiSupport:如果不需要从任意Hwi线程提交Swi线程,则可以禁用此功能。
  • dispatcherTaskSupport:如果在Hwi线程不会调用任何会导致Task被预订的APIs,则可以禁用此功能。例如,Semaphore_post()将导致Task被预订。
  • dispatcherIrpTrackingSupport:此功能支持Hwi_getlrp() API,它返回一个中断的最新地址。如果你的程序不使用此API,则可以禁用此功能。

9.5.5  栈检测
默认情况下,Task模块在切换Task时会检查Task栈是否溢出。为改良Task切换延迟,可以将Task.checkStackFlag属性设置为false以禁用此功能。
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值