diff options
author | Sergey Fedoseev <fedoseev.sergey@gmail.com> | 2019-08-14 14:10:33 (GMT) |
---|---|---|
committer | Victor Stinner <vstinner@redhat.com> | 2019-08-14 14:10:33 (GMT) |
commit | 4fa10dde40356d7c71e5524233bafc221d9e2deb (patch) | |
tree | 61809d93dd79e8ec0cab8986109c0a0ed61b6412 | |
parent | b0c8369c603633f445ccbb5ca7a8742145ff9eec (diff) | |
download | cpython-4fa10dde40356d7c71e5524233bafc221d9e2deb.zip cpython-4fa10dde40356d7c71e5524233bafc221d9e2deb.tar.gz cpython-4fa10dde40356d7c71e5524233bafc221d9e2deb.tar.bz2 |
bpo-36030: Improve performance of some tuple operations (GH-12052)
-rw-r--r-- | Objects/tupleobject.c | 103 |
1 files changed, 71 insertions, 32 deletions
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index aeaf845..79a5d55 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -59,6 +59,15 @@ show_track(void) } #endif +static inline void +tuple_gc_track(PyTupleObject *op) +{ +#ifdef SHOW_TRACK_COUNT + count_tracked++; +#endif + _PyObject_GC_TRACK(op); +} + /* Print summary info about the state of the optimized allocator */ void _PyTuple_DebugMallocStats(FILE *out) @@ -76,25 +85,25 @@ _PyTuple_DebugMallocStats(FILE *out) #endif } -PyObject * -PyTuple_New(Py_ssize_t size) +/* Allocate an uninitialized tuple object. Before making it public following + steps must be done: + - initialize its items + - call tuple_gc_track() on it + Because the empty tuple is always reused and it's already tracked by GC, + this function must not be called with size == 0 (unless from PyTuple_New() + which wraps this function). +*/ +static PyTupleObject * +tuple_alloc(Py_ssize_t size) { PyTupleObject *op; - Py_ssize_t i; if (size < 0) { PyErr_BadInternalCall(); return NULL; } #if PyTuple_MAXSAVESIZE > 0 - if (size == 0 && free_list[0]) { - op = free_list[0]; - Py_INCREF(op); -#ifdef COUNT_ALLOCS - _Py_tuple_zero_allocs++; -#endif - return (PyObject *) op; - } if (size < PyTuple_MAXSAVESIZE && (op = free_list[size]) != NULL) { + assert(size != 0); free_list[size] = (PyTupleObject *) op->ob_item[0]; numfree[size]--; #ifdef COUNT_ALLOCS @@ -113,14 +122,33 @@ PyTuple_New(Py_ssize_t size) /* Check for overflow */ if ((size_t)size > ((size_t)PY_SSIZE_T_MAX - sizeof(PyTupleObject) - sizeof(PyObject *)) / sizeof(PyObject *)) { - return PyErr_NoMemory(); + return (PyTupleObject *)PyErr_NoMemory(); } op = PyObject_GC_NewVar(PyTupleObject, &PyTuple_Type, size); if (op == NULL) return NULL; } - for (i=0; i < size; i++) + return op; +} + +PyObject * +PyTuple_New(Py_ssize_t size) +{ + PyTupleObject *op; +#if PyTuple_MAXSAVESIZE > 0 + if (size == 0 && free_list[0]) { + op = free_list[0]; + Py_INCREF(op); +#ifdef COUNT_ALLOCS + _Py_tuple_zero_allocs++; +#endif + return (PyObject *) op; + } +#endif + op = tuple_alloc(size); + for (Py_ssize_t i = 0; i < size; i++) { op->ob_item[i] = NULL; + } #if PyTuple_MAXSAVESIZE > 0 if (size == 0) { free_list[0] = op; @@ -128,10 +156,7 @@ PyTuple_New(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); + tuple_gc_track(op); return (PyObject *) op; } @@ -211,24 +236,28 @@ PyTuple_Pack(Py_ssize_t n, ...) { Py_ssize_t i; PyObject *o; - PyObject *result; PyObject **items; va_list vargs; + if (n == 0) { + return PyTuple_New(0); + } + va_start(vargs, n); - result = PyTuple_New(n); + PyTupleObject *result = tuple_alloc(n); if (result == NULL) { va_end(vargs); return NULL; } - items = ((PyTupleObject *)result)->ob_item; + items = result->ob_item; for (i = 0; i < n; i++) { o = va_arg(vargs, PyObject *); Py_INCREF(o); items[i] = o; } va_end(vargs); - return result; + tuple_gc_track(result); + return (PyObject *)result; } @@ -421,7 +450,11 @@ tupleitem(PyTupleObject *a, Py_ssize_t i) PyObject * _PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) { - PyTupleObject *tuple = (PyTupleObject *)PyTuple_New(n); + if (n == 0) { + return PyTuple_New(0); + } + + PyTupleObject *tuple = tuple_alloc(n); if (tuple == NULL) { return NULL; } @@ -431,6 +464,7 @@ _PyTuple_FromArray(PyObject *const *src, Py_ssize_t n) Py_INCREF(item); dst[i] = item; } + tuple_gc_track(tuple); return (PyObject *)tuple; } @@ -486,7 +520,11 @@ tupleconcat(PyTupleObject *a, PyObject *bb) if (Py_SIZE(a) > PY_SSIZE_T_MAX - Py_SIZE(b)) return PyErr_NoMemory(); size = Py_SIZE(a) + Py_SIZE(b); - np = (PyTupleObject *) PyTuple_New(size); + if (size == 0) { + return PyTuple_New(0); + } + + np = tuple_alloc(size); if (np == NULL) { return NULL; } @@ -504,6 +542,7 @@ tupleconcat(PyTupleObject *a, PyObject *bb) Py_INCREF(v); dest[i] = v; } + tuple_gc_track(np); return (PyObject *)np; #undef b } @@ -515,8 +554,6 @@ tuplerepeat(PyTupleObject *a, Py_ssize_t n) Py_ssize_t size; PyTupleObject *np; PyObject **p, **items; - if (n < 0) - n = 0; if (Py_SIZE(a) == 0 || n == 1) { if (PyTuple_CheckExact(a)) { /* Since tuples are immutable, we can return a shared @@ -524,13 +561,14 @@ tuplerepeat(PyTupleObject *a, Py_ssize_t n) Py_INCREF(a); return (PyObject *)a; } - if (Py_SIZE(a) == 0) - return PyTuple_New(0); + } + if (Py_SIZE(a) == 0 || n <= 0) { + return PyTuple_New(0); } if (n > PY_SSIZE_T_MAX / Py_SIZE(a)) return PyErr_NoMemory(); size = Py_SIZE(a) * n; - np = (PyTupleObject *) PyTuple_New(size); + np = tuple_alloc(size); if (np == NULL) return NULL; p = np->ob_item; @@ -542,6 +580,7 @@ tuplerepeat(PyTupleObject *a, Py_ssize_t n) p++; } } + tuple_gc_track(np); return (PyObject *) np; } @@ -754,7 +793,6 @@ tuplesubscript(PyTupleObject* self, PyObject* item) else if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength, i; size_t cur; - PyObject* result; PyObject* it; PyObject **src, **dest; @@ -774,11 +812,11 @@ tuplesubscript(PyTupleObject* self, PyObject* item) return (PyObject *)self; } else { - result = PyTuple_New(slicelength); + PyTupleObject* result = tuple_alloc(slicelength); if (!result) return NULL; src = self->ob_item; - dest = ((PyTupleObject *)result)->ob_item; + dest = result->ob_item; for (cur = start, i = 0; i < slicelength; cur += step, i++) { it = src[cur]; @@ -786,7 +824,8 @@ tuplesubscript(PyTupleObject* self, PyObject* item) dest[i] = it; } - return result; + tuple_gc_track(result); + return (PyObject *)result; } } else { |