From 3d54b42d59bcc1b31a369f3497ac22745d63cae6 Mon Sep 17 00:00:00 2001 From: Roberto Ierusalimschy Date: Mon, 30 Sep 2024 14:01:42 -0300 Subject: [PATCH] 'objsize' broke in smaller pieces --- lfunc.c | 15 +++++++++++++ lfunc.h | 1 + lgc.c | 58 +++++++++++++++++------------------------------- lgc.h | 15 +++++++++---- lstate.c | 8 +++++++ lstate.h | 1 + ltable.c | 12 ++++++++++ ltable.h | 1 + manual/manual.of | 43 +++++++++++++++++------------------ 9 files changed, 91 insertions(+), 63 deletions(-) diff --git a/lfunc.c b/lfunc.c index d650c000..2b041281 100644 --- a/lfunc.c +++ b/lfunc.c @@ -264,6 +264,21 @@ Proto *luaF_newproto (lua_State *L) { } +size_t luaF_protosize (Proto *p) { + 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; +} + + void luaF_freeproto (lua_State *L, Proto *f) { if (!(f->flag & PF_FIXED)) { luaM_freearray(L, f->code, cast_sizet(f->sizecode)); diff --git a/lfunc.h b/lfunc.h index 162b55ec..b9651074 100644 --- a/lfunc.h +++ b/lfunc.h @@ -56,6 +56,7 @@ LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level); LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy); LUAI_FUNC void luaF_unlinkupval (UpVal *uv); +LUAI_FUNC size_t luaF_protosize (Proto *p); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, int pc); diff --git a/lgc.c b/lgc.c index a38d11b2..e154402b 100644 --- a/lgc.c +++ b/lgc.c @@ -113,13 +113,7 @@ static void entersweep (lua_State *L); 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; + return luaH_size(gco2t(o)); } case LUA_VLCL: { LClosure *cl = gco2lcl(o); @@ -135,26 +129,10 @@ static size_t objsize (GCObject *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; + return luaF_protosize(gco2p(o)); } 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; + return luaE_statesize(gco2th(o)); } case LUA_VSHRSTR: { TString *ts = gco2ts(o); @@ -164,7 +142,9 @@ static size_t objsize (GCObject *o) { TString *ts = gco2ts(o); return luaS_sizelngstr(ts->u.lnglen, ts->shrlen); } - case LUA_VUPVAL: return sizeof(UpVal); + case LUA_VUPVAL: { + return sizeof(UpVal); + } default: lua_assert(0); return 0; } } @@ -615,7 +595,7 @@ static l_mem traversetable (global_State *g, Table *h) { } else /* not weak */ traversestrongtable(g, h); - return 1 + sizenode(h) + h->alimit; + return 1 + 2*sizenode(h) + h->alimit; } @@ -1291,10 +1271,11 @@ static void minor2inc (lua_State *L, global_State *g, lu_byte kind) { /* ** Decide whether to shift to major mode. It tests two conditions: ** 1) Whether the number of added old objects in this collection is more -** than half the number of new objects. ('step' is the number of objects -** created between minor collections. Except for forward barriers, it -** is the maximum number of objects that can become old in each minor -** collection.) +** than half the number of new objects. ('step' is equal to the debt set +** to trigger the next minor collection; that is equal to the number +** of objects created since the previous minor collection. Except for +** forward barriers, it is the maximum number of objects that can become +** old in each minor collection.) ** 2) Whether the accumulated number of added old objects is larger ** than 'minormajor'% of the number of lived objects after the last ** major collection. (That percentage is computed in 'limit'.) @@ -1678,7 +1659,7 @@ void luaC_runtilstate (lua_State *L, int state, int fast) { /* -** Performs a basic incremental step. The debt and step size are +** Performs a basic incremental step. The step size is ** converted from bytes to "units of work"; then the function loops ** running single steps until adding that many units of work or ** finishing a cycle (pause state). Finally, it sets the debt that @@ -1689,7 +1670,9 @@ static void incstep (lua_State *L, global_State *g) { l_mem work2do = applygcparam(g, STEPMUL, stepsize); l_mem stres; int fast = (work2do == 0); /* special case: do a full collection */ +//printf("\n** %ld %ld %d\n", work2do, stepsize, g->gcstate); do { /* repeat until enough work */ +//printf("%d-", g->gcstate); stres = singlestep(L, fast); /* perform one single step */ if (stres == step2minor) /* returned to minor collections? */ return; /* nothing else to be done here */ @@ -1716,21 +1699,20 @@ void luaC_step (lua_State *L) { if (!gcrunning(g)) /* not running? */ luaE_setdebt(g, 20000); else { -// printf("mem: %ld kind: %s ", gettotalbytes(g), -// g->gckind == KGC_INC ? "inc" : g->gckind == KGC_GENMAJOR ? "genmajor" : -// "genminor"); +//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); +//printf("%d) ", g->gcstate); break; case KGC_GENMINOR: youngcollection(L, g); setminordebt(g); break; } -// printf("-> mem: %ld debt: %ld\n", gettotalbytes(g), g->GCdebt); +//printf("-> mem: %ld debt: %ld\n", gettotalbytes(g), g->GCdebt); } } diff --git a/lgc.h b/lgc.h index 0b16ac7f..a3bc746a 100644 --- a/lgc.h +++ b/lgc.h @@ -160,7 +160,11 @@ */ -/* Default Values for GC parameters */ +/* +** {====================================================== +** Default Values for GC parameters +** ======================================================= +*/ /* ** Minor collections will shift to major ones after LUAI_MINORMAJOR% @@ -189,17 +193,20 @@ /* ** Step multiplier: The collector handles LUAI_GCMUL% work units for ** each new allocated byte. (Each "work unit" corresponds roughly to -** sweeping or marking one object.) +** sweeping one object or traversing one slot.) */ -#define LUAI_GCMUL 20 /* ??? */ +#define LUAI_GCMUL 40 /* How many bytes to allocate before next GC step */ -#define LUAI_GCSTEPSIZE (250 * sizeof(void*)) +#define LUAI_GCSTEPSIZE (200 * sizeof(Table)) #define setgcparam(g,p,v) (g->gcparams[LUA_GCP##p] = luaO_codeparam(v)) #define applygcparam(g,p,x) luaO_applyparam(g->gcparams[LUA_GCP##p], x) +/* }====================================================== */ + + /* ** Control when GC is running: */ diff --git a/lstate.c b/lstate.c index 8e7c8b86..d6b9c90f 100644 --- a/lstate.c +++ b/lstate.c @@ -257,6 +257,14 @@ static void preinit_thread (lua_State *L, global_State *g) { } +size_t luaE_statesize (lua_State *L) { + size_t sz = sizeof(LG) + cast_uint(L->nci) * sizeof(CallInfo); + if (L->stack.p != NULL) + sz += cast_uint(stacksize(L) + EXTRA_STACK) * sizeof(StackValue); + return sz; +} + + static void close_state (lua_State *L) { global_State *g = G(L); if (!completestate(g)) /* closing a partially built state? */ diff --git a/lstate.h b/lstate.h index 2a03576d..e2108668 100644 --- a/lstate.h +++ b/lstate.h @@ -416,6 +416,7 @@ union GCUnion { LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); +LUAI_FUNC size_t luaE_statesize (lua_State *L); LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); LUAI_FUNC void luaE_shrinkCI (lua_State *L); LUAI_FUNC void luaE_checkcstack (lua_State *L); diff --git a/ltable.c b/ltable.c index 80a1bf84..bf44e82e 100644 --- a/ltable.c +++ b/ltable.c @@ -805,6 +805,18 @@ Table *luaH_new (lua_State *L) { } +size_t luaH_size (Table *t) { + size_t sz = sizeof(Table) + + luaH_realasize(t) * (sizeof(Value) + 1); + if (!isdummy(t)) { + sz += sizenode(t) * sizeof(Node); + if (haslastfree(t)) + sz += sizeof(Limbox); + } + return sz; +} + + /* ** Frees a table. */ diff --git a/ltable.h b/ltable.h index c6a87807..c352da38 100644 --- a/ltable.h +++ b/ltable.h @@ -163,6 +163,7 @@ LUAI_FUNC Table *luaH_new (lua_State *L); LUAI_FUNC void luaH_resize (lua_State *L, Table *t, unsigned nasize, unsigned nhsize); LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, unsigned nasize); +LUAI_FUNC size_t luaH_size (Table *t); LUAI_FUNC void luaH_free (lua_State *L, Table *t); LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key); LUAI_FUNC lua_Unsigned luaH_getn (Table *t); diff --git a/manual/manual.of b/manual/manual.of index 1ac537f7..c93fbfcb 100644 --- a/manual/manual.of +++ b/manual/manual.of @@ -608,8 +608,8 @@ An object is considered @def{dead} as soon as the collector can be sure the object will not be accessed again in the normal execution of the program. (@Q{Normal execution} here excludes finalizers, -which can resurrect dead objects @see{finalizers}, -and excludes also operations using the debug library.) +which resurrect dead objects @see{finalizers}, +and it excludes also some operations using the debug library.) Note that the time when the collector can be sure that an object is dead may not coincide with the programmer's expectations. The only guarantees are that Lua will not collect an object @@ -657,25 +657,27 @@ and the @def{garbage-collector step size}. The garbage-collector pause controls how long the collector waits before starting a new cycle. -The collector starts a new cycle when the number of objects +The collector starts a new cycle when the number of bytes hits @M{n%} of the total after the previous collection. Larger values make the collector less aggressive. Values equal to or less than 100 mean the collector will not wait to start a new cycle. A value of 200 means that the collector waits for -the total number of objects to double before starting a new cycle. +the total number of bytes to double before starting a new cycle. The garbage-collector step size controls the size of each incremental step, -specifically how many objects the interpreter creates +specifically how many bytes the interpreter allocates before performing a step: -A value of @M{n} means the interpreter will create -approximately @M{n} objects between steps. +A value of @M{n} means the interpreter will allocate +approximately @M{n} bytes between steps. The garbage-collector step multiplier -controls the size of each GC step. -A value of @M{n} means the interpreter will mark or sweep, -in each step, @M{n%} objects for each created object. +controls how much work each incremental step does. +A value of @M{n} means the interpreter will execute +@M{n%} @emphx{units of work} for each byte allocated. +A unit of work corresponds roughly to traversing one slot +or sweeping one object. Larger values make the collector more aggressive. Beware that values too small can make the collector too slow to ever finish a cycle. @@ -689,7 +691,7 @@ effectively producing a non-incremental, stop-the-world collector. In generational mode, the collector does frequent @emph{minor} collections, which traverses only objects recently created. -If after a minor collection the number of objects is above a limit, +If after a minor collection the number of bytes is above a limit, the collector shifts to a @emph{major} collection, which traverses all objects. The collector will then stay doing major collections until @@ -702,30 +704,30 @@ and the @def{major-minor multiplier}. The minor multiplier controls the frequency of minor collections. For a minor multiplier @M{x}, -a new minor collection will be done when the number of objects +a new minor collection will be done when the number of bytes grows @M{x%} larger than the number in use just after the last major collection. For instance, for a multiplier of 20, -the collector will do a minor collection when the number of objects +the collector will do a minor collection when the number of bytes gets 20% larger than the total after the last major collection. The minor-major multiplier controls the shift to major collections. For a multiplier @M{x}, the collector will shift to a major collection -when the number of old objects grows @M{x%} larger +when the number of bytes from old objects grows @M{x%} larger than the total after the previous major collection. For instance, for a multiplier of 100, -the collector will do a major collection when the number of old objects +the collector will do a major collection when the number of old bytes gets larger than twice the total after the previous major collection. The major-minor multiplier controls the shift back to minor collections. For a multiplier @M{x}, the collector will shift back to minor collections after a major collection collects at least @M{x%} -of the objects allocated during the last cycle. +of the bytes allocated during the last cycle. In particular, for a multiplier of 0, the collector will immediately shift back to minor collections -after doing one cycle of major collections. +after doing one major collection. } @@ -6404,23 +6406,22 @@ gives the exact number of bytes in use by Lua. Performs a garbage-collection step. This option may be followed by an extra argument, an integer with the step size. -The default for this argument is zero. If the size is a positive @id{n}, -the collector acts as if @id{n} new objects have been created. +the collector acts as if @id{n} new bytes have been allocated. If the size is zero, the collector performs a basic step. In incremental mode, a basic step corresponds to the current step size. In generational mode, a basic step performs a full minor collection or -a major collection, +an incremental step, if the collector has scheduled one. In incremental mode, the function returns @true if the step finished a collection cycle. In generational mode, -the function returns @true if the step performed a major collection. +the function returns @true if the step finished a major collection. } @item{@St{isrunning}|