testCommon.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. #include "FreeRTOS.h"
  2. #include "RyanJsonInternal.h"
  3. #include "testCommon.h"
  4. #include "tlsf.h"
  5. #if defined(RyanJsonTestPlatformQemu)
  6. #define unitTlsfPoolSize (600U * 1024U)
  7. #define unitTlsfPoolMin (512U * 1024U)
  8. #else
  9. #define unitTlsfPoolSize (1024U * 1024U)
  10. #endif
  11. typedef struct
  12. {
  13. tlsf_t tlsfHandle;
  14. void *poolBuffer;
  15. size_t poolSize;
  16. } unityTestTlsfCtx_t;
  17. static unityTestTlsfCtx_t gUnityTestTlsfCtx = {NULL, NULL, 0U};
  18. #if defined(RyanJsonTestPlatformQemu)
  19. static uint8_t gQemuTlsfPoolLogged = 0U;
  20. #endif
  21. static uint8_t gAllocSimConfigLogged = 0U;
  22. static uint8_t gAllocSimEnabled = 0U;
  23. static int32_t gOomFailAfter = -1;
  24. static int32_t gOomAllocCount = 0;
  25. static uint8_t gOomDisableRealloc = 0U;
  26. static void *unityTestOomMalloc(size_t size)
  27. {
  28. if (gOomFailAfter >= 0 && gOomAllocCount++ >= gOomFailAfter) { return NULL; }
  29. return unityTestMalloc(size);
  30. }
  31. static void *unityTestOomRealloc(void *block, size_t size)
  32. {
  33. if (gOomFailAfter >= 0 && gOomAllocCount++ >= gOomFailAfter) { return NULL; }
  34. return unityTestRealloc(block, size);
  35. }
  36. uint64_t platformUptimeMs(void)
  37. {
  38. return testPlatformGetUptimeMs();
  39. }
  40. static size_t unityTestCalcSimulatedAllocSize(size_t requestSize)
  41. {
  42. const size_t headerSize = (size_t)RyanJsonTestAllocHeaderSize;
  43. const size_t alignSize = (size_t)RyanJsonTestAllocAlignSize;
  44. size_t allocSize = requestSize;
  45. if (0U == requestSize) { return 0U; }
  46. if (allocSize > (SIZE_MAX - headerSize)) { return 0U; }
  47. allocSize += headerSize;
  48. if (alignSize > 1U) { allocSize = RyanJsonAlign(allocSize, alignSize); }
  49. return allocSize;
  50. }
  51. void unityTestSetAllocSimulation(uint8_t isEnable)
  52. {
  53. if (0U != isEnable) { gAllocSimEnabled = 1U; }
  54. else
  55. {
  56. gAllocSimEnabled = 0U;
  57. }
  58. }
  59. uint8_t unityTestGetAllocSimulation(void)
  60. {
  61. return gAllocSimEnabled;
  62. }
  63. static bool unityTestInitTlsf(void)
  64. {
  65. if (NULL == gUnityTestTlsfCtx.poolBuffer)
  66. {
  67. size_t trySize = unitTlsfPoolSize;
  68. #if defined(RyanJsonTestPlatformQemu)
  69. while (trySize >= unitTlsfPoolMin)
  70. {
  71. gUnityTestTlsfCtx.poolBuffer = v_malloc(trySize);
  72. if (NULL != gUnityTestTlsfCtx.poolBuffer)
  73. {
  74. gUnityTestTlsfCtx.poolSize = trySize;
  75. break;
  76. }
  77. trySize /= 2U;
  78. }
  79. #else
  80. gUnityTestTlsfCtx.poolBuffer = v_malloc(trySize);
  81. if (NULL != gUnityTestTlsfCtx.poolBuffer) { gUnityTestTlsfCtx.poolSize = trySize; }
  82. #endif
  83. if ((NULL == gUnityTestTlsfCtx.poolBuffer) || (0U == gUnityTestTlsfCtx.poolSize)) { return false; }
  84. }
  85. gUnityTestTlsfCtx.tlsfHandle =
  86. tlsf_create_with_pool(gUnityTestTlsfCtx.poolBuffer, gUnityTestTlsfCtx.poolSize, gUnityTestTlsfCtx.poolSize);
  87. return (NULL != gUnityTestTlsfCtx.tlsfHandle);
  88. }
  89. void showMemoryInfo(void)
  90. {
  91. size_t total = 0U;
  92. size_t used = 0U;
  93. size_t maxUsed = 0U;
  94. if (NULL == gUnityTestTlsfCtx.tlsfHandle)
  95. {
  96. testLog("%s:%d tlsf 未初始化\r\n", __FILE__, __LINE__);
  97. return;
  98. }
  99. tlsf_memory_info(gUnityTestTlsfCtx.tlsfHandle, &total, &used, &maxUsed);
  100. testLog("%s:%d tlsf used: %lu, maxUsed: %lu, total: %lu\r\n", __FILE__, __LINE__, (unsigned long)used, (unsigned long)maxUsed,
  101. (unsigned long)total);
  102. }
  103. void logTaskStackRuntimeInfoByHandle(const char *tag, const char *taskName, TaskHandle_t taskHandle)
  104. {
  105. const char *safeTag = "<null>";
  106. const char *safeTaskName = "<null>";
  107. TaskStatus_t taskStatus = {0};
  108. UBaseType_t taskPriority = 0U;
  109. configSTACK_DEPTH_TYPE stackTotalWords = 0U;
  110. configSTACK_DEPTH_TYPE stackFreeMinWords = 0U;
  111. size_t stackUsedPeakWords = 0U;
  112. size_t stackTotalBytes = 0U;
  113. size_t stackFreeMinBytes = 0U;
  114. size_t stackUsedPeakBytes = 0U;
  115. if (NULL != tag) { safeTag = tag; }
  116. if (NULL == taskHandle)
  117. {
  118. testLog("\n[%s] 任务句柄为空,无法获取任务信息\n", safeTag);
  119. return;
  120. }
  121. vTaskGetInfo(taskHandle, &taskStatus, pdTRUE, eInvalid);
  122. if (NULL != taskName) { safeTaskName = taskName; }
  123. else if (NULL != taskStatus.pcTaskName) { safeTaskName = taskStatus.pcTaskName; }
  124. taskPriority = taskStatus.uxCurrentPriority;
  125. stackFreeMinWords = taskStatus.usStackHighWaterMark;
  126. #if (portSTACK_GROWTH < 0)
  127. if ((NULL != taskStatus.pxStackBase) && (NULL != taskStatus.pxEndOfStack) && (taskStatus.pxEndOfStack >= taskStatus.pxStackBase))
  128. {
  129. stackTotalWords = (configSTACK_DEPTH_TYPE)(taskStatus.pxEndOfStack - taskStatus.pxStackBase + 1U);
  130. }
  131. #elif (portSTACK_GROWTH > 0)
  132. if ((NULL != taskStatus.pxStackBase) && (NULL != taskStatus.pxEndOfStack) && (taskStatus.pxStackBase >= taskStatus.pxEndOfStack))
  133. {
  134. stackTotalWords = (configSTACK_DEPTH_TYPE)(taskStatus.pxStackBase - taskStatus.pxEndOfStack + 1U);
  135. }
  136. #endif
  137. if (stackTotalWords >= stackFreeMinWords) { stackUsedPeakWords = stackTotalWords - stackFreeMinWords; }
  138. stackTotalBytes = stackTotalWords * sizeof(StackType_t);
  139. stackFreeMinBytes = stackFreeMinWords * sizeof(StackType_t);
  140. stackUsedPeakBytes = stackUsedPeakWords * sizeof(StackType_t);
  141. testLog("\n[%s] 任务=%s, Tick=%lu, 优先级=%lu, 栈总量=%lu(字)/%lu字节, 已用峰值=%lu(字)/%lu字节, 栈最小剩余=%lu(字)/%lu字节\n",
  142. safeTag, safeTaskName, (unsigned long)xTaskGetTickCount(), (unsigned long)taskPriority, (unsigned long)stackTotalWords,
  143. (unsigned long)stackTotalBytes, (unsigned long)stackUsedPeakWords, (unsigned long)stackUsedPeakBytes,
  144. (unsigned long)stackFreeMinWords, (unsigned long)stackFreeMinBytes);
  145. }
  146. int32_t unityTestGetUse(void)
  147. {
  148. size_t total = 0U;
  149. size_t used = 0U;
  150. size_t maxUsed = 0U;
  151. if (NULL == gUnityTestTlsfCtx.tlsfHandle) { return 0; }
  152. tlsf_memory_info(gUnityTestTlsfCtx.tlsfHandle, &total, &used, &maxUsed);
  153. return (int32_t)used;
  154. }
  155. void *unityTestMalloc(size_t size)
  156. {
  157. size_t allocSize = 0U;
  158. if (NULL == gUnityTestTlsfCtx.tlsfHandle || 0U == size) { return NULL; }
  159. if (0U != gAllocSimEnabled) { allocSize = unityTestCalcSimulatedAllocSize(size); }
  160. else
  161. {
  162. allocSize = size;
  163. }
  164. return tlsf_malloc(gUnityTestTlsfCtx.tlsfHandle, allocSize);
  165. }
  166. void unityTestFree(void *block)
  167. {
  168. if (NULL == gUnityTestTlsfCtx.tlsfHandle || NULL == block) { return; }
  169. tlsf_free(gUnityTestTlsfCtx.tlsfHandle, block);
  170. }
  171. void *unityTestRealloc(void *block, size_t size)
  172. {
  173. size_t allocSize = 0U;
  174. if (NULL == gUnityTestTlsfCtx.tlsfHandle) { return NULL; }
  175. if (0U == size) { return tlsf_realloc(gUnityTestTlsfCtx.tlsfHandle, block, 0U); }
  176. if (0U != gAllocSimEnabled) { allocSize = unityTestCalcSimulatedAllocSize(size); }
  177. else
  178. {
  179. allocSize = size;
  180. }
  181. return tlsf_realloc(gUnityTestTlsfCtx.tlsfHandle, block, allocSize);
  182. }
  183. void unityTestOomBegin(int32_t failAfter, RyanJsonBool_e disableRealloc)
  184. {
  185. gOomFailAfter = failAfter;
  186. gOomAllocCount = 0;
  187. gOomDisableRealloc = (disableRealloc != RyanJsonFalse) ? 1U : 0U;
  188. if (0U != gOomDisableRealloc) { RyanJsonInitHooks(unityTestOomMalloc, unityTestFree, NULL); }
  189. else
  190. {
  191. RyanJsonInitHooks(unityTestOomMalloc, unityTestFree, unityTestOomRealloc);
  192. }
  193. }
  194. void unityTestOomEnd(void)
  195. {
  196. RyanJsonInitHooks(unityTestMalloc, unityTestFree, unityTestRealloc);
  197. gOomFailAfter = -1;
  198. gOomAllocCount = 0;
  199. gOomDisableRealloc = 0U;
  200. }
  201. void ryanJsonTestSetup(void)
  202. {
  203. if (!unityTestInitTlsf())
  204. {
  205. testLog("%s:%d tlsf 初始化失败\r\n", __FILE__, __LINE__);
  206. return;
  207. }
  208. #if defined(RyanJsonTestPlatformQemu)
  209. if (0U == gQemuTlsfPoolLogged)
  210. {
  211. testLog("[QEMU][MEM] tlsfPoolSize=%lu\r\n", (unsigned long)gUnityTestTlsfCtx.poolSize);
  212. gQemuTlsfPoolLogged = 1U;
  213. }
  214. #endif
  215. if (0U == gAllocSimConfigLogged)
  216. {
  217. testLog("[MEM][SIM] header=%lu align=%lu\r\n", (unsigned long)RyanJsonTestAllocHeaderSize,
  218. (unsigned long)RyanJsonTestAllocAlignSize);
  219. gAllocSimConfigLogged = 1U;
  220. }
  221. xPortResetHeapMinimumEverFreeHeapSize();
  222. RyanJsonInitHooks(unityTestMalloc, unityTestFree, unityTestRealloc);
  223. }
  224. void ryanJsonTestTeardown(void)
  225. {
  226. // 兜底恢复默认 hooks,避免某个用例遗留自定义 hooks 影响后续用例。
  227. RyanJsonInitHooks(unityTestMalloc, unityTestFree, unityTestRealloc);
  228. gUnityTestTlsfCtx.tlsfHandle = NULL;
  229. }