diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-03-22 15:28:03 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2010-03-22 15:28:03 -0300 |
commit | 74123e96869bdb55d3967036e2bc0c6f9e0550d6 (patch) | |
tree | 06b60d23fb253c8ff1c640f34e15424455737395 | |
parent | 9c196bebad4f84ffb43f0ef1e19792cc4b795704 (diff) | |
download | lua-74123e96869bdb55d3967036e2bc0c6f9e0550d6.tar.gz lua-74123e96869bdb55d3967036e2bc0c6f9e0550d6.tar.bz2 lua-74123e96869bdb55d3967036e2bc0c6f9e0550d6.zip |
draft version of a generational mode for garbage collection. (Not well
tested; no major collections; ...)
-rw-r--r-- | lapi.c | 8 | ||||
-rw-r--r-- | lbaselib.c | 6 | ||||
-rw-r--r-- | lgc.c | 81 | ||||
-rw-r--r-- | lstate.h | 7 | ||||
-rw-r--r-- | lua.h | 3 |
5 files changed, 70 insertions, 35 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lapi.c,v 2.113 2010/02/09 11:55:37 roberto Exp roberto $ | 2 | ** $Id: lapi.c,v 2.114 2010/03/08 16:55:52 roberto Exp roberto $ |
3 | ** Lua API | 3 | ** Lua API |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -928,6 +928,7 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { | |||
928 | break; | 928 | break; |
929 | } | 929 | } |
930 | case LUA_GCRESTART: { | 930 | case LUA_GCRESTART: { |
931 | g->gckind = KGC_NORMAL; | ||
931 | g->GCthreshold = g->totalbytes; | 932 | g->GCthreshold = g->totalbytes; |
932 | break; | 933 | break; |
933 | } | 934 | } |
@@ -973,6 +974,11 @@ LUA_API int lua_gc (lua_State *L, int what, int data) { | |||
973 | res = (g->GCthreshold != MAX_LUMEM); | 974 | res = (g->GCthreshold != MAX_LUMEM); |
974 | break; | 975 | break; |
975 | } | 976 | } |
977 | case LUA_GCGEN: { /* change collector to generational mode */ | ||
978 | luaC_runtilstate(L, bitmask(GCSpropagate)); | ||
979 | g->gckind = KGC_GEN; | ||
980 | break; | ||
981 | } | ||
976 | default: res = -1; /* invalid option */ | 982 | default: res = -1; /* invalid option */ |
977 | } | 983 | } |
978 | lua_unlock(L); | 984 | lua_unlock(L); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lbaselib.c,v 1.237 2010/03/13 03:57:46 roberto Exp roberto $ | 2 | ** $Id: lbaselib.c,v 1.238 2010/03/19 15:52:48 roberto Exp roberto $ |
3 | ** Basic library | 3 | ** Basic library |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -186,10 +186,10 @@ static int luaB_gcinfo (lua_State *L) { | |||
186 | 186 | ||
187 | static int luaB_collectgarbage (lua_State *L) { | 187 | static int luaB_collectgarbage (lua_State *L) { |
188 | static const char *const opts[] = {"stop", "restart", "collect", | 188 | static const char *const opts[] = {"stop", "restart", "collect", |
189 | "count", "step", "setpause", "setstepmul", "isrunning", NULL}; | 189 | "count", "step", "setpause", "setstepmul", "isrunning", "gen", NULL}; |
190 | static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, | 190 | static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT, |
191 | LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, | 191 | LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL, |
192 | LUA_GCISRUNNING}; | 192 | LUA_GCISRUNNING, LUA_GCGEN}; |
193 | int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; | 193 | int o = optsnum[luaL_checkoption(L, 1, "collect", opts)]; |
194 | int ex = luaL_optint(L, 2, 0); | 194 | int ex = luaL_optint(L, 2, 0); |
195 | int res = lua_gc(L, o, ex); | 195 | int res = lua_gc(L, o, ex); |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lgc.c,v 2.66 2009/12/16 16:42:58 roberto Exp roberto $ | 2 | ** $Id: lgc.c,v 2.67 2009/12/22 15:32:50 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 | */ |
@@ -29,7 +29,7 @@ | |||
29 | #define GCFINALIZECOST 100 | 29 | #define GCFINALIZECOST 100 |
30 | 30 | ||
31 | 31 | ||
32 | #define maskcolors cast_byte(~(bitmask(BLACKBIT)|WHITEBITS)) | 32 | #define maskcolors (~(bitmask(BLACKBIT)|WHITEBITS)) |
33 | 33 | ||
34 | #define makewhite(g,x) \ | 34 | #define makewhite(g,x) \ |
35 | (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g))) | 35 | (gch(x)->marked = cast_byte((gch(x)->marked & maskcolors) | luaC_white(g))) |
@@ -95,10 +95,10 @@ static int iscleared (const TValue *o, int iskey) { | |||
95 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { | 95 | void luaC_barrierf (lua_State *L, GCObject *o, GCObject *v) { |
96 | global_State *g = G(L); | 96 | global_State *g = G(L); |
97 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); | 97 | lua_assert(isblack(o) && iswhite(v) && !isdead(g, v) && !isdead(g, o)); |
98 | lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | 98 | lua_assert(g->gckind == KGC_GEN || |
99 | (g->gcstate != GCSfinalize && g->gcstate != GCSpause)); | ||
99 | lua_assert(gch(o)->tt != LUA_TTABLE); | 100 | lua_assert(gch(o)->tt != LUA_TTABLE); |
100 | /* must keep invariant? */ | 101 | if (g->gcstate == GCSpropagate) /* must keep invariant? */ |
101 | if (g->gcstate == GCSpropagate) | ||
102 | reallymarkobject(g, v); /* restore invariant */ | 102 | reallymarkobject(g, v); /* restore invariant */ |
103 | else /* don't mind */ | 103 | else /* don't mind */ |
104 | makewhite(g, o); /* mark as white just to avoid other barriers */ | 104 | makewhite(g, o); /* mark as white just to avoid other barriers */ |
@@ -109,7 +109,8 @@ void luaC_barrierback (lua_State *L, Table *t) { | |||
109 | global_State *g = G(L); | 109 | global_State *g = G(L); |
110 | GCObject *o = obj2gco(t); | 110 | GCObject *o = obj2gco(t); |
111 | lua_assert(isblack(o) && !isdead(g, o)); | 111 | lua_assert(isblack(o) && !isdead(g, o)); |
112 | lua_assert(g->gcstate != GCSfinalize && g->gcstate != GCSpause); | 112 | lua_assert(g->gckind == KGC_GEN || |
113 | (g->gcstate != GCSfinalize && g->gcstate != GCSpause)); | ||
113 | black2gray(o); /* make table gray (again) */ | 114 | black2gray(o); /* make table gray (again) */ |
114 | t->gclist = g->grayagain; | 115 | t->gclist = g->grayagain; |
115 | g->grayagain = o; | 116 | g->grayagain = o; |
@@ -234,7 +235,6 @@ static void markroot (lua_State *L) { | |||
234 | markvalue(g, &g->l_registry); | 235 | markvalue(g, &g->l_registry); |
235 | markmt(g); | 236 | markmt(g); |
236 | markbeingfnz(g); /* mark any finalizing object left from previous cycle */ | 237 | markbeingfnz(g); /* mark any finalizing object left from previous cycle */ |
237 | g->gcstate = GCSpropagate; | ||
238 | } | 238 | } |
239 | 239 | ||
240 | 240 | ||
@@ -401,8 +401,9 @@ static void traversestack (global_State *g, lua_State *L) { | |||
401 | 401 | ||
402 | 402 | ||
403 | /* | 403 | /* |
404 | ** traverse one gray object, turning it to black. | 404 | ** traverse one gray object, turning it to black (except for threads, |
405 | ** Returns `quantity' traversed. | 405 | ** which are always gray). |
406 | ** Returns 'quantity' traversed. | ||
406 | */ | 407 | */ |
407 | static l_mem propagatemark (global_State *g) { | 408 | static l_mem propagatemark (global_State *g) { |
408 | GCObject *o = g->gray; | 409 | GCObject *o = g->gray; |
@@ -547,13 +548,16 @@ static GCObject **sweeplist (lua_State *L, GCObject **p, lu_mem count) { | |||
547 | GCObject *curr; | 548 | GCObject *curr; |
548 | global_State *g = G(L); | 549 | global_State *g = G(L); |
549 | int deadmask = otherwhite(g); | 550 | int deadmask = otherwhite(g); |
551 | int gckind = g->gckind; | ||
550 | while ((curr = *p) != NULL && count-- > 0) { | 552 | while ((curr = *p) != NULL && count-- > 0) { |
551 | int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask; | 553 | int alive = (gch(curr)->marked ^ WHITEBITS) & deadmask; |
552 | if (gch(curr)->tt == LUA_TTHREAD) | 554 | if (gch(curr)->tt == LUA_TTHREAD) |
553 | sweepthread(L, gco2th(curr), alive); | 555 | sweepthread(L, gco2th(curr), alive); |
554 | if (alive) { | 556 | if (alive) { |
555 | lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); | 557 | lua_assert(!isdead(g, curr) || testbit(gch(curr)->marked, FIXEDBIT)); |
556 | makewhite(g, curr); /* make it white (for next cycle) */ | 558 | /* in generational mode all live objects are kept black, which |
559 | means they grow to old generation */ | ||
560 | if (gckind != KGC_GEN) makewhite(g, curr); | ||
557 | p = &gch(curr)->next; | 561 | p = &gch(curr)->next; |
558 | } | 562 | } |
559 | else { /* must erase `curr' */ | 563 | else { /* must erase `curr' */ |
@@ -700,7 +704,6 @@ void luaC_freeallobjects (lua_State *L) { | |||
700 | 704 | ||
701 | static void atomic (lua_State *L) { | 705 | static void atomic (lua_State *L) { |
702 | global_State *g = G(L); | 706 | global_State *g = G(L); |
703 | g->gcstate = GCSatomic; | ||
704 | lua_assert(!iswhite(obj2gco(g->mainthread))); | 707 | lua_assert(!iswhite(obj2gco(g->mainthread))); |
705 | markobject(g, L); /* mark running thread */ | 708 | markobject(g, L); /* mark running thread */ |
706 | /* registry and global metatables may be changed by API */ | 709 | /* registry and global metatables may be changed by API */ |
@@ -725,8 +728,7 @@ static void atomic (lua_State *L) { | |||
725 | cleartable(g->ephemeron); | 728 | cleartable(g->ephemeron); |
726 | cleartable(g->allweak); | 729 | cleartable(g->allweak); |
727 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ | 730 | g->currentwhite = cast_byte(otherwhite(g)); /* flip current white */ |
728 | g->sweepstrgc = 0; /* go to sweep phase */ | 731 | g->sweepstrgc = 0; /* prepare sweep phase */ |
729 | g->gcstate = GCSsweepstring; | ||
730 | } | 732 | } |
731 | 733 | ||
732 | 734 | ||
@@ -736,13 +738,16 @@ static l_mem singlestep (lua_State *L) { | |||
736 | switch (g->gcstate) { | 738 | switch (g->gcstate) { |
737 | case GCSpause: { | 739 | case GCSpause: { |
738 | markroot(L); /* start a new collection */ | 740 | markroot(L); /* start a new collection */ |
741 | g->gcstate = GCSpropagate; | ||
739 | return 0; | 742 | return 0; |
740 | } | 743 | } |
741 | case GCSpropagate: { | 744 | case GCSpropagate: { |
742 | if (g->gray) | 745 | if (g->gray) |
743 | return propagatemark(g); | 746 | return propagatemark(g); |
744 | else { /* no more `gray' objects */ | 747 | else { /* no more `gray' objects */ |
745 | atomic(L); /* finish mark phase */ | 748 | g->gcstate = GCSatomic; /* finish mark phase */ |
749 | atomic(L); | ||
750 | g->gcstate = GCSsweepstring; | ||
746 | return 0; | 751 | return 0; |
747 | } | 752 | } |
748 | } | 753 | } |
@@ -776,7 +781,33 @@ static l_mem singlestep (lua_State *L) { | |||
776 | } | 781 | } |
777 | 782 | ||
778 | 783 | ||
779 | void luaC_step (lua_State *L) { | 784 | /* |
785 | ** advances the garbage collector until it reaches a state allowed | ||
786 | ** by 'statemask' | ||
787 | */ | ||
788 | void luaC_runtilstate (lua_State *L, int statesmask) { | ||
789 | global_State *g = G(L); | ||
790 | while (!testbit(statesmask, g->gcstate)) | ||
791 | singlestep(L); | ||
792 | } | ||
793 | |||
794 | |||
795 | static void generationalcollection (lua_State *L) { | ||
796 | static int c = 0; | ||
797 | static int prev = 0; | ||
798 | global_State *g = G(L); | ||
799 | int a = g->totalbytes; | ||
800 | lua_assert(g->gcstate == GCSpropagate); | ||
801 | luaC_runtilstate(L, bitmask(GCSpause)); | ||
802 | g->gcstate = GCSpropagate; /* do not run 'markroot' */ | ||
803 | g->GCthreshold = (g->totalbytes/100) * g->gcpause; | ||
804 | /*printf("count: %d old: %d new: %d dif: %d\n", c++, a, g->totalbytes, | ||
805 | g->totalbytes - prev);*/ | ||
806 | prev = g->totalbytes; | ||
807 | } | ||
808 | |||
809 | |||
810 | static void step (lua_State *L) { | ||
780 | global_State *g = G(L); | 811 | global_State *g = G(L); |
781 | l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; /* how much to work */ | 812 | l_mem lim = (GCSTEPSIZE/100) * g->gcstepmul; /* how much to work */ |
782 | lu_mem debt = g->totalbytes - g->GCthreshold; | 813 | lu_mem debt = g->totalbytes - g->GCthreshold; |
@@ -792,14 +823,9 @@ void luaC_step (lua_State *L) { | |||
792 | } | 823 | } |
793 | 824 | ||
794 | 825 | ||
795 | /* | 826 | void luaC_step (lua_State *L) { |
796 | ** advances the garbage collector until it reaches a state allowed | 827 | if (G(L)->gckind == KGC_GEN) generationalcollection(L); |
797 | ** by 'statemask' | 828 | else step(L); |
798 | */ | ||
799 | void luaC_runtilstate (lua_State *L, int statesmask) { | ||
800 | global_State *g = G(L); | ||
801 | while (!testbit(statesmask, g->gcstate)) | ||
802 | singlestep(L); | ||
803 | } | 829 | } |
804 | 830 | ||
805 | 831 | ||
@@ -809,7 +835,8 @@ void luaC_runtilstate (lua_State *L, int statesmask) { | |||
809 | */ | 835 | */ |
810 | void luaC_fullgc (lua_State *L, int isemergency) { | 836 | void luaC_fullgc (lua_State *L, int isemergency) { |
811 | global_State *g = G(L); | 837 | global_State *g = G(L); |
812 | lua_assert(g->gckind == KGC_NORMAL); | 838 | int origkind = g->gckind; |
839 | lua_assert(origkind == KGC_NORMAL || origkind == KGC_GEN); | ||
813 | g->gckind = isemergency ? KGC_EMERGENCY : KGC_FORCED; | 840 | g->gckind = isemergency ? KGC_EMERGENCY : KGC_FORCED; |
814 | if (g->gcstate == GCSpropagate) { /* marking phase? */ | 841 | if (g->gcstate == GCSpropagate) { /* marking phase? */ |
815 | /* must sweep all objects to turn them back to white | 842 | /* must sweep all objects to turn them back to white |
@@ -819,12 +846,12 @@ void luaC_fullgc (lua_State *L, int isemergency) { | |||
819 | } | 846 | } |
820 | /* finish any pending sweep phase */ | 847 | /* finish any pending sweep phase */ |
821 | luaC_runtilstate(L, ~bit2mask(GCSsweepstring, GCSsweep)); | 848 | luaC_runtilstate(L, ~bit2mask(GCSsweepstring, GCSsweep)); |
822 | markroot(L); /* start a new collection */ | 849 | g->gcstate = GCSpause; /* start a new collection */ |
823 | /* run collector up to finalizers */ | 850 | /* run collector up to finalizers */ |
824 | luaC_runtilstate(L, bitmask(GCSfinalize)); | 851 | luaC_runtilstate(L, bitmask(GCSfinalize)); |
825 | g->gckind = KGC_NORMAL; | 852 | g->gckind = origkind; |
826 | if (!isemergency) /* do not run finalizers during emergency GC */ | 853 | if (!isemergency) /* do not run finalizers during emergency GC */ |
827 | luaC_runtilstate(L, ~bitmask(GCSfinalize)); | 854 | luaC_runtilstate(L, bitmask(GCSpause)); |
828 | g->GCthreshold = (g->totalbytes/100) * g->gcpause; | 855 | g->GCthreshold = (g->totalbytes/100) * g->gcpause; |
829 | } | 856 | } |
830 | 857 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lstate.h,v 2.53 2010/02/09 11:55:37 roberto Exp roberto $ | 2 | ** $Id: lstate.h,v 2.54 2010/03/13 15:55:42 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 | */ |
@@ -58,6 +58,7 @@ struct lua_longjmp; /* defined in ldo.c */ | |||
58 | #define KGC_NORMAL 0 | 58 | #define KGC_NORMAL 0 |
59 | #define KGC_FORCED 1 /* gc was forced by the program */ | 59 | #define KGC_FORCED 1 /* gc was forced by the program */ |
60 | #define KGC_EMERGENCY 2 /* gc was forced by an allocation failure */ | 60 | #define KGC_EMERGENCY 2 /* gc was forced by an allocation failure */ |
61 | #define KGC_GEN 3 /* generational collection */ | ||
61 | 62 | ||
62 | 63 | ||
63 | typedef struct stringtable { | 64 | typedef struct stringtable { |
@@ -142,9 +143,9 @@ typedef struct global_State { | |||
142 | struct lua_State *mainthread; | 143 | struct lua_State *mainthread; |
143 | UpVal uvhead; /* head of double-linked list of all open upvalues */ | 144 | UpVal uvhead; /* head of double-linked list of all open upvalues */ |
144 | const lua_Number *version; /* pointer to version number */ | 145 | const lua_Number *version; /* pointer to version number */ |
145 | struct Table *mt[NUM_TAGS]; /* metatables for basic types */ | ||
146 | TString *tmname[TM_N]; /* array with tag-method names */ | ||
147 | TString *envn; /* environment variable name */ | 146 | TString *envn; /* environment variable name */ |
147 | TString *tmname[TM_N]; /* array with tag-method names */ | ||
148 | struct Table *mt[NUM_TAGS]; /* metatables for basic types */ | ||
148 | } global_State; | 149 | } global_State; |
149 | 150 | ||
150 | 151 | ||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lua.h,v 1.262 2010/03/13 03:57:46 roberto Exp roberto $ | 2 | ** $Id: lua.h,v 1.263 2010/03/19 21:04:17 roberto Exp roberto $ |
3 | ** Lua - A Scripting Language | 3 | ** Lua - A Scripting Language |
4 | ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) | 4 | ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) |
5 | ** See Copyright Notice at the end of this file | 5 | ** See Copyright Notice at the end of this file |
@@ -267,6 +267,7 @@ LUA_API int (lua_status) (lua_State *L); | |||
267 | #define LUA_GCSETPAUSE 6 | 267 | #define LUA_GCSETPAUSE 6 |
268 | #define LUA_GCSETSTEPMUL 7 | 268 | #define LUA_GCSETSTEPMUL 7 |
269 | #define LUA_GCISRUNNING 8 | 269 | #define LUA_GCISRUNNING 8 |
270 | #define LUA_GCGEN 9 | ||
270 | 271 | ||
271 | LUA_API int (lua_gc) (lua_State *L, int what, int data); | 272 | LUA_API int (lua_gc) (lua_State *L, int what, int data); |
272 | 273 | ||