aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2012-05-20 17:36:44 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2012-05-20 17:36:44 -0300
commit2a66b34f720cdfb34e3455eb3dbc7fb8aa931981 (patch)
tree421a4e68a69f68a1e841680115874cb70b1e2775
parent8d0e1ed52f4e5a4368343d3807140397176b577e (diff)
downloadlua-2a66b34f720cdfb34e3455eb3dbc7fb8aa931981.tar.gz
lua-2a66b34f720cdfb34e3455eb3dbc7fb8aa931981.tar.bz2
lua-2a66b34f720cdfb34e3455eb3dbc7fb8aa931981.zip
revamp of the GC pace control; more like 5.1: any X Kbytes allocated
makes the GC handle f(X) Kbytes of objects
-rw-r--r--lgc.c213
-rw-r--r--lstate.h4
2 files changed, 120 insertions, 97 deletions
diff --git a/lgc.c b/lgc.c
index ef8646c7..219d86d9 100644
--- a/lgc.c
+++ b/lgc.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lgc.c,v 2.121 2012/05/11 19:22:33 roberto Exp roberto $ 2** $Id: lgc.c,v 2.122 2012/05/14 17:52:56 roberto Exp roberto $
3** Garbage Collector 3** Garbage Collector
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -25,33 +25,36 @@
25 25
26 26
27/* how much to allocate before next GC step */ 27/* how much to allocate before next GC step */
28#define GCSTEPSIZE 1024 28#define GCSTEPSIZE (cast_int(256 * sizeof(void*)))
29 29
30/* maximum number of elements to sweep in each single step */ 30/* cost of sweeping one element (half the size of a small object) */
31#define GCSWEEPMAX 40 31#define GCSWEEPCOST ((sizeof(TString) + 2) / 2)
32 32
33/* cost of sweeping one element */ 33/* maximum number of elements to sweep in each single step */
34#define GCSWEEPCOST 1 34#define GCSWEEPMAX (cast_int((GCSTEPSIZE / GCSWEEPCOST) / 4))
35 35
36/* maximum number of finalizers to call in each GC step */ 36/* maximum number of finalizers to call in each GC step */
37#define GCFINALIZENUM 4 37#define GCFINALIZENUM 4
38 38
39/* cost of marking the root set */ 39/* (arbitrary) cost of atomic step */
40#define GCROOTCOST 10 40#define GCATOMICCOST GCSTEPSIZE
41
42/* cost of atomic step */
43#define GCATOMICCOST 1000
44 41
45/* basic cost to traverse one object (to be added to the links the
46 object may have) */
47#define TRAVCOST 5
48 42
43/*
44** macro to apply the "speed" of the garbage collector: the constant
45** 80 makes the standard 'stepmul' of 200 results in the GC handling
46** 80/200 = 1/2.5 = 0.4Kbytes for every 1Kb allocated.
47** (The computation tries to avoid overflows or underflows.)
48*/
49#define workrate(x,mul) \
50 ((x) < MAX_INT/80 ? ((x) * 80) / mul : ((x) / mul) * 80)
49 51
50/* 52/*
51** standard negative debt for GC; a reasonable "time" to wait before 53** standard negative debt for GC; a reasonable "time" to wait before
52** starting a new cycle 54** starting a new cycle
53*/ 55*/
54#define stddebt(g) (-cast(l_mem, gettotalbytes(g)/100) * g->gcpause) 56#define stddebtest(g,e) (-cast(l_mem, (e)/100) * g->gcpause)
57#define stddebt(g) stddebtest(g, gettotalbytes(g))
55 58
56 59
57/* 60/*
@@ -244,53 +247,57 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz, GCObject **list,
244** upvalues are already linked in 'headuv' list.) 247** upvalues are already linked in 'headuv' list.)
245*/ 248*/
246static void reallymarkobject (global_State *g, GCObject *o) { 249static void reallymarkobject (global_State *g, GCObject *o) {
250 lu_mem size;
247 white2gray(o); 251 white2gray(o);
248 switch (gch(o)->tt) { 252 switch (gch(o)->tt) {
249 case LUA_TSHRSTR: 253 case LUA_TSHRSTR:
250 case LUA_TLNGSTR: { 254 case LUA_TLNGSTR: {
251 gray2black(o); 255 size = sizestring(gco2ts(o));
252 return; /* nothing else to mark */ 256 break; /* nothing else to mark; make it black */
253 } 257 }
254 case LUA_TUSERDATA: { 258 case LUA_TUSERDATA: {
255 Table *mt = gco2u(o)->metatable; 259 Table *mt = gco2u(o)->metatable;
256 markobject(g, mt); 260 markobject(g, mt);
257 markobject(g, gco2u(o)->env); 261 markobject(g, gco2u(o)->env);
258 gray2black(o); /* all pointers marked */ 262 size = sizeudata(gco2u(o));
259 return; 263 break;
260 } 264 }
261 case LUA_TUPVAL: { 265 case LUA_TUPVAL: {
262 UpVal *uv = gco2uv(o); 266 UpVal *uv = gco2uv(o);
263 markvalue(g, uv->v); 267 markvalue(g, uv->v);
264 if (uv->v == &uv->u.value) /* closed? (open upvalues remain gray) */ 268 if (uv->v != &uv->u.value) /* open? */
265 gray2black(o); /* make it black */ 269 return; /* open upvalues remain gray */
266 return; 270 size = sizeof(UpVal);
271 break;
267 } 272 }
268 case LUA_TLCL: { 273 case LUA_TLCL: {
269 gco2lcl(o)->gclist = g->gray; 274 gco2lcl(o)->gclist = g->gray;
270 g->gray = o; 275 g->gray = o;
271 break; 276 return;
272 } 277 }
273 case LUA_TCCL: { 278 case LUA_TCCL: {
274 gco2ccl(o)->gclist = g->gray; 279 gco2ccl(o)->gclist = g->gray;
275 g->gray = o; 280 g->gray = o;
276 break; 281 return;
277 } 282 }
278 case LUA_TTABLE: { 283 case LUA_TTABLE: {
279 linktable(gco2t(o), &g->gray); 284 linktable(gco2t(o), &g->gray);
280 break; 285 return;
281 } 286 }
282 case LUA_TTHREAD: { 287 case LUA_TTHREAD: {
283 gco2th(o)->gclist = g->gray; 288 gco2th(o)->gclist = g->gray;
284 g->gray = o; 289 g->gray = o;
285 break; 290 return;
286 } 291 }
287 case LUA_TPROTO: { 292 case LUA_TPROTO: {
288 gco2p(o)->gclist = g->gray; 293 gco2p(o)->gclist = g->gray;
289 g->gray = o; 294 g->gray = o;
290 break; 295 return;
291 } 296 }
292 default: lua_assert(0); 297 default: lua_assert(0); return;
293 } 298 }
299 gray2black(o);
300 g->GCmemtrav += size;
294} 301}
295 302
296 303
@@ -430,30 +437,26 @@ static void traversestrongtable (global_State *g, Table *h) {
430} 437}
431 438
432 439
433static int traversetable (global_State *g, Table *h) { 440static lu_mem traversetable (global_State *g, Table *h) {
441 char *weakkey, *weakvalue;
434 const TValue *mode = gfasttm(g, h->metatable, TM_MODE); 442 const TValue *mode = gfasttm(g, h->metatable, TM_MODE);
435 markobject(g, h->metatable); 443 markobject(g, h->metatable);
436 if (mode && ttisstring(mode)) { /* is there a weak mode? */ 444 if (mode && ttisstring(mode) && /* is there a weak mode? */
437 int weakkey = (strchr(svalue(mode), 'k') != NULL); 445 ((weakkey = strchr(svalue(mode), 'k')),
438 int weakvalue = (strchr(svalue(mode), 'v') != NULL); 446 (weakvalue = strchr(svalue(mode), 'v')),
439 if (weakkey || weakvalue) { /* is really weak? */ 447 (weakkey || weakvalue))) { /* is really weak? */
440 black2gray(obj2gco(h)); /* keep table gray */ 448 black2gray(obj2gco(h)); /* keep table gray */
441 if (!weakkey) { /* strong keys? */ 449 if (!weakkey) /* strong keys? */
442 traverseweakvalue(g, h); 450 traverseweakvalue(g, h);
443 return TRAVCOST + sizenode(h); 451 else if (!weakvalue) /* strong values? */
444 } 452 traverseephemeron(g, h);
445 else if (!weakvalue) { /* strong values? */ 453 else /* all weak */
446 traverseephemeron(g, h); 454 linktable(h, &g->allweak); /* nothing to traverse now */
447 return TRAVCOST + h->sizearray + sizenode(h);
448 }
449 else {
450 linktable(h, &g->allweak); /* nothing to traverse now */
451 return TRAVCOST;
452 }
453 } /* else go through */
454 } 455 }
455 traversestrongtable(g, h); 456 else /* not weak */
456 return TRAVCOST + h->sizearray + (2 * sizenode(h)); 457 traversestrongtable(g, h);
458 return sizeof(Table) + sizeof(TValue) * h->sizearray +
459 sizeof(Node) * sizenode(h);
457} 460}
458 461
459 462
@@ -470,81 +473,92 @@ static int traverseproto (global_State *g, Proto *f) {
470 markobject(g, f->p[i]); 473 markobject(g, f->p[i]);
471 for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */ 474 for (i = 0; i < f->sizelocvars; i++) /* mark local-variable names */
472 markobject(g, f->locvars[i].varname); 475 markobject(g, f->locvars[i].varname);
473 return TRAVCOST + f->sizek + f->sizeupvalues + f->sizep + f->sizelocvars; 476 return sizeof(Proto) + sizeof(Instruction) * f->sizecode +
477 sizeof(Proto *) * f->sizep +
478 sizeof(TValue) * f->sizek +
479 sizeof(int) * f->sizelineinfo +
480 sizeof(LocVar) * f->sizelocvars +
481 sizeof(Upvaldesc) * f->sizeupvalues;
474} 482}
475 483
476 484
477static int traverseCclosure (global_State *g, CClosure *cl) { 485static lu_mem traverseCclosure (global_State *g, CClosure *cl) {
478 int i; 486 int i;
479 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ 487 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
480 markvalue(g, &cl->upvalue[i]); 488 markvalue(g, &cl->upvalue[i]);
481 return TRAVCOST + cl->nupvalues; 489 return sizeCclosure(cl->nupvalues);
482} 490}
483 491
484static int traverseLclosure (global_State *g, LClosure *cl) { 492static lu_mem traverseLclosure (global_State *g, LClosure *cl) {
485 int i; 493 int i;
486 markobject(g, cl->p); /* mark its prototype */ 494 markobject(g, cl->p); /* mark its prototype */
487 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */ 495 for (i = 0; i < cl->nupvalues; i++) /* mark its upvalues */
488 markobject(g, cl->upvals[i]); 496 markobject(g, cl->upvals[i]);
489 return TRAVCOST + cl->nupvalues; 497 return sizeLclosure(cl->nupvalues);
490} 498}
491 499
492 500
493static int traversestack (global_State *g, lua_State *L) { 501static lu_mem traversestack (global_State *g, lua_State *th) {
494 StkId o = L->stack; 502 StkId o = th->stack;
495 if (o == NULL) 503 if (o == NULL)
496 return 1; /* stack not completely built yet */ 504 return 1; /* stack not completely built yet */
497 for (; o < L->top; o++) 505 for (; o < th->top; o++)
498 markvalue(g, o); 506 markvalue(g, o);
499 if (g->gcstate == GCSatomic) { /* final traversal? */ 507 if (g->gcstate == GCSatomic) { /* final traversal? */
500 StkId lim = L->stack + L->stacksize; /* real end of stack */ 508 StkId lim = th->stack + th->stacksize; /* real end of stack */
501 for (; o < lim; o++) /* clear not-marked stack slice */ 509 for (; o < lim; o++) /* clear not-marked stack slice */
502 setnilvalue(o); 510 setnilvalue(o);
503 } 511 }
504 return TRAVCOST + cast_int(o - L->stack); 512 return sizeof(lua_State) + sizeof(TValue) * th->stacksize;
505} 513}
506 514
507 515
508/* 516/*
509** traverse one gray object, turning it to black (except for threads, 517** traverse one gray object, turning it to black (except for threads,
510** which are always gray). 518** which are always gray).
511** Returns number of values traversed.
512*/ 519*/
513static int propagatemark (global_State *g) { 520static void propagatemark (global_State *g) {
521 lu_mem size;
514 GCObject *o = g->gray; 522 GCObject *o = g->gray;
515 lua_assert(isgray(o)); 523 lua_assert(isgray(o));
516 gray2black(o); 524 gray2black(o);
517 switch (gch(o)->tt) { 525 switch (gch(o)->tt) {
518 case LUA_TTABLE: { 526 case LUA_TTABLE: {
519 Table *h = gco2t(o); 527 Table *h = gco2t(o);
520 g->gray = h->gclist; 528 g->gray = h->gclist; /* remove from 'gray' list */
521 return traversetable(g, h); 529 size = traversetable(g, h);
530 break;
522 } 531 }
523 case LUA_TLCL: { 532 case LUA_TLCL: {
524 LClosure *cl = gco2lcl(o); 533 LClosure *cl = gco2lcl(o);
525 g->gray = cl->gclist; 534 g->gray = cl->gclist; /* remove from 'gray' list */
526 return traverseLclosure(g, cl); 535 size = traverseLclosure(g, cl);
536 break;
527 } 537 }
528 case LUA_TCCL: { 538 case LUA_TCCL: {
529 CClosure *cl = gco2ccl(o); 539 CClosure *cl = gco2ccl(o);
530 g->gray = cl->gclist; 540 g->gray = cl->gclist; /* remove from 'gray' list */
531 return traverseCclosure(g, cl); 541 size = traverseCclosure(g, cl);
542 break;
532 } 543 }
533 case LUA_TTHREAD: { 544 case LUA_TTHREAD: {
534 lua_State *th = gco2th(o); 545 lua_State *th = gco2th(o);
535 g->gray = th->gclist; 546 g->gray = th->gclist; /* remove from 'gray' list */
536 th->gclist = g->grayagain; 547 th->gclist = g->grayagain;
537 g->grayagain = o; 548 g->grayagain = o; /* insert into 'grayagain' list */
538 black2gray(o); 549 black2gray(o);
539 return traversestack(g, th); 550 size = traversestack(g, th);
551 break;
540 } 552 }
541 case LUA_TPROTO: { 553 case LUA_TPROTO: {
542 Proto *p = gco2p(o); 554 Proto *p = gco2p(o);
543 g->gray = p->gclist; 555 g->gray = p->gclist; /* remove from 'gray' list */
544 return traverseproto(g, p); 556 size = traverseproto(g, p);
557 break;
545 } 558 }
546 default: lua_assert(0); return 0; 559 default: lua_assert(0); return;
547 } 560 }
561 g->GCmemtrav += size;
548} 562}
549 563
550 564
@@ -706,7 +720,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
706 int ow = otherwhite(g); 720 int ow = otherwhite(g);
707 int toclear, toset; /* bits to clear and to set in all live objects */ 721 int toclear, toset; /* bits to clear and to set in all live objects */
708 int tostop; /* stop sweep when this is true */ 722 int tostop; /* stop sweep when this is true */
709 l_mem debt = g->GCdebt; /* current debt */
710 if (isgenerational(g)) { /* generational mode? */ 723 if (isgenerational(g)) { /* generational mode? */
711 toclear = ~0; /* clear nothing */ 724 toclear = ~0; /* clear nothing */
712 toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */ 725 toset = bitmask(OLDBIT); /* set the old bit of all surviving objects */
@@ -737,7 +750,6 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) {
737 p = &gch(curr)->next; /* go to next element */ 750 p = &gch(curr)->next; /* go to next element */
738 } 751 }
739 } 752 }
740 luaE_setdebt(g, debt); /* sweeping should not change debt */
741 return p; 753 return p;
742} 754}
743 755
@@ -960,37 +972,42 @@ static void atomic (lua_State *L) {
960} 972}
961 973
962 974
963static l_mem singlestep (lua_State *L) { 975static lu_mem singlestep (lua_State *L) {
964 global_State *g = G(L); 976 global_State *g = G(L);
965 switch (g->gcstate) { 977 switch (g->gcstate) {
966 case GCSpause: { 978 case GCSpause: {
979 g->GCmemtrav = 0; /* start to count memory traversed */
967 if (!isgenerational(g)) 980 if (!isgenerational(g))
968 markroot(g); /* start a new collection */ 981 markroot(g); /* start a new collection */
969 /* in any case, root must be marked */ 982 /* in any case, root must be marked at this point */
970 lua_assert(!iswhite(obj2gco(g->mainthread)) 983 lua_assert(!iswhite(obj2gco(g->mainthread))
971 && !iswhite(gcvalue(&g->l_registry))); 984 && !iswhite(gcvalue(&g->l_registry)));
972 g->gcstate = GCSpropagate; 985 g->gcstate = GCSpropagate;
973 return GCROOTCOST; 986 return g->GCmemtrav;
974 } 987 }
975 case GCSpropagate: { 988 case GCSpropagate: {
976 if (g->gray) 989 if (g->gray) {
977 return propagatemark(g); 990 lu_mem oldtrav = g->GCmemtrav;
991 propagatemark(g);
992 return g->GCmemtrav - oldtrav; /* memory traversed in this step */
993 }
978 else { /* no more `gray' objects */ 994 else { /* no more `gray' objects */
979 g->gcstate = GCSatomic; /* finish mark phase */ 995 g->gcstate = GCSatomic; /* finish mark phase */
996 g->estimate = g->GCmemtrav; /* save what was counted */
980 atomic(L); 997 atomic(L);
981 return GCATOMICCOST; 998 return GCATOMICCOST;
982 } 999 }
983 } 1000 }
984 case GCSsweepstring: { 1001 case GCSsweepstring: {
985 if (g->sweepstrgc < g->strt.size) { 1002 int i;
986 sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]); 1003 for (i = 0; i < GCSWEEPMAX && g->sweepstrgc + i < g->strt.size; i++)
987 return GCSWEEPCOST; 1004 sweepwholelist(L, &g->strt.hash[g->sweepstrgc + i]);
988 } 1005 g->sweepstrgc += i;
989 else { /* no more strings to sweep */ 1006 if (g->sweepstrgc >= g->strt.size) { /* no more strings to sweep? */
990 g->sweepgc = &g->finobj; /* prepare to sweep finalizable objects */ 1007 g->sweepgc = &g->finobj; /* prepare to sweep finalizable objects */
991 g->gcstate = GCSsweepudata; 1008 g->gcstate = GCSsweepudata;
992 return 0;
993 } 1009 }
1010 return i * GCSWEEPCOST;
994 } 1011 }
995 case GCSsweepudata: { 1012 case GCSsweepudata: {
996 if (*g->sweepgc) { 1013 if (*g->sweepgc) {
@@ -1000,7 +1017,7 @@ static l_mem singlestep (lua_State *L) {
1000 else { 1017 else {
1001 g->sweepgc = &g->allgc; /* go to next phase */ 1018 g->sweepgc = &g->allgc; /* go to next phase */
1002 g->gcstate = GCSsweep; 1019 g->gcstate = GCSsweep;
1003 return GCSWEEPCOST; 1020 return 0;
1004 } 1021 }
1005 } 1022 }
1006 case GCSsweep: { 1023 case GCSsweep: {
@@ -1051,14 +1068,17 @@ static void generationalcollection (lua_State *L) {
1051 1068
1052static void step (lua_State *L) { 1069static void step (lua_State *L) {
1053 global_State *g = G(L); 1070 global_State *g = G(L);
1054 l_mem lim = g->gcstepmul; /* how much to work */ 1071 l_mem debt = g->GCdebt;
1072 int stepmul = g->gcstepmul;
1073 if (stepmul <= 0) stepmul = 1;
1055 do { /* always perform at least one single step */ 1074 do { /* always perform at least one single step */
1056 lim -= singlestep(L); 1075 lu_mem work = singlestep(L); /* do some work */
1057 } while (lim > 0 && g->gcstate != GCSpause); 1076 work = workrate(work, stepmul); /* apply work rate */
1058 if (g->gcstate != GCSpause) 1077 debt -= work;
1059 luaE_setdebt(g, g->GCdebt - GCSTEPSIZE); 1078 } while (debt > -GCSTEPSIZE && g->gcstate != GCSpause);
1060 else 1079 if (g->gcstate == GCSpause)
1061 luaE_setdebt(g, stddebt(g)); 1080 debt = stddebtest(g, g->estimate); /* pause until next cycle */
1081 luaE_setdebt(g, debt);
1062} 1082}
1063 1083
1064 1084
@@ -1070,8 +1090,9 @@ void luaC_step (lua_State *L) {
1070 int i; 1090 int i;
1071 if (isgenerational(g)) generationalcollection(L); 1091 if (isgenerational(g)) generationalcollection(L);
1072 else step(L); 1092 else step(L);
1073 for (i = 0; i < GCFINALIZENUM && g->tobefnz; i++) 1093 /* run a few finalizers (or all of them at the end of a collect cycle) */
1074 GCTM(L, 1); /* Call a few pending finalizers */ 1094 for (i = 0; g->tobefnz && (i < GCFINALIZENUM || g->gcstate == GCSpause); i++)
1095 GCTM(L, 1); /* call one finalizer */
1075} 1096}
1076 1097
1077 1098
diff --git a/lstate.h b/lstate.h
index f6c093b3..85359fe3 100644
--- a/lstate.h
+++ b/lstate.h
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lstate.h,v 2.76 2012/01/25 21:05:40 roberto Exp roberto $ 2** $Id: lstate.h,v 2.77 2012/02/01 21:57:15 roberto Exp roberto $
3** Global State 3** Global State
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -113,7 +113,9 @@ typedef struct global_State {
113 void *ud; /* auxiliary data to `frealloc' */ 113 void *ud; /* auxiliary data to `frealloc' */
114 lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */ 114 lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
115 l_mem GCdebt; /* bytes allocated not yet compensated by the collector */ 115 l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
116 lu_mem GCmemtrav; /* memory traversed by the GC */
116 lu_mem lastmajormem; /* memory in use after last major collection */ 117 lu_mem lastmajormem; /* memory in use after last major collection */
118 lu_mem estimate;
117 stringtable strt; /* hash table for strings */ 119 stringtable strt; /* hash table for strings */
118 TValue l_registry; 120 TValue l_registry;
119 unsigned int seed; /* randomized seed for hashes */ 121 unsigned int seed; /* randomized seed for hashes */