From af315bc926dc2372a5a9c382b8c3b1d5464530b0 Mon Sep 17 00:00:00 2001 From: SG Date: Thu, 4 Apr 2024 20:09:36 +0300 Subject: [PATCH 01/16] add tlsf as submodule --- .gitmodules | 3 +++ lib/tlsf | 1 + 2 files changed, 4 insertions(+) create mode 160000 lib/tlsf diff --git a/.gitmodules b/.gitmodules index c4c68a6a77..a8d12803cb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -41,3 +41,6 @@ [submodule "documentation/doxygen/doxygen-awesome-css"] path = documentation/doxygen/doxygen-awesome-css url = https://github.com/jothepro/doxygen-awesome-css.git +[submodule "lib/tlsf"] + path = lib/tlsf + url = https://github.com/espressif/tlsf diff --git a/lib/tlsf b/lib/tlsf new file mode 160000 index 0000000000..8fc595fe22 --- /dev/null +++ b/lib/tlsf @@ -0,0 +1 @@ +Subproject commit 8fc595fe223cd0b3b5d7b29eb86825e4bd38e6e8 From 39899a9b0de3f5ecefea648505a3f8ef784d3bec Mon Sep 17 00:00:00 2001 From: SG Date: Thu, 4 Apr 2024 22:04:17 +0300 Subject: [PATCH 02/16] libs: tlsf --- lib/SConscript | 1 + lib/tlsf.scons | 21 +++++++++++++++++++++ targets/f7/target.json | 3 ++- 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 lib/tlsf.scons diff --git a/lib/SConscript b/lib/SConscript index 8125739325..29c48de6d9 100644 --- a/lib/SConscript +++ b/lib/SConscript @@ -13,6 +13,7 @@ env.Append( libs = env.BuildModules( [ + "tlsf", "mlib", "stm32wb", "freertos", diff --git a/lib/tlsf.scons b/lib/tlsf.scons new file mode 100644 index 0000000000..0a8419dbdc --- /dev/null +++ b/lib/tlsf.scons @@ -0,0 +1,21 @@ +Import("env") + +env.Append( + CPPPATH=[ + "#/lib/tlsf", + ], +) + + +libenv = env.Clone(FW_LIB_NAME="tlsf") +libenv.ApplyLibFlags() + +libenv.Append( + CPPDEFINES=[], +) + +sources = [File("tlsf/tlsf.c")] + +lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources) +libenv.Install("${LIB_DIST_DIR}", lib) +Return("lib") diff --git a/targets/f7/target.json b/targets/f7/target.json index 25872198bf..caa3f58eec 100644 --- a/targets/f7/target.json +++ b/targets/f7/target.json @@ -22,6 +22,7 @@ "print", "flipper7", "furi", + "tlsf", "freertos", "stm32wb", "hwdrivers", @@ -55,4 +56,4 @@ "bit_lib", "datetime" ] -} +} \ No newline at end of file From 4d4010345c7e6ed7580fc3a07154f6788a946926 Mon Sep 17 00:00:00 2001 From: SG Date: Thu, 4 Apr 2024 22:04:43 +0300 Subject: [PATCH 03/16] Furi: tlsf as allocator --- furi/core/memmgr_heap.c | 682 +++++----------------------------------- 1 file changed, 77 insertions(+), 605 deletions(-) diff --git a/furi/core/memmgr_heap.c b/furi/core/memmgr_heap.c index 24bd327fd2..65e1cae1d8 100644 --- a/furi/core/memmgr_heap.c +++ b/furi/core/memmgr_heap.c @@ -1,664 +1,136 @@ -/* - * FreeRTOS Kernel V10.2.1 - * Copyright (C) 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * http://www.FreeRTOS.org - * http://aws.amazon.com/freertos - * - * 1 tab == 4 spaces! - */ - -/* - * A sample implementation of pvPortMalloc() and vPortFree() that combines - * (coalescences) adjacent memory blocks as they are freed, and in so doing - * limits memory fragmentation. - * - * See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the - * memory management pages of http://www.FreeRTOS.org for more information. - */ - -#include "memmgr_heap.h" -#include "check.h" -#include -#include -#include -#include -#include - -/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining -all the API functions to use the MPU wrappers. That should only be done when -task.h is included from an application file. */ -#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE - +#include +#include +#include #include #include -#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE - -#ifdef HEAP_PRINT_DEBUG -#error This feature is broken, logging transport must be replaced with RTT -#endif +extern const void __heap_start__; +extern const void __heap_end__; -#if(configSUPPORT_DYNAMIC_ALLOCATION == 0) -#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0 -#endif +static tlsf_t tlsf = NULL; +static size_t heap_used = 0; +static size_t heap_max_used = 0; -/* Block sizes must not get too small. */ -#define heapMINIMUM_BLOCK_SIZE ((size_t)(xHeapStructSize << 1)) +static inline void memmgr_lock(void) { + vTaskSuspendAll(); +} -/* Assumes 8bit bytes! */ -#define heapBITS_PER_BYTE ((size_t)8) +static inline void memmgr_unlock(void) { + xTaskResumeAll(); +} -/* Heap start end symbols provided by linker */ -extern const void __heap_start__; -extern const void __heap_end__; -uint8_t* ucHeap = (uint8_t*)&__heap_start__; - -/* Define the linked list structure. This is used to link free blocks in order -of their memory address. */ -typedef struct A_BLOCK_LINK { - struct A_BLOCK_LINK* pxNextFreeBlock; /*<< The next free block in the list. */ - size_t xBlockSize; /*<< The size of the free block. */ -} BlockLink_t; - -/*-----------------------------------------------------------*/ - -/* - * Inserts a block of memory that is being freed into the correct position in - * the list of free memory blocks. The block being freed will be merged with - * the block in front it and/or the block behind it if the memory blocks are - * adjacent to each other. - */ -static void prvInsertBlockIntoFreeList(BlockLink_t* pxBlockToInsert); - -/* - * Called automatically to setup the required heap structures the first time - * pvPortMalloc() is called. - */ -static void prvHeapInit(void); - -/*-----------------------------------------------------------*/ - -/* The size of the structure placed at the beginning of each allocated memory -block must by correctly byte aligned. */ -static const size_t xHeapStructSize = (sizeof(BlockLink_t) + ((size_t)(portBYTE_ALIGNMENT - 1))) & - ~((size_t)portBYTE_ALIGNMENT_MASK); - -/* Create a couple of list links to mark the start and end of the list. */ -static BlockLink_t xStart, *pxEnd = NULL; - -/* Keeps track of the number of free bytes remaining, but says nothing about -fragmentation. */ -static size_t xFreeBytesRemaining = 0U; -static size_t xMinimumEverFreeBytesRemaining = 0U; - -/* Gets set to the top bit of an size_t type. When this bit in the xBlockSize -member of an BlockLink_t structure is set then the block belongs to the -application. When the bit is free the block is still part of the free heap -space. */ -static size_t xBlockAllocatedBit = 0; - -/* Furi heap extension */ -#include - -/* Allocation tracking types */ -DICT_DEF2(MemmgrHeapAllocDict, uint32_t, uint32_t) //-V1048 - -DICT_DEF2( //-V1048 - MemmgrHeapThreadDict, - uint32_t, - M_DEFAULT_OPLIST, - MemmgrHeapAllocDict_t, - DICT_OPLIST(MemmgrHeapAllocDict)) - -/* Thread allocation tracing storage */ -static MemmgrHeapThreadDict_t memmgr_heap_thread_dict = {0}; -static volatile uint32_t memmgr_heap_thread_trace_depth = 0; - -/* Initialize tracing storage on start */ -void memmgr_heap_init(void) { - MemmgrHeapThreadDict_init(memmgr_heap_thread_dict); +static inline size_t memmgr_get_heap_size(void) { + return (size_t)&__heap_end__ - (size_t)&__heap_start__; } void memmgr_heap_enable_thread_trace(FuriThreadId thread_id) { - vTaskSuspendAll(); - { - memmgr_heap_thread_trace_depth++; - furi_check(MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id) == NULL); - MemmgrHeapAllocDict_t alloc_dict; - MemmgrHeapAllocDict_init(alloc_dict); - MemmgrHeapThreadDict_set_at(memmgr_heap_thread_dict, (uint32_t)thread_id, alloc_dict); - MemmgrHeapAllocDict_clear(alloc_dict); - memmgr_heap_thread_trace_depth--; - } - (void)xTaskResumeAll(); + UNUSED(thread_id); } void memmgr_heap_disable_thread_trace(FuriThreadId thread_id) { - vTaskSuspendAll(); - { - memmgr_heap_thread_trace_depth++; - furi_check(MemmgrHeapThreadDict_erase(memmgr_heap_thread_dict, (uint32_t)thread_id)); - memmgr_heap_thread_trace_depth--; - } - (void)xTaskResumeAll(); + UNUSED(thread_id); } size_t memmgr_heap_get_thread_memory(FuriThreadId thread_id) { - size_t leftovers = MEMMGR_HEAP_UNKNOWN; - vTaskSuspendAll(); - { - memmgr_heap_thread_trace_depth++; - MemmgrHeapAllocDict_t* alloc_dict = - MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); - if(alloc_dict) { - leftovers = 0; - MemmgrHeapAllocDict_it_t alloc_dict_it; - for(MemmgrHeapAllocDict_it(alloc_dict_it, *alloc_dict); - !MemmgrHeapAllocDict_end_p(alloc_dict_it); - MemmgrHeapAllocDict_next(alloc_dict_it)) { - MemmgrHeapAllocDict_itref_t* data = MemmgrHeapAllocDict_ref(alloc_dict_it); - if(data->key != 0) { - uint8_t* puc = (uint8_t*)data->key; - puc -= xHeapStructSize; - BlockLink_t* pxLink = (void*)puc; - - if((pxLink->xBlockSize & xBlockAllocatedBit) != 0 && - pxLink->pxNextFreeBlock == NULL) { - leftovers += data->value; - } - } - } - } - memmgr_heap_thread_trace_depth--; - } - (void)xTaskResumeAll(); - return leftovers; + UNUSED(thread_id); + return 0; } -#undef traceMALLOC -static inline void traceMALLOC(void* pointer, size_t size) { - FuriThreadId thread_id = furi_thread_get_current_id(); - if(thread_id && memmgr_heap_thread_trace_depth == 0) { - memmgr_heap_thread_trace_depth++; - MemmgrHeapAllocDict_t* alloc_dict = - MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); - if(alloc_dict) { - MemmgrHeapAllocDict_set_at(*alloc_dict, (uint32_t)pointer, (uint32_t)size); - } - memmgr_heap_thread_trace_depth--; - } -} +static bool tlsf_walker_max_free(void* ptr, size_t size, int used, void* user) { + UNUSED(ptr); -#undef traceFREE -static inline void traceFREE(void* pointer, size_t size) { - UNUSED(size); - FuriThreadId thread_id = furi_thread_get_current_id(); - if(thread_id && memmgr_heap_thread_trace_depth == 0) { - memmgr_heap_thread_trace_depth++; - MemmgrHeapAllocDict_t* alloc_dict = - MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); - if(alloc_dict) { - // In some cases thread may want to release memory that was not allocated by it - const bool res = MemmgrHeapAllocDict_erase(*alloc_dict, (uint32_t)pointer); - UNUSED(res); - } - memmgr_heap_thread_trace_depth--; + size_t* max_free_block_size = (size_t*)user; + if(!used && size > *max_free_block_size) { + *max_free_block_size = size; } + + return true; } size_t memmgr_heap_get_max_free_block(void) { - size_t max_free_size = 0; - BlockLink_t* pxBlock; - vTaskSuspendAll(); + size_t max_free_block_size = 0; - pxBlock = xStart.pxNextFreeBlock; - while(pxBlock->pxNextFreeBlock != NULL) { - if(pxBlock->xBlockSize > max_free_size) { - max_free_size = pxBlock->xBlockSize; - } - pxBlock = pxBlock->pxNextFreeBlock; - } + memmgr_lock(); - xTaskResumeAll(); - return max_free_size; -} + pool_t pool = tlsf_get_pool(tlsf); + tlsf_walk_pool(pool, tlsf_walker_max_free, &max_free_block_size); -void memmgr_heap_printf_free_blocks(void) { - BlockLink_t* pxBlock; - //TODO enable when we can do printf with a locked scheduler - //vTaskSuspendAll(); - - pxBlock = xStart.pxNextFreeBlock; - while(pxBlock->pxNextFreeBlock != NULL) { - printf("A %p S %lu\r\n", (void*)pxBlock, (uint32_t)pxBlock->xBlockSize); - pxBlock = pxBlock->pxNextFreeBlock; - } + memmgr_unlock(); - //xTaskResumeAll(); + return max_free_block_size; } -#ifdef HEAP_PRINT_DEBUG -char* ultoa(unsigned long num, char* str, int radix) { - char temp[33]; // at radix 2 the string is at most 32 + 1 null long. - int temp_loc = 0; - int digit; - int str_loc = 0; - - //construct a backward string of the number. - do { - digit = (unsigned long)num % ((unsigned long)radix); - if(digit < 10) - temp[temp_loc++] = digit + '0'; - else - temp[temp_loc++] = digit - 10 + 'A'; - num = ((unsigned long)num) / ((unsigned long)radix); - } while((unsigned long)num > 0); - - temp_loc--; - - //now reverse the string. - while(temp_loc >= 0) { // while there are still chars - str[str_loc++] = temp[temp_loc--]; - } - str[str_loc] = 0; // add null termination. - - return str; -} - -static void print_heap_init(void) { - char tmp_str[33]; - size_t heap_start = (size_t)&__heap_start__; - size_t heap_end = (size_t)&__heap_end__; - - // {PHStart|heap_start|heap_end} - FURI_CRITICAL_ENTER(); - furi_log_puts("{PHStart|"); - ultoa(heap_start, tmp_str, 16); - furi_log_puts(tmp_str); - furi_log_puts("|"); - ultoa(heap_end, tmp_str, 16); - furi_log_puts(tmp_str); - furi_log_puts("}\r\n"); - FURI_CRITICAL_EXIT(); +void memmgr_heap_printf_free_blocks(void) { } -static void print_heap_malloc(void* ptr, size_t size) { - char tmp_str[33]; - const char* name = furi_thread_get_name(furi_thread_get_current_id()); - if(!name) { - name = ""; +void* pvPortMalloc(size_t xSize) { + // memory management in ISR is not allowed + if(FURI_IS_IRQ_MODE()) { + furi_crash("memmgt in ISR"); } - // {thread name|m|address|size} - FURI_CRITICAL_ENTER(); - furi_log_puts("{"); - furi_log_puts(name); - furi_log_puts("|m|0x"); - ultoa((unsigned long)ptr, tmp_str, 16); - furi_log_puts(tmp_str); - furi_log_puts("|"); - utoa(size, tmp_str, 10); - furi_log_puts(tmp_str); - furi_log_puts("}\r\n"); - FURI_CRITICAL_EXIT(); -} + memmgr_lock(); -static void print_heap_free(void* ptr) { - char tmp_str[33]; - const char* name = furi_thread_get_name(furi_thread_get_current_id()); - if(!name) { - name = ""; + // initialize tlsf, if not initialized + if(tlsf == NULL) { + size_t pool_size = (size_t)&__heap_end__ - (size_t)&__heap_start__; + tlsf = tlsf_create_with_pool((void*)&__heap_start__, pool_size, pool_size); } - // {thread name|f|address} - FURI_CRITICAL_ENTER(); - furi_log_puts("{"); - furi_log_puts(name); - furi_log_puts("|f|0x"); - ultoa((unsigned long)ptr, tmp_str, 16); - furi_log_puts(tmp_str); - furi_log_puts("}\r\n"); - FURI_CRITICAL_EXIT(); -} -#endif -/*-----------------------------------------------------------*/ - -void* pvPortMalloc(size_t xWantedSize) { - BlockLink_t *pxBlock, *pxPreviousBlock, *pxNewBlockLink; - void* pvReturn = NULL; - size_t to_wipe = xWantedSize; - - if(FURI_IS_IRQ_MODE()) { - furi_crash("memmgt in ISR"); + // allocate block + void* data = tlsf_malloc(tlsf, xSize); + if(data == NULL) { + furi_crash("out of memory"); } -#ifdef HEAP_PRINT_DEBUG - BlockLink_t* print_heap_block = NULL; -#endif - - /* If this is the first call to malloc then the heap will require - initialisation to setup the list of free blocks. */ - if(pxEnd == NULL) { -#ifdef HEAP_PRINT_DEBUG - print_heap_init(); -#endif - - vTaskSuspendAll(); - { - prvHeapInit(); - memmgr_heap_init(); - } - (void)xTaskResumeAll(); - } else { - mtCOVERAGE_TEST_MARKER(); + // update heap usage + heap_used += tlsf_block_size(data); + heap_used += tlsf_alloc_overhead(); + if(heap_used > heap_max_used) { + heap_max_used = heap_used; } - vTaskSuspendAll(); - { - /* Check the requested block size is not so large that the top bit is - set. The top bit of the block size member of the BlockLink_t structure - is used to determine who owns the block - the application or the - kernel, so it must be free. */ - if((xWantedSize & xBlockAllocatedBit) == 0) { - /* The wanted size is increased so it can contain a BlockLink_t - structure in addition to the requested amount of bytes. */ - if(xWantedSize > 0) { - xWantedSize += xHeapStructSize; - - /* Ensure that blocks are always aligned to the required number - of bytes. */ - if((xWantedSize & portBYTE_ALIGNMENT_MASK) != 0x00) { - /* Byte alignment required. */ - xWantedSize += (portBYTE_ALIGNMENT - (xWantedSize & portBYTE_ALIGNMENT_MASK)); - configASSERT((xWantedSize & portBYTE_ALIGNMENT_MASK) == 0); - } else { - mtCOVERAGE_TEST_MARKER(); - } - } else { - mtCOVERAGE_TEST_MARKER(); - } - - if((xWantedSize > 0) && (xWantedSize <= xFreeBytesRemaining)) { - /* Traverse the list from the start (lowest address) block until - one of adequate size is found. */ - pxPreviousBlock = &xStart; - pxBlock = xStart.pxNextFreeBlock; - while((pxBlock->xBlockSize < xWantedSize) && (pxBlock->pxNextFreeBlock != NULL)) { - pxPreviousBlock = pxBlock; - pxBlock = pxBlock->pxNextFreeBlock; - } - - /* If the end marker was reached then a block of adequate size - was not found. */ - if(pxBlock != pxEnd) { - /* Return the memory space pointed to - jumping over the - BlockLink_t structure at its start. */ - pvReturn = - (void*)(((uint8_t*)pxPreviousBlock->pxNextFreeBlock) + xHeapStructSize); - - /* This block is being returned for use so must be taken out - of the list of free blocks. */ - pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock; - - /* If the block is larger than required it can be split into - two. */ - if((pxBlock->xBlockSize - xWantedSize) > heapMINIMUM_BLOCK_SIZE) { - /* This block is to be split into two. Create a new - block following the number of bytes requested. The void - cast is used to prevent byte alignment warnings from the - compiler. */ - pxNewBlockLink = (void*)(((uint8_t*)pxBlock) + xWantedSize); - configASSERT((((size_t)pxNewBlockLink) & portBYTE_ALIGNMENT_MASK) == 0); - - /* Calculate the sizes of two blocks split from the - single block. */ - pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize; - pxBlock->xBlockSize = xWantedSize; - - /* Insert the new block into the list of free blocks. */ - prvInsertBlockIntoFreeList(pxNewBlockLink); - } else { - mtCOVERAGE_TEST_MARKER(); - } - - xFreeBytesRemaining -= pxBlock->xBlockSize; - - if(xFreeBytesRemaining < xMinimumEverFreeBytesRemaining) { - xMinimumEverFreeBytesRemaining = xFreeBytesRemaining; - } else { - mtCOVERAGE_TEST_MARKER(); - } - - /* The block is being returned - it is allocated and owned - by the application and has no "next" block. */ - pxBlock->xBlockSize |= xBlockAllocatedBit; - pxBlock->pxNextFreeBlock = NULL; - -#ifdef HEAP_PRINT_DEBUG - print_heap_block = pxBlock; -#endif - } else { - mtCOVERAGE_TEST_MARKER(); - } - } else { - mtCOVERAGE_TEST_MARKER(); - } - } else { - mtCOVERAGE_TEST_MARKER(); - } - - traceMALLOC(pvReturn, xWantedSize); - } - (void)xTaskResumeAll(); - -#ifdef HEAP_PRINT_DEBUG - print_heap_malloc(print_heap_block, print_heap_block->xBlockSize & ~xBlockAllocatedBit); -#endif - -#if(configUSE_MALLOC_FAILED_HOOK == 1) - { - if(pvReturn == NULL) { - extern void vApplicationMallocFailedHook(void); - vApplicationMallocFailedHook(); - } else { - mtCOVERAGE_TEST_MARKER(); - } - } -#endif + // clear block content + memset(data, 0, xSize); - configASSERT((((size_t)pvReturn) & (size_t)portBYTE_ALIGNMENT_MASK) == 0); + memmgr_unlock(); - furi_check(pvReturn); - pvReturn = memset(pvReturn, 0, to_wipe); - return pvReturn; + return data; } -/*-----------------------------------------------------------*/ void vPortFree(void* pv) { - uint8_t* puc = (uint8_t*)pv; - BlockLink_t* pxLink; - + // memory management in ISR is not allowed if(FURI_IS_IRQ_MODE()) { furi_crash("memmgt in ISR"); } + // ignore NULL pointer if(pv != NULL) { - /* The memory being freed will have an BlockLink_t structure immediately - before it. */ - puc -= xHeapStructSize; - - /* This casting is to keep the compiler from issuing warnings. */ - pxLink = (void*)puc; - - /* Check the block is actually allocated. */ - configASSERT((pxLink->xBlockSize & xBlockAllocatedBit) != 0); - configASSERT(pxLink->pxNextFreeBlock == NULL); - - if((pxLink->xBlockSize & xBlockAllocatedBit) != 0) { - if(pxLink->pxNextFreeBlock == NULL) { - /* The block is being returned to the heap - it is no longer - allocated. */ - pxLink->xBlockSize &= ~xBlockAllocatedBit; - -#ifdef HEAP_PRINT_DEBUG - print_heap_free(pxLink); -#endif - - vTaskSuspendAll(); - { - furi_assert((size_t)pv >= SRAM_BASE); - furi_assert((size_t)pv < SRAM_BASE + 1024 * 256); - furi_assert(pxLink->xBlockSize >= xHeapStructSize); - furi_assert((pxLink->xBlockSize - xHeapStructSize) < 1024 * 256); - - /* Add this block to the list of free blocks. */ - xFreeBytesRemaining += pxLink->xBlockSize; - traceFREE(pv, pxLink->xBlockSize); - memset(pv, 0, pxLink->xBlockSize - xHeapStructSize); - prvInsertBlockIntoFreeList(((BlockLink_t*)pxLink)); - } - (void)xTaskResumeAll(); - } else { - mtCOVERAGE_TEST_MARKER(); - } - } else { - mtCOVERAGE_TEST_MARKER(); - } - } else { -#ifdef HEAP_PRINT_DEBUG - print_heap_free(pv); -#endif - } -} -/*-----------------------------------------------------------*/ - -size_t xPortGetTotalHeapSize(void) { - return (size_t)&__heap_end__ - (size_t)&__heap_start__; -} -/*-----------------------------------------------------------*/ - -size_t xPortGetFreeHeapSize(void) { - return xFreeBytesRemaining; -} -/*-----------------------------------------------------------*/ + memmgr_lock(); -size_t xPortGetMinimumEverFreeHeapSize(void) { - return xMinimumEverFreeBytesRemaining; -} -/*-----------------------------------------------------------*/ + // clear block content + size_t block_size = tlsf_block_size(pv); + memset(pv, 0, block_size); -void vPortInitialiseBlocks(void) { - /* This just exists to keep the linker quiet. */ -} -/*-----------------------------------------------------------*/ + // update heap usage + heap_used -= block_size; + heap_used -= tlsf_alloc_overhead(); -static void prvHeapInit(void) { - BlockLink_t* pxFirstFreeBlock; - uint8_t* pucAlignedHeap; - size_t uxAddress; - size_t xTotalHeapSize = (size_t)&__heap_end__ - (size_t)&__heap_start__; + // free + tlsf_free(tlsf, pv); - /* Ensure the heap starts on a correctly aligned boundary. */ - uxAddress = (size_t)ucHeap; - - if((uxAddress & portBYTE_ALIGNMENT_MASK) != 0) { - uxAddress += (portBYTE_ALIGNMENT - 1); - uxAddress &= ~((size_t)portBYTE_ALIGNMENT_MASK); - xTotalHeapSize -= uxAddress - (size_t)ucHeap; + memmgr_unlock(); } - - pucAlignedHeap = (uint8_t*)uxAddress; - - /* xStart is used to hold a pointer to the first item in the list of free - blocks. The void cast is used to prevent compiler warnings. */ - xStart.pxNextFreeBlock = (void*)pucAlignedHeap; - xStart.xBlockSize = (size_t)0; - - /* pxEnd is used to mark the end of the list of free blocks and is inserted - at the end of the heap space. */ - uxAddress = ((size_t)pucAlignedHeap) + xTotalHeapSize; - uxAddress -= xHeapStructSize; - uxAddress &= ~((size_t)portBYTE_ALIGNMENT_MASK); - pxEnd = (void*)uxAddress; - pxEnd->xBlockSize = 0; - pxEnd->pxNextFreeBlock = NULL; - - /* To start with there is a single free block that is sized to take up the - entire heap space, minus the space taken by pxEnd. */ - pxFirstFreeBlock = (void*)pucAlignedHeap; - pxFirstFreeBlock->xBlockSize = uxAddress - (size_t)pxFirstFreeBlock; - pxFirstFreeBlock->pxNextFreeBlock = pxEnd; - - /* Only one block exists - and it covers the entire usable heap space. */ - xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize; - xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize; - - /* Work out the position of the top bit in a size_t variable. */ - xBlockAllocatedBit = ((size_t)1) << ((sizeof(size_t) * heapBITS_PER_BYTE) - 1); } -/*-----------------------------------------------------------*/ -static void prvInsertBlockIntoFreeList(BlockLink_t* pxBlockToInsert) { - BlockLink_t* pxIterator; - uint8_t* puc; - - /* Iterate through the list until a block is found that has a higher address - than the block being inserted. */ - for(pxIterator = &xStart; pxIterator->pxNextFreeBlock < pxBlockToInsert; - pxIterator = pxIterator->pxNextFreeBlock) { - /* Nothing to do here, just iterate to the right position. */ - } - - /* Do the block being inserted, and the block it is being inserted after - make a contiguous block of memory? */ - puc = (uint8_t*)pxIterator; - if((puc + pxIterator->xBlockSize) == (uint8_t*)pxBlockToInsert) { - pxIterator->xBlockSize += pxBlockToInsert->xBlockSize; - pxBlockToInsert = pxIterator; - } else { - mtCOVERAGE_TEST_MARKER(); - } - - /* Do the block being inserted, and the block it is being inserted before - make a contiguous block of memory? */ - puc = (uint8_t*)pxBlockToInsert; - if((puc + pxBlockToInsert->xBlockSize) == (uint8_t*)pxIterator->pxNextFreeBlock) { - if(pxIterator->pxNextFreeBlock != pxEnd) { - /* Form one big block from the two blocks. */ - pxBlockToInsert->xBlockSize += pxIterator->pxNextFreeBlock->xBlockSize; - pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock->pxNextFreeBlock; - } else { - pxBlockToInsert->pxNextFreeBlock = pxEnd; - } - } else { - pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; - } +size_t xPortGetFreeHeapSize(void) { + return memmgr_get_heap_size() - heap_used; +} - /* If the block being inserted plugged a gab, so was merged with the block - before and the block after, then it's pxNextFreeBlock pointer will have - already been set, and should not be set here as that would make it point - to itself. */ - if(pxIterator != pxBlockToInsert) { - pxIterator->pxNextFreeBlock = pxBlockToInsert; - } else { - mtCOVERAGE_TEST_MARKER(); - } +size_t xPortGetTotalHeapSize(void) { + return memmgr_get_heap_size(); } + +size_t xPortGetMinimumEverFreeHeapSize(void) { + return memmgr_get_heap_size() - heap_max_used; +} \ No newline at end of file From d6145356a457d347c714c4fde0a8f91fcc261756 Mon Sep 17 00:00:00 2001 From: SG Date: Thu, 4 Apr 2024 23:58:54 +0300 Subject: [PATCH 04/16] Furi: heap walker --- applications/services/cli/cli_commands.c | 44 +++++++- furi/core/memmgr_heap.c | 131 +++++++++++++++++++++-- furi/core/memmgr_heap.h | 12 ++- targets/f7/api_symbols.csv | 4 +- 4 files changed, 178 insertions(+), 13 deletions(-) diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index 43f1c01c4d..9105e40e81 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -429,12 +429,54 @@ void cli_command_free(Cli* cli, FuriString* args, void* context) { printf("Maximum pool block: %zu\r\n", memmgr_pool_get_max_block()); } +typedef struct { + void* addr; + size_t size; +} FreeBlockInfo; + +#define FREE_BLOCK_INFO_MAX 128 + +typedef struct { + FreeBlockInfo free_blocks[FREE_BLOCK_INFO_MAX]; + size_t free_blocks_count; +} FreeBlockContext; + +static bool free_block_walker(void* pointer, size_t size, bool used, void* context) { + FreeBlockContext* free_blocks = (FreeBlockContext*)context; + if(!used) { + if(free_blocks->free_blocks_count < FREE_BLOCK_INFO_MAX) { + free_blocks->free_blocks[free_blocks->free_blocks_count].addr = pointer; + free_blocks->free_blocks[free_blocks->free_blocks_count].size = size; + free_blocks->free_blocks_count++; + } else { + return false; + } + } + return true; +} + void cli_command_free_blocks(Cli* cli, FuriString* args, void* context) { UNUSED(cli); UNUSED(args); UNUSED(context); - memmgr_heap_printf_free_blocks(); + FreeBlockContext* free_blocks = malloc(sizeof(FreeBlockContext)); + free_blocks->free_blocks_count = 0; + + memmgr_heap_walk_blocks(free_block_walker, free_blocks); + + for(size_t i = 0; i < free_blocks->free_blocks_count; i++) { + printf( + "A %p S %zu\r\n", + (void*)free_blocks->free_blocks[i].addr, + free_blocks->free_blocks[i].size); + } + + if(free_blocks->free_blocks_count == FREE_BLOCK_INFO_MAX) { + printf("... and more\r\n"); + } + + free(free_blocks); } void cli_command_i2c(Cli* cli, FuriString* args, void* context) { diff --git a/furi/core/memmgr_heap.c b/furi/core/memmgr_heap.c index 65e1cae1d8..748ab845b5 100644 --- a/furi/core/memmgr_heap.c +++ b/furi/core/memmgr_heap.c @@ -11,6 +11,23 @@ static tlsf_t tlsf = NULL; static size_t heap_used = 0; static size_t heap_max_used = 0; +// Furi heap extension +#include + +// Allocation tracking types +DICT_DEF2(MemmgrHeapAllocDict, uint32_t, uint32_t) //-V1048 + +DICT_DEF2( //-V1048 + MemmgrHeapThreadDict, + uint32_t, + M_DEFAULT_OPLIST, + MemmgrHeapAllocDict_t, + DICT_OPLIST(MemmgrHeapAllocDict)) + +// Thread allocation tracing storage +static MemmgrHeapThreadDict_t memmgr_heap_thread_dict = {0}; +static volatile uint32_t memmgr_heap_thread_trace_depth = 0; + static inline void memmgr_lock(void) { vTaskSuspendAll(); } @@ -23,24 +40,70 @@ static inline size_t memmgr_get_heap_size(void) { return (size_t)&__heap_end__ - (size_t)&__heap_start__; } +// Initialize tracing storage on start +void memmgr_heap_init(void) { + MemmgrHeapThreadDict_init(memmgr_heap_thread_dict); +} + void memmgr_heap_enable_thread_trace(FuriThreadId thread_id) { - UNUSED(thread_id); + memmgr_lock(); + { + memmgr_heap_thread_trace_depth++; + furi_check(MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id) == NULL); + MemmgrHeapAllocDict_t alloc_dict; + MemmgrHeapAllocDict_init(alloc_dict); + MemmgrHeapThreadDict_set_at(memmgr_heap_thread_dict, (uint32_t)thread_id, alloc_dict); + MemmgrHeapAllocDict_clear(alloc_dict); + memmgr_heap_thread_trace_depth--; + } + memmgr_unlock(); } void memmgr_heap_disable_thread_trace(FuriThreadId thread_id) { - UNUSED(thread_id); + memmgr_lock(); + { + memmgr_heap_thread_trace_depth++; + furi_check(MemmgrHeapThreadDict_erase(memmgr_heap_thread_dict, (uint32_t)thread_id)); + memmgr_heap_thread_trace_depth--; + } + memmgr_unlock(); } size_t memmgr_heap_get_thread_memory(FuriThreadId thread_id) { - UNUSED(thread_id); - return 0; + size_t leftovers = MEMMGR_HEAP_UNKNOWN; + vTaskSuspendAll(); + { + memmgr_heap_thread_trace_depth++; + MemmgrHeapAllocDict_t* alloc_dict = + MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); + if(alloc_dict) { + leftovers = 0; + MemmgrHeapAllocDict_it_t alloc_dict_it; + for(MemmgrHeapAllocDict_it(alloc_dict_it, *alloc_dict); + !MemmgrHeapAllocDict_end_p(alloc_dict_it); + MemmgrHeapAllocDict_next(alloc_dict_it)) { + MemmgrHeapAllocDict_itref_t* data = MemmgrHeapAllocDict_ref(alloc_dict_it); + if(data->key != 0) { + block_header_t* block = block_from_ptr((uint8_t*)data->key); + if(!block_is_free(block)) { + // TODO: with tlsf we know the size of the block, so we don't need to store it on the dict + leftovers += data->value; + } + } + } + } + memmgr_heap_thread_trace_depth--; + } + (void)xTaskResumeAll(); + return leftovers; } static bool tlsf_walker_max_free(void* ptr, size_t size, int used, void* user) { UNUSED(ptr); + bool free = !used; size_t* max_free_block_size = (size_t*)user; - if(!used && size > *max_free_block_size) { + if(free && size > *max_free_block_size) { *max_free_block_size = size; } @@ -60,7 +123,52 @@ size_t memmgr_heap_get_max_free_block(void) { return max_free_block_size; } -void memmgr_heap_printf_free_blocks(void) { +typedef struct { + BlockWalker walker; + void* context; +} BlockWalkerWrapper; + +static bool tlsf_walker_wrapper(void* ptr, size_t size, int used, void* user) { + BlockWalkerWrapper* wrapper = (BlockWalkerWrapper*)user; + return wrapper->walker(ptr, size, used, wrapper->context); +} + +void memmgr_heap_walk_blocks(BlockWalker walker, void* context) { + memmgr_lock(); + + BlockWalkerWrapper wrapper = {walker, context}; + pool_t pool = tlsf_get_pool(tlsf); + tlsf_walk_pool(pool, tlsf_walker_wrapper, &wrapper); + + memmgr_unlock(); +} + +static inline void memmgr_heap_trace_malloc(void* pointer, size_t size) { + FuriThreadId thread_id = furi_thread_get_current_id(); + if(thread_id && memmgr_heap_thread_trace_depth == 0) { + memmgr_heap_thread_trace_depth++; + MemmgrHeapAllocDict_t* alloc_dict = + MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); + if(alloc_dict) { + MemmgrHeapAllocDict_set_at(*alloc_dict, (uint32_t)pointer, (uint32_t)size); + } + memmgr_heap_thread_trace_depth--; + } +} + +static inline void memmgr_heap_trace_free(void* pointer) { + FuriThreadId thread_id = furi_thread_get_current_id(); + if(thread_id && memmgr_heap_thread_trace_depth == 0) { + memmgr_heap_thread_trace_depth++; + MemmgrHeapAllocDict_t* alloc_dict = + MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); + if(alloc_dict) { + // In some cases thread may want to release memory that was not allocated by it + const bool res = MemmgrHeapAllocDict_erase(*alloc_dict, (uint32_t)pointer); + UNUSED(res); + } + memmgr_heap_thread_trace_depth--; + } } void* pvPortMalloc(size_t xSize) { @@ -75,6 +183,7 @@ void* pvPortMalloc(size_t xSize) { if(tlsf == NULL) { size_t pool_size = (size_t)&__heap_end__ - (size_t)&__heap_start__; tlsf = tlsf_create_with_pool((void*)&__heap_start__, pool_size, pool_size); + memmgr_heap_init(); } // allocate block @@ -93,6 +202,9 @@ void* pvPortMalloc(size_t xSize) { // clear block content memset(data, 0, xSize); + // trace allocation + memmgr_heap_trace_malloc(data, xSize); + memmgr_unlock(); return data; @@ -119,12 +231,15 @@ void vPortFree(void* pv) { // free tlsf_free(tlsf, pv); + // trace free + memmgr_heap_trace_free(pv); + memmgr_unlock(); } } size_t xPortGetFreeHeapSize(void) { - return memmgr_get_heap_size() - heap_used; + return memmgr_get_heap_size() - heap_used - tlsf_size(tlsf); } size_t xPortGetTotalHeapSize(void) { @@ -132,5 +247,5 @@ size_t xPortGetTotalHeapSize(void) { } size_t xPortGetMinimumEverFreeHeapSize(void) { - return memmgr_get_heap_size() - heap_max_used; + return memmgr_get_heap_size() - heap_max_used - tlsf_size(tlsf); } \ No newline at end of file diff --git a/furi/core/memmgr_heap.h b/furi/core/memmgr_heap.h index 7d889f1520..2f61deb642 100644 --- a/furi/core/memmgr_heap.h +++ b/furi/core/memmgr_heap.h @@ -40,9 +40,17 @@ size_t memmgr_heap_get_thread_memory(FuriThreadId thread_id); */ size_t memmgr_heap_get_max_free_block(void); -/** Print the address and size of all free blocks to stdout +typedef bool (*BlockWalker)(void* pointer, size_t size, bool used, void* context); + +/** + * @brief Walk through all heap blocks + * @warning This function will lock memory manager and may cause deadlocks if any malloc/free is called inside the callback. + * Also, printf and furi_log contains malloc calls, so do not use them. + * + * @param walker + * @param context */ -void memmgr_heap_printf_free_blocks(void); +void memmgr_heap_walk_blocks(BlockWalker walker, void* context); #ifdef __cplusplus } diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 6e65b94719..1d0cf168d8 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,60.4,, +Version,+,61.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -2360,7 +2360,7 @@ Function,+,memmgr_heap_disable_thread_trace,void,FuriThreadId Function,+,memmgr_heap_enable_thread_trace,void,FuriThreadId Function,+,memmgr_heap_get_max_free_block,size_t, Function,+,memmgr_heap_get_thread_memory,size_t,FuriThreadId -Function,+,memmgr_heap_printf_free_blocks,void, +Function,+,memmgr_heap_walk_blocks,void,"BlockWalker, void*" Function,-,memmgr_pool_get_free,size_t, Function,-,memmgr_pool_get_max_block,size_t, Function,+,memmove,void*,"void*, const void*, size_t" From c868f924acb0624ce5980f6a14ba4cc8a6cdaa58 Mon Sep 17 00:00:00 2001 From: SG Date: Fri, 5 Apr 2024 00:04:18 +0300 Subject: [PATCH 05/16] shmal fixshesh --- furi/core/memmgr_heap.c | 2 +- targets/f18/api_symbols.csv | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/furi/core/memmgr_heap.c b/furi/core/memmgr_heap.c index 748ab845b5..f45c2da3be 100644 --- a/furi/core/memmgr_heap.c +++ b/furi/core/memmgr_heap.c @@ -86,7 +86,7 @@ size_t memmgr_heap_get_thread_memory(FuriThreadId thread_id) { if(data->key != 0) { block_header_t* block = block_from_ptr((uint8_t*)data->key); if(!block_is_free(block)) { - // TODO: with tlsf we know the size of the block, so we don't need to store it on the dict + // with tlsf we know the size of the block, so we don't need to store it on the dict leftovers += data->value; } } diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index f6199445d1..79ad306485 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,60.4,, +Version,+,61.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1980,7 +1980,7 @@ Function,+,memmgr_heap_disable_thread_trace,void,FuriThreadId Function,+,memmgr_heap_enable_thread_trace,void,FuriThreadId Function,+,memmgr_heap_get_max_free_block,size_t, Function,+,memmgr_heap_get_thread_memory,size_t,FuriThreadId -Function,+,memmgr_heap_printf_free_blocks,void, +Function,+,memmgr_heap_walk_blocks,void,"BlockWalker, void*" Function,-,memmgr_pool_get_free,size_t, Function,-,memmgr_pool_get_max_block,size_t, Function,+,memmove,void*,"void*, const void*, size_t" From 0f4b048b8a47a2078edb9b9e557e68586e5650f1 Mon Sep 17 00:00:00 2001 From: SG Date: Fri, 5 Apr 2024 00:04:54 +0300 Subject: [PATCH 06/16] f18: tlsf --- targets/f18/target.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/targets/f18/target.json b/targets/f18/target.json index 43e9254cd4..a61c1373e1 100644 --- a/targets/f18/target.json +++ b/targets/f18/target.json @@ -13,6 +13,7 @@ "print", "flipper18", "furi", + "tlsf", "freertos", "stm32wb", "hwdrivers", @@ -68,4 +69,4 @@ "ibutton", "infrared" ] -} +} \ No newline at end of file From 2a234e4129f210d3be8ef8c4ae88b58e276cf841 Mon Sep 17 00:00:00 2001 From: SG Date: Fri, 5 Apr 2024 00:26:57 +0300 Subject: [PATCH 07/16] PVS: ignore tlsf --- .pvsoptions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pvsoptions b/.pvsoptions index 8606eef154..590a34de8b 100644 --- a/.pvsoptions +++ b/.pvsoptions @@ -1 +1 @@ ---ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e lib/mjs -e */arm-none-eabi/* +--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/tlsf -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/microtar -e lib/mlib -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e lib/mjs -e */arm-none-eabi/* From 5e3d3d5dbe1878b9fe6cb7d99d73e9f6a835c991 Mon Sep 17 00:00:00 2001 From: SG Date: Mon, 8 Apr 2024 04:05:44 +0300 Subject: [PATCH 08/16] I like to moving --- furi/core/memmgr_heap.c | 60 ++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/furi/core/memmgr_heap.c b/furi/core/memmgr_heap.c index f45c2da3be..fd0d1df5e1 100644 --- a/furi/core/memmgr_heap.c +++ b/furi/core/memmgr_heap.c @@ -3,6 +3,7 @@ #include #include #include +#include extern const void __heap_start__; extern const void __heap_end__; @@ -11,9 +12,6 @@ static tlsf_t tlsf = NULL; static size_t heap_used = 0; static size_t heap_max_used = 0; -// Furi heap extension -#include - // Allocation tracking types DICT_DEF2(MemmgrHeapAllocDict, uint32_t, uint32_t) //-V1048 @@ -69,6 +67,34 @@ void memmgr_heap_disable_thread_trace(FuriThreadId thread_id) { memmgr_unlock(); } +static inline void memmgr_heap_trace_malloc(void* pointer, size_t size) { + FuriThreadId thread_id = furi_thread_get_current_id(); + if(thread_id && memmgr_heap_thread_trace_depth == 0) { + memmgr_heap_thread_trace_depth++; + MemmgrHeapAllocDict_t* alloc_dict = + MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); + if(alloc_dict) { + MemmgrHeapAllocDict_set_at(*alloc_dict, (uint32_t)pointer, (uint32_t)size); + } + memmgr_heap_thread_trace_depth--; + } +} + +static inline void memmgr_heap_trace_free(void* pointer) { + FuriThreadId thread_id = furi_thread_get_current_id(); + if(thread_id && memmgr_heap_thread_trace_depth == 0) { + memmgr_heap_thread_trace_depth++; + MemmgrHeapAllocDict_t* alloc_dict = + MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); + if(alloc_dict) { + // In some cases thread may want to release memory that was not allocated by it + const bool res = MemmgrHeapAllocDict_erase(*alloc_dict, (uint32_t)pointer); + UNUSED(res); + } + memmgr_heap_thread_trace_depth--; + } +} + size_t memmgr_heap_get_thread_memory(FuriThreadId thread_id) { size_t leftovers = MEMMGR_HEAP_UNKNOWN; vTaskSuspendAll(); @@ -143,34 +169,6 @@ void memmgr_heap_walk_blocks(BlockWalker walker, void* context) { memmgr_unlock(); } -static inline void memmgr_heap_trace_malloc(void* pointer, size_t size) { - FuriThreadId thread_id = furi_thread_get_current_id(); - if(thread_id && memmgr_heap_thread_trace_depth == 0) { - memmgr_heap_thread_trace_depth++; - MemmgrHeapAllocDict_t* alloc_dict = - MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); - if(alloc_dict) { - MemmgrHeapAllocDict_set_at(*alloc_dict, (uint32_t)pointer, (uint32_t)size); - } - memmgr_heap_thread_trace_depth--; - } -} - -static inline void memmgr_heap_trace_free(void* pointer) { - FuriThreadId thread_id = furi_thread_get_current_id(); - if(thread_id && memmgr_heap_thread_trace_depth == 0) { - memmgr_heap_thread_trace_depth++; - MemmgrHeapAllocDict_t* alloc_dict = - MemmgrHeapThreadDict_get(memmgr_heap_thread_dict, (uint32_t)thread_id); - if(alloc_dict) { - // In some cases thread may want to release memory that was not allocated by it - const bool res = MemmgrHeapAllocDict_erase(*alloc_dict, (uint32_t)pointer); - UNUSED(res); - } - memmgr_heap_thread_trace_depth--; - } -} - void* pvPortMalloc(size_t xSize) { // memory management in ISR is not allowed if(FURI_IS_IRQ_MODE()) { From e895ba0c89c91bb2a830c35c574e075cf0651715 Mon Sep 17 00:00:00 2001 From: SG Date: Mon, 8 Apr 2024 04:10:00 +0300 Subject: [PATCH 09/16] merge upcoming changes --- furi/core/memmgr_heap.c | 6 +++++- targets/f18/api_symbols.csv | 4 ++-- targets/f7/api_symbols.csv | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/furi/core/memmgr_heap.c b/furi/core/memmgr_heap.c index fd0d1df5e1..630e26bd9e 100644 --- a/furi/core/memmgr_heap.c +++ b/furi/core/memmgr_heap.c @@ -187,7 +187,11 @@ void* pvPortMalloc(size_t xSize) { // allocate block void* data = tlsf_malloc(tlsf, xSize); if(data == NULL) { - furi_crash("out of memory"); + if(xSize == 0) { + furi_crash("malloc(0)"); + } else { + furi_crash("out of memory"); + } } // update heap usage diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 72116ccfdf..79ad306485 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,60.5,, +Version,+,61.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1980,7 +1980,7 @@ Function,+,memmgr_heap_disable_thread_trace,void,FuriThreadId Function,+,memmgr_heap_enable_thread_trace,void,FuriThreadId Function,+,memmgr_heap_get_max_free_block,size_t, Function,+,memmgr_heap_get_thread_memory,size_t,FuriThreadId -Function,+,memmgr_heap_printf_free_blocks,void, +Function,+,memmgr_heap_walk_blocks,void,"BlockWalker, void*" Function,-,memmgr_pool_get_free,size_t, Function,-,memmgr_pool_get_max_block,size_t, Function,+,memmove,void*,"void*, const void*, size_t" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 4ddff921bc..506a267ce3 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,60.5,, +Version,+,61.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -2371,7 +2371,7 @@ Function,+,memmgr_heap_disable_thread_trace,void,FuriThreadId Function,+,memmgr_heap_enable_thread_trace,void,FuriThreadId Function,+,memmgr_heap_get_max_free_block,size_t, Function,+,memmgr_heap_get_thread_memory,size_t,FuriThreadId -Function,+,memmgr_heap_printf_free_blocks,void, +Function,+,memmgr_heap_walk_blocks,void,"BlockWalker, void*" Function,-,memmgr_pool_get_free,size_t, Function,-,memmgr_pool_get_max_block,size_t, Function,+,memmove,void*,"void*, const void*, size_t" From 463dc8c727e91cde3027c58b238bb286506cef89 Mon Sep 17 00:00:00 2001 From: SG Date: Mon, 8 Apr 2024 20:27:58 +0300 Subject: [PATCH 10/16] memmgr: alloc aligned, realloc --- furi/core/memmgr.c | 39 ++++---------- furi/core/memmgr_heap.c | 114 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 122 insertions(+), 31 deletions(-) diff --git a/furi/core/memmgr.c b/furi/core/memmgr.c index 768adc05df..0fe79dff00 100644 --- a/furi/core/memmgr.c +++ b/furi/core/memmgr.c @@ -4,6 +4,8 @@ #include extern void* pvPortMalloc(size_t xSize); +extern void* pvPortAllocAligned(size_t xSize, size_t xAlignment); +extern void* pvPortRealloc(void* pv, size_t xSize); extern void vPortFree(void* pv); extern size_t xPortGetFreeHeapSize(void); extern size_t xPortGetTotalHeapSize(void); @@ -18,18 +20,7 @@ void free(void* ptr) { } void* realloc(void* ptr, size_t size) { - if(size == 0) { - vPortFree(ptr); - return NULL; - } - - void* p = pvPortMalloc(size); - if(ptr != NULL) { - memcpy(p, ptr, size); - vPortFree(ptr); - } - - return p; + return pvPortRealloc(ptr, size); } void* calloc(size_t count, size_t size) { @@ -47,6 +38,14 @@ char* strdup(const char* s) { return y; } +void* aligned_malloc(size_t size, size_t alignment) { + return pvPortAllocAligned(size, alignment); +} + +void aligned_free(void* p) { + vPortFree(p); +} + size_t memmgr_get_free_heap(void) { return xPortGetFreeHeapSize(); } @@ -92,20 +91,4 @@ size_t memmgr_pool_get_free(void) { size_t memmgr_pool_get_max_block(void) { return furi_hal_memory_max_pool_block(); -} - -void* aligned_malloc(size_t size, size_t alignment) { - void* p1; // original block - void** p2; // aligned block - int offset = alignment - 1 + sizeof(void*); - if((p1 = (void*)malloc(size + offset)) == NULL) { - return NULL; - } - p2 = (void**)(((size_t)(p1) + offset) & ~(alignment - 1)); - p2[-1] = p1; - return p2; -} - -void aligned_free(void* p) { - free(((void**)p)[-1]); } \ No newline at end of file diff --git a/furi/core/memmgr_heap.c b/furi/core/memmgr_heap.c index 630e26bd9e..d6ca3f2556 100644 --- a/furi/core/memmgr_heap.c +++ b/furi/core/memmgr_heap.c @@ -204,11 +204,11 @@ void* pvPortMalloc(size_t xSize) { // clear block content memset(data, 0, xSize); + memmgr_unlock(); + // trace allocation memmgr_heap_trace_malloc(data, xSize); - memmgr_unlock(); - return data; } @@ -233,11 +233,119 @@ void vPortFree(void* pv) { // free tlsf_free(tlsf, pv); + memmgr_unlock(); + // trace free memmgr_heap_trace_free(pv); + } +} - memmgr_unlock(); +extern void* pvPortAllocAligned(size_t xSize, size_t xAlignment) { + // memory management in ISR is not allowed + if(FURI_IS_IRQ_MODE()) { + furi_crash("memmgt in ISR"); + } + + memmgr_lock(); + + // initialize tlsf, if not initialized + if(tlsf == NULL) { + size_t pool_size = (size_t)&__heap_end__ - (size_t)&__heap_start__; + tlsf = tlsf_create_with_pool((void*)&__heap_start__, pool_size, pool_size); + memmgr_heap_init(); + } + + // allocate block + void* data = tlsf_memalign(tlsf, xAlignment, xSize); + if(data == NULL) { + if(xSize == 0) { + furi_crash("malloc_aligned(0)"); + } else { + furi_crash("out of memory"); + } + } + + // update heap usage + heap_used += tlsf_block_size(data); + heap_used += tlsf_alloc_overhead(); + if(heap_used > heap_max_used) { + heap_max_used = heap_used; + } + + memmgr_unlock(); + + // clear block content + memset(data, 0, xSize); + + // trace allocation + memmgr_heap_trace_malloc(data, xSize); + + return data; +} + +extern void* pvPortRealloc(void* pv, size_t xSize) { + // size 0 is considered as free + if(xSize == 0) { + vPortFree(pv); + return NULL; + } + + // realloc(NULL, size) is equivalent to malloc(size) + if(pv == NULL) { + return pvPortMalloc(xSize); + } + + // realloc things // + + // memory management in ISR is not allowed + if(FURI_IS_IRQ_MODE()) { + furi_crash("memmgt in ISR"); + } + + memmgr_lock(); + + // initialize tlsf, if not initialized + if(tlsf == NULL) { + size_t pool_size = (size_t)&__heap_end__ - (size_t)&__heap_start__; + tlsf = tlsf_create_with_pool((void*)&__heap_start__, pool_size, pool_size); + memmgr_heap_init(); + } + + // trace old block as free + size_t old_size = 0; + if(pv != NULL) { + old_size = tlsf_block_size(pv); + memmgr_heap_trace_free(pv); + } + + // reallocate block + void* data = tlsf_realloc(tlsf, pv, xSize); + if(data == NULL) { + if(xSize == 0) { + furi_crash("realloc(0)"); + } else { + furi_crash("out of memory"); + } } + + // update heap usage + heap_used -= old_size; + heap_used += tlsf_block_size(data); + if(heap_used > heap_max_used) { + heap_max_used = heap_used; + } + + // clear remain block content, if the new size is bigger + if(xSize > old_size) { + memset((uint8_t*)data + old_size, 0, xSize - old_size); + } + + memmgr_unlock(); + + // trace allocation + memmgr_heap_trace_malloc(data, xSize); + + return data; } size_t xPortGetFreeHeapSize(void) { From 3a4bff82f40b6f2856ef5ebedb5463513405b3cd Mon Sep 17 00:00:00 2001 From: SG Date: Tue, 9 Apr 2024 05:12:15 +0300 Subject: [PATCH 11/16] Furi: distinct name for auxiliary memory pool --- applications/services/cli/cli_commands.c | 4 ++-- furi/core/memmgr.c | 4 ++-- furi/core/memmgr.h | 10 +++++----- furi/core/thread.c | 4 ++-- targets/f18/api_symbols.csv | 6 +++--- targets/f7/api_symbols.csv | 6 +++--- targets/f7/fatfs/sector_cache.c | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index 9105e40e81..56d05785fa 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -425,8 +425,8 @@ void cli_command_free(Cli* cli, FuriString* args, void* context) { printf("Minimum heap size: %zu\r\n", memmgr_get_minimum_free_heap()); printf("Maximum heap block: %zu\r\n", memmgr_heap_get_max_free_block()); - printf("Pool free: %zu\r\n", memmgr_pool_get_free()); - printf("Maximum pool block: %zu\r\n", memmgr_pool_get_max_block()); + printf("Aux pool total free: %zu\r\n", memmgr_aux_pool_get_free()); + printf("Aux pool max free block: %zu\r\n", memmgr_pool_get_max_block()); } typedef struct { diff --git a/furi/core/memmgr.c b/furi/core/memmgr.c index 0fe79dff00..5785bff6ea 100644 --- a/furi/core/memmgr.c +++ b/furi/core/memmgr.c @@ -78,14 +78,14 @@ void* __wrap__realloc_r(struct _reent* r, void* ptr, size_t size) { return realloc(ptr, size); } -void* memmgr_alloc_from_pool(size_t size) { +void* memmgr_aux_pool_alloc(size_t size) { void* p = furi_hal_memory_alloc(size); if(p == NULL) p = malloc(size); return p; } -size_t memmgr_pool_get_free(void) { +size_t memmgr_aux_pool_get_free(void) { return furi_hal_memory_get_free(); } diff --git a/furi/core/memmgr.h b/furi/core/memmgr.h index bc0c35faa7..7a3f7b8f39 100644 --- a/furi/core/memmgr.h +++ b/furi/core/memmgr.h @@ -51,22 +51,22 @@ void* aligned_malloc(size_t size, size_t alignment); void aligned_free(void* p); /** - * @brief Allocate memory from separate memory pool. That memory can't be freed. + * @brief Allocate memory from the auxiliary memory pool. That memory can't be freed. * * @param size * @return void* */ -void* memmgr_alloc_from_pool(size_t size); +void* memmgr_aux_pool_alloc(size_t size); /** - * @brief Get free memory pool size + * @brief Get the auxiliary poll free memory size * * @return size_t */ -size_t memmgr_pool_get_free(void); +size_t memmgr_aux_pool_get_free(void); /** - * @brief Get max free block size from memory pool + * @brief Get max free block size from the auxiliary memory pool * * @return size_t */ diff --git a/furi/core/thread.c b/furi/core/thread.c index f9f73b4f75..c9bf79d32a 100644 --- a/furi/core/thread.c +++ b/furi/core/thread.c @@ -276,8 +276,8 @@ void furi_thread_start(FuriThread* thread) { stack, thread, priority, - memmgr_alloc_from_pool(sizeof(StackType_t) * stack), - memmgr_alloc_from_pool(sizeof(StaticTask_t))); + memmgr_aux_pool_alloc(sizeof(StackType_t) * stack), + memmgr_aux_pool_alloc(sizeof(StaticTask_t))); } else { BaseType_t ret = xTaskCreate( furi_thread_body, thread->name, stack, thread, priority, &thread->task_handle); diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index 79ad306485..d1beda897f 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,61.0,, +Version,+,61.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1972,7 +1972,8 @@ Function,+,memchr,void*,"const void*, int, size_t" Function,+,memcmp,int,"const void*, const void*, size_t" Function,+,memcpy,void*,"void*, const void*, size_t" Function,-,memmem,void*,"const void*, size_t, const void*, size_t" -Function,-,memmgr_alloc_from_pool,void*,size_t +Function,-,memmgr_aux_pool_alloc,void*,size_t +Function,-,memmgr_aux_pool_get_free,size_t, Function,+,memmgr_get_free_heap,size_t, Function,+,memmgr_get_minimum_free_heap,size_t, Function,+,memmgr_get_total_heap,size_t, @@ -1981,7 +1982,6 @@ Function,+,memmgr_heap_enable_thread_trace,void,FuriThreadId Function,+,memmgr_heap_get_max_free_block,size_t, Function,+,memmgr_heap_get_thread_memory,size_t,FuriThreadId Function,+,memmgr_heap_walk_blocks,void,"BlockWalker, void*" -Function,-,memmgr_pool_get_free,size_t, Function,-,memmgr_pool_get_max_block,size_t, Function,+,memmove,void*,"void*, const void*, size_t" Function,-,mempcpy,void*,"void*, const void*, size_t" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 506a267ce3..291e57b276 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,61.0,, +Version,+,61.1,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -2363,7 +2363,8 @@ Function,+,memchr,void*,"const void*, int, size_t" Function,+,memcmp,int,"const void*, const void*, size_t" Function,+,memcpy,void*,"void*, const void*, size_t" Function,-,memmem,void*,"const void*, size_t, const void*, size_t" -Function,-,memmgr_alloc_from_pool,void*,size_t +Function,-,memmgr_aux_pool_alloc,void*,size_t +Function,-,memmgr_aux_pool_get_free,size_t, Function,+,memmgr_get_free_heap,size_t, Function,+,memmgr_get_minimum_free_heap,size_t, Function,+,memmgr_get_total_heap,size_t, @@ -2372,7 +2373,6 @@ Function,+,memmgr_heap_enable_thread_trace,void,FuriThreadId Function,+,memmgr_heap_get_max_free_block,size_t, Function,+,memmgr_heap_get_thread_memory,size_t,FuriThreadId Function,+,memmgr_heap_walk_blocks,void,"BlockWalker, void*" -Function,-,memmgr_pool_get_free,size_t, Function,-,memmgr_pool_get_max_block,size_t, Function,+,memmove,void*,"void*, const void*, size_t" Function,-,mempcpy,void*,"void*, const void*, size_t" diff --git a/targets/f7/fatfs/sector_cache.c b/targets/f7/fatfs/sector_cache.c index 319dd21732..df86cb7f15 100644 --- a/targets/f7/fatfs/sector_cache.c +++ b/targets/f7/fatfs/sector_cache.c @@ -19,7 +19,7 @@ static SectorCache* cache = NULL; void sector_cache_init(void) { if(cache == NULL) { - cache = memmgr_alloc_from_pool(sizeof(SectorCache)); + cache = memmgr_aux_pool_alloc(sizeof(SectorCache)); } if(cache != NULL) { From e1f7f86c94c02fe4b2ab163c56ef431769eb6630 Mon Sep 17 00:00:00 2001 From: SG Date: Tue, 9 Apr 2024 05:12:56 +0300 Subject: [PATCH 12/16] Furi: put idle and timer thread to mem2 --- furi/flipper.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/furi/flipper.c b/furi/flipper.c index c7ba3b4fb1..6c7b9831a4 100644 --- a/furi/flipper.c +++ b/furi/flipper.c @@ -51,12 +51,17 @@ void flipper_init(void) { FURI_LOG_I(TAG, "Startup complete"); } +PLACE_IN_SECTION("MB_MEM2") static StaticTask_t idle_task_tcb; +PLACE_IN_SECTION("MB_MEM2") static StackType_t idle_task_stack[configIDLE_TASK_STACK_DEPTH]; +PLACE_IN_SECTION("MB_MEM2") static StaticTask_t timer_task_tcb; +PLACE_IN_SECTION("MB_MEM2") static StackType_t timer_task_stack[configTIMER_TASK_STACK_DEPTH]; + void vApplicationGetIdleTaskMemory( StaticTask_t** tcb_ptr, StackType_t** stack_ptr, uint32_t* stack_size) { - *tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t)); - *stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configIDLE_TASK_STACK_DEPTH); + *tcb_ptr = &idle_task_tcb; + *stack_ptr = idle_task_stack; *stack_size = configIDLE_TASK_STACK_DEPTH; } @@ -64,7 +69,7 @@ void vApplicationGetTimerTaskMemory( StaticTask_t** tcb_ptr, StackType_t** stack_ptr, uint32_t* stack_size) { - *tcb_ptr = memmgr_alloc_from_pool(sizeof(StaticTask_t)); - *stack_ptr = memmgr_alloc_from_pool(sizeof(StackType_t) * configTIMER_TASK_STACK_DEPTH); + *tcb_ptr = &timer_task_tcb; + *stack_ptr = timer_task_stack; *stack_size = configTIMER_TASK_STACK_DEPTH; } \ No newline at end of file From 50e852a25fc8b81e23be1c8ad308751fe29e6a16 Mon Sep 17 00:00:00 2001 From: SG Date: Tue, 9 Apr 2024 05:13:27 +0300 Subject: [PATCH 13/16] Furi: fix smal things in allocator --- furi/core/memmgr_heap.c | 87 ++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 53 deletions(-) diff --git a/furi/core/memmgr_heap.c b/furi/core/memmgr_heap.c index d6ca3f2556..5afeb8f671 100644 --- a/furi/core/memmgr_heap.c +++ b/furi/core/memmgr_heap.c @@ -38,11 +38,17 @@ static inline size_t memmgr_get_heap_size(void) { return (size_t)&__heap_end__ - (size_t)&__heap_start__; } -// Initialize tracing storage on start -void memmgr_heap_init(void) { +// Initialize tracing storage +static void memmgr_heap_init(void) { MemmgrHeapThreadDict_init(memmgr_heap_thread_dict); } +__attribute__((constructor)) static void memmgr_init(void) { + size_t pool_size = (size_t)&__heap_end__ - (size_t)&__heap_start__; + tlsf = tlsf_create_with_pool((void*)&__heap_start__, pool_size, pool_size); + memmgr_heap_init(); +} + void memmgr_heap_enable_thread_trace(FuriThreadId thread_id) { memmgr_lock(); { @@ -97,7 +103,7 @@ static inline void memmgr_heap_trace_free(void* pointer) { size_t memmgr_heap_get_thread_memory(FuriThreadId thread_id) { size_t leftovers = MEMMGR_HEAP_UNKNOWN; - vTaskSuspendAll(); + memmgr_lock(); { memmgr_heap_thread_trace_depth++; MemmgrHeapAllocDict_t* alloc_dict = @@ -112,7 +118,6 @@ size_t memmgr_heap_get_thread_memory(FuriThreadId thread_id) { if(data->key != 0) { block_header_t* block = block_from_ptr((uint8_t*)data->key); if(!block_is_free(block)) { - // with tlsf we know the size of the block, so we don't need to store it on the dict leftovers += data->value; } } @@ -120,7 +125,7 @@ size_t memmgr_heap_get_thread_memory(FuriThreadId thread_id) { } memmgr_heap_thread_trace_depth--; } - (void)xTaskResumeAll(); + memmgr_unlock(); return leftovers; } @@ -177,13 +182,6 @@ void* pvPortMalloc(size_t xSize) { memmgr_lock(); - // initialize tlsf, if not initialized - if(tlsf == NULL) { - size_t pool_size = (size_t)&__heap_end__ - (size_t)&__heap_start__; - tlsf = tlsf_create_with_pool((void*)&__heap_start__, pool_size, pool_size); - memmgr_heap_init(); - } - // allocate block void* data = tlsf_malloc(tlsf, xSize); if(data == NULL) { @@ -201,13 +199,13 @@ void* pvPortMalloc(size_t xSize) { heap_max_used = heap_used; } - // clear block content - memset(data, 0, xSize); + // trace allocation + memmgr_heap_trace_malloc(data, xSize); memmgr_unlock(); - // trace allocation - memmgr_heap_trace_malloc(data, xSize); + // clear block content + memset(data, 0, xSize); return data; } @@ -222,8 +220,10 @@ void vPortFree(void* pv) { if(pv != NULL) { memmgr_lock(); - // clear block content + // get block size size_t block_size = tlsf_block_size(pv); + + // clear block content memset(pv, 0, block_size); // update heap usage @@ -233,10 +233,10 @@ void vPortFree(void* pv) { // free tlsf_free(tlsf, pv); - memmgr_unlock(); - // trace free memmgr_heap_trace_free(pv); + + memmgr_unlock(); } } @@ -248,13 +248,6 @@ extern void* pvPortAllocAligned(size_t xSize, size_t xAlignment) { memmgr_lock(); - // initialize tlsf, if not initialized - if(tlsf == NULL) { - size_t pool_size = (size_t)&__heap_end__ - (size_t)&__heap_start__; - tlsf = tlsf_create_with_pool((void*)&__heap_start__, pool_size, pool_size); - memmgr_heap_init(); - } - // allocate block void* data = tlsf_memalign(tlsf, xAlignment, xSize); if(data == NULL) { @@ -272,19 +265,19 @@ extern void* pvPortAllocAligned(size_t xSize, size_t xAlignment) { heap_max_used = heap_used; } + // trace allocation + memmgr_heap_trace_malloc(data, xSize); + memmgr_unlock(); // clear block content memset(data, 0, xSize); - // trace allocation - memmgr_heap_trace_malloc(data, xSize); - return data; } extern void* pvPortRealloc(void* pv, size_t xSize) { - // size 0 is considered as free + // realloc(ptr, 0) is equivalent to free(ptr) if(xSize == 0) { vPortFree(pv); return NULL; @@ -295,7 +288,7 @@ extern void* pvPortRealloc(void* pv, size_t xSize) { return pvPortMalloc(xSize); } - // realloc things // + /* realloc things */ // memory management in ISR is not allowed if(FURI_IS_IRQ_MODE()) { @@ -304,28 +297,16 @@ extern void* pvPortRealloc(void* pv, size_t xSize) { memmgr_lock(); - // initialize tlsf, if not initialized - if(tlsf == NULL) { - size_t pool_size = (size_t)&__heap_end__ - (size_t)&__heap_start__; - tlsf = tlsf_create_with_pool((void*)&__heap_start__, pool_size, pool_size); - memmgr_heap_init(); - } - // trace old block as free - size_t old_size = 0; - if(pv != NULL) { - old_size = tlsf_block_size(pv); - memmgr_heap_trace_free(pv); - } + size_t old_size = tlsf_block_size(pv); + + // trace free + memmgr_heap_trace_free(pv); // reallocate block void* data = tlsf_realloc(tlsf, pv, xSize); if(data == NULL) { - if(xSize == 0) { - furi_crash("realloc(0)"); - } else { - furi_crash("out of memory"); - } + furi_crash("out of memory"); } // update heap usage @@ -335,16 +316,16 @@ extern void* pvPortRealloc(void* pv, size_t xSize) { heap_max_used = heap_used; } + // trace allocation + memmgr_heap_trace_malloc(data, xSize); + + memmgr_unlock(); + // clear remain block content, if the new size is bigger if(xSize > old_size) { memset((uint8_t*)data + old_size, 0, xSize - old_size); } - memmgr_unlock(); - - // trace allocation - memmgr_heap_trace_malloc(data, xSize); - return data; } From 5bca6d2e842625c234a114d0a8db2fc7a9c178aa Mon Sep 17 00:00:00 2001 From: SG Date: Tue, 9 Apr 2024 15:23:46 +0300 Subject: [PATCH 14/16] Furi: remove aligned_free. Use free instead. --- furi/core/memmgr.c | 4 ---- furi/core/memmgr.h | 11 ++--------- lib/flipper_application/elf/elf_file.c | 6 +++--- targets/f18/api_symbols.csv | 3 +-- targets/f7/api_symbols.csv | 3 +-- 5 files changed, 7 insertions(+), 20 deletions(-) diff --git a/furi/core/memmgr.c b/furi/core/memmgr.c index 5785bff6ea..bb10403437 100644 --- a/furi/core/memmgr.c +++ b/furi/core/memmgr.c @@ -42,10 +42,6 @@ void* aligned_malloc(size_t size, size_t alignment) { return pvPortAllocAligned(size, alignment); } -void aligned_free(void* p) { - vPortFree(p); -} - size_t memmgr_get_free_heap(void) { return xPortGetFreeHeapSize(); } diff --git a/furi/core/memmgr.h b/furi/core/memmgr.h index 7a3f7b8f39..d386331183 100644 --- a/furi/core/memmgr.h +++ b/furi/core/memmgr.h @@ -36,20 +36,13 @@ size_t memmgr_get_total_heap(void); size_t memmgr_get_minimum_free_heap(void); /** - * An aligned version of malloc, used when you need to get the aligned space on the heap - * Freeing the received address is performed ONLY through the aligned_free function + * An aligned version of malloc, used when you need to get the aligned space on the heap. * @param size * @param alignment * @return void* */ void* aligned_malloc(size_t size, size_t alignment); -/** - * Freed space obtained through the aligned_malloc function - * @param p pointer to result of aligned_malloc - */ -void aligned_free(void* p); - /** * @brief Allocate memory from the auxiliary memory pool. That memory can't be freed. * @@ -59,7 +52,7 @@ void aligned_free(void* p); void* memmgr_aux_pool_alloc(size_t size); /** - * @brief Get the auxiliary poll free memory size + * @brief Get the auxiliary pool free memory size * * @return size_t */ diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index 6543168662..4d36f3460c 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -713,7 +713,7 @@ static bool elf_relocate_fast(ELFFile* elf, ELFSection* s) { } } - aligned_free(s->fast_rel->data); + free(s->fast_rel->data); free(s->fast_rel); s->fast_rel = NULL; @@ -780,10 +780,10 @@ void elf_file_free(ELFFile* elf) { ELFSectionDict_next(it)) { const ELFSectionDict_itref_t* itref = ELFSectionDict_cref(it); if(itref->value.data) { - aligned_free(itref->value.data); + free(itref->value.data); } if(itref->value.fast_rel) { - aligned_free(itref->value.fast_rel->data); + free(itref->value.fast_rel->data); free(itref->value.fast_rel); } free((void*)itref->key); diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index d1beda897f..ea4d997acf 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,61.1,, +Version,+,62.0,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -515,7 +515,6 @@ Function,-,acoshf,float,float Function,-,acoshl,long double,long double Function,-,acosl,long double,long double Function,-,aligned_alloc,void*,"size_t, size_t" -Function,+,aligned_free,void,void* Function,+,aligned_malloc,void*,"size_t, size_t" Function,-,arc4random,__uint32_t, Function,-,arc4random_buf,void,"void*, size_t" diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index 291e57b276..cf1eb642de 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,61.1,, +Version,+,62.0,, Header,+,applications/drivers/subghz/cc1101_ext/cc1101_ext_interconnect.h,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, @@ -584,7 +584,6 @@ Function,-,acoshf,float,float Function,-,acoshl,long double,long double Function,-,acosl,long double,long double Function,-,aligned_alloc,void*,"size_t, size_t" -Function,+,aligned_free,void,void* Function,+,aligned_malloc,void*,"size_t, size_t" Function,-,arc4random,__uint32_t, Function,-,arc4random_buf,void,"void*, size_t" From 0d3a717762764ecb394b2e87797fb006e9d07929 Mon Sep 17 00:00:00 2001 From: SG Date: Tue, 9 Apr 2024 17:08:12 +0300 Subject: [PATCH 15/16] aligned_malloc -> aligned_alloc --- furi/core/memmgr.c | 2 +- furi/core/memmgr.h | 8 -------- lib/flipper_application/elf/elf_file.c | 2 +- targets/f18/api_symbols.csv | 3 +-- targets/f7/api_symbols.csv | 3 +-- 5 files changed, 4 insertions(+), 14 deletions(-) diff --git a/furi/core/memmgr.c b/furi/core/memmgr.c index bb10403437..6c89378506 100644 --- a/furi/core/memmgr.c +++ b/furi/core/memmgr.c @@ -38,7 +38,7 @@ char* strdup(const char* s) { return y; } -void* aligned_malloc(size_t size, size_t alignment) { +void* aligned_alloc(size_t size, size_t alignment) { return pvPortAllocAligned(size, alignment); } diff --git a/furi/core/memmgr.h b/furi/core/memmgr.h index d386331183..796a1f5378 100644 --- a/furi/core/memmgr.h +++ b/furi/core/memmgr.h @@ -35,14 +35,6 @@ size_t memmgr_get_total_heap(void); */ size_t memmgr_get_minimum_free_heap(void); -/** - * An aligned version of malloc, used when you need to get the aligned space on the heap. - * @param size - * @param alignment - * @return void* - */ -void* aligned_malloc(size_t size, size_t alignment); - /** * @brief Allocate memory from the auxiliary memory pool. That memory can't be freed. * diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index 4d36f3460c..80d86b6375 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -461,7 +461,7 @@ static bool elf_load_section_data(ELFFile* elf, ELFSection* section, Elf32_Shdr* return true; } - section->data = aligned_malloc(section_header->sh_size, section_header->sh_addralign); + section->data = aligned_alloc(section_header->sh_size, section_header->sh_addralign); section->size = section_header->sh_size; if(section_header->sh_type == SHT_NOBITS) { diff --git a/targets/f18/api_symbols.csv b/targets/f18/api_symbols.csv index ea4d997acf..195a36702f 100644 --- a/targets/f18/api_symbols.csv +++ b/targets/f18/api_symbols.csv @@ -514,8 +514,7 @@ Function,-,acosh,double,double Function,-,acoshf,float,float Function,-,acoshl,long double,long double Function,-,acosl,long double,long double -Function,-,aligned_alloc,void*,"size_t, size_t" -Function,+,aligned_malloc,void*,"size_t, size_t" +Function,+,aligned_alloc,void*,"size_t, size_t" Function,-,arc4random,__uint32_t, Function,-,arc4random_buf,void,"void*, size_t" Function,-,arc4random_uniform,__uint32_t,__uint32_t diff --git a/targets/f7/api_symbols.csv b/targets/f7/api_symbols.csv index cf1eb642de..d381e350f6 100644 --- a/targets/f7/api_symbols.csv +++ b/targets/f7/api_symbols.csv @@ -583,8 +583,7 @@ Function,-,acosh,double,double Function,-,acoshf,float,float Function,-,acoshl,long double,long double Function,-,acosl,long double,long double -Function,-,aligned_alloc,void*,"size_t, size_t" -Function,+,aligned_malloc,void*,"size_t, size_t" +Function,+,aligned_alloc,void*,"size_t, size_t" Function,-,arc4random,__uint32_t, Function,-,arc4random_buf,void,"void*, size_t" Function,-,arc4random_uniform,__uint32_t,__uint32_t From f1e6de796410e3aa9ac462d536d52b838b71ec41 Mon Sep 17 00:00:00 2001 From: SG Date: Tue, 9 Apr 2024 17:10:59 +0300 Subject: [PATCH 16/16] aligned_alloc, parameters order --- furi/core/memmgr.c | 2 +- lib/flipper_application/elf/elf_file.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/furi/core/memmgr.c b/furi/core/memmgr.c index 6c89378506..768d448904 100644 --- a/furi/core/memmgr.c +++ b/furi/core/memmgr.c @@ -38,7 +38,7 @@ char* strdup(const char* s) { return y; } -void* aligned_alloc(size_t size, size_t alignment) { +void* aligned_alloc(size_t alignment, size_t size) { return pvPortAllocAligned(size, alignment); } diff --git a/lib/flipper_application/elf/elf_file.c b/lib/flipper_application/elf/elf_file.c index 80d86b6375..e117e546a2 100644 --- a/lib/flipper_application/elf/elf_file.c +++ b/lib/flipper_application/elf/elf_file.c @@ -461,7 +461,7 @@ static bool elf_load_section_data(ELFFile* elf, ELFSection* section, Elf32_Shdr* return true; } - section->data = aligned_alloc(section_header->sh_size, section_header->sh_addralign); + section->data = aligned_alloc(section_header->sh_addralign, section_header->sh_size); section->size = section_header->sh_size; if(section_header->sh_type == SHT_NOBITS) {