Issue #4688: Add a heuristic so that tuples and dicts containing only

untrackable objects are not tracked by the garbage collector. This can
reduce the size of collections and therefore the garbage collection overhead
on long-running programs, depending on their particular use of datatypes.

(trivia: this makes the "binary_trees" benchmark from the Computer Language
Shootout 40% faster)
This commit is contained in:
Antoine Pitrou 2009-03-23 18:41:45 +00:00
parent e5b78563b6
commit f8387af262
11 changed files with 401 additions and 2 deletions

View file

@ -23,11 +23,36 @@ Py_ssize_t fast_tuple_allocs;
Py_ssize_t tuple_zero_allocs;
#endif
/* Debug statistic to count GC tracking of tuples.
Please note that tuples are only untracked when considered by the GC, and
many of them will be dead before. Therefore, a tracking rate close to 100%
does not necessarily prove that the heuristic is inefficient.
*/
#ifdef SHOW_TRACK_COUNT
static Py_ssize_t count_untracked = 0;
static Py_ssize_t count_tracked = 0;
static void
show_track(void)
{
fprintf(stderr, "Tuples created: %" PY_FORMAT_SIZE_T "d\n",
count_tracked + count_untracked);
fprintf(stderr, "Tuples tracked by the GC: %" PY_FORMAT_SIZE_T
"d\n", count_tracked);
fprintf(stderr, "%.2f%% tuple tracking rate\n\n",
(100.0*count_tracked/(count_untracked+count_tracked)));
}
#endif
PyObject *
PyTuple_New(register Py_ssize_t size)
{
register PyTupleObject *op;
Py_ssize_t i;
#ifdef SHOW_TRACK_COUNT
count_tracked++;
#endif
if (size < 0) {
PyErr_BadInternalCall();
return NULL;
@ -131,6 +156,32 @@ PyTuple_SetItem(register PyObject *op, register Py_ssize_t i, PyObject *newitem)
return 0;
}
void
_PyTuple_MaybeUntrack(PyObject *op)
{
PyTupleObject *t;
Py_ssize_t i, n;
if (!PyTuple_CheckExact(op) || !_PyObject_GC_IS_TRACKED(op))
return;
t = (PyTupleObject *) op;
n = Py_SIZE(t);
for (i = 0; i < n; i++) {
PyObject *elt = PyTuple_GET_ITEM(t, i);
/* Tuple with NULL elements aren't
fully constructed, don't untrack
them yet. */
if (!elt ||
_PyObject_GC_MAY_BE_TRACKED(elt))
return;
}
#ifdef SHOW_TRACK_COUNT
count_tracked--;
count_untracked++;
#endif
_PyObject_GC_UNTRACK(op);
}
PyObject *
PyTuple_Pack(Py_ssize_t n, ...)
{
@ -880,6 +931,9 @@ PyTuple_Fini(void)
(void)PyTuple_ClearFreeList();
#endif
#ifdef SHOW_TRACK_COUNT
show_track();
#endif
}
/*********************** Tuple Iterator **************************/