Skip to content

Commit c718a8e

Browse files
committed
gh-129210: Skip second reachability check in ft GC if no finalizers run
As for the regular GIL garbage collector, skip the second reachability check if no objects to-be-collected have finalizers, and hence none can be resurrected. In (so far very limited) testing this gives a ~10% overall performance improvement to the motivating benchmark's runtime and a ~35% improvement to its reported time. The pyperformance gc_traversal and gc_collect benchmarks show no significant difference and a 6% improvement respectively.
1 parent 6ae3f84 commit c718a8e

File tree

1 file changed

+9
-4
lines changed

1 file changed

+9
-4
lines changed

Python/gc_free_threading.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,22 +1593,25 @@ debug_cycle(const char *msg, PyObject *op)
15931593
* Note that this may remove some (or even all) of the objects from the
15941594
* list, due to refcounts falling to 0.
15951595
*/
1596-
static void
1596+
static int
15971597
finalize_garbage(struct collection_state *state)
15981598
{
15991599
// NOTE: the unreachable worklist holds a strong reference to the object
16001600
// to prevent it from being deallocated while we are holding on to it.
1601+
int finalizer_run = 0;
16011602
PyObject *op;
16021603
WORKSTACK_FOR_EACH(&state->unreachable, op) {
16031604
if (!_PyGC_FINALIZED(op)) {
16041605
destructor finalize = Py_TYPE(op)->tp_finalize;
16051606
if (finalize != NULL) {
16061607
_PyGC_SET_FINALIZED(op);
16071608
finalize(op);
1609+
finalizer_run = 1;
16081610
assert(!_PyErr_Occurred(_PyThreadState_GET()));
16091611
}
16101612
}
16111613
}
1614+
return finalizer_run;
16121615
}
16131616

16141617
// Break reference cycles by clearing the containers involved.
@@ -2009,11 +2012,13 @@ gc_collect_internal(PyInterpreterState *interp, struct collection_state *state,
20092012
// Call weakref callbacks and finalizers after unpausing other threads to
20102013
// avoid potential deadlocks.
20112014
call_weakref_callbacks(state);
2012-
finalize_garbage(state);
2015+
int check_resurrected = finalize_garbage(state);
20132016

2014-
// Handle any objects that may have resurrected after the finalization.
20152017
_PyEval_StopTheWorld(interp);
2016-
err = handle_resurrected_objects(state);
2018+
// Handle any objects that may have resurrected after finalization, if any
2019+
if (check_resurrected) {
2020+
err = handle_resurrected_objects(state);
2021+
}
20172022
// Clear free lists in all threads
20182023
_PyGC_ClearAllFreeLists(interp);
20192024
_PyEval_StartTheWorld(interp);

0 commit comments

Comments
 (0)