585|0

504

帖子

4

TA的资源

纯净的硅(高级)

楼主
 

《嵌入式软件的时间分析》从书中到实践-使用Tracealyzer进行RTOS堆分析 [复制链接]

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

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

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

 

一. 前言

前面分享了使用Tracealyzer进行RTOS任务栈分析,这一篇继续分享另外一个很重要的实践案例即堆的使用分析。

二. 事件

启动时xTraceKernelPortEnable创建事件记录PSF_EVENT_HEAP_CREATE

if (pxKernelPortData->xSystemHeapHandle == 0)
  {
    xTraceHeapCreate("System Heap", 0, 0, configTOTAL_HEAP_SIZE, &pxKernelPortData->xSystemHeapHandle);
  }
 

FreeRTOSConfig.h需要配置堆大小我这里使用了编译器符号,&_heap_size,按照实际设置即可。

#define configTOTAL_HEAP_SIZE                   &_heap_size

xTraceHeapCreate实现如下,会发送事件PSF_EVENT_HEAP_CREATE

traceResult xTraceHeapCreate(const char *szName, TraceUnsignedBaseType_t uxCurrent, TraceUnsignedBaseType_t uxHighWaterMark, TraceUnsignedBaseType_t uxMax, TraceHeapHandle_t *pxHeapHandle)
{
  TraceUnsignedBaseType_t uxStates[3];

  uxStates[TRC_HEAP_STATE_INDEX_CURRENT] = uxCurrent;
  uxStates[TRC_HEAP_STATE_INDEX_HIGHWATERMARK] = uxHighWaterMark;
  uxStates[TRC_HEAP_STATE_INDEX_MAX] = uxMax;

  return xTraceObjectRegisterInternal(PSF_EVENT_HEAP_CREATE, 0, szName, 3, uxStates, TRC_ENTRY_OPTION_HEAP, (TraceObjectHandle_t*)pxHeapHandle);
}
 

事件记录如下,即一个指针加3个WORD的uxStates信息

if (xTraceEventBegin(uiEventCode, sizeof(void*) + uxStateCount * sizeof(TraceUnsignedBaseType_t), &xEventHandle) == TRC_SUCCESS)
    {
        xTraceEventAddPointer(xEventHandle, pvObject);
        for (i = 0; i < uxStateCount; i++)
        {
            xTraceEventAddUnsignedBaseType(xEventHandle, uxStates[i]);
        }
        xTraceEventEnd(xEventHandle);
    }
 

 

宏TRC_CFG_INCLUDE_MEMMANG_EVENTS要配置为1

TRC_CFG_SCHEDULING_ONLY配置为0

在pvPortMalloc和pvPortFree接口中,对应的事件记录处理

trcKernelPort.h中

#undef traceMALLOC
#define traceMALLOC( pvAddress, uiSize ) \
    if (xTraceIsRecorderEnabled()) \
    { \
        xTraceHeapAlloc(xTraceKernelPortGetSystemHeapHandle(), pvAddress, uiSize); \
    }

#undef traceFREE
#define traceFREE( pvAddress, uiSize ) \
    if (xTraceIsRecorderEnabled()) \
    { \
        xTraceHeapFree(xTraceKernelPortGetSystemHeapHandle(), pvAddress, uiSize); \
    }

#endif

 

 

最终调用xTraceHeapAlloc和xTraceHeapFree实现

存储的事件为

PSF_EVENT_MALLOC 或PSF_EVENT_MALLOC_FAILED,参数是一个地址一个大小

 if (xTraceEventBegin(pvAddress != 0 ? PSF_EVENT_MALLOC : PSF_EVENT_MALLOC_FAILED, sizeof(void*) + sizeof(TraceUnsignedBaseType_t), &xEventHandle) == TRC_SUCCESS)
    {
        xTraceEventAddPointer(xEventHandle, pvAddress);
        xTraceEventAddUnsignedBaseType(xEventHandle, uxSize);
        xTraceEventEnd(xEventHandle);
    }
 

PSF_EVENT_FREE 或PSF_EVENT_FREE_FAILED,参数是一个地址一个大小

 if (xTraceEventBegin(pvAddress != 0 ? PSF_EVENT_FREE : PSF_EVENT_FREE_FAILED, sizeof(void*) + sizeof(TraceUnsignedBaseType_t), &xEventHandle) == TRC_SUCCESS)
    {
        xTraceEventAddPointer(xEventHandle, pvAddress);
        xTraceEventAddUnsignedBaseType(xEventHandle, uxSize);
        xTraceEventEnd(xEventHandle);
    }
 

事件信息存储在

全局变量pxKernelPortData->xSystemHeapHandle中

对应的初始化

traceResult xTraceHeapCreate(const char *szName, TraceUnsignedBaseType_t uxCurrent, TraceUnsignedBaseType_t uxHighWaterMark, TraceUnsignedBaseType_t uxMax, TraceHeapHandle_t *pxHeapHandle)
{
    TraceUnsignedBaseType_t uxStates[3];

    uxStates[TRC_HEAP_STATE_INDEX_CURRENT] = uxCurrent;
    uxStates[TRC_HEAP_STATE_INDEX_HIGHWATERMARK] = uxHighWaterMark;
    uxStates[TRC_HEAP_STATE_INDEX_MAX] = uxMax;

    return xTraceObjectRegisterInternal(PSF_EVENT_HEAP_CREATE, 0, szName, 3, uxStates, TRC_ENTRY_OPTION_HEAP, (TraceObjectHandle_t*)pxHeapHandle);
}
 

xTraceHeapCreate调用xTraceObjectRegisterInternal,从&pxEntryTable->axEntries[xIndex]中创建分配空间出来

 *pxObjectHandle = (TraceObjectHandle_t)xEntryHandle;

所以pxKernelPortData->xSystemHeapHandle即指向上述pxEntryTable->axEntries分配出来的xEntryHandle,

指向的内容是

如下3个索引的WORD,即当前值,heap的最大值,heap的最大使用值。

#define TRC_HEAP_STATE_INDEX_CURRENT        0
#define TRC_HEAP_STATE_INDEX_HIGHWATERMARK  1
#define TRC_HEAP_STATE_INDEX_MAX            2
 

 

以下就是获取出CURRENT值

 if (pvAddress != 0)
  {
    /* This should never fail */
    TRC_ASSERT_ALWAYS_EVALUATE(xTraceEntryGetState(xHeapHandle, TRC_HEAP_STATE_INDEX_CURRENT, &uxCurrent) == TRC_SUCCESS);

    /* This should never fail */
    TRC_ASSERT_ALWAYS_EVALUATE(xTraceEntryGetState(xHeapHandle, TRC_HEAP_STATE_INDEX_HIGHWATERMARK, &uxHighWaterMark) == TRC_SUCCESS);

    uxCurrent += uxSize;

    if (uxCurrent > uxHighWaterMark)
    {
      uxHighWaterMark = uxCurrent;
      /* This should never fail */
      TRC_ASSERT_ALWAYS_EVALUATE(xTraceEntrySetState(xHeapHandle, TRC_HEAP_STATE_INDEX_HIGHWATERMARK, uxHighWaterMark) == TRC_SUCCESS);
    }

    /* This should never fail */
    TRC_ASSERT_ALWAYS_EVALUATE(xTraceEntrySetState(xHeapHandle, TRC_HEAP_STATE_INDEX_CURRENT, uxCurrent) == TRC_SUCCESS);
  }
 

抓包事件如下,2个参数

#define PSF_EVENT_MALLOC                                    0x38
#define PSF_EVENT_FREE                                      0x39
#define PSF_EVENT_MALLOC_FAILED                             0xE9
#define PSF_EVENT_FREE_FAILED                               0xEA
 

 

那么找如下字段即可

0x38 0x20

0x39 0x20

0xE9 0x20

0xEA 0x20

必然要如下38 20表示MALLOC事件,0x009C是事件计数,

0x00007EAC是时间戳,0x081096E0是堆地址,0x00000070是申请的大小112字节。

 

 

 

三. 实测

菜单栏views->Memory Heap Utilization打开窗口

 

 

显示堆的申请和释放过程,实际就是一个计数器,申请就递增,释放就减少,如果这个数一

直递增说明申请的多释放的少,最终导致堆不够。

 

 

Event log视图也可以看到事件

 

 

Trace视图也可以看到事件

 

 

Trace视图双击malloc或者free,弹出窗口,显示malloc和free的历史,可以看到谁申请了什么时候释放了,这样可以追踪申请和释放是否正常

 

 

 

四. 总结

以上分享使用Tracealyzer进行堆分析的案例,实际就是一个计数器事件,malloc则计数值增加free则递减,可以看到什么时候malloc什么时候free,如果有未free则可以通过图表结合前后事件分析出来。

 

 

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

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

查找数据手册?

EEWorld Datasheet 技术支持

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

 
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
快速回复 返回顶部 返回列表