test_malloc_caps.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. /*
  2. Tests for the capabilities-based memory allocator.
  3. */
  4. #include <esp_types.h>
  5. #include <stdio.h>
  6. #include "unity.h"
  7. #include "esp_attr.h"
  8. #include "esp_heap_caps.h"
  9. #include "esp_spi_flash.h"
  10. #include <stdlib.h>
  11. #include <sys/param.h>
  12. TEST_CASE("Capabilities allocator test", "[heap]")
  13. {
  14. char *m1, *m2[10];
  15. int x;
  16. size_t free8start, free32start, free8, free32;
  17. /* It's important we printf() something before we take the empty heap sizes,
  18. as the first printf() in a task allocates heap resources... */
  19. printf("Testing capabilities allocator...\n");
  20. free8start = heap_caps_get_free_size(MALLOC_CAP_8BIT);
  21. free32start = heap_caps_get_free_size(MALLOC_CAP_32BIT);
  22. printf("Free 8bit-capable memory (start): %dK, 32-bit capable memory %dK\n", free8start, free32start);
  23. TEST_ASSERT(free32start >= free8start);
  24. printf("Allocating 10K of 8-bit capable RAM\n");
  25. m1= heap_caps_malloc(10*1024, MALLOC_CAP_8BIT);
  26. printf("--> %p\n", m1);
  27. free8 = heap_caps_get_free_size(MALLOC_CAP_8BIT);
  28. free32 = heap_caps_get_free_size(MALLOC_CAP_32BIT);
  29. printf("Free 8bit-capable memory (both reduced): %dK, 32-bit capable memory %dK\n", free8, free32);
  30. //Both should have gone down by 10K; 8bit capable ram is also 32-bit capable
  31. TEST_ASSERT(free8<(free8start-10*1024));
  32. TEST_ASSERT(free32<(free32start-10*1024));
  33. //Assume we got DRAM back
  34. TEST_ASSERT((((int)m1)&0xFF000000)==0x3F000000);
  35. free(m1);
  36. //The goal here is to allocate from IRAM. Since there is no external IRAM (yet)
  37. //the following gives size of IRAM-only (not D/IRAM) memory.
  38. size_t free_iram = heap_caps_get_free_size(MALLOC_CAP_INTERNAL) -
  39. heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
  40. size_t alloc32 = MIN(free_iram / 2, 10*1024) & (~3);
  41. if(free_iram) {
  42. printf("Freeing; allocating %u bytes of 32K-capable RAM\n", alloc32);
  43. m1 = heap_caps_malloc(alloc32, MALLOC_CAP_32BIT);
  44. printf("--> %p\n", m1);
  45. //Check that we got IRAM back
  46. TEST_ASSERT((((int)m1)&0xFF000000)==0x40000000);
  47. free8 = heap_caps_get_free_size(MALLOC_CAP_8BIT);
  48. free32 = heap_caps_get_free_size(MALLOC_CAP_32BIT);
  49. printf("Free 8bit-capable memory (after 32-bit): %dK, 32-bit capable memory %dK\n", free8, free32);
  50. //Only 32-bit should have gone down by alloc32: 32-bit isn't necessarily 8bit capable
  51. TEST_ASSERT(free32<(free32start-alloc32));
  52. TEST_ASSERT(free8==free8start);
  53. free(m1);
  54. } else {
  55. printf("This platform has no 32-bit only capable RAM, jumping to next test \n");
  56. }
  57. printf("Allocating impossible caps\n");
  58. m1= heap_caps_malloc(10*1024, MALLOC_CAP_8BIT|MALLOC_CAP_EXEC);
  59. printf("--> %p\n", m1);
  60. TEST_ASSERT(m1==NULL);
  61. if(free_iram) {
  62. printf("Testing changeover iram -> dram");
  63. // priorities will exhaust IRAM first, then start allocating from DRAM
  64. for (x=0; x<10; x++) {
  65. m2[x]= heap_caps_malloc(alloc32, MALLOC_CAP_32BIT);
  66. printf("--> %p\n", m2[x]);
  67. }
  68. TEST_ASSERT((((int)m2[0])&0xFF000000)==0x40000000);
  69. TEST_ASSERT((((int)m2[9])&0xFF000000)==0x3F000000);
  70. } else {
  71. printf("This platform has no IRAM-only so changeover will never occur, jumping to next test\n");
  72. }
  73. printf("Test if allocating executable code still gives IRAM, even with dedicated IRAM region depleted\n");
  74. if(free_iram) {
  75. // (the allocation should come from D/IRAM)
  76. free_iram = heap_caps_get_free_size(MALLOC_CAP_EXEC);
  77. m1= heap_caps_malloc(MIN(free_iram / 2, 10*1024), MALLOC_CAP_EXEC);
  78. printf("--> %p\n", m1);
  79. TEST_ASSERT((((int)m1)&0xFF000000)==0x40000000);
  80. for (x=0; x<10; x++) free(m2[x]);
  81. } else {
  82. // (the allocation should come from D/IRAM)
  83. free_iram = heap_caps_get_free_size(MALLOC_CAP_EXEC);
  84. m1= heap_caps_malloc(MIN(free_iram / 2, 10*1024), MALLOC_CAP_EXEC);
  85. printf("--> %p\n", m1);
  86. TEST_ASSERT((((int)m1)&0xFF000000)==0x40000000);
  87. }
  88. free(m1);
  89. printf("Done.\n");
  90. }
  91. TEST_CASE("heap_caps metadata test", "[heap]")
  92. {
  93. /* need to print something as first printf allocates some heap */
  94. printf("heap_caps metadata test\n");
  95. heap_caps_print_heap_info(MALLOC_CAP_8BIT);
  96. heap_caps_print_heap_info(MALLOC_CAP_32BIT);
  97. multi_heap_info_t original;
  98. heap_caps_get_info(&original, MALLOC_CAP_8BIT);
  99. void *b = heap_caps_malloc(original.largest_free_block, MALLOC_CAP_8BIT);
  100. TEST_ASSERT_NOT_NULL(b);
  101. printf("After allocating %d bytes:\n", original.largest_free_block);
  102. heap_caps_print_heap_info(MALLOC_CAP_8BIT);
  103. multi_heap_info_t after;
  104. heap_caps_get_info(&after, MALLOC_CAP_8BIT);
  105. TEST_ASSERT(after.largest_free_block < original.largest_free_block);
  106. TEST_ASSERT(after.total_free_bytes < original.total_free_bytes);
  107. free(b);
  108. heap_caps_get_info(&after, MALLOC_CAP_8BIT);
  109. /* Allow some leeway here, because LWIP sometimes allocates up to 144 bytes in the background
  110. as part of timer management.
  111. */
  112. TEST_ASSERT_INT32_WITHIN(200, after.total_free_bytes, original.total_free_bytes);
  113. TEST_ASSERT_INT32_WITHIN(200, after.largest_free_block, original.largest_free_block);
  114. TEST_ASSERT(after.minimum_free_bytes < original.total_free_bytes);
  115. }
  116. /* Small function runs from IRAM to check that malloc/free/realloc
  117. all work OK when cache is disabled...
  118. */
  119. static IRAM_ATTR __attribute__((noinline)) bool iram_malloc_test(void)
  120. {
  121. spi_flash_guard_get()->start(); // Disables flash cache
  122. bool result = true;
  123. void *x = heap_caps_malloc(64, MALLOC_CAP_32BIT);
  124. result = result && (x != NULL);
  125. void *y = heap_caps_realloc(x, 32, MALLOC_CAP_32BIT);
  126. result = result && (y != NULL);
  127. heap_caps_free(y);
  128. spi_flash_guard_get()->end(); // Re-enables flash cache
  129. return result;
  130. }
  131. TEST_CASE("heap_caps_xxx functions work with flash cache disabled", "[heap]")
  132. {
  133. TEST_ASSERT( iram_malloc_test() );
  134. }