【简介】
我们在之前的帖子中已经介绍了perf counter 的移植适配(https://forum.eepw.com.cn/thread/396851/1),perf counter 在2.5.2 版本中 添加了 __stack_usage__ 宏来实现函数调用使用的栈深度信息计算的功能。这个工具对于要确认某个函数所占用的函数栈深度就是味到嘴边的服务了。对应的宏函数实现如下:
/*! * \brief measure the stack usage of the given code segement * \param[in] __STR a name for this measurement * \param[in] __perfc_stack_limit the stack based address (stack limit) * \param[in] ... an optional code segement, in which we can read the measured * result from __stack_used__. */ #define __stack_usage__(__STR, __perfc_stack_base, ...) \ \ perfc_using(uintptr_t __stack_used__ = (uintptr_t)-1, \ PERFC_SAFE_NAME(nSP) = __perfc_port_get_sp(), \ {perfc_stack_fill( PERFC_SAFE_NAME(nSP), \ (uintptr_t)(__perfc_stack_base));}, \ { \ PERFC_SAFE_NAME(nSP) &= (~((uintptr_t)0x07)); \ uintptr_t PERFC_SAFE_NAME(nStackLimit) \ = (uintptr_t)(__perfc_stack_base); \ PERFC_SAFE_NAME(nStackLimit) \ = (PERFC_SAFE_NAME(nStackLimit) + 7) \ & (~((uintptr_t)0x07)); \ if (PERFC_SAFE_NAME(nSP) <= PERFC_SAFE_NAME(nStackLimit)) { \ if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \ __perf_counter_printf__( \ "\r\n-------------------------------------\r\n" \ __STR " Stack Overflow!!!" \ " SP: [0x%08"PRIxPTR"]" \ " Stack Base: [0x%08"PRIxPTR"]\r\n", \ PERFC_SAFE_NAME(nSP), \ PERFC_SAFE_NAME(nStackLimit)); \ } else { \ __VA_ARGS__; \ } \ } else { \ __stack_used__ \ = PERFC_SAFE_NAME(nSP) \ - PERFC_SAFE_NAME(nStackLimit) \ - perfc_stack_remain(PERFC_SAFE_NAME(nStackLimit)); \ if (__PLOOC_VA_NUM_ARGS(__VA_ARGS__) == 0) { \ __perf_counter_printf__( \ "\r\n-------------------------------------\r\n" \ __STR " Stack Used: %"PRIuPTR" bytes\r\n", \ __stack_used__); \ } else { \ __VA_ARGS__; \ } \ } \ })
上述宏函数的实现细节我们可以先不关注,我们按照使用说明文档来编写如下代码来验证宏函数
uintptr_t nStackLimit = __perfc_port_get_sp() - 512; __stack_usage__("PRINTF",nStackLimit) { PRINTF("cycle counter %lld.\r\n",lCycleUsed); }
上述代码的宏定义展开后代码如下
uintptr_t nStackLimit = __perfc_port_get_sp() - 512; for (uintptr_t __stack_used__ = (uintptr_t)-1, __nSP382 = __perfc_port_get_sp(), *__perfc_using_382_ptr = # 382 "../src/main.c" 3 4 ((void *)0) # 382 "../src/main.c" ; __perfc_using_382_ptr++ == # 382 "../src/main.c" 3 4 ((void *)0) # 382 "../src/main.c" ? (({perfc_stack_fill( __nSP382, (uintptr_t)(nStackLimit));}),1) : 0; ({ __nSP382 &= (~((uintptr_t)0x07)); uintptr_t __nStackLimit382 = (uintptr_t)(nStackLimit); __nStackLimit382 = (__nStackLimit382 + 7) & (~((uintptr_t)0x07)); if (__nSP382 <= __nStackLimit382) { if (0 == 0) { printf( "\r\n-------------------------------------\r\n" "PRINTF" " Stack Overflow!!!" " SP: [0x%08""x""]" " Stack Base: [0x%08""x""]\r\n", __nSP382, __nStackLimit382); } else { ; } } else { __stack_used__ = __nSP382 - __nStackLimit382 - perfc_stack_remain(__nStackLimit382); if (0 == 0) { printf( "\r\n-------------------------------------\r\n" "PRINTF" " Stack Used: %""u"" bytes\r\n", __stack_used__); } else { ; } } }) ) { printf("cycle counter %lld.\r\n",lCycleUsed); }
上述函数运行完输出结果信息如下,统计的printf 函数使用的栈为 448 bytes.
我们 debug 下上述代码确认下函数栈的使用。
在调用该函数前查看SP 指针为 0x2040 04F8
debug 事printf 调用 __swrite 分支时最大栈使用为 0x2040 0338
上述栈最大深度使用0x2040 04F8 - 0x2040 0338 = 1c0 = 448 和上述工具输出结果一致,此工具对于代码段栈深度评估也是一大利器。