From 50955e27f592441a223c6267956e470f98eeb3c0 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Fri, 23 Aug 2013 10:34:54 -0300 Subject: [PATCH] C functions and strings now go to the local list; first version of the local collector --- lfunc.c | 5 +-- lgc.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++----- lgc.h | 3 +- lstate.c | 4 ++- lstate.h | 4 ++- lstring.c | 4 +-- 6 files changed, 107 insertions(+), 15 deletions(-) diff --git a/lfunc.c b/lfunc.c index cb0b4ef6..d1185ec6 100644 --- a/lfunc.c +++ b/lfunc.c @@ -1,5 +1,5 @@ /* -** $Id: lfunc.c,v 2.32 2013/08/07 12:18:11 roberto Exp roberto $ +** $Id: lfunc.c,v 2.33 2013/08/16 18:55:49 roberto Exp roberto $ ** Auxiliary functions to manipulate prototypes and closures ** See Copyright Notice in lua.h */ @@ -21,7 +21,8 @@ Closure *luaF_newCclosure (lua_State *L, int n) { - Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl; + Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), + &G(L)->localgc, 0)->cl; c->c.nupvalues = cast_byte(n); return c; } diff --git a/lgc.c b/lgc.c index fddc43cf..c261bd73 100644 --- a/lgc.c +++ b/lgc.c @@ -1,5 +1,5 @@ /* -** $Id: lgc.c,v 2.149 2013/08/21 19:21:16 roberto Exp roberto $ +** $Id: lgc.c,v 2.150 2013/08/21 20:09:51 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -24,6 +24,12 @@ +/* +** How memory to allocate before a new local collection +*/ +#define GCLOCALPAUSE 8000 + + /* ** cost of sweeping one element (the size of a small object divided ** by some adjust for the sweep speed) @@ -191,9 +197,9 @@ void luaC_checkupvalcolor (global_State *g, UpVal *uv) { void luaC_fix (lua_State *L, GCObject *o) { global_State *g = G(L); - lua_assert(g->allgc == o); + lua_assert(g->localgc == o); white2gray(o); - g->allgc = o->gch.next; /* remove object from 'allgc' list */ + g->localgc = o->gch.next; /* remove object from 'localgc' list */ o->gch.next = g->fixedgc; /* link it to 'fixedgc' list */ g->fixedgc = o; } @@ -873,6 +879,72 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { /* }====================================================== */ +/* +** {====================================================== +** Local Collection +** ======================================================= +*/ + +/* +** Traverse a thread, local marking all its collectable objects +*/ +static void localmarkthread (lua_State *l) { + StkId o = l->stack; + if (o == NULL) + return; /* stack not completely built yet */ + for (; o < l->top; o++) { /* mark live elements in the stack */ + if (iscollectable(o)) + l_setbit(gcvalue(o)->gch.marked, LOCALBLACK); + } +} + + +/* +** Mark all that is locally accessible (accessible directly from +** a thread) +*/ +static void localmark (global_State *g) { + GCObject *thread = hvalue(&g->l_registry)->next; + for (; thread != NULL; thread = gch(thread)->next) /* traverse all threads */ + localmarkthread(gco2th(thread)); + localmarkthread(g->mainthread); +} + + +static void localsweep (lua_State *L, global_State *g) { + GCObject **p = &g->localgc; + while (*p != NULL) { + GCObject *curr = *p; + if (!islocal(curr)) { /* is 'curr' no more local? */ + *p = curr->gch.next; /* remove 'curr' from list */ + curr->gch.next = g->allgc; /* link 'curr' in 'allgc' list */ + g->allgc = curr; + } + else { /* still local */ + if (testbit(curr->gch.marked, LOCALBLACK)) { /* locally alive? */ + resetbit(curr->gch.marked, LOCALBLACK); + p = &curr->gch.next; /* go to next element */ + } + else { /* object is dead */ + *p = curr->gch.next; /* remove 'curr' from list */ + freeobj(L, curr); /* erase 'curr' */ + } + } + } +} + + +static void luaC_localcollection (lua_State *L) { + global_State *g = G(L); + lua_assert(g->gcstate == GCSpause); + localmark(g); + localsweep(L, g); +} + +/* }====================================================== */ + + + /* ** {====================================================== ** GC control @@ -885,13 +957,13 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { ** cycle will start when memory use hits threshold */ static void setpause (global_State *g, l_mem estimate) { - l_mem debt, threshold; + l_mem threshold; estimate = estimate / PAUSEADJ; /* adjust 'estimate' */ threshold = (g->gcpause < MAX_LMEM / estimate) /* overflow? */ ? estimate * g->gcpause /* no overflow */ : MAX_LMEM; /* overflow; truncate to maximum */ - debt = -cast(l_mem, threshold - gettotalbytes(g)); - luaE_setdebt(g, debt); + g->GCthreshold = threshold; + luaE_setdebt(g, -GCLOCALPAUSE); } @@ -936,6 +1008,7 @@ void luaC_freeallobjects (lua_State *L) { g->currentwhite = WHITEBITS; /* this "white" makes all objects look dead */ g->gckind = KGC_NORMAL; sweepwholelist(L, &g->finobj); /* finalizers can create objs. in 'finobj' */ + sweepwholelist(L, &g->localgc); sweepwholelist(L, &g->allgc); sweepwholelist(L, &g->fixedgc); /* collect fixed objects */ lua_assert(g->strt.nuse == 0); @@ -1017,8 +1090,9 @@ static lu_mem singlestep (lua_State *L) { return GCSWEEPMAX*GCSWEEPCOST; } else { + sweepwholelist(L, &g->localgc); g->gcstate = GCSsweep; - return 0; + return GCLOCALPAUSE / 4; /* some magic for now */ } } case GCSsweep: { @@ -1090,7 +1164,19 @@ void luaC_forcestep (lua_State *L) { */ void luaC_step (lua_State *L) { global_State *g = G(L); - if (g->gcrunning) luaC_forcestep(L); + if (g->gcrunning) { + if (g->gcstate != GCSpause) { + luaC_forcestep(L); + } + else { + luaC_localcollection(L); + if (gettotalbytes(g) > g->GCthreshold) { + luaC_forcestep(L); /* restart collection */ + } + else + luaE_setdebt(g, -GCLOCALPAUSE); + } + } else luaE_setdebt(g, -GCSTEPSIZE); /* avoid being called too often */ } diff --git a/lgc.h b/lgc.h index ccaaeab3..b931ae1a 100644 --- a/lgc.h +++ b/lgc.h @@ -1,5 +1,5 @@ /* -** $Id: lgc.h,v 2.64 2013/08/21 19:21:16 roberto Exp roberto $ +** $Id: lgc.h,v 2.65 2013/08/21 20:09:51 roberto Exp roberto $ ** Garbage Collector ** See Copyright Notice in lua.h */ @@ -77,6 +77,7 @@ #define BLACKBIT 2 /* object is black */ #define FINALIZEDBIT 3 /* object has been marked for finalization */ #define LOCALBIT 4 /* object is not local */ +#define LOCALBLACK 5 /* object is 'locally black' */ /* bit 7 is currently used by tests (luaL_checkmemory) */ #define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT) diff --git a/lstate.c b/lstate.c index c8fc27c5..30fbc27c 100644 --- a/lstate.c +++ b/lstate.c @@ -1,5 +1,5 @@ /* -** $Id: lstate.c,v 2.103 2013/08/21 19:21:16 roberto Exp roberto $ +** $Id: lstate.c,v 2.104 2013/08/21 20:09:51 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -280,6 +280,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->seed = makeseed(L); g->gcrunning = 0; /* no GC while building state */ g->GCestimate = 0; + g->GCthreshold = 10000; g->strt.size = g->strt.nuse = g->strt.empty = 0; g->strt.hash = NULL; setnilvalue(&g->l_registry); @@ -288,6 +289,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) { g->version = lua_version(NULL); g->gcstate = GCSpause; g->allgc = NULL; + g->localgc = NULL; g->finobj = NULL; g->tobefnz = NULL; g->fixedgc = NULL; diff --git a/lstate.h b/lstate.h index 2c89aad6..9c0434b9 100644 --- a/lstate.h +++ b/lstate.h @@ -1,5 +1,5 @@ /* -** $Id: lstate.h,v 2.87 2013/08/21 20:09:51 roberto Exp roberto $ +** $Id: lstate.h,v 2.88 2013/08/22 15:21:48 roberto Exp roberto $ ** Global State ** See Copyright Notice in lua.h */ @@ -118,6 +118,7 @@ typedef struct global_State { l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ lu_mem GCmemtrav; /* memory traversed by the GC */ lu_mem GCestimate; /* an estimate of the non-garbage memory in use */ + lu_mem GCthreshold; /* threshold to start a new GC cycle */ stringtable strt; /* hash table for strings */ TValue l_registry; unsigned int seed; /* randomized seed for hashes */ @@ -126,6 +127,7 @@ typedef struct global_State { lu_byte gckind; /* kind of GC running */ lu_byte gcrunning; /* true if GC is running */ GCObject *allgc; /* list of all collectable objects */ + GCObject *localgc; /* list of local objects */ GCObject *finobj; /* list of collectable objects with finalizers */ GCObject **sweepgc; /* current position of sweep in list 'allgc' */ GCObject **sweepfin; /* current position of sweep in list 'finobj' */ diff --git a/lstring.c b/lstring.c index e53c6375..6d1ce978 100644 --- a/lstring.c +++ b/lstring.c @@ -1,5 +1,5 @@ /* -** $Id: lstring.c,v 2.29 2013/08/21 19:21:16 roberto Exp roberto $ +** $Id: lstring.c,v 2.30 2013/08/22 15:21:48 roberto Exp roberto $ ** String table (keeps all strings handled by Lua) ** See Copyright Notice in lua.h */ @@ -106,7 +106,7 @@ static TString *createstrobj (lua_State *L, const char *str, size_t l, TString *ts; size_t totalsize; /* total size of TString object */ totalsize = sizeof(TString) + ((l + 1) * sizeof(char)); - ts = &luaC_newobj(L, tag, totalsize, NULL, 0)->ts; + ts = &luaC_newobj(L, tag, totalsize, &G(L)->localgc, 0)->ts; ts->tsv.len = l; ts->tsv.hash = h; ts->tsv.extra = 0;