497|0

504

帖子

4

TA的资源

纯净的硅(高级)

楼主
 

《嵌入式软件的时间分析》从书中到实践-Tracealyzer事件记录格式与丢事件监测 [复制链接]

书中分享了很多理论,方法和案例,

基于本书,本人在此基础上再分享一些更贴近实战的案例分享。

本人公众号 嵌入式Lee(嵌入式软硬件技术:RTOS,GUI,FS,协议栈,ARM,总线,嵌入式C,开发环境 and blablaba....多年经验分享,非硬货不发,带你扒开每一个技术背后的根本原理。)

 

一. 前言

本文继续在前面的基础上分析Tracealyzer发送到上位机的事件信息是如何记录的。

直接从代码结合抓包数据进行分析。

二.事件记录格式

trcKernelPort.h中定义了很多事件类型,以PSF_EVENT_开头

 

 

每次记录事件,都是按照如下形式进行

先xTraceEventBegin

然后TraceEventAddxxx

然后xTraceEventEnd

其中xTraceEventBegin调用xTraceEventBeginOffline即宏TRC_EVENT_BEGIN_OFFLINE实现如下

#define TRC_EVENT_BEGIN_OFFLINE(uiEventCode, uiPayloadSize, pxEventHandle) \
    ( \
        (xTraceEventBeginRawOffline(sizeof(TraceBaseEvent_t) + (uiPayloadSize), pxEventHandle)) == TRC_SUCCESS ? \
        ( \
            pxTraceEventDataTable->coreEventData[TRC_CFG_GET_CURRENT_CORE()].eventCounter++, \
            SET_BASE_EVENT_DATA((TraceBaseEvent_t*)(((TraceEventData_t*)*(pxEventHandle))->pvBlob), \
                uiEventCode, \
                (((TraceEventData_t*)*(pxEventHandle))->size - sizeof(TraceBaseEvent_t)) / sizeof(uint32_t), \
                pxTraceEventDataTable->coreEventData[TRC_CFG_GET_CURRENT_CORE()].eventCounter), \
            ((TraceEventData_t*)*(pxEventHandle))->offset += sizeof(TraceBaseEvent_t), \
            TRC_SUCCESS \
        ) : TRC_FAIL \
    )
其中eventCounter++即递增事件计数,SET_BASE_EVENT_DATA即设置每个事件的基本信息,

事件格式,即如下包括事件ID,总的事件计数,和时间戳

 

/**
 * @internal Trace Base Event Structure
 */
typedef struct {
    uint16_t EventID;       /**< */
    uint16_t EventCount;    /**< */
    uint32_t TS;            /**< */
} TraceBaseEvent_t;

其中 SET_BASE_EVENT_DATA实现如下

#define SET_BASE_EVENT_DATA(pxEvent, eventId, paramCount, eventCount) \
    ( \
        (pxEvent)->EventID = TRC_EVENT_SET_PARAM_COUNT(eventId, paramCount), \
        (pxEvent)->EventCount = TRC_EVENT_SET_EVENT_COUNT(eventCount), \
        xTraceTimestampGet(&(pxEvent)->TS) \
    )
 

 

事件ID,TRC_EVENT_SET_PARAM_COUNT如下高4位表示参数个数,低12位表示事件类型,即PSF_EVENT_开始的宏。

#define TRC_EVENT_SET_PARAM_COUNT(id, n) (((uint16_t)(id)) | ((((uint16_t)(n)) & 0xF) << 12))

 

所以可以看到事件记录格式如下

EEWORLDIMGTK1

 

添加了上述信息后然后调用TraceEventAddxxx添加参数,

最后调用xTraceEventEnd将事件写入到发送缓存中。

以任务切换事件为例,如果切换到执行某个任务,则回调traceTASK_SWITCHED_IN

即xTraceTaskSwitch

traceResult xTraceTaskSwitch(void *pvTask, TraceUnsignedBaseType_t uxPriority)
{
    traceResult xResult = TRC_FAIL;
    TraceEventHandle_t xEventHandle = 0;
    void* pvCurrent = 0;

    TRACE_ALLOC_CRITICAL_SECTION();
    
    (void)pvTask;
    (void)uxPriority;
    if (xTraceIsRecorderEnabled() == 0)
    {
        return xResult;
    }
    TRACE_ENTER_CRITICAL_SECTION();
    xTraceStateSet(TRC_STATE_IN_TASKSWITCH);
    xTraceTaskGetCurrent(&pvCurrent);
    if (pvCurrent != pvTask)
    {
        xTraceTaskSetCurrent(pvTask);
        
        if (xTraceEventBegin(PSF_EVENT_TASK_ACTIVATE, sizeof(void*) + sizeof(uint32_t), &xEventHandle) == TRC_SUCCESS)
        {
            xTraceEventAddPointer(xEventHandle, pvTask);
            xTraceEventAdd32(xEventHandle, (uint32_t)uxPriority);
            xTraceEventEnd(xEventHandle);
            xResult = TRC_SUCCESS;
        }
    }
    xTraceStateSet(TRC_STATE_IN_APPLICATION);
    TRACE_EXIT_CRITICAL_SECTION();
    return xResult;
}

 

其中核心的事件记录处理如下

   if (xTraceEventBegin(PSF_EVENT_TASK_ACTIVATE, sizeof(void*) + sizeof(uint32_t), &xEventHandle) == TRC_SUCCESS)
        {
            xTraceEventAddPointer(xEventHandle, pvTask);
            xTraceEventAdd32(xEventHandle, (uint32_t)uxPriority);
            xTraceEventEnd(xEventHandle);
            xResult = TRC_SUCCESS;
        }

 

事件类型是PSF_EVENT_TASK_ACTIVATE=0x37

参数为两个

一个(void*)类型的任务地址,即pvTask

一个uint32_t类型的任务优先级,即uxPriority

所以传入xTraceEventBegin的参数大小是sizeof(void*) + sizeof(uint32_t)即两个WORD。

xTraceEventAddPointer添加指针参数,实现如下

#define TRC_EVENT_ADD_POINTER(xEventHandle, value) \
    TRC_COMMA_EXPR_TO_STATEMENT_EXPR_3( \
        ((void**)((TraceEventData_t*)(xEventHandle))->pvBlob)[((TraceEventData_t*)(xEventHandle))->offset / sizeof(void*)] = (value), \
        ((TraceEventData_t*)(xEventHandle))->offset += sizeof(void*), \
        TRC_SUCCESS \
    )
 

xTraceEventAdd32添加ige无符号32位值,实现如下

#define TRC_EVENT_ADD_32(xEventHandle, value) \
    TRC_COMMA_EXPR_TO_STATEMENT_EXPR_3( \
        ((uint32_t*)((TraceEventData_t*)(xEventHandle))->pvBlob)[((TraceEventData_t*)(xEventHandle))->offset / sizeof(uint32_t)] = (value), \
        ((TraceEventData_t*)(xEventHandle))->offset += sizeof(uint32_t), \
        TRC_SUCCESS \
    )

 

xTraceEventAdd32添加ige无符号32位值,实现如下

#define TRC_EVENT_ADD_32(xEventHandle, value) \
    TRC_COMMA_EXPR_TO_STATEMENT_EXPR_3( \
        ((uint32_t*)((TraceEventData_t*)(xEventHandle))->pvBlob)[((TraceEventData_t*)(xEventHandle))->offset / sizeof(uint32_t)] = (value), \
        ((TraceEventData_t*)(xEventHandle))->offset += sizeof(uint32_t), \
        TRC_SUCCESS \
    )

 

上述基本事件信息和参数都存储在pvBlob开始的区域,

最后xTraceEventEnd->xTraceEventEndOffline->xTraceStreamPortCommit将事件存入发送缓存区。

最后清除pvBlob记录,以便下次继续进行事件记录。

#define RESET_EVENT_DATA(p) \
    ( \
        (p)->pvBlob = 0, \
        (p)->size = 0, \
        (p)->offset = 0 \
    )
 

 

EEWORLDIMGTK2

对应抓取的包如下

0x2037表示是PSF_EVENT_TASK_ACTIVATE事件,0x00BE是事件计数值,0x00012809是时间戳,,0x081103A8是任务地址,0x00000001是任务优先级。

后面0x20EB是另外一个事件,事件参数有2个,事件ID是0xEB可以看到是PSF_EVENT_UNUSED_STACK,事件计数器0x00BF是在前一个事件基础上递增,时间戳是0x00013911,参数1是0x081103A8,参数2是0x00000FA0.

可以看到xTraceStackMonitorReport中,PSF_EVENT_UNUSED_STACK事件除了基本事件信息后面就是任务地址和栈最低MARK值,这里是0x00000FA0,说明该任务最少剩余该大小栈未使用。

 if (xTraceEventBegin(PSF_EVENT_UNUSED_STACK, sizeof(void*) + sizeof(uint32_t), &xEventHandle) == TRC_SUCCESS)
        {
            xTraceEventAddPointer(xEventHandle, pxStackMonitorEntry->pvTask);
            xTraceEventAdd32(xEventHandle, (uint32_t)pxStackMonitorEntry->uxPreviousLowWaterMark);
            xTraceEventEnd(xEventHandle);
        }
 

 

EEWORLDIMGTK3

三.丢事件监测

EEWORLDIMGTK4

如上图live Stream可能会显示丢事件数,其实现原理如下

#define TRC_EVENT_BEGIN_OFFLINE(uiEventCode, uiPayloadSize, pxEventHandle) \
    ( \
        (xTraceEventBeginRawOffline(sizeof(TraceBaseEvent_t) + (uiPayloadSize), pxEventHandle)) == TRC_SUCCESS ? \
        ( \
            pxTraceEventDataTable->coreEventData[TRC_CFG_GET_CURRENT_CORE()].eventCounter++, \
            SET_BASE_EVENT_DATA((TraceBaseEvent_t*)(((TraceEventData_t*)*(pxEventHandle))->pvBlob), \
                uiEventCode, \
                (((TraceEventData_t*)*(pxEventHandle))->size - sizeof(TraceBaseEvent_t)) / sizeof(uint32_t), \
                pxTraceEventDataTable->coreEventData[TRC_CFG_GET_CURRENT_CORE()].eventCounter), \
            ((TraceEventData_t*)*(pxEventHandle))->offset += sizeof(TraceBaseEvent_t), \
            TRC_SUCCESS \
        ) : TRC_FAIL \
    )

 

每记录一个事件时,TRC_EVENT_BEGIN_OFFLINE宏中,事件计数递增eventCounter++,然后

SET_BASE_EVENT_DATA记录到事件信息中

typedef struct {
    uint16_t EventID;       /**< */
    uint16_t EventCount;    /**< */
    uint32_t TS;            /**< */
} TraceBaseEvent_t;

 

EventCount会递增,上位机可以通过该值是否连续递增来确认是否丢事件,以及丢了多少个事件。

四. 总结

以上分析了Tracealyzer的发送到上位机的事件记录是如何组织的,基于此就可以手动解析事件信息方便调试分析。甚至可以自己开发类似的GUI或者其他测试分析工具。

 

 

 

此帖出自汽车电子论坛
点赞 关注

回复
举报
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表