Skip to content

Commit e8ea348

Browse files
bpo-37729: gc: write stats at once (GH-15050)
gc used several PySys_WriteStderr() calls to write stats. It caused stats mixed up when stderr is shared by multiple processes like this: gc: collecting generation 2... gc: objects in each generation: 0 0gc: collecting generation 2... gc: objects in each generation: 0 0 126077 126077 gc: objects in permanent generation: 0 gc: objects in permanent generation: 0 gc: done, 112575 unreachable, 0 uncollectablegc: done, 112575 unreachable, 0 uncollectable, 0.2223s elapsed , 0.2344s elapsed (cherry picked from commit bf8162c) Co-authored-by: Inada Naoki <songofacandy@gmail.com>
1 parent 5349f8c commit e8ea348

1 file changed

Lines changed: 25 additions & 20 deletions

File tree

Modules/gcmodule.c

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -962,6 +962,25 @@ clear_freelists(void)
962962
(void)PyContext_ClearFreeList();
963963
}
964964

965+
// Show stats for objects in each gennerations.
966+
static void
967+
show_stats_each_generations(struct _gc_runtime_state *state)
968+
{
969+
char buf[100];
970+
size_t pos = 0;
971+
972+
for (int i = 0; i < NUM_GENERATIONS && pos < sizeof(buf); i++) {
973+
pos += PyOS_snprintf(buf+pos, sizeof(buf)-pos,
974+
" %"PY_FORMAT_SIZE_T"d",
975+
gc_list_size(GEN_HEAD(state, i)));
976+
}
977+
978+
PySys_FormatStderr(
979+
"gc: objects in each generation:%s\n"
980+
"gc: objects in permanent generation: %zd\n",
981+
buf, gc_list_size(&state->permanent_generation.head));
982+
}
983+
965984
/* This is the main function. Read this to understand how the
966985
* collection process works. */
967986
static Py_ssize_t
@@ -979,17 +998,9 @@ collect(struct _gc_runtime_state *state, int generation,
979998
_PyTime_t t1 = 0; /* initialize to prevent a compiler warning */
980999

9811000
if (state->debug & DEBUG_STATS) {
982-
PySys_WriteStderr("gc: collecting generation %d...\n",
983-
generation);
984-
PySys_WriteStderr("gc: objects in each generation:");
985-
for (i = 0; i < NUM_GENERATIONS; i++)
986-
PySys_FormatStderr(" %zd",
987-
gc_list_size(GEN_HEAD(state, i)));
988-
PySys_WriteStderr("\ngc: objects in permanent generation: %zd",
989-
gc_list_size(&state->permanent_generation.head));
1001+
PySys_WriteStderr("gc: collecting generation %d...\n", generation);
1002+
show_stats_each_generations(state);
9901003
t1 = _PyTime_GetMonotonicClock();
991-
992-
PySys_WriteStderr("\n");
9931004
}
9941005

9951006
if (PyDTrace_GC_START_ENABLED())
@@ -1103,16 +1114,10 @@ collect(struct _gc_runtime_state *state, int generation,
11031114
debug_cycle("uncollectable", FROM_GC(gc));
11041115
}
11051116
if (state->debug & DEBUG_STATS) {
1106-
_PyTime_t t2 = _PyTime_GetMonotonicClock();
1107-
1108-
if (m == 0 && n == 0)
1109-
PySys_WriteStderr("gc: done");
1110-
else
1111-
PySys_FormatStderr(
1112-
"gc: done, %zd unreachable, %zd uncollectable",
1113-
n+m, n);
1114-
PySys_WriteStderr(", %.4fs elapsed\n",
1115-
_PyTime_AsSecondsDouble(t2 - t1));
1117+
double d = _PyTime_AsSecondsDouble(_PyTime_GetMonotonicClock() - t1);
1118+
PySys_FormatStderr(
1119+
"gc: done, %zd unreachable, %zd uncollectable, %.4fs elapsed\n",
1120+
n+m, n, d);
11161121
}
11171122

11181123
/* Append instances in the uncollectable set to a Python

0 commit comments

Comments
 (0)