feat(bw): make more RAM available to Lua scripts on some radios (#5717)

This commit is contained in:
philmoz
2024-12-22 12:56:33 +10:00
committed by GitHub
parent e4ba477e34
commit fc642aaf48
3 changed files with 147 additions and 103 deletions
+141 -35
View File
@@ -19,35 +19,137 @@
* GNU General Public License for more details.
*/
#include <stdlib.h>
#include <string.h>
#include "edgetx.h"
#include "bin_allocator.h"
#include "edgetx.h"
template <int SIZE_SLOT, int NUM_BINS>
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;
}
+1 -68
View File
@@ -21,76 +21,9 @@
#pragma once
#include "debug.h"
template <int SIZE_SLOT, int NUM_BINS> 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 <stddef.h>
#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)
+5
View File
@@ -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)