فهرست منبع

Heap: fix free bytes calculation for TLSF heap

* Closes https://github.com/espressif/esp-idf/issues/8270
Omar Chebib 4 سال پیش
والد
کامیت
4ce4c5a68a

+ 10 - 1
components/heap/multi_heap.c

@@ -189,6 +189,7 @@ void *multi_heap_malloc_impl(multi_heap_handle_t heap, size_t size)
     void *result = tlsf_malloc(heap->heap_data, size);
     if(result) {
         heap->free_bytes -= tlsf_block_size(result);
+        heap->free_bytes -= tlsf_alloc_overhead();
         if (heap->free_bytes < heap->minimum_free_bytes) {
             heap->minimum_free_bytes = heap->free_bytes;
         }
@@ -209,6 +210,7 @@ void multi_heap_free_impl(multi_heap_handle_t heap, void *p)
 
     multi_heap_internal_lock(heap);
     heap->free_bytes += tlsf_block_size(p);
+    heap->free_bytes += tlsf_alloc_overhead();
     tlsf_free(heap->heap_data, p);
     multi_heap_internal_unlock(heap);
 }
@@ -231,6 +233,8 @@ void *multi_heap_realloc_impl(multi_heap_handle_t heap, void *p, size_t size)
     size_t previous_block_size =  tlsf_block_size(p);
     void *result = tlsf_realloc(heap->heap_data, p, size);
     if(result) {
+        /* No need to subtract the tlsf_alloc_overhead() as it has already
+         * been subtracted when allocating the block at first with malloc */
         heap->free_bytes += previous_block_size;
         heap->free_bytes -= tlsf_block_size(result);
         if (heap->free_bytes < heap->minimum_free_bytes) {
@@ -262,6 +266,7 @@ void *multi_heap_aligned_alloc_impl_offs(multi_heap_handle_t heap, size_t size,
     void *result = tlsf_memalign_offs(heap->heap_data, alignment, size, offset);
     if(result) {
         heap->free_bytes -= tlsf_block_size(result);
+        heap->free_bytes -= tlsf_alloc_overhead();
         if(heap->free_bytes < heap->minimum_free_bytes) {
             heap->minimum_free_bytes = heap->free_bytes;
         }
@@ -353,6 +358,7 @@ static void multi_heap_get_info_tlsf(void* ptr, size_t size, int used, void* use
 void multi_heap_get_info_impl(multi_heap_handle_t heap, multi_heap_info_t *info)
 {
     uint32_t sl_interval;
+    uint32_t overhead;
 
     memset(info, 0, sizeof(multi_heap_info_t));
 
@@ -362,7 +368,10 @@ void multi_heap_get_info_impl(multi_heap_handle_t heap, multi_heap_info_t *info)
 
     multi_heap_internal_lock(heap);
     tlsf_walk_pool(tlsf_get_pool(heap->heap_data), multi_heap_get_info_tlsf, info);
-    info->total_allocated_bytes = (heap->pool_size - tlsf_size()) - heap->free_bytes;
+    /* TLSF has an overhead per block. Calculate the total amoun of overhead, it shall not be
+     * part of the allocated bytes */
+    overhead = info->allocated_blocks * tlsf_alloc_overhead();
+    info->total_allocated_bytes = (heap->pool_size - tlsf_size()) - heap->free_bytes - overhead;
     info->minimum_free_bytes = heap->minimum_free_bytes;
     info->total_free_bytes = heap->free_bytes;
     if (info->largest_free_block) {

+ 4 - 2
components/heap/test/test_malloc_caps.c

@@ -122,8 +122,10 @@ TEST_CASE("IRAM_8BIT capability test", "[heap]")
 
     TEST_ASSERT((((int)ptr)&0xFF000000)==0x40000000);
 
-    TEST_ASSERT(heap_caps_get_free_size(MALLOC_CAP_IRAM_8BIT) == (free_size - heap_caps_get_allocated_size(ptr)));
-    TEST_ASSERT(heap_caps_get_free_size(MALLOC_CAP_32BIT) == (free_size32 - heap_caps_get_allocated_size(ptr)));
+    /* As the heap allocator may present an overhead for allocated blocks,
+     * we need to check that the free heap size is now smaller than former free size. */
+    TEST_ASSERT(heap_caps_get_free_size(MALLOC_CAP_IRAM_8BIT) <= (free_size - heap_caps_get_allocated_size(ptr)));
+    TEST_ASSERT(heap_caps_get_free_size(MALLOC_CAP_32BIT) <= (free_size32 - heap_caps_get_allocated_size(ptr)));
 
     free(ptr);
 }

+ 20 - 0
components/heap/test_multi_heap_host/test_multi_heap.cpp

@@ -503,3 +503,23 @@ TEST_CASE("multi_heap aligned allocations", "[multi_heap]")
     printf("[ALIGNED_ALLOC] heap_size after: %d \n", multi_heap_free_size(heap));
     REQUIRE((old_size - multi_heap_free_size(heap)) <= leakage);
 }
+
+// TLSF has some overhead when allocating blocks, check that overhead
+TEST_CASE("multi_heap allocation overhead", "[multi_heap]")
+{
+    uint8_t heapdata[4 * 1024];
+    size_t alloc_size = 256;
+    multi_heap_handle_t heap = multi_heap_register(heapdata, sizeof(heapdata));
+    size_t free_bytes_1 = multi_heap_free_size(heap);
+
+    /* Allocate any amount of data, in any case there will be an overhead */
+    void *x = multi_heap_malloc(heap, alloc_size);
+
+    /* free_bytes_2 should be free_bytes_1 - alloc_size - overhead.
+     * We don't know the value of overhead, let's check that it is non-zero */
+    size_t free_bytes_2 = multi_heap_free_size(heap);
+    REQUIRE( free_bytes_1 > free_bytes_2 );
+    REQUIRE( free_bytes_1 - free_bytes_2 > alloc_size );
+
+    multi_heap_free(heap, x);
+}