summaryrefslogtreecommitdiff
path: root/Objects/tupleobject.c
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/tupleobject.c')
-rw-r--r--Objects/tupleobject.c64
1 files changed, 59 insertions, 5 deletions
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index bbc78f4ddb..3249cccdb7 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -19,10 +19,32 @@ static PyTupleObject *free_list[PyTuple_MAXSAVESIZE];
static int numfree[PyTuple_MAXSAVESIZE];
#endif
#ifdef COUNT_ALLOCS
-int fast_tuple_allocs;
-int tuple_zero_allocs;
+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)
{
@@ -64,7 +86,6 @@ PyTuple_New(register Py_ssize_t size)
{
return PyErr_NoMemory();
}
- nbytes += sizeof(PyTupleObject) - sizeof(PyObject *);
op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size);
if (op == NULL)
@@ -79,6 +100,9 @@ PyTuple_New(register Py_ssize_t size)
Py_INCREF(op); /* extra INCREF so that this is never freed */
}
#endif
+#ifdef SHOW_TRACK_COUNT
+ count_tracked++;
+#endif
_PyObject_GC_TRACK(op);
return (PyObject *) op;
}
@@ -131,6 +155,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, ...)
{
@@ -483,7 +533,7 @@ tupleindex(PyTupleObject *self, PyObject *args)
else if (cmp < 0)
return NULL;
}
- PyErr_SetString(PyExc_ValueError, "tuple.index(x): x not in list");
+ PyErr_SetString(PyExc_ValueError, "tuple.index(x): x not in tuple");
return NULL;
}
@@ -824,7 +874,8 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
/* XXX UNREF/NEWREF interface should be more symmetrical */
_Py_DEC_REFTOTAL;
- _PyObject_GC_UNTRACK(v);
+ if (_PyObject_GC_IS_TRACKED(v))
+ _PyObject_GC_UNTRACK(v);
_Py_ForgetReference((PyObject *) v);
/* DECREF items deleted by shrinkage */
for (i = newsize; i < oldsize; i++) {
@@ -880,6 +931,9 @@ PyTuple_Fini(void)
(void)PyTuple_ClearFreeList();
#endif
+#ifdef SHOW_TRACK_COUNT
+ show_track();
+#endif
}
/*********************** Tuple Iterator **************************/