From fc642aaf48820206db3f9b5dc1233a6e7c10aa6d Mon Sep 17 00:00:00 2001 From: philmoz Date: Sun, 22 Dec 2024 13:56:33 +1100 Subject: [PATCH] feat(bw): make more RAM available to Lua scripts on some radios (#5717) --- radio/src/bin_allocator.cpp | 176 +++++++++++++++++++++++++++++------- radio/src/bin_allocator.h | 69 +------------- radio/src/edgetx.cpp | 5 + 3 files changed, 147 insertions(+), 103 deletions(-) diff --git a/radio/src/bin_allocator.cpp b/radio/src/bin_allocator.cpp index 4dc63b09a..88d668582 100644 --- a/radio/src/bin_allocator.cpp +++ b/radio/src/bin_allocator.cpp @@ -19,35 +19,137 @@ * GNU General Public License for more details. */ -#include -#include -#include "edgetx.h" #include "bin_allocator.h" +#include "edgetx.h" +template +class BinAllocator +{ + private: + union Bin { + char data[SIZE_SLOT]; + union Bin* next; + }; + union Bin bins[NUM_BINS]; + union Bin* freeList; + int freeCount; -BinAllocator_slots1 slots1 __SDRAM; -BinAllocator_slots2 slots2 __SDRAM; + public: + BinAllocator() + { + freeCount = NUM_BINS; + memclear(bins, sizeof(bins)); + freeList = &bins[0]; + for (int i = 0; i < NUM_BINS - 1; i += 1) { + bins[i].next = &bins[i+1]; + } + } + + bool is_member(void * ptr) { + return (ptr >= bins[0].data && ptr <= bins[NUM_BINS-1].data); + } + + bool free(void * ptr) + { + if (is_member(ptr)) { + union Bin* b = (union Bin*)ptr; + b->next = freeList; + freeList = b; + freeCount += 1; + // TRACE("\tBinAllocator<%d> free %p", SIZE_SLOT, ptr); + return true; + } + // TRACE("\tBinAllocator<%d> free - %p NOT FOUND", SIZE_SLOT, ptr); + return false; + } + + void * malloc(size_t size) + { + if (size > SIZE_SLOT) { + // TRACE("BinAllocator<%d> malloc [%lu] size > SIZE_SLOT", SIZE_SLOT, size); + return nullptr; + } + if (freeList) { + union Bin* b = freeList; + freeList = freeList->next; + freeCount -= 1; + // TRACE("\tBinAllocator<%d> malloc [%lu] - %p", SIZE_SLOT, size, b); + return b->data; + } + // TRACE("BinAllocator<%d> malloc [%lu] no free slots", SIZE_SLOT , size); + return nullptr; + } + + size_t size(void * ptr) { return is_member(ptr) ? SIZE_SLOT : 0; } + + bool can_fit(void * ptr, size_t size) + { + return is_member(ptr) && size <= SIZE_SLOT; + } + + int freeSlots() { return freeCount; } + int avail() { return freeCount * SIZE_SLOT; } +}; + +#if defined(SIMU) +typedef BinAllocator<40,300> BinAllocator_slots1; +typedef BinAllocator<80,100> BinAllocator_slots2; +#elif defined(CCMRAM) +#if defined(DEBUG) +typedef BinAllocator<28,400> BinAllocator_slots1; +typedef BinAllocator<92,90> BinAllocator_slots2; +#else +typedef BinAllocator<28,415> BinAllocator_slots1; +typedef BinAllocator<92,100> BinAllocator_slots2; +#endif +#else +typedef BinAllocator<28,200> BinAllocator_slots1; +typedef BinAllocator<92,50> BinAllocator_slots2; +#endif + +BinAllocator_slots1 slots1; +BinAllocator_slots2 slots2; #if defined(DEBUG) int SimulateMallocFailure = 0; //set this to simulate allocation failure +int totalAllocated = 0; +int totalFreed = 0; +int missedAlloc = 0; +int missedFree = 0; #endif -bool bin_free(void * ptr) +int bin_avail() { - //return TRUE if ours - return slots1.free(ptr) || slots2.free(ptr); + return slots1.avail() + slots2.avail(); } -void * bin_malloc(size_t size) { - //try to allocate from our space - void * res = slots1.malloc(size); - return res ? res : slots2.malloc(size); +static bool bin_free(void * ptr) +{ + // return TRUE if ours + bool res = slots1.free(ptr); + if (!res) res = slots2.free(ptr); +#if defined(DEBUG) + if (res) totalFreed += 1; + else missedFree += 1; +#endif + return res; } -void * bin_realloc(void * ptr, size_t size) +static void * bin_malloc(size_t size) { + // try to allocate from our space + void* res = slots1.malloc(size); + if (!res) res = slots2.malloc(size); +#if defined(DEBUG) + if (res) totalAllocated += 1; + else missedAlloc += 1; +#endif + return res; +} + +static void * bin_realloc(void * ptr, size_t size) { if (ptr == nullptr) { - //no previous data, try our malloc + // no previous data, try our malloc return bin_malloc(size); } else { @@ -56,7 +158,7 @@ void * bin_realloc(void * ptr, size_t size) return nullptr; } - //we have existing data + // we have existing data // if it fits in current slot, return it // TODO if new size is smaller, try to relocate in smaller slot if ( slots1.can_fit(ptr, size) ) { @@ -68,28 +170,30 @@ void * bin_realloc(void * ptr, size_t size) return ptr; } - //we need a bigger slot + // we need a bigger slot void * res = bin_malloc(size); if (res == nullptr) { // we don't have the space, use libc malloc // TRACE("bin_malloc [%lu] FAILURE", size); res = malloc(size); if (res == nullptr) { - TRACE("libc malloc [%lu] FAILURE", size); + // TRACE("libc malloc [%lu] FAILURE", size); return nullptr; } } - //copy data + // copy data memcpy(res, ptr, slots1.size(ptr) + slots2.size(ptr)); bin_free(ptr); return res; } } - void *bin_l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { - (void)ud; (void)osize; /* not used */ + // (void)ud; (void)osize; /* not used */ + + void* res = nullptr; + if (nsize == 0) { if (ptr) { // avoid a bunch of NULL pointer free calls if (!bin_free(ptr)) { @@ -98,24 +202,18 @@ void *bin_l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) free(ptr); } } - return nullptr; - } - else { + } else { #if defined(DEBUG) - if (SimulateMallocFailure < 0 ) { - //delayed failure - if (++SimulateMallocFailure == 0) { + if (SimulateMallocFailure < 0) { + // delayed failure + if (++SimulateMallocFailure == 0) SimulateMallocFailure = 1; - } } - if ( SimulateMallocFailure > 0) { - // simulate one malloc failure - TRACE("bin_l_alloc(): simulating malloc failure at %p[%lu]", ptr, nsize); - return 0; - } -#endif // #if defined(DEBUG) + // normal alloc if <= 0, otherwise will return nullptr + if ( SimulateMallocFailure <= 0) { +#endif // try our allocator, if it fails use libc allocator - void * res = bin_realloc(ptr, nsize); + res = bin_realloc(ptr, nsize); if (res && ptr) { // TRACE("OUR realloc %p[%lu] -> %p[%lu]", ptr, osize, res, nsize); } @@ -127,6 +225,14 @@ void *bin_l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) // dumpFreeMemory(); // } } - return res; +#if defined(DEBUG) + } +#endif } + +#if defined(DEBUG) + TRACE("bin_l_alloc(%p,%p,%lu,%lu) - S1F %d, S2F %d, TA %d, TF %d, MA %d, MF %d",ud,ptr,osize,nsize,slots1.freeSlots(),slots2.freeSlots(),totalAllocated,totalFreed,missedAlloc,missedFree); +#endif + + return res; } diff --git a/radio/src/bin_allocator.h b/radio/src/bin_allocator.h index 401114c97..a9e0d9431 100644 --- a/radio/src/bin_allocator.h +++ b/radio/src/bin_allocator.h @@ -21,76 +21,9 @@ #pragma once -#include "debug.h" - -template class BinAllocator { -private: - PACK(struct Bin { - char data[SIZE_SLOT]; - bool Used; - }); - struct Bin Bins[NUM_BINS]; - int NoUsedBins; -public: - BinAllocator() : NoUsedBins(0) { - memclear(Bins, sizeof(Bins)); - } - bool free(void * ptr) { - for (size_t n = 0; n < NUM_BINS; ++n) { - if (ptr == Bins[n].data) { - Bins[n].Used = false; - --NoUsedBins; - // TRACE("\tBinAllocator<%d> free %lu ------", SIZE_SLOT, n); - return true; - } - } - return false; - } - bool is_member(void * ptr) { - return (ptr >= Bins[0].data && ptr <= Bins[NUM_BINS-1].data); - } - void * malloc(size_t size) { - if (size > SIZE_SLOT) { - // TRACE("BinAllocator<%d> malloc [%lu] size > SIZE_SLOT", SIZE_SLOT, size); - return nullptr; - } - if (NoUsedBins >= NUM_BINS) { - // TRACE("BinAllocator<%d> malloc [%lu] no free slots", SIZE_SLOT, size); - return nullptr; - } - for (size_t n = 0; n < NUM_BINS; ++n) { - if (!Bins[n].Used) { - Bins[n].Used = true; - ++NoUsedBins; - // TRACE("\tBinAllocator<%d> malloc %lu[%lu]", SIZE_SLOT, n, size); - return Bins[n].data; - } - } - // TRACE("BinAllocator<%d> malloc [%lu] no free slots", SIZE_SLOT , size); - return nullptr; - } - size_t size(void * ptr) { - return is_member(ptr) ? SIZE_SLOT : 0; - } - bool can_fit(void * ptr, size_t size) { - return is_member(ptr) && size <= SIZE_SLOT; //todo is_member check is redundant - } - unsigned int capacity() { return NUM_BINS; } - unsigned int size() { return NoUsedBins; } -}; - -#if defined(SIMU) -typedef BinAllocator<39,300> BinAllocator_slots1; -typedef BinAllocator<79,100> BinAllocator_slots2; -#else -typedef BinAllocator<27,200> BinAllocator_slots1; -typedef BinAllocator<91,50> BinAllocator_slots2; -#endif +#include #if defined(USE_BIN_ALLOCATOR) -extern BinAllocator_slots1 slots1; -extern BinAllocator_slots2 slots2; - // wrapper for our BinAllocator for Lua void *bin_l_alloc (void *ud, void *ptr, size_t osize, size_t nsize); #endif //#if defined(USE_BIN_ALLOCATOR) diff --git a/radio/src/edgetx.cpp b/radio/src/edgetx.cpp index cb07a0f45..c461430c4 100644 --- a/radio/src/edgetx.cpp +++ b/radio/src/edgetx.cpp @@ -1881,8 +1881,13 @@ uint32_t availableMemory() struct mallinfo info = mallinfo(); +#if defined(USE_BIN_ALLOCATOR) + extern int bin_avail(); + return ((uint32_t)((unsigned char *)&_heap_end - heap)) + info.fordblks + bin_avail(); +#else return ((uint32_t)((unsigned char *)&_heap_end - heap)) + info.fordblks; #endif +#endif } #define FEATURE_ENABLED(f) (g_model.f == OVERRIDE_GLOBAL && g_eeGeneral.f == 0) || (g_model.f == OVERRIDE_ON)