feat(f4): more free memory on handsets with CCM RAM (#5804)
Alternative Lua memory allocator for radios with CCM RAM - primarily GX12 at present
This commit is contained in:
@@ -531,8 +531,8 @@ if(SDRAM)
|
||||
message("Target has SDRAM, do not use BIN_ALLOCATOR")
|
||||
else()
|
||||
# Nano's malloc does work well with lua, use our own
|
||||
add_definitions(-DUSE_BIN_ALLOCATOR)
|
||||
set(SRC ${SRC} bin_allocator.cpp)
|
||||
add_definitions(-DUSE_CUSTOM_ALLOCATOR)
|
||||
set(SRC ${SRC} lua/custom_allocator.cpp)
|
||||
endif()
|
||||
|
||||
# Bootloader
|
||||
|
||||
@@ -3,6 +3,9 @@ PROVIDE(_heap_start = _eram);
|
||||
|
||||
INCLUDE section_ccm.ld
|
||||
|
||||
PROVIDE(_ccm_heap_start = _eccm);
|
||||
PROVIDE(_ccm_heap_end = _main_stack_start);
|
||||
|
||||
/* Reserve heap space in RAM */
|
||||
._user_heap(NOLOAD) :
|
||||
{
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
|
||||
#if defined(LUA)
|
||||
#include "lua/lua_states.h"
|
||||
#include "lua/custom_allocator.h"
|
||||
#endif
|
||||
|
||||
RadioData g_eeGeneral;
|
||||
@@ -1891,9 +1892,8 @@ 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();
|
||||
#if defined(USE_CUSTOM_ALLOCATOR)
|
||||
return ((uint32_t)((unsigned char *)&_heap_end - heap)) + info.fordblks + custom_avail();
|
||||
#else
|
||||
return ((uint32_t)((unsigned char *)&_heap_end - heap)) + info.fordblks;
|
||||
#endif
|
||||
|
||||
@@ -51,8 +51,8 @@ static void luaStandaloneInit()
|
||||
{
|
||||
luaClose(&lsStandalone);
|
||||
|
||||
#if defined(USE_BIN_ALLOCATOR)
|
||||
lsStandalone = lua_newstate(bin_l_alloc, nullptr); //we use our own allocator!
|
||||
#if defined(USE_CUSTOM_ALLOCATOR)
|
||||
lsStandalone = lua_newstate(custom_l_alloc, nullptr); //we use our own allocator!
|
||||
#elif defined(LUA_ALLOCATOR_TRACER)
|
||||
memclear(&lsStandaloneTrace, sizeof(lsStandaloneTrace));
|
||||
lsStandaloneTrace.script = "lua_newstate(scripts)";
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "bin_allocator.h"
|
||||
#include <stddef.h>
|
||||
#include "edgetx.h"
|
||||
|
||||
template <int SIZE_SLOT, int NUM_BINS>
|
||||
@@ -94,14 +94,6 @@ class BinAllocator
|
||||
#if defined(SIMU)
|
||||
typedef BinAllocator<40,300> BinAllocator_slots1;
|
||||
typedef BinAllocator<80,100> BinAllocator_slots2;
|
||||
#elif defined(STM32F4)
|
||||
#if defined(DEBUG)
|
||||
typedef BinAllocator<28,395> BinAllocator_slots1;
|
||||
typedef BinAllocator<92,85> BinAllocator_slots2;
|
||||
#else
|
||||
typedef BinAllocator<28,415> BinAllocator_slots1;
|
||||
typedef BinAllocator<92,98> BinAllocator_slots2;
|
||||
#endif
|
||||
#else
|
||||
typedef BinAllocator<28,200> BinAllocator_slots1;
|
||||
typedef BinAllocator<92,50> BinAllocator_slots2;
|
||||
@@ -118,7 +110,7 @@ int missedAlloc = 0;
|
||||
int missedFree = 0;
|
||||
#endif
|
||||
|
||||
int bin_avail()
|
||||
int custom_avail()
|
||||
{
|
||||
return slots1.avail() + slots2.avail();
|
||||
}
|
||||
@@ -188,7 +180,7 @@ static void * bin_realloc(void * ptr, size_t size)
|
||||
}
|
||||
}
|
||||
|
||||
void *bin_l_alloc (void *ud, void *ptr, size_t osize, size_t nsize)
|
||||
void *custom_l_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
|
||||
{
|
||||
// (void)ud; (void)osize; /* not used */
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "edgetx.h"
|
||||
|
||||
/*
|
||||
Custom memory allocator for Lua that adds all available CCM RAM to the memory pool
|
||||
- maintains a free list of available CCM RAM, order by address
|
||||
- allocates from the smallest available free block
|
||||
- coalesces adjacent blocks on free
|
||||
*/
|
||||
|
||||
typedef struct _memblk {
|
||||
int size; // actual size of block. Available / allocated size = 'size' - sizeof(int)
|
||||
struct _memblk* next;
|
||||
} memblk;
|
||||
|
||||
#define MIN_SIZE 12 // Minimum size for free block (4 for 'size' field, 8 for data)
|
||||
|
||||
// CCM RAM available region
|
||||
extern memblk _ccm_heap_start;
|
||||
extern int _ccm_heap_end;
|
||||
|
||||
// Init flag
|
||||
static bool started = false;
|
||||
|
||||
// Free list
|
||||
static memblk* ccm_list = nullptr;
|
||||
|
||||
// CCM region for checking if blocks belong here
|
||||
static unsigned char* ccm_start;
|
||||
static unsigned char* ccm_end;
|
||||
|
||||
// Initialise free list
|
||||
static void init()
|
||||
{
|
||||
if (!started) {
|
||||
started = true;
|
||||
|
||||
ccm_start = (unsigned char*)&_ccm_heap_start;
|
||||
ccm_end = (unsigned char*)&_ccm_heap_end;
|
||||
|
||||
ccm_list = &_ccm_heap_start;
|
||||
ccm_list->next = nullptr;
|
||||
ccm_list->size = ccm_end - ccm_start;
|
||||
}
|
||||
}
|
||||
|
||||
// Return free memory available
|
||||
uint32_t custom_avail()
|
||||
{
|
||||
uint32_t free = 0;
|
||||
for (memblk* b = ccm_list; b; b = b->next) {
|
||||
free += (b->size - sizeof(int));
|
||||
}
|
||||
return free;
|
||||
}
|
||||
|
||||
// Free memory block
|
||||
static void ccm_free(void* ptr)
|
||||
{
|
||||
// Check that block belongs in CCM RAM
|
||||
if (ptr >= ccm_start && ptr < ccm_end) {
|
||||
memblk* prev = nullptr;
|
||||
memblk* next = ccm_list;
|
||||
memblk* p = (memblk*)(((unsigned char*)ptr) - sizeof(int));
|
||||
// Find place in list
|
||||
while (next && (p > next)) {
|
||||
prev = next;
|
||||
next = next->next;
|
||||
}
|
||||
// Link into list
|
||||
p->next = next;
|
||||
if (prev == nullptr) {
|
||||
ccm_list = p;
|
||||
} else {
|
||||
prev->next = p;
|
||||
if ((((unsigned char*)prev) + prev->size) == (unsigned char*)p) {
|
||||
// Merge adjacent
|
||||
prev->next = p->next;
|
||||
prev->size += p->size;
|
||||
p = prev;
|
||||
}
|
||||
}
|
||||
if ((((unsigned char*)p) + p->size) == (unsigned char*)next) {
|
||||
// Merge adjacent
|
||||
p->next = next->next;
|
||||
p->size += next->size;
|
||||
}
|
||||
} else {
|
||||
// Not CCM RAM - let system handle it.
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate new block
|
||||
static void* ccm_malloc(size_t nsize)
|
||||
{
|
||||
// Add space for 'size' field and align to 32 bit size
|
||||
int asize = (nsize + sizeof(int) + 3) & 0xFFFFFFFC;
|
||||
|
||||
memblk* prev = nullptr;
|
||||
memblk* next = ccm_list;
|
||||
memblk* p = nullptr;
|
||||
memblk* pprev = nullptr;
|
||||
// Find smallest block that will fit
|
||||
while (next) {
|
||||
if (next->size >= asize) {
|
||||
if (!p || (p && (p->size < next->size))) {
|
||||
pprev = prev;
|
||||
p = next;
|
||||
if (p->size == asize) break; // exact fit
|
||||
}
|
||||
}
|
||||
prev = next;
|
||||
next = next->next;
|
||||
}
|
||||
|
||||
void* res;
|
||||
|
||||
if (p) {
|
||||
if (p->size <= (asize + MIN_SIZE)) {
|
||||
// Using entire block - unlink it
|
||||
if (pprev)
|
||||
pprev->next = p->next;
|
||||
else
|
||||
ccm_list = p->next;
|
||||
} else {
|
||||
// reduce size of block and return end part
|
||||
p->size -= asize;
|
||||
p = (memblk*)(((unsigned char*)p) + p->size);
|
||||
p->size = asize;
|
||||
}
|
||||
res = ((unsigned char*)p) + sizeof(int);
|
||||
} else {
|
||||
// No space - let system handle it
|
||||
res = malloc(nsize);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Re-allocate existing block
|
||||
static void* ccm_realloc(void* ptr, size_t osize, size_t nsize)
|
||||
{
|
||||
// Add space for 'size' field and align to 32 bit size
|
||||
int asize = (nsize + sizeof(int) + 3) & 0xFFFFFFFC;
|
||||
|
||||
// Check that block belongs in CCM RAM
|
||||
if (ptr >= ccm_start && ptr < ccm_end) {
|
||||
memblk* p = (memblk*)(((unsigned char*)ptr) - sizeof(int));
|
||||
if (asize <= p->size)
|
||||
return ptr; // fits in already allocated space
|
||||
|
||||
void* np = ccm_malloc(nsize);
|
||||
memcpy(np, ptr, osize);
|
||||
ccm_free(ptr);
|
||||
return np;
|
||||
} else {
|
||||
// In theory nsize might fit in available CCM RAM; but since block is
|
||||
// already in normal RAM we just let system handle it.
|
||||
return realloc(ptr, nsize);
|
||||
}
|
||||
}
|
||||
|
||||
void* custom_l_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
|
||||
{
|
||||
(void)ud; /* not used */
|
||||
|
||||
init();
|
||||
|
||||
if (nsize == 0) {
|
||||
if (ptr) { // avoid a bunch of NULL pointer free calls
|
||||
ccm_free(ptr);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
else if (ptr) {
|
||||
return ccm_realloc(ptr, osize, nsize);
|
||||
} else {
|
||||
return ccm_malloc(nsize);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) EdgeTX
|
||||
*
|
||||
* Based on code named
|
||||
* opentx - https://github.com/opentx/opentx
|
||||
* th9x - http://code.google.com/p/th9x
|
||||
* er9x - http://code.google.com/p/er9x
|
||||
* gruvin9x - http://code.google.com/p/gruvin9x
|
||||
*
|
||||
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#if defined(STM32F4)
|
||||
#include "ccm_allocator.cpp"
|
||||
#else
|
||||
#include "bin_allocator.cpp"
|
||||
#endif
|
||||
@@ -21,9 +21,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(USE_BIN_ALLOCATOR)
|
||||
// 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)
|
||||
#if defined(USE_CUSTOM_ALLOCATOR)
|
||||
// wrapper for our custom allocator for Lua
|
||||
void *custom_l_alloc(void *ud, void *ptr, size_t osize, size_t nsize);
|
||||
int custom_avail();
|
||||
#endif
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "edgetx.h"
|
||||
#include "bin_allocator.h"
|
||||
#include "custom_allocator.h"
|
||||
|
||||
#include "lua_api.h"
|
||||
#include "lua_event.h"
|
||||
@@ -1351,8 +1351,8 @@ void luaInit()
|
||||
L = nullptr;
|
||||
|
||||
if (luaState != INTERPRETER_PANIC) {
|
||||
#if defined(USE_BIN_ALLOCATOR)
|
||||
L = lua_newstate(bin_l_alloc, nullptr); //we use our own allocator!
|
||||
#if defined(USE_CUSTOM_ALLOCATOR)
|
||||
L = lua_newstate(custom_l_alloc, nullptr); //we use our own allocator!
|
||||
#elif defined(LUA_ALLOCATOR_TRACER)
|
||||
memclear(&lsScriptsTrace, sizeof(lsScriptsTrace));
|
||||
lsScriptsTrace.script = "lua_newstate(scripts)";
|
||||
|
||||
@@ -343,8 +343,8 @@ void luaInitThemesAndWidgets()
|
||||
{
|
||||
TRACE("luaInitThemesAndWidgets");
|
||||
|
||||
#if defined(USE_BIN_ALLOCATOR)
|
||||
lsWidgets = lua_newstate(bin_l_alloc, NULL); //we use our own allocator!
|
||||
#if defined(USE_CUSTOM_ALLOCATOR)
|
||||
lsWidgets = lua_newstate(custom_l_alloc, NULL); //we use our own allocator!
|
||||
#elif defined(LUA_ALLOCATOR_TRACER)
|
||||
memclear(&lsWidgetsTrace, sizeof(lsWidgetsTrace));
|
||||
lsWidgetsTrace.script = "lua_newstate(widgets)";
|
||||
|
||||
Reference in New Issue
Block a user