diff options
Diffstat (limited to 'Objects/tupleobject.c')
-rw-r--r-- | Objects/tupleobject.c | 64 |
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 **************************/ |