查看: 932|回复: 0

[评测分享] 【Telink-泰凌微电子 B91通用开发套件】(四)FreeRtos任务栈统计

[复制链接]
  • TA的每日心情
    奋斗
    1 小时前
  • 签到天数: 127 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2023-10-26 12:31:08 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 andeyqi 于 2023-10-26 14:24 编辑

    简介:

           嵌入式开发中我们通常对任务栈的大小设置通常根据经验值来设定,设置的小了会造成栈溢出,设置大了会造成资源的浪费。如果能够计算出栈在任务过程中使用的最大深度的话对就可以根据实际情况来设置避免资源的浪费。计算任务栈的使用大小通常使用水印法,初始化时将栈设置为特定的magic ,栈内未使用的部分会时连续的magic,连续magic 的大小和栈的总深度的比较即可计算出栈的最大使用率。

    实现方式:
    本次实现基于freertos来实现,上述的实现方式主要需要实现如下几个部分:
    1.创建任务的时候将任务栈初始化为特定的magic(0xa5)
    2.将任务tcb信息中的栈的起始地址和栈深度缓存下来
    3.计算栈的非踩踏区域的长度和栈深度计算栈的最大使用率


    1.创建任务的时候将任务栈初始化为特定的magic(0xa5)

    FreeRTOS 创建任务的时候会根据配置项目,决定是否将栈初始化特定的magic,代码如下:


    init_magic.png


    只要配置 tskSET_NEW_STACKS_TO_KNOWN_VALUE == 1就会初始化栈为特定的魔数(0xa5),  通过如下代码可知配置configUSE_STACK_MAX_USAGE  = 1 会定义tskSET_NEW_STACKS_TO_KNOWN_VALUE = 1,我们在freertos 的配置文件中定义该宏即可

    1. /* If any of the following are set then task stacks are filled with a known
    2. * value so the high water mark can be determined.  If none of the following are
    3. * set then don't fill the stack so there is no unnecessary dependency on memset. */
    4. #if ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark2 == 1 ) || (configUSE_STACK_MAX_USAGE == 1))
    5.     #define tskSET_NEW_STACKS_TO_KNOWN_VALUE    1
    6. #else
    7.     #define tskSET_NEW_STACKS_TO_KNOWN_VALUE    0
    8. #endif
    复制代码
    对应FreeRtos配置追加如下宏配置:
    freertos_config.png

    修改如下配置将在栈创建深度信息通知给hook函数处理,修改如下:

    patch1.png


    patch2.png


    2.将任务tcb信息中的栈的起始地址和栈深度缓存下来

    freertos 有很多hook 函数时可以供用户使用来劫持操作系统的信息,我们可以通过如下的回调函数(traceTASK_CREATE)截取系统的栈信息。
    trace_macro.png

    3.计算栈的非踩踏区域的长度和栈深度计算栈的最大使用率

    添加stack 命令计算显示当前的栈信息,代码如下。

    1. #include <stdint.h>
    2. #include <stdio.h>
    3. #include <stdlib.h>
    4. #include <string.h>
    5. #include "FreeRTOS.h"
    6. #if (configUSE_PERF_CNT == 1)
    7. #include "perf_counter.h"
    8. #endif
    9. #include "littleshell.h"
    10. #include "trace_dump.h"

    11. #if ((configUSE_STACK_MAX_USAGE == 0 )&& (configUSE_PERF_CNT == 1))
    12.     #error perf is depend on configUSE_STACK_MAX_USAGE = 1
    13. #endif


    14. #if ( configUSE_STACK_MAX_USAGE == 1 )

    15. struct task_stack_info
    16. {
    17.     char task_name[configMAX_TASK_NAME_LEN];
    18.     uint32_t stack_deep;
    19.     uint32_t*  stack_tail;
    20. };

    21. struct task_stack_info_tbl
    22. {
    23.     uint8_t num;
    24.     struct task_stack_info * tasks;
    25. };

    26. #define OS_NUM_TASKS_SUPPORT 10

    27. static struct task_stack_info stack_all[OS_NUM_TASKS_SUPPORT];

    28. static struct task_stack_info_tbl task_stacks =
    29. {
    30.     .num = 0,
    31.     .tasks = stack_all,
    32. };


    33. #define TASK_STACK_NAME(i) task_stacks.tasks[i].task_name
    34. #define TASK_STACK_DEEP(i) task_stacks.tasks[i].stack_deep
    35. #define TASK_STACK_TAIL(i) task_stacks.tasks[i].stack_tail
    36. #define TASK_STACK_TAIL_OFF_ADDR(i,off) &task_stacks.tasks[i].stack_tail[off]



    37. void task_create_hook_stack(char * name ,unsigned int deep,unsigned int * stack_tail)
    38. {
    39.     uint8_t i_loop = task_stacks.num;
    40.     uint8_t len,i;
    41.     char * p_task_name;

    42.     if(i_loop < OS_NUM_TASKS_SUPPORT)
    43.     {
    44.         p_task_name = TASK_STACK_NAME(i_loop);
    45.         strcpy(TASK_STACK_NAME(i_loop),name);
    46.         if((len = strlen(TASK_STACK_NAME(i_loop))) != (configMAX_TASK_NAME_LEN-1))
    47.         {
    48.             for(i = len;i < configMAX_TASK_NAME_LEN-1;i++)
    49.                 p_task_name[i] = '\0';
    50.         }
    51.         p_task_name[configMAX_TASK_NAME_LEN-1] = '\0';
    52.         TASK_STACK_DEEP(i_loop) = deep*4;
    53.         TASK_STACK_TAIL(i_loop) = stack_tail;
    54.         /* if use pref to set perf default value */
    55. #if ( configUSE_PERF_CNT == 1 )
    56.         memset((void*)TASK_STACK_TAIL(i_loop),0,sizeof(task_cycle_info_t)+8);
    57. #endif
    58.         task_stacks.num++;
    59.     }
    60.     else
    61.     {
    62.         printf("task num is max than OS_NUM_TASKS_SUPPORT.\r\n");
    63.     }
    64. }


    65. static int buff_continuous_numbers(uint8_t * buff,uint8_t data)
    66. {
    67.     int l = 0;

    68.     if(NULL == buff)
    69.         return 0;

    70.     while(data == buff[l++]);

    71.     return  --l;
    72. }

    73. extern size_t xPortGetFreeHeapSize( void );

    74. unsigned int stack(char argc,char ** argv)
    75. {
    76.     uint8_t i,j;
    77.     int len,name_len;
    78.     char task_name[configMAX_TASK_NAME_LEN];

    79.     if(argc == 1)
    80.     {
    81.         //logctrl_instance()->is_sync = 1;
    82.         printf("taskname\tdeep\tused\taddress\t\t\tusage\r\n");
    83.         for(i = 0;i < task_stacks.num;i++)
    84.         {
    85. #if ( configUSE_PERF_CNT != 1 )
    86.             len = buff_continuous_numbers((uint8_t *)TASK_STACK_TAIL(i),0xa5);
    87. #else
    88.             len = buff_continuous_numbers((uint8_t *)TASK_STACK_TAIL_OFF_ADDR(i,WORD_OF_CYCEL_INFO),0xa5);
    89.             if(len)
    90.                 len += BYTE_OF_CYCEL_INFO;
    91. #endif
    92.         strcpy(task_name,TASK_STACK_NAME(i));
    93.         task_name[configMAX_TASK_NAME_LEN - 1] = '\0';
    94.         if((name_len = strlen(TASK_STACK_NAME(i))) != (configMAX_TASK_NAME_LEN-1))
    95.         {
    96.             for(j = name_len;j < configMAX_TASK_NAME_LEN-1;j++)
    97.                 task_name[j] = ' ';
    98.         }
    99.             printf("%s\t%d\t%d\t0x%08p~0x%08p\t%d%%\r\n",task_name,TASK_STACK_DEEP(i),
    100.             TASK_STACK_DEEP(i)-len,TASK_STACK_TAIL(i),
    101.             TASK_STACK_TAIL(i)+(TASK_STACK_DEEP(i)/4),(100-(len*100)/TASK_STACK_DEEP(i)));
    102.         }
    103.         printf("\r\nHeap Total:%d\tFree:%d\r\n",configTOTAL_HEAP_SIZE,xPortGetFreeHeapSize());
    104.         //logctrl_instance()->is_sync = 0;
    105.     }
    106.     if(argc == 2)
    107.     {
    108.         uint8_t index = atoi(argv[1]);
    109.         if(index >=  task_stacks.num)
    110.             goto out;
    111.         printf("task name [%s] stack deep 0x%x\r\n",TASK_STACK_NAME(index),TASK_STACK_DEEP(index));
    112.         //logctrl_instance()->is_sync = 1;
    113.         trace_byte_stream((uint8_t *)TASK_STACK_TAIL(index),TASK_STACK_DEEP(index),0);
    114.         //logctrl_instance()->is_sync = 0;
    115.     }
    116. out:
    117.     return 0;
    118. }

    119. //LTSH_FUNCTION_EXPORT(stack,"show task statck info");

    120. #if ( configUSE_PERF_CNT == 1 )

    121. unsigned int perf(char argc,char ** argv)
    122. {
    123.     uint8_t i,j,len;
    124.     int64_t count = get_system_ticks();
    125.     char task_name[configMAX_TASK_NAME_LEN];

    126.     //logctrl_instance()->is_sync = 1;
    127.     if(argc == 1)
    128.     {
    129.         printf("taskname\trecent\t\tactive\tusedmax\t\tusedmin\t\tusedavg\t\tcpuusage\r\n");
    130.         for(i = 0;i < task_stacks.num;i++)
    131.         {
    132.             task_cycle_info_t * pcycle = get_rtos_task_cycle_info_by_stack(TASK_STACK_TAIL(i));
    133.             task_name[configMAX_TASK_NAME_LEN - 1] = '\0';
    134.             strcpy(task_name,TASK_STACK_NAME(i));
    135.             if((len = strlen(TASK_STACK_NAME(i))) != (configMAX_TASK_NAME_LEN-1))
    136.             {
    137.                 for(j = len;j < configMAX_TASK_NAME_LEN-1;j++)
    138.                     task_name[j] = ' ';
    139.             }
    140.             printf("%s\t%010d\t%d\t%010d\t%010d\t%010d\t%.2f\r\n",
    141.                    task_name,pcycle->nUsedRecent,pcycle->wActiveCount,
    142.                    pcycle->nUsedMax,pcycle->nUsedMin,pcycle->lUsedTotal/pcycle->wActiveCount,
    143.                    ((double)(pcycle->lUsedTotal))/((double)count)*((double)100.0f));
    144.         }
    145.     }
    146.     //logctrl_instance()->is_sync = 0;
    147.     return 0;
    148. }

    149. LTSH_FUNCTION_EXPORT(perf,"show perf info");
    150. #endif

    151. #endif /* end of configUSE_STACK_MAX_USAGE */

    复制代码


    运行效果:

    输入stack 命令即可查看当前任务的栈使用深度,根据输出结果来确认栈大小设置是否合理。

    stack.png


    ==================资料分割线==================
    代码和官方下载的资料已上传至如下git路径












    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    手机版|小黑屋|与非网

    GMT+8, 2024-5-14 20:56 , Processed in 0.120470 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.