aboutsummaryrefslogtreecommitdiff
path: root/lgc.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-01-30 11:44:42 -0200
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2019-01-30 11:44:42 -0200
commit2c32bff60987d38a60a58d4f0123f3783da60a63 (patch)
treedd97348ac388dd6087c320994bdce6ff18be02e2 /lgc.c
parent264659bd53e92969a1e17d65c0266597cde24b5d (diff)
downloadlua-2c32bff60987d38a60a58d4f0123f3783da60a63.tar.gz
lua-2c32bff60987d38a60a58d4f0123f3783da60a63.tar.bz2
lua-2c32bff60987d38a60a58d4f0123f3783da60a63.zip
After a "bad collections", avoid switching back back to generational
After a major bad collection (one that collects too few objects), next collection will be major again. In that case, avoid switching back to generational mode (as it will have to switch again to incremental to do next major collection).
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