@@ -483,11 +483,12 @@ validate_consistent_old_space(PyGC_Head *head)
483483/* Set all gc_refs = ob_refcnt. After this, gc_refs is > 0 and
484484 * PREV_MASK_COLLECTING bit is set for all objects in containers.
485485 */
486- static void
486+ static Py_ssize_t
487487update_refs (PyGC_Head * containers )
488488{
489489 PyGC_Head * next ;
490490 PyGC_Head * gc = GC_NEXT (containers );
491+ Py_ssize_t candidates = 0 ;
491492
492493 while (gc != containers ) {
493494 next = GC_NEXT (gc );
@@ -519,7 +520,9 @@ update_refs(PyGC_Head *containers)
519520 */
520521 _PyObject_ASSERT (op , gc_get_refs (gc ) != 0 );
521522 gc = next ;
523+ candidates ++ ;
522524 }
525+ return candidates ;
523526}
524527
525528/* A traversal callback for subtract_refs. */
@@ -1240,15 +1243,15 @@ flag set but it does not clear it to skip unnecessary iteration. Before the
12401243flag is cleared (for example, by using 'clear_unreachable_mask' function or
12411244by a call to 'move_legacy_finalizers'), the 'unreachable' list is not a normal
12421245list and we can not use most gc_list_* functions for it. */
1243- static inline void
1246+ static inline Py_ssize_t
12441247deduce_unreachable (PyGC_Head * base , PyGC_Head * unreachable ) {
12451248 validate_list (base , collecting_clear_unreachable_clear );
12461249 /* Using ob_refcnt and gc_refs, calculate which objects in the
12471250 * container set are reachable from outside the set (i.e., have a
12481251 * refcount greater than 0 when all the references within the
12491252 * set are taken into account).
12501253 */
1251- update_refs (base ); // gc_prev is used for gc_refs
1254+ Py_ssize_t candidates = update_refs (base ); // gc_prev is used for gc_refs
12521255 subtract_refs (base );
12531256
12541257 /* Leave everything reachable from outside base in base, and move
@@ -1289,6 +1292,7 @@ deduce_unreachable(PyGC_Head *base, PyGC_Head *unreachable) {
12891292 move_unreachable (base , unreachable ); // gc_prev is pointer again
12901293 validate_list (base , collecting_clear_unreachable_clear );
12911294 validate_list (unreachable , collecting_set_unreachable_set );
1295+ return candidates ;
12921296}
12931297
12941298/* Handle objects that may have resurrected after a call to 'finalize_garbage', moving
@@ -1366,6 +1370,7 @@ add_stats(GCState *gcstate, int gen, struct gc_collection_stats *stats)
13661370 gcstate -> generation_stats [gen ].duration += stats -> duration ;
13671371 gcstate -> generation_stats [gen ].collected += stats -> collected ;
13681372 gcstate -> generation_stats [gen ].uncollectable += stats -> uncollectable ;
1373+ gcstate -> generation_stats [gen ].candidates += stats -> candidates ;
13691374 gcstate -> generation_stats [gen ].collections += 1 ;
13701375}
13711376
@@ -1662,6 +1667,7 @@ gc_collect_increment(PyThreadState *tstate, struct gc_collection_stats *stats)
16621667 Py_ssize_t objects_marked = mark_at_start (tstate );
16631668 GC_STAT_ADD (1 , objects_transitively_reachable , objects_marked );
16641669 gcstate -> work_to_do -= objects_marked ;
1670+ stats -> candidates += objects_marked ;
16651671 validate_spaces (gcstate );
16661672 return ;
16671673 }
@@ -1754,7 +1760,7 @@ gc_collect_region(PyThreadState *tstate,
17541760 assert (!_PyErr_Occurred (tstate ));
17551761
17561762 gc_list_init (& unreachable );
1757- deduce_unreachable (from , & unreachable );
1763+ stats -> candidates = deduce_unreachable (from , & unreachable );
17581764 validate_consistent_old_space (from );
17591765 untrack_tuples (from );
17601766
@@ -1844,10 +1850,11 @@ do_gc_callback(GCState *gcstate, const char *phase,
18441850 assert (PyList_CheckExact (gcstate -> callbacks ));
18451851 PyObject * info = NULL ;
18461852 if (PyList_GET_SIZE (gcstate -> callbacks ) != 0 ) {
1847- info = Py_BuildValue ("{sisnsnsd }" ,
1853+ info = Py_BuildValue ("{sisnsnsnsd }" ,
18481854 "generation" , generation ,
18491855 "collected" , stats -> collected ,
18501856 "uncollectable" , stats -> uncollectable ,
1857+ "candidates" , stats -> candidates ,
18511858 "duration" , stats -> duration );
18521859 if (info == NULL ) {
18531860 PyErr_FormatUnraisable ("Exception ignored while invoking gc callbacks" );
0 commit comments