feat(bw): make more RAM available to Lua scripts on some radios (#5717)
This commit is contained in:
+141
-35
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user