mirror of
https://github.com/python/cpython.git
synced 2025-11-26 21:33:10 +00:00
Issue #16351: New function gc.get_stats() returns per-generation collection statistics.
This commit is contained in:
parent
d2217a83d4
commit
d4156c1693
4 changed files with 111 additions and 0 deletions
|
|
@ -67,6 +67,24 @@ The :mod:`gc` module provides the following functions:
|
||||||
returned.
|
returned.
|
||||||
|
|
||||||
|
|
||||||
|
.. function:: get_stats()
|
||||||
|
|
||||||
|
Return a list of 3 per-generation dictionaries containing collection
|
||||||
|
statistics since interpreter start. At this moment, each dictionary will
|
||||||
|
contain the following items:
|
||||||
|
|
||||||
|
* ``collections`` is the number of times this generation was collected;
|
||||||
|
|
||||||
|
* ``collected`` is the total number of objects collected inside this
|
||||||
|
generation;
|
||||||
|
|
||||||
|
* ``uncollectable`` is the total number of objects which were found
|
||||||
|
to be uncollectable (and were therefore moved to the :data:`garbage`
|
||||||
|
list) inside this generation.
|
||||||
|
|
||||||
|
.. versionadded:: 3.4
|
||||||
|
|
||||||
|
|
||||||
.. function:: set_threshold(threshold0[, threshold1[, threshold2]])
|
.. function:: set_threshold(threshold0[, threshold1[, threshold2]])
|
||||||
|
|
||||||
Set the garbage collection thresholds (the collection frequency). Setting
|
Set the garbage collection thresholds (the collection frequency). Setting
|
||||||
|
|
|
||||||
|
|
@ -610,6 +610,32 @@ class GCTests(unittest.TestCase):
|
||||||
stderr = run_command(code % "gc.DEBUG_SAVEALL")
|
stderr = run_command(code % "gc.DEBUG_SAVEALL")
|
||||||
self.assertNotIn(b"uncollectable objects at shutdown", stderr)
|
self.assertNotIn(b"uncollectable objects at shutdown", stderr)
|
||||||
|
|
||||||
|
def test_get_stats(self):
|
||||||
|
stats = gc.get_stats()
|
||||||
|
self.assertEqual(len(stats), 3)
|
||||||
|
for st in stats:
|
||||||
|
self.assertIsInstance(st, dict)
|
||||||
|
self.assertEqual(set(st),
|
||||||
|
{"collected", "collections", "uncollectable"})
|
||||||
|
self.assertGreaterEqual(st["collected"], 0)
|
||||||
|
self.assertGreaterEqual(st["collections"], 0)
|
||||||
|
self.assertGreaterEqual(st["uncollectable"], 0)
|
||||||
|
# Check that collection counts are incremented correctly
|
||||||
|
if gc.isenabled():
|
||||||
|
self.addCleanup(gc.enable)
|
||||||
|
gc.disable()
|
||||||
|
old = gc.get_stats()
|
||||||
|
gc.collect(0)
|
||||||
|
new = gc.get_stats()
|
||||||
|
self.assertEqual(new[0]["collections"], old[0]["collections"] + 1)
|
||||||
|
self.assertEqual(new[1]["collections"], old[1]["collections"])
|
||||||
|
self.assertEqual(new[2]["collections"], old[2]["collections"])
|
||||||
|
gc.collect(2)
|
||||||
|
new = gc.get_stats()
|
||||||
|
self.assertEqual(new[0]["collections"], old[0]["collections"] + 1)
|
||||||
|
self.assertEqual(new[1]["collections"], old[1]["collections"])
|
||||||
|
self.assertEqual(new[2]["collections"], old[2]["collections"] + 1)
|
||||||
|
|
||||||
|
|
||||||
class GCCallbackTests(unittest.TestCase):
|
class GCCallbackTests(unittest.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #16351: New function gc.get_stats() returns per-generation collection
|
||||||
|
statistics.
|
||||||
|
|
||||||
- Issue #14897: Enhance error messages of struct.pack and
|
- Issue #14897: Enhance error messages of struct.pack and
|
||||||
struct.pack_into. Patch by Matti Mäki.
|
struct.pack_into. Patch by Matti Mäki.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,18 @@ static Py_ssize_t long_lived_pending = 0;
|
||||||
static int debug;
|
static int debug;
|
||||||
static PyObject *tmod = NULL;
|
static PyObject *tmod = NULL;
|
||||||
|
|
||||||
|
/* Running stats per generation */
|
||||||
|
struct gc_generation_stats {
|
||||||
|
/* total number of collections */
|
||||||
|
Py_ssize_t collections;
|
||||||
|
/* total number of collected objects */
|
||||||
|
Py_ssize_t collected;
|
||||||
|
/* total number of uncollectable objects (put into gc.garbage) */
|
||||||
|
Py_ssize_t uncollectable;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct gc_generation_stats generation_stats[NUM_GENERATIONS];
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------
|
||||||
gc_refs values.
|
gc_refs values.
|
||||||
|
|
||||||
|
|
@ -852,6 +864,7 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable)
|
||||||
PyGC_Head finalizers; /* objects with, & reachable from, __del__ */
|
PyGC_Head finalizers; /* objects with, & reachable from, __del__ */
|
||||||
PyGC_Head *gc;
|
PyGC_Head *gc;
|
||||||
double t1 = 0.0;
|
double t1 = 0.0;
|
||||||
|
struct gc_generation_stats *stats = &generation_stats[generation];
|
||||||
|
|
||||||
if (debug & DEBUG_STATS) {
|
if (debug & DEBUG_STATS) {
|
||||||
PySys_WriteStderr("gc: collecting generation %d...\n",
|
PySys_WriteStderr("gc: collecting generation %d...\n",
|
||||||
|
|
@ -993,10 +1006,14 @@ collect(int generation, Py_ssize_t *n_collected, Py_ssize_t *n_uncollectable)
|
||||||
Py_FatalError("unexpected exception during garbage collection");
|
Py_FatalError("unexpected exception during garbage collection");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update stats */
|
||||||
if (n_collected)
|
if (n_collected)
|
||||||
*n_collected = m;
|
*n_collected = m;
|
||||||
if (n_uncollectable)
|
if (n_uncollectable)
|
||||||
*n_uncollectable = n;
|
*n_uncollectable = n;
|
||||||
|
stats->collections++;
|
||||||
|
stats->collected += m;
|
||||||
|
stats->uncollectable += n;
|
||||||
return n+m;
|
return n+m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1343,6 +1360,52 @@ gc_get_objects(PyObject *self, PyObject *noargs)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(gc_get_stats__doc__,
|
||||||
|
"get_stats() -> [...]\n"
|
||||||
|
"\n"
|
||||||
|
"Return a list of dictionaries containing per-generation statistics.\n");
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
gc_get_stats(PyObject *self, PyObject *noargs)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
PyObject *result;
|
||||||
|
struct gc_generation_stats stats[NUM_GENERATIONS], *st;
|
||||||
|
|
||||||
|
/* To get consistent values despite allocations while constructing
|
||||||
|
the result list, we use a snapshot of the running stats. */
|
||||||
|
for (i = 0; i < NUM_GENERATIONS; i++) {
|
||||||
|
stats[i] = generation_stats[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
result = PyList_New(0);
|
||||||
|
if (result == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_GENERATIONS; i++) {
|
||||||
|
PyObject *dict;
|
||||||
|
st = &stats[i];
|
||||||
|
dict = Py_BuildValue("{snsnsn}",
|
||||||
|
"collections", st->collections,
|
||||||
|
"collected", st->collected,
|
||||||
|
"uncollectable", st->uncollectable
|
||||||
|
);
|
||||||
|
if (dict == NULL)
|
||||||
|
goto error;
|
||||||
|
if (PyList_Append(result, dict)) {
|
||||||
|
Py_DECREF(dict);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
Py_DECREF(dict);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
|
||||||
|
error:
|
||||||
|
Py_XDECREF(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(gc_is_tracked__doc__,
|
PyDoc_STRVAR(gc_is_tracked__doc__,
|
||||||
"is_tracked(obj) -> bool\n"
|
"is_tracked(obj) -> bool\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
@ -1393,6 +1456,7 @@ static PyMethodDef GcMethods[] = {
|
||||||
{"collect", (PyCFunction)gc_collect,
|
{"collect", (PyCFunction)gc_collect,
|
||||||
METH_VARARGS | METH_KEYWORDS, gc_collect__doc__},
|
METH_VARARGS | METH_KEYWORDS, gc_collect__doc__},
|
||||||
{"get_objects", gc_get_objects,METH_NOARGS, gc_get_objects__doc__},
|
{"get_objects", gc_get_objects,METH_NOARGS, gc_get_objects__doc__},
|
||||||
|
{"get_stats", gc_get_stats, METH_NOARGS, gc_get_stats__doc__},
|
||||||
{"is_tracked", gc_is_tracked, METH_O, gc_is_tracked__doc__},
|
{"is_tracked", gc_is_tracked, METH_O, gc_is_tracked__doc__},
|
||||||
{"get_referrers", gc_get_referrers, METH_VARARGS,
|
{"get_referrers", gc_get_referrers, METH_VARARGS,
|
||||||
gc_get_referrers__doc__},
|
gc_get_referrers__doc__},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue