better control for number of finalizers called at each GC cycle

(increases progressively)
This commit is contained in:
Roberto Ierusalimschy 2014-02-13 12:46:38 -02:00
parent 733c58595b
commit de3b1c9b53
4 changed files with 57 additions and 36 deletions

72
lgc.c
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.c,v 2.170 2014/02/11 12:28:47 roberto Exp roberto $ ** $Id: lgc.c,v 2.171 2014/02/13 12:11:34 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -33,8 +33,8 @@
/* maximum number of elements to sweep in each single step */ /* maximum number of elements to sweep in each single step */
#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4)) #define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))
/* maximum number of finalizers to call in each GC step */ /* cost of calling one finalizer */
#define GCFINALIZENUM 4 #define GCFINALIZECOST GCSWEEPCOST
/* /*
@ -960,6 +960,7 @@ static l_mem atomic (lua_State *L) {
origweak = g->weak; origall = g->allweak; origweak = g->weak; origall = g->allweak;
work += g->GCmemtrav; /* stop counting (objects being finalized) */ work += g->GCmemtrav; /* stop counting (objects being finalized) */
separatetobefnz(g, 0); /* separate objects to be finalized */ separatetobefnz(g, 0); /* separate objects to be finalized */
g->gcfinnum = 1; /* there may be objects to be finalized */
markbeingfnz(g); /* mark objects that will be finalized */ markbeingfnz(g); /* mark objects that will be finalized */
propagateall(g); /* remark, to propagate 'resurrection' */ propagateall(g); /* remark, to propagate 'resurrection' */
work -= g->GCmemtrav; /* restart counting */ work -= g->GCmemtrav; /* restart counting */
@ -1014,7 +1015,7 @@ static lu_mem singlestep (lua_State *L) {
int sw; int sw;
propagateall(g); /* make sure gray list is empty */ propagateall(g); /* make sure gray list is empty */
g->GCestimate = g->GCmemtrav; /* save what was counted */; g->GCestimate = g->GCmemtrav; /* save what was counted */;
work = atomic(L); /* add what was traversed by 'atomic' */ work = atomic(L); /* work is what was traversed by 'atomic' */
g->GCestimate += work; /* estimate of total memory traversed */ g->GCestimate += work; /* estimate of total memory traversed */
sw = entersweep(L); sw = entersweep(L);
return work + sw * GCSWEEPCOST; return work + sw * GCSWEEPCOST;
@ -1034,8 +1035,13 @@ static lu_mem singlestep (lua_State *L) {
case GCSswpend: { /* finish sweeps */ case GCSswpend: { /* finish sweeps */
makewhite(g, obj2gco(g->mainthread)); /* sweep main thread */ makewhite(g, obj2gco(g->mainthread)); /* sweep main thread */
checkSizes(L, g); checkSizes(L, g);
g->gcstate = GCScallfin;
return 0;
}
case GCScallfin: { /* state to finish calling finalizers */
/* do nothing here; should be handled by 'luaC_forcestep' */
g->gcstate = GCSpause; /* finish collection */ g->gcstate = GCSpause; /* finish collection */
return GCSWEEPCOST; return 0;
} }
default: lua_assert(0); return 0; default: lua_assert(0); return 0;
} }
@ -1053,24 +1059,18 @@ void luaC_runtilstate (lua_State *L, int statesmask) {
} }
static void incstep (lua_State *L) { /*
** run a few finalizers
*/
static int dosomefinalization (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
l_mem debt = g->GCdebt; unsigned int i;
int stepmul = g->gcstepmul; lua_assert(!g->tobefnz || g->gcfinnum > 0);
if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values (and 0) */ for (i = 0; g->tobefnz && i < g->gcfinnum; i++)
/* convert debt from Kb to 'work units' (avoid zero debt and overflows) */ GCTM(L, 1); /* call one finalizer */
debt = (debt / STEPMULADJ) + 1; g->gcfinnum = (!g->tobefnz) ? 0 /* nothing more to finalize? */
debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM; : g->gcfinnum * 2; /* else call a few more next time */
do { /* always perform at least one single step */ return i;
lu_mem work = singlestep(L); /* do some work */
debt -= work;
} while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
if (g->gcstate == GCSpause)
setpause(g, g->GCestimate); /* pause until next cycle */
else {
debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */
luaE_setdebt(g, debt);
}
} }
@ -1079,11 +1079,29 @@ static void incstep (lua_State *L) {
*/ */
void luaC_forcestep (lua_State *L) { void luaC_forcestep (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
int i; l_mem debt = g->GCdebt;
incstep(L); int stepmul = g->gcstepmul;
/* run a few finalizers (or all of them at the end of a collect cycle) */ if (stepmul < 40) stepmul = 40; /* avoid ridiculous low values (and 0) */
for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++) /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */
GCTM(L, 1); /* call one finalizer */ debt = (debt / STEPMULADJ) + 1;
debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
do {
if (g->gcstate == GCScallfin && g->tobefnz) {
unsigned int n = dosomefinalization(L);
debt -= (n * GCFINALIZECOST);
}
else { /* perform one single step */
lu_mem work = singlestep(L);
debt -= work;
}
} while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
if (g->gcstate == GCSpause)
setpause(g, g->GCestimate); /* pause until next cycle */
else {
debt = (debt / stepmul) * STEPMULADJ; /* convert 'work units' to Kb */
luaE_setdebt(g, debt);
dosomefinalization(L);
}
} }

5
lgc.h
View File

@ -1,5 +1,5 @@
/* /*
** $Id: lgc.h,v 2.77 2014/02/11 12:18:12 roberto Exp roberto $ ** $Id: lgc.h,v 2.78 2014/02/13 12:11:34 roberto Exp roberto $
** Garbage Collector ** Garbage Collector
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -43,7 +43,8 @@
#define GCSswpfinobj 4 #define GCSswpfinobj 4
#define GCSswptobefnz 5 #define GCSswptobefnz 5
#define GCSswpend 6 #define GCSswpend 6
#define GCSpause 7 #define GCScallfin 7
#define GCSpause 8
#define issweepphase(g) \ #define issweepphase(g) \

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lstate.c,v 2.117 2014/02/11 12:18:12 roberto Exp roberto $ ** $Id: lstate.c,v 2.118 2014/02/13 12:11:34 roberto Exp roberto $
** Global State ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -214,10 +214,10 @@ static void f_luaopen (lua_State *L, void *ud) {
/* /*
** preinitialize a state with consistent values without allocating ** preinitialize a thread with consistent values without allocating
** any memory (to avoid errors) ** any memory (to avoid errors)
*/ */
static void preinit_state (lua_State *L, global_State *g) { static void preinit_thread (lua_State *L, global_State *g) {
G(L) = g; G(L) = g;
L->stack = NULL; L->stack = NULL;
L->ci = NULL; L->ci = NULL;
@ -264,7 +264,7 @@ LUA_API lua_State *lua_newthread (lua_State *L) {
g->mainthread->next = obj2gco(L1); g->mainthread->next = obj2gco(L1);
setthvalue(L, L->top, L1); setthvalue(L, L->top, L1);
api_incr_top(L); api_incr_top(L);
preinit_state(L1, g); preinit_thread(L1, g);
L1->hookmask = L->hookmask; L1->hookmask = L->hookmask;
L1->basehookcount = L->basehookcount; L1->basehookcount = L->basehookcount;
L1->hook = L->hook; L1->hook = L->hook;
@ -298,8 +298,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
L->tt = LUA_TTHREAD; L->tt = LUA_TTHREAD;
g->currentwhite = bitmask(WHITE0BIT); g->currentwhite = bitmask(WHITE0BIT);
L->marked = luaC_white(g); L->marked = luaC_white(g);
g->gckind = KGC_NORMAL; preinit_thread(L, g);
preinit_state(L, g);
g->frealloc = f; g->frealloc = f;
g->ud = ud; g->ud = ud;
g->mainthread = L; g->mainthread = L;
@ -313,12 +312,14 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
g->panic = NULL; g->panic = NULL;
g->version = NULL; g->version = NULL;
g->gcstate = GCSpause; g->gcstate = GCSpause;
g->gckind = KGC_NORMAL;
g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL; g->allgc = g->finobj = g->tobefnz = g->fixedgc = NULL;
g->sweepgc = NULL; g->sweepgc = NULL;
g->gray = g->grayagain = NULL; g->gray = g->grayagain = NULL;
g->weak = g->ephemeron = g->allweak = NULL; g->weak = g->ephemeron = g->allweak = NULL;
g->totalbytes = sizeof(LG); g->totalbytes = sizeof(LG);
g->GCdebt = 0; g->GCdebt = 0;
g->gcfinnum = 0;
g->gcpause = LUAI_GCPAUSE; g->gcpause = LUAI_GCPAUSE;
g->gcstepmul = LUAI_GCMUL; g->gcstepmul = LUAI_GCMUL;
for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL; for (i=0; i < LUA_NUMTAGS; i++) g->mt[i] = NULL;

View File

@ -1,5 +1,5 @@
/* /*
** $Id: lstate.h,v 2.98 2014/02/11 12:18:12 roberto Exp roberto $ ** $Id: lstate.h,v 2.99 2014/02/13 12:11:34 roberto Exp roberto $
** Global State ** Global State
** See Copyright Notice in lua.h ** See Copyright Notice in lua.h
*/ */
@ -125,6 +125,7 @@ typedef struct global_State {
GCObject *tobefnz; /* list of userdata to be GC */ GCObject *tobefnz; /* list of userdata to be GC */
GCObject *fixedgc; /* list of objects not to be collected */ GCObject *fixedgc; /* list of objects not to be collected */
Mbuffer buff; /* temporary buffer for string concatenation */ Mbuffer buff; /* temporary buffer for string concatenation */
unsigned int gcfinnum; /* number of finalizers to call in each GC step */
int gcpause; /* size of pause between successive GCs */ int gcpause; /* size of pause between successive GCs */
int gcstepmul; /* GC `granularity' */ int gcstepmul; /* GC `granularity' */
lua_CFunction panic; /* to be called in unprotected errors */ lua_CFunction panic; /* to be called in unprotected errors */