summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergey Fedoseev <fedoseev.sergey@gmail.com>2019-08-14 14:10:33 (GMT)
committerVictor Stinner <vstinner@redhat.com>2019-08-14 14:10:33 (GMT)
commit4fa10dde40356d7c71e5524233bafc221d9e2deb (patch)
tree61809d93dd79e8ec0cab8986109c0a0ed61b6412
parentb0c8369c603633f445ccbb5ca7a8742145ff9eec (diff)
downloadcpython-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.c103
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 {