summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorInada Naoki <songofacandy@gmail.com>2019-08-02 07:25:29 (GMT)
committerGitHub <noreply@github.com>2019-08-02 07:25:29 (GMT)
commitbf8162c8c45338470bbe487c8769bba20bde66c2 (patch)
treec938215f7b6b03328b9c536e5b600742f03d2934
parent4b3e97592376d5f8a3b75192b399a2da1be642cb (diff)
downloadcpython-bf8162c8c45338470bbe487c8769bba20bde66c2.zip
cpython-bf8162c8c45338470bbe487c8769bba20bde66c2.tar.gz
cpython-bf8162c8c45338470bbe487c8769bba20bde66c2.tar.bz2
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
-rw-r--r--Modules/gcmodule.c45
1 files changed, 25 insertions, 20 deletions
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 2ee7651..7586cd3 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -962,6 +962,25 @@ clear_freelists(void)
(void)PyContext_ClearFreeList();
}
+// Show stats for objects in each gennerations.
+static void
+show_stats_each_generations(struct _gc_runtime_state *state)
+{
+ char buf[100];
+ size_t pos = 0;
+
+ for (int i = 0; i < NUM_GENERATIONS && pos < sizeof(buf); i++) {
+ pos += PyOS_snprintf(buf+pos, sizeof(buf)-pos,
+ " %"PY_FORMAT_SIZE_T"d",
+ gc_list_size(GEN_HEAD(state, i)));
+ }
+
+ PySys_FormatStderr(
+ "gc: objects in each generation:%s\n"
+ "gc: objects in permanent generation: %zd\n",
+ buf, gc_list_size(&state->permanent_generation.head));
+}
+
/* This is the main function. Read this to understand how the
* collection process works. */
static Py_ssize_t
@@ -979,17 +998,9 @@ collect(struct _gc_runtime_state *state, int generation,
_PyTime_t t1 = 0; /* initialize to prevent a compiler warning */
if (state->debug & DEBUG_STATS) {
- PySys_WriteStderr("gc: collecting generation %d...\n",
- generation);
- PySys_WriteStderr("gc: objects in each generation:");
- for (i = 0; i < NUM_GENERATIONS; i++)
- PySys_FormatStderr(" %zd",
- gc_list_size(GEN_HEAD(state, i)));
- PySys_WriteStderr("\ngc: objects in permanent generation: %zd",
- gc_list_size(&state->permanent_generation.head));
+ PySys_WriteStderr("gc: collecting generation %d...\n", generation);
+ show_stats_each_generations(state);
t1 = _PyTime_GetMonotonicClock();
-
- PySys_WriteStderr("\n");
}
if (PyDTrace_GC_START_ENABLED())
@@ -1103,16 +1114,10 @@ collect(struct _gc_runtime_state *state, int generation,
debug_cycle("uncollectable", FROM_GC(gc));
}
if (state->debug & DEBUG_STATS) {
- _PyTime_t t2 = _PyTime_GetMonotonicClock();
-
- if (m == 0 && n == 0)
- PySys_WriteStderr("gc: done");
- else
- PySys_FormatStderr(
- "gc: done, %zd unreachable, %zd uncollectable",
- n+m, n);
- PySys_WriteStderr(", %.4fs elapsed\n",
- _PyTime_AsSecondsDouble(t2 - t1));
+ double d = _PyTime_AsSecondsDouble(_PyTime_GetMonotonicClock() - t1);
+ PySys_FormatStderr(
+ "gc: done, %zd unreachable, %zd uncollectable, %.4fs elapsed\n",
+ n+m, n, d);
}
/* Append instances in the uncollectable set to a Python