@@ -1838,18 +1838,32 @@ gc_collect_region(PyThreadState *tstate,
18381838 */
18391839static void
18401840do_gc_callback (GCState * gcstate , const char * phase ,
1841- int generation , struct gc_collection_stats * stats )
1841+ int generation , struct gc_collection_stats * stats ,
1842+ PyTime_t * t1 , PyTime_t * t2 )
18421843{
18431844 assert (!PyErr_Occurred ());
18441845
18451846 /* The local variable cannot be rebound, check it for sanity */
18461847 assert (PyList_CheckExact (gcstate -> callbacks ));
18471848 PyObject * info = NULL ;
18481849 if (PyList_GET_SIZE (gcstate -> callbacks ) != 0 ) {
1849- info = Py_BuildValue ("{sisnsn}" ,
1850- "generation" , generation ,
1851- "collected" , stats -> collected ,
1852- "uncollectable" , stats -> uncollectable );
1850+ PyTime_t dt = 0 ;
1851+ if (t1 && t2 && * t1 > 0 && * t2 > 0 ) {
1852+ dt = * t2 - * t1 ;
1853+ }
1854+ if (dt > 0 ) {
1855+ info = Py_BuildValue ("{sisnsnsd}" ,
1856+ "generation" , generation ,
1857+ "collected" , stats -> collected ,
1858+ "uncollectable" , stats -> uncollectable ,
1859+ "collection_time" , PyTime_AsSecondsDouble (dt ));
1860+ }
1861+ else {
1862+ info = Py_BuildValue ("{sisnsn}" ,
1863+ "generation" , generation ,
1864+ "collected" , stats -> collected ,
1865+ "uncollectable" , stats -> uncollectable );
1866+ }
18531867 if (info == NULL ) {
18541868 PyErr_FormatUnraisable ("Exception ignored while invoking gc callbacks" );
18551869 return ;
@@ -1884,12 +1898,13 @@ do_gc_callback(GCState *gcstate, const char *phase,
18841898
18851899static void
18861900invoke_gc_callback (GCState * gcstate , const char * phase ,
1887- int generation , struct gc_collection_stats * stats )
1901+ int generation , struct gc_collection_stats * stats ,
1902+ PyTime_t * t1 , PyTime_t * t2 )
18881903{
18891904 if (gcstate -> callbacks == NULL ) {
18901905 return ;
18911906 }
1892- do_gc_callback (gcstate , phase , generation , stats );
1907+ do_gc_callback (gcstate , phase , generation , stats , t1 , t2 );
18931908}
18941909
18951910static int
@@ -2077,17 +2092,18 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
20772092
20782093 struct gc_collection_stats stats = { 0 };
20792094 if (reason != _Py_GC_REASON_SHUTDOWN ) {
2080- invoke_gc_callback (gcstate , "start" , generation , & stats );
2095+ invoke_gc_callback (gcstate , "start" , generation , & stats , NULL , NULL );
20812096 }
2082- PyTime_t t1 ;
20832097 if (gcstate -> debug & _PyGC_DEBUG_STATS ) {
20842098 PySys_WriteStderr ("gc: collecting generation %d...\n" , generation );
2085- (void )PyTime_PerfCounterRaw (& t1 );
20862099 show_stats_each_generations (gcstate );
20872100 }
20882101 if (PyDTrace_GC_START_ENABLED ()) {
20892102 PyDTrace_GC_START (generation );
20902103 }
2104+ PyTime_t t1 = {0 };
2105+ (void )PyTime_PerfCounterRaw (& t1 );
2106+
20912107 PyObject * exc = _PyErr_GetRaisedException (tstate );
20922108 switch (generation ) {
20932109 case 0 :
@@ -2102,11 +2118,14 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
21022118 default :
21032119 Py_UNREACHABLE ();
21042120 }
2121+ PyTime_t t2 = {0 };
2122+ (void )PyTime_PerfCounterRaw (& t2 );
2123+
21052124 if (PyDTrace_GC_DONE_ENABLED ()) {
21062125 PyDTrace_GC_DONE (stats .uncollectable + stats .collected );
21072126 }
21082127 if (reason != _Py_GC_REASON_SHUTDOWN ) {
2109- invoke_gc_callback (gcstate , "stop" , generation , & stats );
2128+ invoke_gc_callback (gcstate , "stop" , generation , & stats , & t1 , & t2 );
21102129 }
21112130 _PyErr_SetRaisedException (tstate , exc );
21122131 GC_STAT_ADD (generation , objects_collected , stats .collected );
@@ -2121,8 +2140,6 @@ _PyGC_Collect(PyThreadState *tstate, int generation, _PyGC_Reason reason)
21212140 _Py_atomic_store_int (& gcstate -> collecting , 0 );
21222141
21232142 if (gcstate -> debug & _PyGC_DEBUG_STATS ) {
2124- PyTime_t t2 ;
2125- (void )PyTime_PerfCounterRaw (& t2 );
21262143 double d = PyTime_AsSecondsDouble (t2 - t1 );
21272144 PySys_WriteStderr (
21282145 "gc: done, %zd unreachable, %zd uncollectable, %.4fs elapsed\n" ,
0 commit comments