Przeglądaj źródła

Several tweaks in the garbage collector

- back with step size in collectgarbage("step")
- adjustments in defaults for some GC parameters
- adjustments in 'luaO_codeparam'
Roberto Ierusalimschy 1 rok temu
rodzic
commit
12b6f610b0
8 zmienionych plików z 98 dodań i 56 usunięć
  1. 12 6
      lapi.c
  2. 4 6
      lbaselib.c
  3. 2 2
      lgc.h
  4. 9 9
      lobject.c
  5. 2 2
      lobject.h
  6. 39 30
      manual/manual.of
  7. 2 0
      testes/files.lua
  8. 28 1
      testes/gc.lua

+ 12 - 6
lapi.c

@@ -416,10 +416,11 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) {
     luaC_checkGC(L);
     luaC_checkGC(L);
     o = index2value(L, idx);  /* previous call may reallocate the stack */
     o = index2value(L, idx);  /* previous call may reallocate the stack */
   }
   }
-  if (len != NULL)
-    *len = tsslen(tsvalue(o));
   lua_unlock(L);
   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: {
     case LUA_GCSTEP: {
       lu_byte oldstp = g->gcstp;
       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) */
       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 */
         res = 1;  /* signal it */
+      g->gcstp = oldstp;  /* restore previous state */
       break;
       break;
     }
     }
     case LUA_GCISRUNNING: {
     case LUA_GCISRUNNING: {

+ 4 - 6
lbaselib.c

@@ -213,7 +213,8 @@ static int luaB_collectgarbage (lua_State *L) {
       return 1;
       return 1;
     }
     }
     case LUA_GCSTEP: {
     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);
       checkvalres(res);
       lua_pushboolean(L, res);
       lua_pushboolean(L, res);
       return 1;
       return 1;
@@ -239,7 +240,7 @@ static int luaB_collectgarbage (lua_State *L) {
         LUA_GCPPAUSE, LUA_GCPSTEPMUL, LUA_GCPSTEPSIZE};
         LUA_GCPPAUSE, LUA_GCPSTEPMUL, LUA_GCPSTEPSIZE};
       int p = pnum[luaL_checkoption(L, 2, NULL, params)];
       int p = pnum[luaL_checkoption(L, 2, NULL, params)];
       lua_Integer value = luaL_checkinteger(L, 3);
       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;
       return 1;
     }
     }
     default: {
     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) {
 static const char *getmode (lua_State *L, int idx) {
   const char *mode = luaL_optstring(L, idx, "bt");
   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");
     luaL_argerror(L, idx, "invalid mode");
   return mode;
   return mode;
 }
 }

+ 2 - 2
lgc.h

@@ -171,13 +171,13 @@
 ** Major collections will shift to minor ones after a collection
 ** Major collections will shift to minor ones after a collection
 ** collects at least LUAI_MAJORMINOR% of the new objects.
 ** 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%
 ** A young (minor) collection will run after creating LUAI_GENMINORMUL%
 ** new objects.
 ** new objects.
 */
 */
-#define LUAI_GENMINORMUL         20
+#define LUAI_GENMINORMUL         25
 
 
 
 
 /* incremental */
 /* incremental */

+ 9 - 9
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
 ** The exponent is represented using excess-7. Mimicking IEEE 754, the
 ** representation normalizes the number when possible, assuming an extra
 ** 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) {
 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 */
     return 0xFF;  /* return maximum value */
   else {
   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 {
     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);
       return ((p >> log) - 0x10) | ((log + 1) << 4);
     }
     }
   }
   }

+ 2 - 2
lobject.h

@@ -427,8 +427,8 @@ typedef struct TString {
 ** Get string and length */
 ** Get string and length */
 #define getlstr(ts, len)  \
 #define getlstr(ts, len)  \
 	(strisshr(ts) \
 	(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))
 
 
 /* }================================================================== */
 /* }================================================================== */
 
 

+ 39 - 30
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 total number of objects to double before starting a new cycle.
 The default value is 300; the maximum value is 1000.
 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
 The garbage-collector step size controls the
 size of each incremental step,
 size of each incremental step,
 specifically how many objects the interpreter creates
 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.
 approximately @M{n} objects between steps.
 The default value is 250.
 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}
 @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.
 The minor multiplier controls the frequency of minor collections.
 For a minor multiplier @M{x},
 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 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,
 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 objects
 gets 20% larger than the total after the last major collection.
 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.
 The minor-major multiplier controls the shift to major collections.
 For a multiplier @M{x},
 For a multiplier @M{x},
@@ -728,11 +728,10 @@ For a multiplier @M{x},
 the collector will shift back to minor collections
 the collector will shift back to minor collections
 after a major collection collects at least @M{x%}
 after a major collection collects at least @M{x%}
 of the objects allocated during the last cycle.
 of the objects allocated during the last cycle.
-
 In particular, for a multiplier of 0,
 In particular, for a multiplier of 0,
 the collector will immediately shift back to minor collections
 the collector will immediately shift back to minor collections
 after doing one cycle of major 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.
 memory in use by Lua by 1024.
 }
 }
 
 
-@item{@defid{LUA_GCSTEP}|
+@item{@defid{LUA_GCSTEP} (int n)|
 Performs a step of garbage collection.
 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.
 the reader function should return the entire chunk in the first read.
 (As an example, @Lid{luaL_loadbufferx} does that.)
 (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
 @id{lua_load} can return
 @Lid{LUA_OK}, @Lid{LUA_ERRSYNTAX}, or @Lid{LUA_ERRMEM}.
 @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}|
 @item{@St{step}|
 Performs a garbage-collection 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,
 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,
 In generational mode,
-the step performs a full minor collection or
+a basic step performs a full minor collection or
 a major collection,
 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.
 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{stepmul}| The step multiplier. }
 @item{@St{stepsize}| The step size. }
 @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
 so, the value returned as the previous value may not be
-equal to the last value set.
+exactly the last value set.
 }
 }
 
 
 }
 }

+ 2 - 0
testes/files.lua

@@ -74,6 +74,8 @@ io.input(io.stdin); io.output(io.stdout);
 
 
 os.remove(file)
 os.remove(file)
 assert(not loadfile(file))
 assert(not loadfile(file))
+-- Lua code cannot use chunks with fixed buffers
+checkerr("invalid mode", load, "", "", "B")
 checkerr("", dofile, file)
 checkerr("", dofile, file)
 assert(not io.open(file))
 assert(not io.open(file))
 io.output(file)
 io.output(file)

+ 28 - 1
testes/gc.lua

@@ -35,7 +35,7 @@ do
     collectgarbage("setparam", "pause", t[i])
     collectgarbage("setparam", "pause", t[i])
     for j = 1, #t do
     for j = 1, #t do
       collectgarbage("setparam", "stepmul", t[j])
       collectgarbage("setparam", "stepmul", t[j])
-      collectgarbage("step")
+      collectgarbage("step", t[j])
     end
     end
   end
   end
   -- restore original parameters
   -- restore original parameters
@@ -45,6 +45,33 @@ do
 end
 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
 _G["while"] = 234