From 54ca9db68881d694881c875255e40d3e66a8ed7c Mon Sep 17 00:00:00 2001 From: Yichen Yan Date: Sat, 18 May 2024 10:30:20 +0800 Subject: [PATCH 1/2] Update incremental GC impl --- 0002-310-inc_gc.patch | 61 +++++++++++++++++++++++++------------------ python3.spec | 3 +++ 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/0002-310-inc_gc.patch b/0002-310-inc_gc.patch index 2eb6baf..8fc26f5 100644 --- a/0002-310-inc_gc.patch +++ b/0002-310-inc_gc.patch @@ -162,7 +162,7 @@ index 6c28b2b677..87e5007462 100644 self.assertFalse( any(l is element for element in gc.get_objects(generation=0)) diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c -index 43ae6fa98b..d5be3caef6 100644 +index 43ae6fa98b..53c268c1b5 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -66,7 +66,7 @@ module gc @@ -459,7 +459,7 @@ index 43ae6fa98b..d5be3caef6 100644 move_unreachable(base, unreachable); // gc_prev is pointer again validate_list(base, collecting_clear_unreachable_clear); validate_list(unreachable, collecting_set_unreachable_set); -@@ -1177,26 +1245,232 @@ handle_resurrected_objects(PyGC_Head *unreachable, PyGC_Head* still_unreachable, +@@ -1177,26 +1245,241 @@ handle_resurrected_objects(PyGC_Head *unreachable, PyGC_Head* still_unreachable, gc_list_merge(resurrected, old_generation); } @@ -547,6 +547,8 @@ index 43ae6fa98b..d5be3caef6 100644 +struct container_and_flag { + PyGC_Head *container; + int visited_space; ++ int limit; ++ int size; +}; + +/* A traversal callback for adding to container) */ @@ -554,6 +556,9 @@ index 43ae6fa98b..d5be3caef6 100644 +visit_add_to_container(PyObject *op, void *arg) +{ + struct container_and_flag *cf = (struct container_and_flag *)arg; ++ if (cf->size >= cf->limit) { ++ return 0; ++ } + int visited = cf->visited_space; + if (_PyObject_IS_GC(op)) { + PyGC_Head *gc = AS_GC(op); @@ -561,21 +566,23 @@ index 43ae6fa98b..d5be3caef6 100644 + gc_old_space(gc) != visited) { + gc_flip_old_space(gc); + gc_list_move(gc, cf->container); ++ cf->size++; + } + } + return 0; +} + +static uintptr_t -+expand_region_transitively_reachable(PyGC_Head *container, PyGC_Head *gc, GCState *gcstate) ++expand_region_transitively_reachable(PyGC_Head *container, PyGC_Head *gc, GCState *gcstate, int limit) +{ + validate_list(container, collecting_clear_unreachable_clear); + + struct container_and_flag arg = { + .container = container, + .visited_space = gcstate->visited_space, ++ .limit = limit, ++ .size = 0 + }; -+ uintptr_t size = 0; + while (gc != container) { + assert(is_in_visited(gc, gcstate->visited_space)); + PyObject *op = FROM_GC(gc); @@ -584,9 +591,8 @@ index 43ae6fa98b..d5be3caef6 100644 + visit_add_to_container, + &arg); + gc = GC_NEXT(gc); -+ size++; + } -+ return size; ++ return arg.size; +} + +/* Do bookkeeping for a completed GC cycle */ @@ -618,6 +624,7 @@ index 43ae6fa98b..d5be3caef6 100644 + return; + } + Py_ssize_t region_size = 0; ++ uintptr_t expand = 0; + while (region_size < gcstate->work_to_do) { + if (gc_list_is_empty(not_visited)) { + break; @@ -625,7 +632,9 @@ index 43ae6fa98b..d5be3caef6 100644 + PyGC_Head *gc = _PyGCHead_NEXT(not_visited); + gc_list_move(gc, &increment); + gc_set_old_space(gc, gcstate->visited_space); -+ region_size += expand_region_transitively_reachable(&increment, gc, gcstate); ++ expand = expand_region_transitively_reachable(&increment, gc, gcstate, ++ gcstate-> work_to_do * 2 - region_size); ++ region_size += expand; + } + assert(region_size == gc_list_size(&increment)); + PyGC_Head survivors; @@ -706,7 +715,7 @@ index 43ae6fa98b..d5be3caef6 100644 assert(gcstate->garbage != NULL); assert(!_PyErr_Occurred(tstate)); -@@ -1208,51 +1482,21 @@ gc_collect_main(PyThreadState *tstate, int generation, +@@ -1208,51 +1491,21 @@ gc_collect_main(PyThreadState *tstate, int generation, } #endif @@ -770,7 +779,7 @@ index 43ae6fa98b..d5be3caef6 100644 /* All objects in unreachable are trash, but objects reachable from * legacy finalizers (e.g. tp_del) can't safely be deleted. -@@ -1266,7 +1510,6 @@ gc_collect_main(PyThreadState *tstate, int generation, +@@ -1266,7 +1519,6 @@ gc_collect_main(PyThreadState *tstate, int generation, * and we move those into the finalizers list too. */ move_legacy_finalizer_reachable(&finalizers); @@ -778,7 +787,7 @@ index 43ae6fa98b..d5be3caef6 100644 validate_list(&finalizers, collecting_clear_unreachable_clear); validate_list(&unreachable, collecting_set_unreachable_clear); -@@ -1278,27 +1521,27 @@ gc_collect_main(PyThreadState *tstate, int generation, +@@ -1278,27 +1530,27 @@ gc_collect_main(PyThreadState *tstate, int generation, } /* Clear weakrefs and invoke callbacks as necessary. */ @@ -813,7 +822,7 @@ index 43ae6fa98b..d5be3caef6 100644 /* Collect statistics on uncollectable objects found and print * debugging information. */ for (gc = GC_NEXT(&finalizers); gc != &finalizers; gc = GC_NEXT(gc)) { -@@ -1306,71 +1549,23 @@ gc_collect_main(PyThreadState *tstate, int generation, +@@ -1306,71 +1558,23 @@ gc_collect_main(PyThreadState *tstate, int generation, if (gcstate->debug & DEBUG_UNCOLLECTABLE) debug_cycle("uncollectable", FROM_GC(gc)); } @@ -891,7 +900,7 @@ index 43ae6fa98b..d5be3caef6 100644 /* The local variable cannot be rebound, check it for sanity */ assert(PyList_CheckExact(gcstate->callbacks)); -@@ -1378,8 +1573,8 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, +@@ -1378,8 +1582,8 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, if (PyList_GET_SIZE(gcstate->callbacks) != 0) { info = Py_BuildValue("{sisnsn}", "generation", generation, @@ -902,7 +911,7 @@ index 43ae6fa98b..d5be3caef6 100644 if (info == NULL) { PyErr_WriteUnraisable(NULL); return; -@@ -1398,82 +1593,24 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, +@@ -1398,82 +1602,24 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, Py_DECREF(cb); } Py_XDECREF(info); @@ -995,7 +1004,7 @@ index 43ae6fa98b..d5be3caef6 100644 /*[clinic input] gc.enable -@@ -1540,18 +1677,7 @@ gc_collect_impl(PyObject *module, int generation) +@@ -1540,18 +1686,7 @@ gc_collect_impl(PyObject *module, int generation) return -1; } @@ -1015,7 +1024,7 @@ index 43ae6fa98b..d5be3caef6 100644 } /*[clinic input] -@@ -1606,14 +1732,10 @@ gc_set_threshold(PyObject *self, PyObject *args) +@@ -1606,14 +1741,10 @@ gc_set_threshold(PyObject *self, PyObject *args) { GCState *gcstate = get_gc_state(); if (!PyArg_ParseTuple(args, "i|ii:set_threshold", @@ -1033,7 +1042,7 @@ index 43ae6fa98b..d5be3caef6 100644 Py_RETURN_NONE; } -@@ -1629,9 +1751,9 @@ gc_get_threshold_impl(PyObject *module) +@@ -1629,9 +1760,9 @@ gc_get_threshold_impl(PyObject *module) { GCState *gcstate = get_gc_state(); return Py_BuildValue("(iii)", @@ -1046,7 +1055,7 @@ index 43ae6fa98b..d5be3caef6 100644 } /*[clinic input] -@@ -1646,9 +1768,9 @@ gc_get_count_impl(PyObject *module) +@@ -1646,9 +1777,9 @@ gc_get_count_impl(PyObject *module) { GCState *gcstate = get_gc_state(); return Py_BuildValue("(iii)", @@ -1059,7 +1068,7 @@ index 43ae6fa98b..d5be3caef6 100644 } static int -@@ -1697,13 +1819,19 @@ gc_get_referrers(PyObject *self, PyObject *args) +@@ -1697,13 +1828,19 @@ gc_get_referrers(PyObject *self, PyObject *args) } GCState *gcstate = get_gc_state(); @@ -1084,7 +1093,7 @@ index 43ae6fa98b..d5be3caef6 100644 } /* Append obj to list; return true if error (out of memory), false if OK. */ -@@ -1800,7 +1928,7 @@ gc_get_objects_impl(PyObject *module, Py_ssize_t generation) +@@ -1800,7 +1937,7 @@ gc_get_objects_impl(PyObject *module, Py_ssize_t generation) /* If generation is not passed or None, get all objects from all generations */ for (i = 0; i < NUM_GENERATIONS; i++) { @@ -1093,7 +1102,7 @@ index 43ae6fa98b..d5be3caef6 100644 goto error; } } -@@ -1918,10 +2046,16 @@ gc_freeze_impl(PyObject *module) +@@ -1918,10 +2055,16 @@ gc_freeze_impl(PyObject *module) /*[clinic end generated code: output=502159d9cdc4c139 input=b602b16ac5febbe5]*/ { GCState *gcstate = get_gc_state(); @@ -1114,7 +1123,7 @@ index 43ae6fa98b..d5be3caef6 100644 Py_RETURN_NONE; } -@@ -1939,7 +2073,8 @@ gc_unfreeze_impl(PyObject *module) +@@ -1939,7 +2082,8 @@ gc_unfreeze_impl(PyObject *module) { GCState *gcstate = get_gc_state(); gc_list_merge(&gcstate->permanent_generation.head, @@ -1124,7 +1133,7 @@ index 43ae6fa98b..d5be3caef6 100644 Py_RETURN_NONE; } -@@ -2076,35 +2211,88 @@ PyGC_IsEnabled(void) +@@ -2076,35 +2220,88 @@ PyGC_IsEnabled(void) return gcstate->enabled; } @@ -1229,7 +1238,7 @@ index 43ae6fa98b..d5be3caef6 100644 _PyGC_CollectNoFail(PyThreadState *tstate) { /* Ideally, this function is only called on interpreter shutdown, -@@ -2113,16 +2301,7 @@ _PyGC_CollectNoFail(PyThreadState *tstate) +@@ -2113,16 +2310,7 @@ _PyGC_CollectNoFail(PyThreadState *tstate) during interpreter shutdown (and then never finish it). See http://bugs.python.org/issue8713#msg195178 for an example. */ @@ -1247,7 +1256,7 @@ index 43ae6fa98b..d5be3caef6 100644 } void -@@ -2262,6 +2441,14 @@ PyObject_IS_GC(PyObject *obj) +@@ -2262,6 +2450,14 @@ PyObject_IS_GC(PyObject *obj) return _PyObject_IS_GC(obj); } @@ -1262,7 +1271,7 @@ index 43ae6fa98b..d5be3caef6 100644 static PyObject * _PyObject_GC_Alloc(int use_calloc, size_t basicsize) { -@@ -2286,16 +2473,14 @@ _PyObject_GC_Alloc(int use_calloc, size_t basicsize) +@@ -2286,16 +2482,14 @@ _PyObject_GC_Alloc(int use_calloc, size_t basicsize) g->_gc_next = 0; g->_gc_prev = 0; @@ -1283,7 +1292,7 @@ index 43ae6fa98b..d5be3caef6 100644 } PyObject *op = FROM_GC(g); return op; -@@ -2369,8 +2554,8 @@ PyObject_GC_Del(void *op) +@@ -2369,8 +2563,8 @@ PyObject_GC_Del(void *op) gc_list_remove(g); } GCState *gcstate = get_gc_state(); diff --git a/python3.spec b/python3.spec index 312d407..1af8274 100644 --- a/python3.spec +++ b/python3.spec @@ -1494,6 +1494,9 @@ CheckPython optimized # ====================================================== %changelog +* Wed May 18 2024 Yichen Yan - 3.10.13-3 +- Enhance Incremental GC + * Wed Mar 13 2024 Yichen Yan - 3.10.13-2 - Add Incremental garbage collection -- Gitee From bc538acab5b34ea4707e578afeaf1242b74c83aa Mon Sep 17 00:00:00 2001 From: oraluben Date: Tue, 21 May 2024 03:22:46 +0000 Subject: [PATCH 2/2] update 0002-310-inc_gc.patch. Signed-off-by: oraluben --- 0002-310-inc_gc.patch | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/0002-310-inc_gc.patch b/0002-310-inc_gc.patch index 8fc26f5..aa5c577 100644 --- a/0002-310-inc_gc.patch +++ b/0002-310-inc_gc.patch @@ -581,7 +581,7 @@ index 43ae6fa98b..53c268c1b5 100644 + .container = container, + .visited_space = gcstate->visited_space, + .limit = limit, -+ .size = 0 ++ .size = 1 + }; + while (gc != container) { + assert(is_in_visited(gc, gcstate->visited_space)); -- Gitee