qinyunti 发表于 2024-6-23 16:15

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

<div class='showpostmsg'><p>书中分享了很多理论,方法和案例,</p>

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

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

<p>&nbsp;</p>

<div></div>

<h1>一.&nbsp;<strong>前言</strong></h1>

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

<h1>二.&nbsp;<strong>事件</strong></h1>

<p>启动时xTraceKernelPortEnable创建事件记录PSF_EVENT_HEAP_CREATE</p>

<section>
<pre>
<code>if (pxKernelPortData-&gt;xSystemHeapHandle == 0)
{
    xTraceHeapCreate("System Heap", 0, 0, configTOTAL_HEAP_SIZE, &amp;pxKernelPortData-&gt;xSystemHeapHandle);
}</code></pre>

<div contenteditable="false" tabindex="-1">&nbsp;</div>
</section>

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

<pre>
<code>#define configTOTAL_HEAP_SIZE                   &amp;_heap_size</code></pre>

<p>xTraceHeapCreate实现如下,会发送事件PSF_EVENT_HEAP_CREATE</p>

<section>
<pre>
<code>traceResult xTraceHeapCreate(const char *szName, TraceUnsignedBaseType_t uxCurrent, TraceUnsignedBaseType_t uxHighWaterMark, TraceUnsignedBaseType_t uxMax, TraceHeapHandle_t *pxHeapHandle)
{
TraceUnsignedBaseType_t uxStates;

uxStates = uxCurrent;
uxStates = uxHighWaterMark;
uxStates = uxMax;

return xTraceObjectRegisterInternal(PSF_EVENT_HEAP_CREATE, 0, szName, 3, uxStates, TRC_ENTRY_OPTION_HEAP, (TraceObjectHandle_t*)pxHeapHandle);
}</code></pre>

<div contenteditable="false" tabindex="-1">&nbsp;</div>
</section>

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

<section>
<pre>
<code>if (xTraceEventBegin(uiEventCode, sizeof(void*) + uxStateCount * sizeof(TraceUnsignedBaseType_t), &amp;xEventHandle) == TRC_SUCCESS)
    {
      xTraceEventAddPointer(xEventHandle, pvObject);
      for (i = 0; i &lt; uxStateCount; i++)
      {
            xTraceEventAddUnsignedBaseType(xEventHandle, uxStates);
      }
      xTraceEventEnd(xEventHandle);
    }</code></pre>

<div contenteditable="false" tabindex="-1">&nbsp;</div>
</section>

<p>&nbsp;</p>

<p>宏TRC_CFG_INCLUDE_MEMMANG_EVENTS要配置为1</p>

<p>TRC_CFG_SCHEDULING_ONLY配置为0</p>

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

<p>trcKernelPort.h中</p>

<section>
<pre>
<code>#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

</code></pre>

<div contenteditable="false" tabindex="-1">&nbsp;</div>
</section>

<p>&nbsp;</p>

<p>最终调用xTraceHeapAlloc和xTraceHeapFree实现</p>

<p>存储的事件为</p>

<p>PSF_EVENT_MALLOC&nbsp;或PSF_EVENT_MALLOC_FAILED,参数是一个地址一个大小</p>

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

<div contenteditable="false" tabindex="-1">&nbsp;</div>
</section>

<p>PSF_EVENT_FREE&nbsp;或PSF_EVENT_FREE_FAILED,参数是一个地址一个大小</p>

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

<div contenteditable="false" tabindex="-1">&nbsp;</div>
</section>

<p>事件信息存储在</p>

<p>全局变量pxKernelPortData-&gt;xSystemHeapHandle中</p>

<p>对应的初始化</p>

<section>
<pre>
<code>traceResult xTraceHeapCreate(const char *szName, TraceUnsignedBaseType_t uxCurrent, TraceUnsignedBaseType_t uxHighWaterMark, TraceUnsignedBaseType_t uxMax, TraceHeapHandle_t *pxHeapHandle)
{
    TraceUnsignedBaseType_t uxStates;

    uxStates = uxCurrent;
    uxStates = uxHighWaterMark;
    uxStates = uxMax;

    return xTraceObjectRegisterInternal(PSF_EVENT_HEAP_CREATE, 0, szName, 3, uxStates, TRC_ENTRY_OPTION_HEAP, (TraceObjectHandle_t*)pxHeapHandle);
}</code></pre>

<div contenteditable="false" tabindex="-1">&nbsp;</div>
</section>

<p>xTraceHeapCreate调用xTraceObjectRegisterInternal,从&amp;pxEntryTable-&gt;axEntries中创建分配空间出来</p>

<pre>
<code> *pxObjectHandle = (TraceObjectHandle_t)xEntryHandle;</code></pre>

<p>所以pxKernelPortData-&gt;xSystemHeapHandle即指向上述pxEntryTable-&gt;axEntries分配出来的xEntryHandle,</p>

<p>指向的内容是</p>

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

<section>
<pre>
<code>#define TRC_HEAP_STATE_INDEX_CURRENT      0
#define TRC_HEAP_STATE_INDEX_HIGHWATERMARK1
#define TRC_HEAP_STATE_INDEX_MAX            2</code></pre>

<div contenteditable="false" tabindex="-1">&nbsp;</div>
</section>

<p>&nbsp;</p>

<p>以下就是获取出CURRENT值</p>

<section>
<pre>
<code> if (pvAddress != 0)
{
    /* This should never fail */
    TRC_ASSERT_ALWAYS_EVALUATE(xTraceEntryGetState(xHeapHandle, TRC_HEAP_STATE_INDEX_CURRENT, &amp;uxCurrent) == TRC_SUCCESS);

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

    uxCurrent += uxSize;

    if (uxCurrent &gt; 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);
}
</code></pre>

<div contenteditable="false" tabindex="-1">&nbsp;</div>
</section>

<p>抓包事件如下,2个参数</p>

<section>
<pre>
<code>#define PSF_EVENT_MALLOC                                    0x38
#define PSF_EVENT_FREE                                    0x39
#define PSF_EVENT_MALLOC_FAILED                           0xE9
#define PSF_EVENT_FREE_FAILED                               0xEA
</code></pre>

<div contenteditable="false" tabindex="-1">&nbsp;</div>
</section>

<p>&nbsp;</p>

<p>那么找如下字段即可</p>

<p>0x38 0x20</p>

<p>0x39 0x20</p>

<p>0xE9 0x20</p>

<p>0xEA 0x20</p>

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

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

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>&nbsp;</p>

<h1>三.&nbsp;<strong>实测</strong></h1>

<p>菜单栏views-&gt;Memory Heap Utilization打开窗口</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

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

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

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>Event log视图也可以看到事件</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>Trace视图也可以看到事件</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

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

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>&nbsp;</p>

<h1>四.&nbsp;<strong>总结</strong></h1>

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

<p>&nbsp;</p>

<p>&nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>
页: [1]
查看完整版本: 《嵌入式软件的时间分析》从书中到实践-使用Tracealyzer进行RTOS堆分析