Browse Source

better control for number of finalizers called at each GC cycle
(increases progressively)

Roberto Ierusalimschy 11 years ago
parent
commit
de3b1c9b53
4 changed files with 52 additions and 31 deletions
  1. 40 22
      lgc.c
  2. 3 2
      lgc.h
  3. 7 6
      lstate.c
  4. 2 1
      lstate.h

+ 40 - 22
lgc.c

@@ -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 */
-#define GCFINALIZENUM	4
+/* cost of calling one finalizer */
+#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,7 +1059,25 @@ 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);
+  unsigned int i;
+  lua_assert(!g->tobefnz || g->gcfinnum > 0);
+  for (i = 0; g->tobefnz && i < g->gcfinnum; i++)
+    GCTM(L, 1);  /* call one finalizer */
+  g->gcfinnum = (!g->tobefnz) ? 0  /* nothing more to finalize? */
+                    : g->gcfinnum * 2;  /* else call a few more next time */
+  return i;
+}
+
+
+/*
+** performs a basic GC step
+*/
+void luaC_forcestep (lua_State *L) {
   global_State *g = G(L);
   global_State *g = G(L);
   l_mem debt = g->GCdebt;
   l_mem debt = g->GCdebt;
   int stepmul = g->gcstepmul;
   int stepmul = g->gcstepmul;
@@ -1061,32 +1085,26 @@ static void incstep (lua_State *L) {
   /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */
   /* convert debt from Kb to 'work units' (avoid zero debt and overflows) */
   debt = (debt / STEPMULADJ) + 1;
   debt = (debt / STEPMULADJ) + 1;
   debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
   debt = (debt < MAX_LMEM / stepmul) ? debt * stepmul : MAX_LMEM;
-  do {  /* always perform at least one single step */
-    lu_mem work = singlestep(L);  /* do some work */
-    debt -= work;
+  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);
   } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
   if (g->gcstate == GCSpause)
   if (g->gcstate == GCSpause)
     setpause(g, g->GCestimate);  /* pause until next cycle */
     setpause(g, g->GCestimate);  /* pause until next cycle */
   else {
   else {
     debt = (debt / stepmul) * STEPMULADJ;  /* convert 'work units' to Kb */
     debt = (debt / stepmul) * STEPMULADJ;  /* convert 'work units' to Kb */
     luaE_setdebt(g, debt);
     luaE_setdebt(g, debt);
+    dosomefinalization(L);
   }
   }
 }
 }
 
 
 
 
-/*
-** performs a basic GC step
-*/
-void luaC_forcestep (lua_State *L) {
-  global_State *g = G(L);
-  int i;
-  incstep(L);
-  /* run a few finalizers (or all of them at the end of a collect cycle) */
-  for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++)
-    GCTM(L, 1);  /* call one finalizer */
-}
-
-
 /*
 /*
 ** performs a basic GC step when collector is running
 ** performs a basic GC step when collector is running
 */
 */

+ 3 - 2
lgc.h

@@ -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)  \

+ 7 - 6
lstate.c

@@ -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_state(L, g);
+  preinit_thread(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;

+ 2 - 1
lstate.h

@@ -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 */