aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
Diffstat (limited to 'lgc.c')
-rw-r--r--lgc.c158
1 files changed, 114 insertions, 44 deletions
diff --git a/lgc.c b/lgc.c
index 0c3386e7..bf0460d5 100644
--- a/lgc.c
+++ b/lgc.c
@@ -101,6 +101,7 @@
101 101
102static void reallymarkobject (global_State *g, GCObject *o); 102static void reallymarkobject (global_State *g, GCObject *o);
103static lu_mem atomic (lua_State *L); 103static lu_mem atomic (lua_State *L);
104static void entersweep (lua_State *L);
104 105
105 106
106/* 107/*
@@ -1162,15 +1163,7 @@ static void youngcollection (lua_State *L, global_State *g) {
1162} 1163}
1163 1164
1164 1165
1165/* 1166static void atomic2gen (lua_State *L, global_State *g) {
1166** Enter generational mode. Must go until the end of an atomic cycle
1167** to ensure that all threads are in the gray list. Then, turn all
1168** objects into old and finishes the collection.
1169*/
1170static void entergen (lua_State *L, global_State *g) {
1171 luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */
1172 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
1173 atomic(L);
1174 /* sweep all elements making them old */ 1167 /* sweep all elements making them old */
1175 sweep2old(L, &g->allgc); 1168 sweep2old(L, &g->allgc);
1176 /* everything alive now is old */ 1169 /* everything alive now is old */
@@ -1183,15 +1176,31 @@ static void entergen (lua_State *L, global_State *g) {
1183 sweep2old(L, &g->tobefnz); 1176 sweep2old(L, &g->tobefnz);
1184 1177
1185 g->gckind = KGC_GEN; 1178 g->gckind = KGC_GEN;
1179 g->lastatomic = 0;
1186 g->GCestimate = gettotalbytes(g); /* base for memory control */ 1180 g->GCestimate = gettotalbytes(g); /* base for memory control */
1187 finishgencycle(L, g); 1181 finishgencycle(L, g);
1188} 1182}
1189 1183
1190 1184
1191/* 1185/*
1186** Enter generational mode. Must go until the end of an atomic cycle
1187** to ensure that all threads and weak tables are in the gray lists.
1188** Then, turn all objects into old and finishes the collection.
1189*/
1190static lu_mem entergen (lua_State *L, global_State *g) {
1191 lu_mem numobjs;
1192 luaC_runtilstate(L, bitmask(GCSpause)); /* prepare to start a new cycle */
1193 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
1194 numobjs = atomic(L); /* propagates all and then do the atomic stuff */
1195 atomic2gen(L, g);
1196 return numobjs;
1197}
1198
1199
1200/*
1192** Enter incremental mode. Turn all objects white, make all 1201** Enter incremental mode. Turn all objects white, make all
1193** intermediate lists point to NULL (to avoid invalid pointers), 1202** intermediate lists point to NULL (to avoid invalid pointers),
1194** and go to pause state. 1203** and go to the pause state.
1195*/ 1204*/
1196static void enterinc (global_State *g) { 1205static void enterinc (global_State *g) {
1197 whitelist(g, g->allgc); 1206 whitelist(g, g->allgc);
@@ -1201,6 +1210,7 @@ static void enterinc (global_State *g) {
1201 g->finobjrold = g->finobjold = g->finobjsur = NULL; 1210 g->finobjrold = g->finobjold = g->finobjsur = NULL;
1202 g->gcstate = GCSpause; 1211 g->gcstate = GCSpause;
1203 g->gckind = KGC_INC; 1212 g->gckind = KGC_INC;
1213 g->lastatomic = 0;
1204} 1214}
1205 1215
1206 1216
@@ -1215,54 +1225,114 @@ void luaC_changemode (lua_State *L, int newmode) {
1215 else 1225 else
1216 enterinc(g); /* entering incremental mode */ 1226 enterinc(g); /* entering incremental mode */
1217 } 1227 }
1228 g->lastatomic = 0;
1218} 1229}
1219 1230
1220 1231
1221/* 1232/*
1222** Does a full collection in generational mode. 1233** Does a full collection in generational mode.
1223*/ 1234*/
1224static void fullgen (lua_State *L, global_State *g) { 1235static lu_mem fullgen (lua_State *L, global_State *g) {
1225 enterinc(g); 1236 enterinc(g);
1226 entergen(L, g); 1237 return entergen(L, g);
1238}
1239
1240
1241/*
1242** Set debt for the next minor collection, which will happen when
1243** memory grows 'genminormul'%.
1244*/
1245static void setminordebt (global_State *g) {
1246 luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
1227} 1247}
1228 1248
1229 1249
1230/* 1250/*
1231** Does a generational "step". If memory grows 'genmajormul'% larger 1251** Does a major collection after last collection was a "bad collection".
1232** than last major collection (kept in 'g->GCestimate'), does a major 1252**
1233** collection. Otherwise, does a minor collection and set debt to make 1253** When the program is building a big struture, it allocates lots of
1234** another collection when memory grows 'genminormul'% larger. 1254** memory but generates very little garbage. In those scenarios,
1235** When it does a major collection, it then checks whether it could 1255** the generational mode just wastes time doing small collections, and
1236** reclaim at least ?? memory. If not, it sets a long pause for the 1256** major collections are frequently what we call a "bad collection", a
1237** next collection. (Therefore, the next collection will be a major 1257** collection that frees too few objects. To avoid the cost of switching
1238** one, too.) 1258** between generational mode and the incremental mode needed for full
1259** (major) collections, the collector tries to stay in incremental mode
1260** after a bad collection, and to switch back to generational mode only
1261** after a "good" collection (one that traverses less than 9/8 objects
1262** of the previous one).
1263** The collector must choose whether to stay in incremental mode or to
1264** switch back to generational mode before sweeping. At this point, it
1265** does not know the real memory in use, so it cannot use memory to
1266** decide whether to return to generational mode. Instead, it uses the
1267** number of objects traversed (returned by 'atomic') as a proxy. The
1268** field 'g->lastatomic' keeps this count from the last collection.
1269** ('g->lastatomic != 0' also means that the last collection was bad.)
1270*/
1271static void stepgenfull (lua_State *L, global_State *g) {
1272 lu_mem newatomic; /* count of traversed objects */
1273 lu_mem lastatomic = g->lastatomic; /* count from last collection */
1274 if (g->gckind == KGC_GEN) /* still in generational mode? */
1275 enterinc(g); /* enter incremental mode */
1276 luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
1277 newatomic = atomic(L); /* mark everybody */
1278 if (newatomic < lastatomic + (lastatomic >> 3)) { /* good collection? */
1279 atomic2gen(L, g); /* return to generational mode */
1280 setminordebt(g);
1281 }
1282 else { /* another bad collection; stay in incremental mode */
1283 g->GCestimate = gettotalbytes(g); /* first estimate */;
1284 entersweep(L);
1285 luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */
1286 setpause(g);
1287 g->lastatomic = newatomic;
1288 }
1289}
1290
1291
1292/*
1293** Does a generational "step".
1294** Usually, this means doing a minor collection and setting the debt to
1295** make another collection when memory grows 'genminormul'% larger.
1296**
1297** However, there are exceptions. If memory grows 'genmajormul'%
1298** larger than it was at the end of the last major collection (kept
1299** in 'g->GCestimate'), the function does a major collection. At the
1300** end, it checks whether the major collection was able to free a
1301** decent amount of memory (at least half the growth in memory since
1302** previous major collection). If so, the collector keeps its state,
1303** and the next collection will probably be minor again. Otherwise,
1304** we have what we call a "bad collection". In that case, set the field
1305** 'g->lastatomic' to signal that fact, so that the next collection will
1306** go to 'stepgenfull'.
1307**
1239** 'GCdebt <= 0' means an explicit call to GC step with "size" zero; 1308** 'GCdebt <= 0' means an explicit call to GC step with "size" zero;
1240** in that case, always do a minor collection. 1309** in that case, do a minor collection.
1241*/ 1310*/
1242static void genstep (lua_State *L, global_State *g) { 1311static void genstep (lua_State *L, global_State *g) {
1243 lu_mem majorbase = g->GCestimate; /* memory after last major collection */ 1312 if (g->lastatomic != 0) /* last collection was a bad one? */
1244 lu_mem majorinc = (majorbase / 100) * getgcparam(g->genmajormul); 1313 stepgenfull(L, g); /* do a full step */
1245 lu_mem memnew = gettotalbytes(g); 1314 else {
1246 if (g->GCdebt > 0 && memnew > majorbase + majorinc) { 1315 lu_mem majorbase = g->GCestimate; /* memory after last major collection */
1247 fullgen(L, g); 1316 lu_mem majorinc = (majorbase / 100) * getgcparam(g->genmajormul);
1248 memnew = gettotalbytes(g); 1317 if (g->GCdebt > 0 && gettotalbytes(g) > majorbase + majorinc) {
1249 if (memnew < majorbase + (majorinc / 2)) { 1318 lu_mem numobjs = fullgen(L, g); /* do a major collection */
1250 /* collected at least half of memory growth since last major 1319 if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
1251 collection; go back to minor collections */ 1320 /* collected at least half of memory growth since last major
1252 luaE_setdebt(g, -(cast(l_mem, (memnew / 100)) * g->genminormul)); 1321 collection; keep doing minor collections */
1322 setminordebt(g);
1323 }
1324 else { /* bad collection */
1325 g->lastatomic = numobjs; /* signal that last collection was bad */
1326 setpause(g); /* do a long wait for next (major) collection */
1327 }
1253 } 1328 }
1254 else { 1329 else { /* regular case; do a minor collection */
1255 /* memory seems to be growing; do a long wait for next (major) 1330 youngcollection(L, g);
1256 collection */ 1331 setminordebt(g);
1257 setpause(g); 1332 g->GCestimate = majorbase; /* preserve base value */
1258 } 1333 }
1259 } 1334 }
1260 else { 1335 lua_assert(isdecGCmodegen(g));
1261 youngcollection(L, g);
1262 memnew = gettotalbytes(g);
1263 luaE_setdebt(g, -(cast(l_mem, (memnew / 100)) * g->genminormul));
1264 g->GCestimate = majorbase; /* preserve base value */
1265 }
1266} 1336}
1267 1337
1268/* }====================================================== */ 1338/* }====================================================== */
@@ -1493,10 +1563,10 @@ static void incstep (lua_State *L, global_State *g) {
1493void luaC_step (lua_State *L) { 1563void luaC_step (lua_State *L) {
1494 global_State *g = G(L); 1564 global_State *g = G(L);
1495 if (g->gcrunning) { /* running? */ 1565 if (g->gcrunning) { /* running? */
1496 if (g->gckind == KGC_INC) 1566 if(isdecGCmodegen(g))
1497 incstep(L, g);
1498 else
1499 genstep(L, g); 1567 genstep(L, g);
1568 else
1569 incstep(L, g);
1500 } 1570 }
1501} 1571}
1502 1572