From ddfa1fbccfe4c1ec69f7396a4f5842abe70927ba Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Thu, 19 Sep 2024 19:02:14 -0300 Subject: GC back to controling pace counting bytes Memory is the resource we want to save. Still to be reviewed again. --- lgc.c | 307 +++++++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 182 insertions(+), 125 deletions(-) (limited to 'lgc.c') diff --git a/lgc.c b/lgc.c index 92034635..a38d11b2 100644 --- a/lgc.c +++ b/lgc.c @@ -18,7 +18,6 @@ #include "ldo.h" #include "lfunc.h" #include "lgc.h" -#include "llex.h" #include "lmem.h" #include "lobject.h" #include "lstate.h" @@ -27,13 +26,6 @@ #include "ltm.h" -/* -** Number of fixed (luaC_fix) objects in a Lua state: metafield names, -** plus reserved words, plus "_ENV", plus the memory-error message. -*/ -#define NFIXED (TM_N + NUM_RESERVED + 2) - - /* ** Maximum number of elements to sweep in each single step. ** (Large enough to dissipate fixed overheads but small enough @@ -42,6 +34,12 @@ #define GCSWEEPMAX 20 +/* +** Cost (in work units) of running one finalizer. +*/ +#define CWUFIN 10 + + /* mask with all color bits */ #define maskcolors (bitmask(BLACKBIT) | WHITEBITS) @@ -95,7 +93,7 @@ static void reallymarkobject (global_State *g, GCObject *o); -static l_obj atomic (lua_State *L); +static void atomic (lua_State *L); static void entersweep (lua_State *L); @@ -112,6 +110,66 @@ static void entersweep (lua_State *L); #define gnodelast(h) gnode(h, cast_sizet(sizenode(h))) +static size_t objsize (GCObject *o) { + switch (o->tt) { + case LUA_VTABLE: { + /* Fow now, table size does not consider 'haslastfree' */ + Table *t = gco2t(o); + size_t sz = sizeof(Table) + + luaH_realasize(t) * (sizeof(Value) + 1); + if (!isdummy(t)) + sz += sizenode(t) * sizeof(Node); + return sz; + } + case LUA_VLCL: { + LClosure *cl = gco2lcl(o); + return sizeLclosure(cl->nupvalues); + } + case LUA_VCCL: { + CClosure *cl = gco2ccl(o); + return sizeCclosure(cl->nupvalues); + break; + } + case LUA_VUSERDATA: { + Udata *u = gco2u(o); + return sizeudata(u->nuvalue, u->len); + } + case LUA_VPROTO: { + Proto *p = gco2p(o); + size_t sz = sizeof(Proto) + + cast_uint(p->sizep) * sizeof(Proto*) + + cast_uint(p->sizek) * sizeof(TValue) + + cast_uint(p->sizelocvars) * sizeof(LocVar) + + cast_uint(p->sizeupvalues) * sizeof(Upvaldesc); + if (!(p->flag & PF_FIXED)) { + sz += cast_uint(p->sizecode) * sizeof(Instruction) + + cast_uint(p->sizelineinfo) * sizeof(lu_byte) + + cast_uint(p->sizeabslineinfo) * sizeof(AbsLineInfo); + } + return sz; + } + case LUA_VTHREAD: { + lua_State *L1 = gco2th(o); + size_t sz = sizeof(lua_State) + LUA_EXTRASPACE + + cast_uint(L1->nci) * sizeof(CallInfo); + if (L1->stack.p != NULL) + sz += cast_uint(stacksize(L1) + EXTRA_STACK) * sizeof(StackValue); + return sz; + } + case LUA_VSHRSTR: { + TString *ts = gco2ts(o); + return sizestrshr(cast_uint(ts->shrlen)); + } + case LUA_VLNGSTR: { + TString *ts = gco2ts(o); + return luaS_sizelngstr(ts->u.lnglen, ts->shrlen); + } + case LUA_VUPVAL: return sizeof(UpVal); + default: lua_assert(0); return 0; + } +} + + static GCObject **getgclist (GCObject *o) { switch (o->tt) { case LUA_VTABLE: return &gco2t(o)->gclist; @@ -250,7 +308,6 @@ GCObject *luaC_newobjdt (lua_State *L, lu_byte tt, size_t sz, size_t offset) { global_State *g = G(L); char *p = cast_charp(luaM_newobject(L, novariant(tt), sz)); GCObject *o = cast(GCObject *, p + offset); - g->GCdebt--; o->marked = luaC_white(g); o->tt = tt; o->next = g->allgc; @@ -290,7 +347,7 @@ GCObject *luaC_newobj (lua_State *L, lu_byte tt, size_t sz) { ** (only closures can), and a userdata's metatable must be a table. */ static void reallymarkobject (global_State *g, GCObject *o) { - g->GCmarked++; + g->GCmarked += cast(l_mem, objsize(o)); switch (o->tt) { case LUA_VSHRSTR: case LUA_VLNGSTR: { @@ -338,14 +395,10 @@ static void markmt (global_State *g) { /* ** mark all objects in list of being-finalized */ -static l_obj markbeingfnz (global_State *g) { +static void markbeingfnz (global_State *g) { GCObject *o; - l_obj count = 0; - for (o = g->tobefnz; o != NULL; o = o->next) { - count++; + for (o = g->tobefnz; o != NULL; o = o->next) markobject(g, o); - } - return count; } @@ -360,8 +413,7 @@ static l_obj markbeingfnz (global_State *g) { ** upvalues, as they have nothing to be checked. (If the thread gets an ** upvalue later, it will be linked in the list again.) */ -static l_obj remarkupvals (global_State *g) { - l_obj work = 0; +static void remarkupvals (global_State *g) { lua_State *thread; lua_State **p = &g->twups; while ((thread = *p) != NULL) { @@ -380,9 +432,7 @@ static l_obj remarkupvals (global_State *g) { } } } - work++; } - return work; } @@ -401,7 +451,7 @@ static void cleargraylists (global_State *g) { */ static void restartcollection (global_State *g) { cleargraylists(g); - g->GCmarked = NFIXED; + g->GCmarked = 0; markobject(g, g->mainthread); markvalue(g, &g->l_registry); markmt(g); @@ -546,7 +596,7 @@ static void traversestrongtable (global_State *g, Table *h) { } -static void traversetable (global_State *g, Table *h) { +static l_mem traversetable (global_State *g, Table *h) { const char *weakkey, *weakvalue; const TValue *mode = gfasttm(g, h->metatable, TM_MODE); TString *smode; @@ -565,15 +615,17 @@ static void traversetable (global_State *g, Table *h) { } else /* not weak */ traversestrongtable(g, h); + return 1 + sizenode(h) + h->alimit; } -static void traverseudata (global_State *g, Udata *u) { +static l_mem traverseudata (global_State *g, Udata *u) { int i; markobjectN(g, u->metatable); /* mark its metatable */ for (i = 0; i < u->nuvalue; i++) markvalue(g, &u->uv[i].uv); genlink(g, obj2gco(u)); + return 1 + u->nuvalue; } @@ -582,7 +634,7 @@ static void traverseudata (global_State *g, Udata *u) { ** arrays can be larger than needed; the extra slots are filled with ** NULL, so the use of 'markobjectN') */ -static void traverseproto (global_State *g, Proto *f) { +static l_mem traverseproto (global_State *g, Proto *f) { int i; markobjectN(g, f->source); for (i = 0; i < f->sizek; i++) /* mark literals */ @@ -593,26 +645,29 @@ static void traverseproto (global_State *g, Proto *f) { markobjectN(g, f->p[i]); for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ markobjectN(g, f->locvars[i].varname); + return 1 + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; } -static void traverseCclosure (global_State *g, CClosure *cl) { +static l_mem traverseCclosure (global_State *g, CClosure *cl) { int i; for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ markvalue(g, &cl->upvalue[i]); + return 1 + cl->nupvalues; } /* ** Traverse a Lua closure, marking its prototype and its upvalues. ** (Both can be NULL while closure is being created.) */ -static void traverseLclosure (global_State *g, LClosure *cl) { +static l_mem traverseLclosure (global_State *g, LClosure *cl) { int i; markobjectN(g, cl->p); /* mark its prototype */ for (i = 0; i < cl->nupvalues; i++) { /* visit its upvalues */ UpVal *uv = cl->upvals[i]; markobjectN(g, uv); /* mark upvalue */ } + return 1 + cl->nupvalues; } @@ -628,13 +683,13 @@ static void traverseLclosure (global_State *g, LClosure *cl) { ** (which can only happen in generational mode) or if the traverse is in ** the propagate phase (which can only happen in incremental mode). */ -static void traversethread (global_State *g, lua_State *th) { +static l_mem traversethread (global_State *g, lua_State *th) { UpVal *uv; StkId o = th->stack.p; if (isold(th) || g->gcstate == GCSpropagate) linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ if (o == NULL) - return; /* stack not completely built yet */ + return 0; /* stack not completely built yet */ lua_assert(g->gcstate == GCSatomic || th->openupval == NULL || isintwups(th)); for (; o < th->top.p; o++) /* mark live elements in the stack */ @@ -652,35 +707,33 @@ static void traversethread (global_State *g, lua_State *th) { g->twups = th; } } + return 1 + (th->top.p - th->stack.p); } /* -** traverse one gray object, turning it to black. +** traverse one gray object, turning it to black. Return an estimate +** of the number of slots traversed. */ -static void propagatemark (global_State *g) { +static l_mem propagatemark (global_State *g) { GCObject *o = g->gray; nw2black(o); g->gray = *getgclist(o); /* remove from 'gray' list */ switch (o->tt) { - case LUA_VTABLE: traversetable(g, gco2t(o)); break; - case LUA_VUSERDATA: traverseudata(g, gco2u(o)); break; - case LUA_VLCL: traverseLclosure(g, gco2lcl(o)); break; - case LUA_VCCL: traverseCclosure(g, gco2ccl(o)); break; - case LUA_VPROTO: traverseproto(g, gco2p(o)); break; - case LUA_VTHREAD: traversethread(g, gco2th(o)); break; - default: lua_assert(0); + case LUA_VTABLE: return traversetable(g, gco2t(o)); + case LUA_VUSERDATA: return traverseudata(g, gco2u(o)); + case LUA_VLCL: return traverseLclosure(g, gco2lcl(o)); + case LUA_VCCL: return traverseCclosure(g, gco2ccl(o)); + case LUA_VPROTO: return traverseproto(g, gco2p(o)); + case LUA_VTHREAD: return traversethread(g, gco2th(o)); + default: lua_assert(0); return 0; } } -static l_obj propagateall (global_State *g) { - l_obj work = 0; - while (g->gray) { +static void propagateall (global_State *g) { + while (g->gray) propagatemark(g); - work++; - } - return work; } @@ -690,9 +743,8 @@ static l_obj propagateall (global_State *g) { ** inverts the direction of the traversals, trying to speed up ** convergence on chains in the same table. */ -static l_obj convergeephemerons (global_State *g) { +static void convergeephemerons (global_State *g) { int changed; - l_obj work = 0; int dir = 0; do { GCObject *w; @@ -707,11 +759,9 @@ static l_obj convergeephemerons (global_State *g) { propagateall(g); /* propagate changes */ changed = 1; /* will have to revisit all ephemeron tables */ } - work++; } dir = !dir; /* invert direction next time */ } while (changed); /* repeat until no more changes */ - return work; } /* }====================================================== */ @@ -727,8 +777,7 @@ static l_obj convergeephemerons (global_State *g) { /* ** clear entries with unmarked keys from all weaktables in list 'l' */ -static l_obj clearbykeys (global_State *g, GCObject *l) { - l_obj work = 0; +static void clearbykeys (global_State *g, GCObject *l) { for (; l; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *limit = gnodelast(h); @@ -739,9 +788,7 @@ static l_obj clearbykeys (global_State *g, GCObject *l) { if (isempty(gval(n))) /* is entry empty? */ clearkey(n); /* clear its key */ } - work++; } - return work; } @@ -749,8 +796,7 @@ static l_obj clearbykeys (global_State *g, GCObject *l) { ** clear entries with unmarked values from all weaktables in list 'l' up ** to element 'f' */ -static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) { - l_obj work = 0; +static void clearbyvalues (global_State *g, GCObject *l, GCObject *f) { for (; l != f; l = gco2t(l)->gclist) { Table *h = gco2t(l); Node *n, *limit = gnodelast(h); @@ -767,9 +813,7 @@ static l_obj clearbyvalues (global_State *g, GCObject *l, GCObject *f) { if (isempty(gval(n))) /* is entry empty? */ clearkey(n); /* clear its key */ } - work++; } - return work; } @@ -781,7 +825,6 @@ static void freeupval (lua_State *L, UpVal *uv) { static void freeobj (lua_State *L, GCObject *o) { - G(L)->GCtotalobjs--; switch (o->tt) { case LUA_VPROTO: luaF_freeproto(L, gco2p(o)); @@ -835,12 +878,11 @@ static void freeobj (lua_State *L, GCObject *o) { ** for next collection cycle. Return where to continue the traversal or ** NULL if list is finished. */ -static GCObject **sweeplist (lua_State *L, GCObject **p, l_obj countin) { +static GCObject **sweeplist (lua_State *L, GCObject **p, l_mem countin) { global_State *g = G(L); int ow = otherwhite(g); - l_obj i; int white = luaC_white(g); /* current white */ - for (i = 0; *p != NULL && i < countin; i++) { + while (*p != NULL && countin-- > 0) { GCObject *curr = *p; int marked = curr->marked; if (isdeadm(ow, marked)) { /* is 'curr' dead? */ @@ -1052,8 +1094,8 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) { ** approximately (marked * pause / 100). */ static void setpause (global_State *g) { - l_obj threshold = applygcparam(g, PAUSE, g->GCmarked); - l_obj debt = threshold - gettotalobjs(g); + l_mem threshold = applygcparam(g, PAUSE, g->GCmarked); + l_mem debt = threshold - gettotalbytes(g); if (debt < 0) debt = 0; luaE_setdebt(g, debt); } @@ -1103,7 +1145,7 @@ static void sweep2old (lua_State *L, GCObject **p) { */ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, GCObject *limit, GCObject **pfirstold1, - l_obj *paddedold) { + l_mem *paddedold) { static const lu_byte nextage[] = { G_SURVIVAL, /* from G_NEW */ G_OLD1, /* from G_SURVIVAL */ @@ -1113,7 +1155,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, G_TOUCHED1, /* from G_TOUCHED1 (do not change) */ G_TOUCHED2 /* from G_TOUCHED2 (do not change) */ }; - l_obj addedold = 0; + l_mem addedold = 0; int white = luaC_white(g); GCObject *curr; while ((curr = *p) != limit) { @@ -1132,7 +1174,7 @@ static GCObject **sweepgen (lua_State *L, global_State *g, GCObject **p, lua_assert(age != G_OLD1); /* advanced in 'markold' */ setage(curr, nextage[age]); if (getage(curr) == G_OLD1) { - addedold++; /* one more object becoming old */ + addedold += cast(l_mem, objsize(curr)); /* bytes becoming old */ if (*pfirstold1 == NULL) *pfirstold1 = curr; /* first OLD1 object in the list */ } @@ -1257,9 +1299,9 @@ static void minor2inc (lua_State *L, global_State *g, lu_byte kind) { ** than 'minormajor'% of the number of lived objects after the last ** major collection. (That percentage is computed in 'limit'.) */ -static int checkminormajor (global_State *g, l_obj addedold1) { - l_obj step = applygcparam(g, MINORMUL, g->GCmajorminor); - l_obj limit = applygcparam(g, MINORMAJOR, g->GCmajorminor); +static int checkminormajor (global_State *g, l_mem addedold1) { + l_mem step = applygcparam(g, MINORMUL, g->GCmajorminor); + l_mem limit = applygcparam(g, MINORMAJOR, g->GCmajorminor); return (addedold1 >= (step >> 1) || g->GCmarked >= limit); } @@ -1269,8 +1311,8 @@ static int checkminormajor (global_State *g, l_obj addedold1) { ** sweep all lists and advance pointers. Finally, finish the collection. */ static void youngcollection (lua_State *L, global_State *g) { - l_obj addedold1 = 0; - l_obj marked = g->GCmarked; /* preserve 'g->GCmarked' */ + l_mem addedold1 = 0; + l_mem marked = g->GCmarked; /* preserve 'g->GCmarked' */ GCObject **psurvival; /* to point to first non-dead survival object */ GCObject *dummy; /* dummy out parameter to 'sweepgen' */ lua_assert(g->gcstate == GCSpropagate); @@ -1346,7 +1388,9 @@ static void atomic2gen (lua_State *L, global_State *g) { /* ** Set debt for the next minor collection, which will happen when -** total number of objects grows 'genminormul'%. +** total number of bytes grows 'genminormul'% in relation to +** the base, GCmajorminor, which is the number of bytes being used +** after the last major collection. */ static void setminordebt (global_State *g) { luaE_setdebt(g, applygcparam(g, MINORMUL, g->GCmajorminor)); @@ -1404,18 +1448,18 @@ static void fullgen (lua_State *L, global_State *g) { */ static int checkmajorminor (lua_State *L, global_State *g) { if (g->gckind == KGC_GENMAJOR) { /* generational mode? */ - l_obj numobjs = gettotalobjs(g); - l_obj addedobjs = numobjs - g->GCmajorminor; - l_obj limit = applygcparam(g, MAJORMINOR, addedobjs); - l_obj tobecollected = numobjs - g->GCmarked; + l_mem numbytes = gettotalbytes(g); + l_mem addedobjs = numbytes - g->GCmajorminor; + l_mem limit = applygcparam(g, MAJORMINOR, addedobjs); + l_mem tobecollected = numbytes - g->GCmarked; if (tobecollected > limit) { atomic2gen(L, g); /* return to generational mode */ setminordebt(g); - return 0; /* exit incremental collection */ + return 1; /* exit incremental collection */ } } g->GCmajorminor = g->GCmarked; /* prepare for next collection */ - return 1; /* stay doing incremental collections */ + return 0; /* stay doing incremental collections */ } /* }====================================================== */ @@ -1474,8 +1518,7 @@ void luaC_freeallobjects (lua_State *L) { } -static l_obj atomic (lua_State *L) { - l_obj work = 0; +static void atomic (lua_State *L) { global_State *g = G(L); GCObject *origweak, *origall; GCObject *grayagain = g->grayagain; /* save original list */ @@ -1487,33 +1530,32 @@ static l_obj atomic (lua_State *L) { /* registry and global metatables may be changed by API */ markvalue(g, &g->l_registry); markmt(g); /* mark global metatables */ - work += propagateall(g); /* empties 'gray' list */ + propagateall(g); /* empties 'gray' list */ /* remark occasional upvalues of (maybe) dead threads */ - work += remarkupvals(g); - work += propagateall(g); /* propagate changes */ + remarkupvals(g); + propagateall(g); /* propagate changes */ g->gray = grayagain; - work += propagateall(g); /* traverse 'grayagain' list */ - work += convergeephemerons(g); + propagateall(g); /* traverse 'grayagain' list */ + convergeephemerons(g); /* at this point, all strongly accessible objects are marked. */ /* Clear values from weak tables, before checking finalizers */ - work += clearbyvalues(g, g->weak, NULL); - work += clearbyvalues(g, g->allweak, NULL); + clearbyvalues(g, g->weak, NULL); + clearbyvalues(g, g->allweak, NULL); origweak = g->weak; origall = g->allweak; separatetobefnz(g, 0); /* separate objects to be finalized */ - work += markbeingfnz(g); /* mark objects that will be finalized */ - work += propagateall(g); /* remark, to propagate 'resurrection' */ - work += convergeephemerons(g); + markbeingfnz(g); /* mark objects that will be finalized */ + propagateall(g); /* remark, to propagate 'resurrection' */ + convergeephemerons(g); /* at this point, all resurrected objects are marked. */ /* remove dead objects from weak tables */ - work += clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron */ - work += clearbykeys(g, g->allweak); /* clear keys from all 'allweak' */ + clearbykeys(g, g->ephemeron); /* clear keys from all ephemeron */ + clearbykeys(g, g->allweak); /* clear keys from all 'allweak' */ /* clear values from resurrected weak tables */ - work += clearbyvalues(g, g->weak, origweak); - work += clearbyvalues(g, g->allweak, origall); + clearbyvalues(g, g->weak, origweak); + clearbyvalues(g, g->allweak, origall); luaS_clearcache(g); g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ lua_assert(g->gray == NULL); - return work; } @@ -1524,7 +1566,7 @@ static l_obj atomic (lua_State *L) { static void sweepstep (lua_State *L, global_State *g, lu_byte nextstate, GCObject **nextlist, int fast) { if (g->sweepgc) - g->sweepgc = sweeplist(L, g->sweepgc, fast ? MAX_LOBJ : GCSWEEPMAX); + g->sweepgc = sweeplist(L, g->sweepgc, fast ? MAX_LMEM : GCSWEEPMAX); else { /* enter next state */ g->gcstate = nextstate; g->sweepgc = nextlist; @@ -1544,72 +1586,80 @@ static void sweepstep (lua_State *L, global_State *g, ** That avoids traversing twice some objects, such as threads and ** weak tables. */ -static l_obj singlestep (lua_State *L, int fast) { + +#define step2pause -3 /* finished collection; entered pause state */ +#define atomicstep -2 /* atomic step */ +#define step2minor -1 /* moved to minor collections */ + + +static l_mem singlestep (lua_State *L, int fast) { global_State *g = G(L); - l_obj work; + l_mem stepresult; lua_assert(!g->gcstopem); /* collector is not reentrant */ g->gcstopem = 1; /* no emergency collections while collecting */ switch (g->gcstate) { case GCSpause: { restartcollection(g); g->gcstate = GCSpropagate; - work = 1; + stepresult = 1; break; } case GCSpropagate: { if (fast || g->gray == NULL) { g->gcstate = GCSenteratomic; /* finish propagate phase */ - work = 0; - } - else { - propagatemark(g); /* traverse one gray object */ - work = 1; + stepresult = 1; } + else + stepresult = propagatemark(g); /* traverse one gray object */ break; } case GCSenteratomic: { - work = atomic(L); + atomic(L); if (checkmajorminor(L, g)) + stepresult = step2minor; + else { entersweep(L); + stepresult = atomicstep; + } break; } case GCSswpallgc: { /* sweep "regular" objects */ sweepstep(L, g, GCSswpfinobj, &g->finobj, fast); - work = GCSWEEPMAX; + stepresult = GCSWEEPMAX; break; } case GCSswpfinobj: { /* sweep objects with finalizers */ sweepstep(L, g, GCSswptobefnz, &g->tobefnz, fast); - work = GCSWEEPMAX; + stepresult = GCSWEEPMAX; break; } case GCSswptobefnz: { /* sweep objects to be finalized */ sweepstep(L, g, GCSswpend, NULL, fast); - work = GCSWEEPMAX; + stepresult = GCSWEEPMAX; break; } case GCSswpend: { /* finish sweeps */ checkSizes(L, g); g->gcstate = GCScallfin; - work = 0; + stepresult = GCSWEEPMAX; break; } case GCScallfin: { /* call finalizers */ if (g->tobefnz && !g->gcemergency) { g->gcstopem = 0; /* ok collections during finalizers */ GCTM(L); /* call one finalizer */ - work = 1; + stepresult = CWUFIN; } else { /* emergency mode or no more finalizers */ g->gcstate = GCSpause; /* finish collection */ - work = 0; + stepresult = step2pause; } break; } default: lua_assert(0); return 0; } g->gcstopem = 0; - return work; + return stepresult; } @@ -1635,25 +1685,26 @@ void luaC_runtilstate (lua_State *L, int state, int fast) { ** controls when next step will be performed. */ static void incstep (lua_State *L, global_State *g) { - l_obj stepsize = applygcparam(g, STEPSIZE, 100); - l_obj work2do = applygcparam(g, STEPMUL, stepsize); - int fast = 0; - if (work2do == 0) { /* special case: do a full collection */ - work2do = MAX_LOBJ; /* do unlimited work */ - fast = 1; - } - do { /* repeat until pause or enough work */ - l_obj work = singlestep(L, fast); /* perform one single step */ - if (g->gckind == KGC_GENMINOR) /* returned to minor collections? */ + l_mem stepsize = applygcparam(g, STEPSIZE, 100); + l_mem work2do = applygcparam(g, STEPMUL, stepsize); + l_mem stres; + int fast = (work2do == 0); /* special case: do a full collection */ + do { /* repeat until enough work */ + stres = singlestep(L, fast); /* perform one single step */ + if (stres == step2minor) /* returned to minor collections? */ return; /* nothing else to be done here */ - work2do -= work; - } while (work2do > 0 && g->gcstate != GCSpause); + else if (stres == step2pause || (stres == atomicstep && !fast)) + break; /* end of cycle or atomic */ + else + work2do -= stres; + } while (fast || work2do > 0); if (g->gcstate == GCSpause) setpause(g); /* pause until next cycle */ else luaE_setdebt(g, stepsize); } + /* ** Performs a basic GC step if collector is running. (If collector is ** not running, set a reasonable debt to avoid it being called at @@ -1663,17 +1714,23 @@ void luaC_step (lua_State *L) { global_State *g = G(L); lua_assert(!g->gcemergency); if (!gcrunning(g)) /* not running? */ - luaE_setdebt(g, 2000); + luaE_setdebt(g, 20000); else { +// printf("mem: %ld kind: %s ", gettotalbytes(g), +// g->gckind == KGC_INC ? "inc" : g->gckind == KGC_GENMAJOR ? "genmajor" : +// "genminor"); switch (g->gckind) { case KGC_INC: case KGC_GENMAJOR: +// printf("(%d -> ", g->gcstate); incstep(L, g); +// printf("%d) ", g->gcstate); break; case KGC_GENMINOR: youngcollection(L, g); setminordebt(g); break; } +// printf("-> mem: %ld debt: %ld\n", gettotalbytes(g), g->GCdebt); } } @@ -1692,7 +1749,7 @@ static void fullinc (lua_State *L, global_State *g) { luaC_runtilstate(L, GCSpause, 1); luaC_runtilstate(L, GCScallfin, 1); /* run up to finalizers */ /* 'marked' must be correct after a full GC cycle */ - lua_assert(g->GCmarked == gettotalobjs(g)); + /* lua_assert(g->GCmarked == gettotalobjs(g)); ??? */ luaC_runtilstate(L, GCSpause, 1); /* finish collection */ setpause(g); } -- cgit v1.2.3-55-g6feb