Tie in the EGC with the SDK's heap knowledge. (#2319)

Added `node.egc.meminfo()` to expose LVM usage (to make the regular
`node.egc.ON_MEM_LIMIT` option usable).

Extended the `node.egc.ON_MEM_LIMIT` option to also take negative limits,
in which case that's taken as a request to keep a certain amount of heap
available for non-Lua use.
This commit is contained in:
Johny Mattsson 2018-04-06 22:52:03 +10:00 committed by Marcel Stör
parent 18f33f5ff1
commit 085f35da73
6 changed files with 39 additions and 6 deletions

View File

@ -14,6 +14,7 @@
#include C_HEADER_STRING
#ifndef LUA_CROSS_COMPILER
#include "vfs.h"
#include "user_interface.h"
#else
#endif
@ -791,6 +792,11 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
}
if (L != NULL && (mode & EGC_ALWAYS)) /* always collect memory if requested */
luaC_fullgc(L);
#ifndef LUA_CROSS_COMPILER
if (L != NULL && (mode & EGC_ON_MEM_LIMIT) && G(L)->memlimit < 0 &&
(system_get_free_heap_size() < (-G(L)->memlimit)))
luaC_fullgc(L);
#endif
if(nsize > osize && L != NULL) {
#if defined(LUA_STRESS_EMERGENCY_GC)
luaC_fullgc(L);

View File

@ -4,7 +4,7 @@
#include "lstate.h"
#include "c_types.h"
void legc_set_mode(lua_State *L, int mode, unsigned limit) {
void legc_set_mode(lua_State *L, int mode, int limit) {
global_State *g = G(L);
g->egcmode = mode;

View File

@ -11,7 +11,7 @@
#define EGC_ON_MEM_LIMIT 2 // run EGC when an upper memory limit is hit
#define EGC_ALWAYS 4 // always run EGC before an allocation
void legc_set_mode(lua_State *L, int mode, unsigned limit);
void legc_set_mode(lua_State *L, int mode, int limit);
#endif

View File

@ -82,7 +82,7 @@ typedef struct global_State {
Mbuffer buff; /* temporary buffer for string concatentation */
lu_mem GCthreshold;
lu_mem totalbytes; /* number of bytes currently allocated */
lu_mem memlimit; /* maximum number of bytes that can be allocated, 0 = no limit. */
l_mem memlimit; /* maximum number of bytes that can be allocated, 0 = no limit. <0 used with EGC_ON_MEM_LIMIT when free heap falls below -memlimit */
lu_mem estimate; /* an estimate of number of bytes actually in use */
lu_mem gcdept; /* how much GC is `behind schedule' */
int gcpause; /* size of pause between successive GCs */

View File

@ -462,14 +462,23 @@ static int node_stripdebug (lua_State *L) {
// See legc.h and lecg.c.
static int node_egc_setmode(lua_State* L) {
unsigned mode = luaL_checkinteger(L, 1);
unsigned limit = luaL_optinteger (L, 2, 0);
int limit = luaL_optinteger (L, 2, 0);
luaL_argcheck(L, mode <= (EGC_ON_ALLOC_FAILURE | EGC_ON_MEM_LIMIT | EGC_ALWAYS), 1, "invalid mode");
luaL_argcheck(L, !(mode & EGC_ON_MEM_LIMIT) || limit>0, 1, "limit must be non-zero");
luaL_argcheck(L, !(mode & EGC_ON_MEM_LIMIT) || limit!=0, 1, "limit must be non-zero");
legc_set_mode( L, mode, limit );
return 0;
}
// totalallocated, estimatedused = node.egc.meminfo()
static int node_egc_meminfo(lua_State *L) {
global_State *g = G(L);
lua_pushinteger(L, g->totalbytes);
lua_pushinteger(L, g->estimate);
return 2;
}
//
// Lua: osprint(true/false)
// Allows you to turn on the native Espressif SDK printing
@ -560,6 +569,7 @@ static int node_random (lua_State *L) {
// Module function map
static const LUA_REG_TYPE node_egc_map[] = {
{ LSTRKEY( "meminfo" ), LFUNCVAL( node_egc_meminfo ) },
{ LSTRKEY( "setmode" ), LFUNCVAL( node_egc_setmode ) },
{ LSTRKEY( "NOT_ACTIVE" ), LNUMVAL( EGC_NOT_ACTIVE ) },
{ LSTRKEY( "ON_ALLOC_FAILURE" ), LNUMVAL( EGC_ON_ALLOC_FAILURE ) },

View File

@ -484,7 +484,7 @@ provides more detailed information on the EGC.
- `mode`
- `node.egc.NOT_ACTIVE` EGC inactive, no collection cycle will be forced in low memory situations
- `node.egc.ON_ALLOC_FAILURE` Try to allocate a new block of memory, and run the garbage collector if the allocation fails. If the allocation fails even after running the garbage collector, the allocator will return with error.
- `node.egc.ON_MEM_LIMIT` Run the garbage collector when the memory used by the Lua script goes beyond an upper `limit`. If the upper limit can't be satisfied even after running the garbage collector, the allocator will return with error.
- `node.egc.ON_MEM_LIMIT` Run the garbage collector when the memory used by the Lua script goes beyond an upper `limit`. If the upper limit can't be satisfied even after running the garbage collector, the allocator will return with error. If the given limit is negative, it is interpreted as the desired amount of heap which should be left available. Whenever the free heap (as reported by `node.heap()` falls below the requested limit, the garbage collector will be run.
- `node.egc.ALWAYS` Run the garbage collector before each memory allocation. If the allocation fails even after running the garbage collector, the allocator will return with error. This mode is very efficient with regards to memory savings, but it's also the slowest.
- `level` in the case of `node.egc.ON_MEM_LIMIT`, this specifies the memory limit.
@ -495,6 +495,23 @@ provides more detailed information on the EGC.
`node.egc.setmode(node.egc.ALWAYS, 4096) -- This is the default setting at startup.`
`node.egc.setmode(node.egc.ON_ALLOC_FAILURE) -- This is the fastest activeEGC mode.`
`node.egc.setmode(node.egc.ON_MEM_LIMIT, 30720) -- Only allow the Lua runtime to allocate at most 30k, collect garbage if limit is about to be hit`
`node.egc.setmode(node.egc.ON_MEM_LIMIT, -6144) -- Try to keep at least 6k heap available for non-Lua use (e.g. network buffers)`
## node.egc.meminfo()
Returns memory usage information for the Lua runtime.
####Syntax
`total_allocated, estimated_used = node.egc.meminfo()`
#### Parameters
None.
#### Returns
- `total_allocated` The total number of bytes allocated by the Lua runtime. This is the number which is relevant when using the `node.egc.ON_MEM_LIMIT` option with positive limit values.
- `estimated_used` This value shows the estimated usage of the allocated memory.
# node.task module