Explorar el Código

better control for GC cycles

Roberto Ierusalimschy hace 21 años
padre
commit
0b06241483
Se han modificado 6 ficheros con 77 adiciones y 55 borrados
  1. 5 5
      lapi.c
  2. 51 33
      lgc.c
  3. 7 6
      lgc.h
  4. 2 3
      lmem.c
  5. 8 6
      lstate.c
  6. 4 2
      lstate.h

+ 5 - 5
lapi.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lapi.c,v 2.16 2004/08/12 17:02:51 roberto Exp roberto $
+** $Id: lapi.c,v 2.17 2004/08/17 17:45:45 roberto Exp roberto $
 ** Lua API
 ** See Copyright Notice in lua.h
 */
@@ -831,7 +831,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
       break;
     }
     case LUA_GCRESTART: {
-      g->GCthreshold = g->nblocks;
+      g->GCthreshold = g->totalbytes;
       break;
     }
     case LUA_GCCOLLECT: {
@@ -840,13 +840,13 @@ LUA_API int lua_gc (lua_State *L, int what, int data) {
     }
     case LUA_GCCOUNT: {
       /* GC values are expressed in Kbytes: #bytes/2^10 */
-      res = cast(int, g->nblocks >> 10);
+      res = cast(int, g->totalbytes >> 10);
       break;
     }
     case LUA_GCSTEP: {
       lu_mem a = (cast(lu_mem, data) << 10);
-      if (a <= g->nblocks)
-        g->GCthreshold = g->nblocks - a;
+      if (a <= g->totalbytes)
+        g->GCthreshold = g->totalbytes - a;
       else
         g->GCthreshold = 0;
       luaC_step(L);

+ 51 - 33
lgc.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.c,v 2.8 2004/08/10 19:17:23 roberto Exp roberto $
+** $Id: lgc.c,v 2.9 2004/08/24 20:12:06 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -23,13 +23,11 @@
 #include "ltm.h"
 
 
-#define GCSTEPSIZE	(40*sizeof(TValue))
+#define GCSTEPSIZE	1000
 #define STEPMUL		2
-#define GCSWEEPMAX	40
-#define GCSWEEPCOST	1
-#define GCFINALIZECOST	(10*sizeof(TValue))
-#define WAITNEXTCYCLE	(40 * GCSTEPSIZE)
-#define WAITNEXTCYCLEGN	(200 * GCSTEPSIZE)
+#define GCSWEEPMAX	10
+#define GCSWEEPCOST	30
+#define GCFINALIZECOST	100
 
 
 #define FIXEDMASK	bitmask(FIXEDBIT)
@@ -408,10 +406,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) {
   global_State *g = G(L);
   int whitebit = otherwhite(g);
   int deadmask = whitebit | FIXEDMASK;
-  while ((curr = *p) != NULL) {
+  int generational = g->gcgenerational;
+  while ((curr = *p) != NULL && count-- > 0) {
     if ((curr->gch.marked ^ whitebit) & deadmask) {
       lua_assert(!isdead(g, curr) || testbit(curr->gch.marked, FIXEDBIT));
-      if (!G(L)->gcgenerational || isdead(g, curr))
+      if (!generational || isdead(g, curr))
         makewhite(g, curr);
       if (curr->gch.tt == LUA_TTHREAD)
         sweepwholelist(L, &gco2th(curr)->openupval);
@@ -424,17 +423,11 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_int32 count) {
         g->rootgc = curr->gch.next;  /* adjust first */
       freeobj(L, curr);
     }
-    if (count-- == 0) break;
   }
   return p;
 }
 
 
-static void sweepstrings (lua_State *L) {
-  global_State *g = G(L);
-  sweepwholelist(L, &G(L)->strt.hash[g->sweepstrgc++]);
-}
-
 
 static void freelist (lua_State *L, GCObject **p) {
   while (*p) {
@@ -532,6 +525,7 @@ static void remarkupvals (global_State *g) {
 
 static void atomic (lua_State *L) {
   global_State *g = G(L);
+  int aux;
   lua_assert(g->gray == NULL);
   /* remark occasional upvalues of (maybe) dead threads */
   remarkupvals(g);
@@ -554,7 +548,11 @@ static void atomic (lua_State *L) {
   g->sweepstrgc = 0;
   g->sweepgc = &g->rootgc;
   g->gcstate = GCSsweepstring;
-  if (g->gcgenerational++ > 20) g->gcgenerational = 0;
+  aux = g->gcgenerational;
+  g->gcgenerational = (g->estimate <= 4*g->prevestimate/2);
+  if (!aux)  /* last collection was full? */
+    g->prevestimate = g->estimate;  /* keep estimate of last full collection */
+  g->estimate = g->totalbytes;  /* first estimate */
 }
 
 
@@ -562,6 +560,14 @@ static l_mem singlestep (lua_State *L) {
   global_State *g = G(L);
   /*lua_checkmemory(L);*/
   switch (g->gcstate) {
+    case GCSpause: {
+      /* start a new collection */
+      if (g->gcgenerational)
+        atomic(L);
+      else
+        markroot(L);
+      return 0;
+    }
     case GCSpropagate: {
       if (g->gray)
         return propagatemark(g);
@@ -571,33 +577,31 @@ static l_mem singlestep (lua_State *L) {
       }
     }
     case GCSsweepstring: {
-      sweepstrings(L);
+      lu_mem old = g->totalbytes;
+      sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);
       if (g->sweepstrgc >= g->strt.size)  /* nothing more to sweep? */
         g->gcstate = GCSsweep;  /* end sweep-string phase */
+      g->estimate -= old - g->totalbytes;
       return GCSWEEPCOST;
     }
     case GCSsweep: {
+      lu_mem old = g->totalbytes;
       g->sweepgc = sweeplist(L, g->sweepgc, GCSWEEPMAX);
       if (*g->sweepgc == NULL) {  /* nothing more to sweep? */
         checkSizes(L);
         g->gcstate = GCSfinalize;  /* end sweep phase */
       }
-      return GCSWEEPCOST;
+      g->estimate -= old - g->totalbytes;
+      return GCSWEEPMAX*GCSWEEPCOST;
     }
     case GCSfinalize: {
       if (g->tmudata) {
         GCTM(L);
         return GCFINALIZECOST;
       }
-      else {  /* no more `udata' to finalize */
-        if (g->gcgenerational) {
-          atomic(L);
-          return WAITNEXTCYCLEGN;
-        }
-        else {
-          markroot(L);  /* may restart collection */
-          return WAITNEXTCYCLE;
-        }
+      else {
+        g->gcstate = GCSpause;  /* end collection */
+        return 0;
       }
     }
     default: lua_assert(0); return 0;
@@ -607,18 +611,30 @@ static l_mem singlestep (lua_State *L) {
 
 void luaC_step (lua_State *L) {
   global_State *g = G(L);
-  l_mem lim = (g->nblocks - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL;
+  l_mem lim = (g->totalbytes - (g->GCthreshold - GCSTEPSIZE)) * STEPMUL;
+/*printf("step(%c): ", g->gcgenerational?'g':' ');*/
   do {
+    /*printf("%c", "_pswf"[g->gcstate]);*/
     lim -= singlestep(L);
+    if (g->gcstate == GCSpause)
+      break;
   } while (lim > 0);
-  g->GCthreshold = g->nblocks + GCSTEPSIZE - lim/STEPMUL;
-  lua_assert((long)g->nblocks + (long)GCSTEPSIZE >= lim/STEPMUL);
+/*printf("\n");*/
+  if (g->gcstate != GCSpause)
+    g->GCthreshold = g->totalbytes + GCSTEPSIZE;  /* - lim/STEPMUL; */
+  else {
+/*printf("---\n");*/
+    lua_assert(g->totalbytes >= g->estimate);
+    g->GCthreshold = 2*g->estimate;
+    if (g->GCthreshold < g->totalbytes + GCSTEPSIZE)
+      g->GCthreshold = g->totalbytes + GCSTEPSIZE;
+  }
 }
 
 
 void luaC_fullgc (lua_State *L) {
   global_State *g = G(L);
-  if (g->gcstate == GCSpropagate || g->gcgenerational) {
+  if (g->gcstate <= GCSpropagate || g->gcgenerational) {
     g->gcgenerational = 0;
     /* reset sweep marks to sweep all elements (returning them to white) */
     g->sweepstrgc = 0;
@@ -631,6 +647,7 @@ void luaC_fullgc (lua_State *L) {
   }
   /* finish any pending sweep phase */
   while (g->gcstate != GCSfinalize) {
+    lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);
     singlestep(L);
   }
   markroot(L);
@@ -639,7 +656,8 @@ void luaC_fullgc (lua_State *L) {
     singlestep(L);
     g->gcgenerational = 0;  /* keep it in this mode */
   }
-  g->GCthreshold = g->nblocks + GCSTEPSIZE;
+  lua_assert(g->estimate == g->totalbytes);
+  g->GCthreshold = 2*g->estimate;
   luaC_callGCTM(L);  /* call finalizers */
 }
 
@@ -686,7 +704,7 @@ void luaC_linkupval (lua_State *L, UpVal *uv) {
     }
     else {  /* sweep phase: sweep it (turning it into white) */
       makewhite(g, o);
-      lua_assert(g->gcstate != GCSfinalize);
+      lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause);
     }
   }
 }

+ 7 - 6
lgc.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lgc.h,v 2.6 2004/08/10 19:17:23 roberto Exp roberto $
+** $Id: lgc.h,v 2.7 2004/08/24 20:12:06 roberto Exp roberto $
 ** Garbage Collector
 ** See Copyright Notice in lua.h
 */
@@ -14,10 +14,11 @@
 /*
 ** Possible states of the Garbage Collector
 */
-#define GCSpropagate	0
-#define GCSsweepstring	1
-#define GCSsweep	2
-#define GCSfinalize	3
+#define GCSpause	0
+#define GCSpropagate	1
+#define GCSsweepstring	2
+#define GCSsweep	3
+#define GCSfinalize	4
 
 
 /*
@@ -71,7 +72,7 @@
 #define luaC_white(g)	cast(lu_byte, (g)->currentwhite)
 
 
-#define luaC_checkGC(L) { if (G(L)->nblocks >= G(L)->GCthreshold) \
+#define luaC_checkGC(L) { if (G(L)->totalbytes >= G(L)->GCthreshold) \
 	luaC_step(L); }
 
 

+ 2 - 3
lmem.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lmem.c,v 1.63 2003/11/27 18:18:37 roberto Exp roberto $
+** $Id: lmem.c,v 1.64 2004/04/30 20:13:38 roberto Exp roberto $
 ** Interface to Memory Manager
 ** See Copyright Notice in lua.h
 */
@@ -77,8 +77,7 @@ void *luaM_realloc (lua_State *L, void *block, lu_mem osize, lu_mem nsize) {
   if (block == NULL && nsize > 0)
     luaD_throw(L, LUA_ERRMEM);
   lua_assert((nsize == 0) == (block == NULL));
-  g->nblocks -= osize;
-  g->nblocks += nsize;
+  g->totalbytes = (g->totalbytes - osize) + nsize;
   return block;
 }
 

+ 8 - 6
lstate.c

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.c,v 2.10 2004/06/17 14:25:31 roberto Exp roberto $
+** $Id: lstate.c,v 2.11 2004/08/24 20:12:06 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -77,11 +77,12 @@ static void freestack (lua_State *L, lua_State *L1) {
 */
 static void f_luaopen (lua_State *L, void *ud) {
   Udata *u;  /* head of udata list */
+  global_State *g = G(L);
   UNUSED(ud);
   u = cast(Udata *, luaM_malloc(L, sizeudata(0)));
   u->uv.len = 0;
   u->uv.metatable = NULL;
-  G(L)->firstudata = obj2gco(u);
+  g->firstudata = obj2gco(u);
   luaC_link(L, obj2gco(u), LUA_TUSERDATA);
   setbit(u->uv.marked, FIXEDBIT);
   setbit(L->marked, FIXEDBIT);
@@ -93,7 +94,8 @@ static void f_luaopen (lua_State *L, void *ud) {
   luaT_init(L);
   luaX_init(L);
   luaS_fix(luaS_newliteral(L, MEMERRMSG));
-  G(L)->GCthreshold = 4*G(L)->nblocks;
+  g->GCthreshold = 4*g->totalbytes;
+  g->prevestimate = g->estimate = g->totalbytes;
 }
 
 
@@ -128,7 +130,7 @@ static void close_state (lua_State *L) {
   luaM_freearray(L, G(L)->strt.hash, G(L)->strt.size, TString *);
   luaZ_freebuffer(L, &g->buff);
   freestack(L, L);
-  lua_assert(g->nblocks == sizeof(LG));
+  lua_assert(g->totalbytes == sizeof(LG));
   (*g->realloc)(g->ud, fromstate(L), state_size(LG), 0);
 }
 
@@ -177,7 +179,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   setnilvalue(registry(L));
   luaZ_initbuffer(L, &g->buff);
   g->panic = NULL;
-  g->gcstate = GCSfinalize;
+  g->gcstate = GCSpause;
   g->gcgenerational = 0;
   g->rootgc = obj2gco(L);
   g->sweepstrgc = 0;
@@ -190,7 +192,7 @@ LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud) {
   setnilvalue(gkey(g->dummynode));
   setnilvalue(gval(g->dummynode));
   g->dummynode->next = NULL;
-  g->nblocks = sizeof(LG);
+  g->totalbytes = sizeof(LG);
   if (luaD_rawrunprotected(L, f_luaopen, NULL) != 0) {
     /* memory allocation error: free partial state */
     close_state(L);

+ 4 - 2
lstate.h

@@ -1,5 +1,5 @@
 /*
-** $Id: lstate.h,v 2.5 2004/06/02 19:07:55 roberto Exp roberto $
+** $Id: lstate.h,v 2.6 2004/08/24 20:12:06 roberto Exp roberto $
 ** Global State
 ** See Copyright Notice in lua.h
 */
@@ -82,7 +82,9 @@ typedef struct global_State {
   GCObject *tmudata;  /* list of userdata to be GC */
   Mbuffer buff;  /* temporary buffer for string concatentation */
   lu_mem GCthreshold;
-  lu_mem nblocks;  /* number of `bytes' currently allocated */
+  lu_mem totalbytes;  /* number of bytes currently allocated */
+  lu_mem estimate;  /* an estimate of number of bytes actually in use */
+  lu_mem prevestimate;  /* previous estimate */
   lua_CFunction panic;  /* to be called in unprotected errors */
   TValue _registry;
   struct lua_State *mainthread;