lua

A copy of the Lua development repository
Log | Files | Refs | README

commit 12b6f610b0f1b4157c04f0db264f1f1d0634709b
parent e81f586001d767c8de9b760ae2e2c3b5da1542c6
Author: Roberto Ierusalimschy <roberto@inf.puc-rio.br>
Date:   Wed, 27 Dec 2023 12:08:44 -0300

Several tweaks in the garbage collector

- back with step size in collectgarbage("step")
- adjustments in defaults for some GC parameters
- adjustments in 'luaO_codeparam'

Diffstat:
Mlapi.c | 18++++++++++++------
Mlbaselib.c | 10++++------
Mlgc.h | 4++--
Mlobject.c | 18+++++++++---------
Mlobject.h | 4++--
Mmanual/manual.of | 69+++++++++++++++++++++++++++++++++++++++------------------------------
Mtestes/files.lua | 2++
Mtestes/gc.lua | 29++++++++++++++++++++++++++++-
8 files changed, 98 insertions(+), 56 deletions(-)

diff --git a/lapi.c b/lapi.c @@ -416,10 +416,11 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { luaC_checkGC(L); o = index2value(L, idx); /* previous call may reallocate the stack */ } - if (len != NULL) - *len = tsslen(tsvalue(o)); lua_unlock(L); - return getstr(tsvalue(o)); + if (len != NULL) + return getlstr(tsvalue(o), *len); + else + return getstr(tsvalue(o)); } @@ -1174,11 +1175,16 @@ LUA_API int lua_gc (lua_State *L, int what, ...) { } case LUA_GCSTEP: { lu_byte oldstp = g->gcstp; + l_obj n = va_arg(argp, int); + int work = 0; /* true if GC did some work */ g->gcstp = 0; /* allow GC to run (other bits must be zero here) */ - luaC_step(L); /* run one basic step */ - g->gcstp = oldstp; /* restore previous state */ - if (g->gcstate == GCSpause) /* end of cycle? */ + if (n <= 0) + n = g->GCdebt; /* force to run one basic step */ + luaE_setdebt(g, g->GCdebt - n); + luaC_condGC(L, (void)0, work = 1); + if (work && g->gcstate == GCSpause) /* end of cycle? */ res = 1; /* signal it */ + g->gcstp = oldstp; /* restore previous state */ break; } case LUA_GCISRUNNING: { diff --git a/lbaselib.c b/lbaselib.c @@ -213,7 +213,8 @@ static int luaB_collectgarbage (lua_State *L) { return 1; } case LUA_GCSTEP: { - int res = lua_gc(L, o); + lua_Integer n = luaL_optinteger(L, 2, 0); + int res = lua_gc(L, o, (int)n); checkvalres(res); lua_pushboolean(L, res); return 1; @@ -239,7 +240,7 @@ static int luaB_collectgarbage (lua_State *L) { LUA_GCPPAUSE, LUA_GCPSTEPMUL, LUA_GCPSTEPSIZE}; int p = pnum[luaL_checkoption(L, 2, NULL, params)]; lua_Integer value = luaL_checkinteger(L, 3); - lua_pushinteger(L, lua_gc(L, o, p, value)); + lua_pushinteger(L, lua_gc(L, o, p, (int)value)); return 1; } default: { @@ -337,10 +338,7 @@ static int load_aux (lua_State *L, int status, int envidx) { static const char *getmode (lua_State *L, int idx) { const char *mode = luaL_optstring(L, idx, "bt"); - int i = 0; - if (mode[i] == 'b') i++; - if (mode[i] == 't') i++; - if (mode[i] != '\0') + if (strchr(mode, 'B') != NULL) /* Lua code cannot use fixed buffers */ luaL_argerror(L, idx, "invalid mode"); return mode; } diff --git a/lgc.h b/lgc.h @@ -171,13 +171,13 @@ ** Major collections will shift to minor ones after a collection ** collects at least LUAI_MAJORMINOR% of the new objects. */ -#define LUAI_MAJORMINOR 80 +#define LUAI_MAJORMINOR 50 /* ** A young (minor) collection will run after creating LUAI_GENMINORMUL% ** new objects. */ -#define LUAI_GENMINORMUL 20 +#define LUAI_GENMINORMUL 25 /* incremental */ diff --git a/lobject.c b/lobject.c @@ -50,22 +50,22 @@ int luaO_ceillog2 (unsigned int x) { } /* -** Encodes 'p'% as a floating-point byte, represented as (eeeeexxx). +** Encodes 'p'% as a floating-point byte, represented as (eeeexxxx). ** The exponent is represented using excess-7. Mimicking IEEE 754, the ** representation normalizes the number when possible, assuming an extra -** 1 before the mantissa (xxx) and adding one to the exponent (eeeeexxx) -** to signal that. So, the real value is (1xxx) * 2^(eeeee - 8) if -** eeeee != 0, and (xxx) * 2^-7 otherwise. +** 1 before the mantissa (xxxx) and adding one to the exponent (eeee) +** to signal that. So, the real value is (1xxxx) * 2^(eeee - 7 - 1) if +** eeee != 0, and (xxxx) * 2^-7 otherwise (subnormal numbers). */ unsigned int luaO_codeparam (unsigned int p) { - if (p >= (cast(lu_mem, 0xF) << 0xF) / 128 * 100) /* overflow? */ + if (p >= (cast(lu_mem, 0x1F) << (0xF - 7 - 1)) * 100u) /* overflow? */ return 0xFF; /* return maximum value */ else { - p = (p * 128u) / 100; - if (p <= 0xF) - return p; + p = (cast(l_uint32, p) * 128 + 99) / 100; /* round up the division */ + if (p < 0x10) /* subnormal number? */ + return p; /* exponent bits are already zero; nothing else to do */ else { - int log = luaO_ceillog2(p + 1) - 5; + int log = luaO_ceillog2(p + 1) - 5; /* preserve 5 bits */ return ((p >> log) - 0x10) | ((log + 1) << 4); } } diff --git a/lobject.h b/lobject.h @@ -427,8 +427,8 @@ typedef struct TString { ** Get string and length */ #define getlstr(ts, len) \ (strisshr(ts) \ - ? (cast_void(len = (ts)->shrlen), rawgetshrstr(ts)) \ - : (cast_void(len = (ts)->u.lnglen), (ts)->contents)) + ? (cast_void((len) = (ts)->shrlen), rawgetshrstr(ts)) \ + : (cast_void((len) = (ts)->u.lnglen), (ts)->contents)) /* }================================================================== */ diff --git a/manual/manual.of b/manual/manual.of @@ -666,18 +666,6 @@ A value of 200 means that the collector waits for the total number of objects to double before starting a new cycle. The default value is 300; the maximum value is 1000. -The garbage-collector step multiplier -controls the speed of the collector relative to -object creation, -that is, -how many objects it marks or sweeps for each object created. -Larger values make the collector more aggressive. -Beware that values too small can -make the collector too slow to ever finish a cycle. -The default value is 200; the maximum value is 1000. -As a special case, a zero value means unlimited work, -effectively producing a non-incremental, stop-the-world collector. - The garbage-collector step size controls the size of each incremental step, specifically how many objects the interpreter creates @@ -686,6 +674,17 @@ A value of @M{n} means the interpreter will create approximately @M{n} objects between steps. The default value is 250. +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. +Larger values make the collector more aggressive. +Beware that values too small can +make the collector too slow to ever finish a cycle. +The default value is 200; the maximum value is 1000. +As a special case, a zero value means unlimited work, +effectively producing a non-incremental, stop-the-world collector. + } @sect3{genmode| @title{Generational Garbage Collection} @@ -707,11 +706,12 @@ 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 -grows @M{x%} larger than the number in use just after the last collection. +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 gets 20% larger than the total after the last major collection. -The default value is 20. +The default value is 25. The minor-major multiplier controls the shift to major collections. For a multiplier @M{x}, @@ -728,11 +728,10 @@ 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. - In particular, for a multiplier of 0, the collector will immediately shift back to minor collections after doing one cycle of major collections. -The default value is 80. +The default value is 50. } @@ -3327,7 +3326,7 @@ Returns the remainder of dividing the current amount of bytes of memory in use by Lua by 1024. } -@item{@defid{LUA_GCSTEP}| +@item{@defid{LUA_GCSTEP} (int n)| Performs a step of garbage collection. } @@ -3686,9 +3685,12 @@ Moreover, for a fixed buffer, the reader function should return the entire chunk in the first read. (As an example, @Lid{luaL_loadbufferx} does that.) -@id{lua_load} uses the stack internally, -so the reader function must always leave the stack -unmodified when returning. +The function @Lid{lua_load} fully preserves the Lua stack +through the calls to the reader function, +except that it may push some values for internal use +before the first call, +and it restores the stack size to its original size plus one +(for the pushed result) after the last call. @id{lua_load} can return @Lid{LUA_OK}, @Lid{LUA_ERRSYNTAX}, or @Lid{LUA_ERRMEM}. @@ -6344,13 +6346,24 @@ gives the exact number of bytes in use by Lua. @item{@St{step}| 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. +If the size is zero, +the collector performs a basic step. In incremental mode, -that step corresponds to the current step size; -the function returns @true if the step finished a collection cycle. +a basic step corresponds to the current step size. In generational mode, -the step performs a full minor collection or +a basic step performs a full minor collection or a major collection, -if the collector has scheduled one; +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. } @@ -6382,13 +6395,9 @@ The argument @id{param} must have one of the following values: @item{@St{stepmul}| The step multiplier. } @item{@St{stepsize}| The step size. } } -To be able to divide by 100 -(as most parameters are given as percentages) -without using floating-point arithmetic, -Lua stores these parameters encoded. -This encoding approximates the real value; +Lua rounds these values before storing them; so, the value returned as the previous value may not be -equal to the last value set. +exactly the last value set. } } diff --git a/testes/files.lua b/testes/files.lua @@ -74,6 +74,8 @@ io.input(io.stdin); io.output(io.stdout); os.remove(file) assert(not loadfile(file)) +-- Lua code cannot use chunks with fixed buffers +checkerr("invalid mode", load, "", "", "B") checkerr("", dofile, file) assert(not io.open(file)) io.output(file) diff --git a/testes/gc.lua b/testes/gc.lua @@ -35,7 +35,7 @@ do collectgarbage("setparam", "pause", t[i]) for j = 1, #t do collectgarbage("setparam", "stepmul", t[j]) - collectgarbage("step") + collectgarbage("step", t[j]) end end -- restore original parameters @@ -45,6 +45,33 @@ do end +-- +-- test the "size" of basic GC steps (whatever they mean...) +-- +do print("steps") + + local function dosteps (siz) + collectgarbage() + local a = {} + for i=1,100 do a[i] = {{}}; local b = {} end + local x = gcinfo() + local i = 0 + repeat -- do steps until it completes a collection cycle + i = i+1 + until collectgarbage("step", siz) + assert(gcinfo() < x) + return i -- number of steps + end + + collectgarbage"stop" + + if not _port then + assert(dosteps(10) < dosteps(2)) + end + +end + + _G["while"] = 234