bpo-40521: Make tuple free list per-interpreter (GH-20247) · python/cpython@69ac6e5
@@ -14,28 +14,6 @@ class tuple "PyTupleObject *" "&PyTuple_Type"
14141515#include "clinic/tupleobject.c.h"
161617-/* Speed optimization to avoid frequent malloc/free of small tuples */
18-#ifndef PyTuple_MAXSAVESIZE
19-#define PyTuple_MAXSAVESIZE 20 /* Largest tuple to save on free list */
20-#endif
21-#ifndef PyTuple_MAXFREELIST
22-#define PyTuple_MAXFREELIST 2000 /* Maximum number of tuples of each size to save */
23-#endif
24-25-/* bpo-40521: tuple free lists are shared by all interpreters. */
26-#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
27-# undef PyTuple_MAXSAVESIZE
28-# define PyTuple_MAXSAVESIZE 0
29-#endif
30-31-#if PyTuple_MAXSAVESIZE > 0
32-/* Entries 1 up to PyTuple_MAXSAVESIZE are free lists, entry 0 is the empty
33- tuple () of which at most one instance will be allocated.
34-*/
35-static PyTupleObject *free_list[PyTuple_MAXSAVESIZE];
36-static int numfree[PyTuple_MAXSAVESIZE];
37-#endif
38-3917static inline void
4018tuple_gc_track(PyTupleObject *op)
4119{
@@ -47,14 +25,14 @@ void
4725_PyTuple_DebugMallocStats(FILE *out)
4826{
4927#if PyTuple_MAXSAVESIZE > 0
50-int i;
51-char buf[128];
52-for (i = 1; i < PyTuple_MAXSAVESIZE; i++) {
28+PyInterpreterState *interp = _PyInterpreterState_GET();
29+struct _Py_tuple_state *state = &interp->tuple;
30+for (int i = 1; i < PyTuple_MAXSAVESIZE; i++) {
31+char buf[128];
5332PyOS_snprintf(buf, sizeof(buf),
5433"free %d-sized PyTupleObject", i);
55-_PyDebugAllocatorStats(out,
56-buf,
57-numfree[i], _PyObject_VAR_SIZE(&PyTuple_Type, i));
34+_PyDebugAllocatorStats(out, buf, state->numfree[i],
35+_PyObject_VAR_SIZE(&PyTuple_Type, i));
5836 }
5937#endif
6038}
@@ -68,18 +46,18 @@ _PyTuple_DebugMallocStats(FILE *out)
6846 which wraps this function).
6947*/
7048static PyTupleObject *
71-tuple_alloc(Py_ssize_t size)
49+tuple_alloc(struct _Py_tuple_state *state, Py_ssize_t size)
7250{
7351PyTupleObject *op;
7452if (size < 0) {
7553PyErr_BadInternalCall();
7654return NULL;
7755 }
7856#if PyTuple_MAXSAVESIZE > 0
79-if (size < PyTuple_MAXSAVESIZE && (op = free_list[size]) != NULL) {
57+if (size < PyTuple_MAXSAVESIZE && (op = state->free_list[size]) != NULL) {
8058assert(size != 0);
81-free_list[size] = (PyTupleObject *) op->ob_item[0];
82-numfree[size]--;
59+state->free_list[size] = (PyTupleObject *) op->ob_item[0];
60+state->numfree[size]--;
8361/* Inline PyObject_InitVar */
8462#ifdef Py_TRACE_REFS
8563Py_SET_SIZE(op, size);
@@ -107,13 +85,15 @@ PyTuple_New(Py_ssize_t size)
10785{
10886PyTupleObject *op;
10987#if PyTuple_MAXSAVESIZE > 0
110-if (size == 0 && free_list[0]) {
111-op = free_list[0];
88+PyInterpreterState *interp = _PyInterpreterState_GET();
89+struct _Py_tuple_state *state = &interp->tuple;
90+if (size == 0 && state->free_list[0]) {
91+op = state->free_list[0];
11292Py_INCREF(op);
11393return (PyObject *) op;
11494 }
11595#endif
116-op = tuple_alloc(size);
96+op = tuple_alloc(state, size);
11797if (op == NULL) {
11898return NULL;
11999 }
@@ -122,8 +102,8 @@ PyTuple_New(Py_ssize_t size)
122102 }
123103#if PyTuple_MAXSAVESIZE > 0
124104if (size == 0) {
125-free_list[0] = op;
126-++numfree[0];
105+state->free_list[0] = op;
106+++state->numfree[0];
127107Py_INCREF(op); /* extra INCREF so that this is never freed */
128108 }
129109#endif
@@ -210,8 +190,11 @@ PyTuple_Pack(Py_ssize_t n, ...)
210190return PyTuple_New(0);
211191 }
212192193+PyInterpreterState *interp = _PyInterpreterState_GET();
194+struct _Py_tuple_state *state = &interp->tuple;
195+213196va_start(vargs, n);
214-PyTupleObject *result = tuple_alloc(n);
197+PyTupleObject *result = tuple_alloc(state, n);
215198if (result == NULL) {
216199va_end(vargs);
217200return NULL;
@@ -233,22 +216,24 @@ PyTuple_Pack(Py_ssize_t n, ...)
233216static void
234217tupledealloc(PyTupleObject *op)
235218{
236-Py_ssize_t i;
237219Py_ssize_t len = Py_SIZE(op);
238220PyObject_GC_UnTrack(op);
239221Py_TRASHCAN_BEGIN(op, tupledealloc)
240222if (len > 0) {
241-i = len;
242-while (--i >= 0)
223+Py_ssize_t i = len;
224+while (--i >= 0) {
243225Py_XDECREF(op->ob_item[i]);
226+ }
244227#if PyTuple_MAXSAVESIZE > 0
228+PyInterpreterState *interp = _PyInterpreterState_GET();
229+struct _Py_tuple_state *state = &interp->tuple;
245230if (len < PyTuple_MAXSAVESIZE &&
246-numfree[len] < PyTuple_MAXFREELIST &&
231+state->numfree[len] < PyTuple_MAXFREELIST &&
247232Py_IS_TYPE(op, &PyTuple_Type))
248233 {
249-op->ob_item[0] = (PyObject *) free_list[len];
250-numfree[len]++;
251-free_list[len] = op;
234+op->ob_item[0] = (PyObject *) state->free_list[len];
235+state->numfree[len]++;
236+state->free_list[len] = op;
252237 goto done; /* return */
253238 }
254239#endif
@@ -423,7 +408,9 @@ _PyTuple_FromArray(PyObject *const *src, Py_ssize_t n)
423408return PyTuple_New(0);
424409 }
425410426-PyTupleObject *tuple = tuple_alloc(n);
411+PyInterpreterState *interp = _PyInterpreterState_GET();
412+struct _Py_tuple_state *state = &interp->tuple;
413+PyTupleObject *tuple = tuple_alloc(state, n);
427414if (tuple == NULL) {
428415return NULL;
429416 }
@@ -481,7 +468,8 @@ tupleconcat(PyTupleObject *a, PyObject *bb)
481468Py_TYPE(bb)->tp_name);
482469return NULL;
483470 }
484-#define b ((PyTupleObject *)bb)
471+PyTupleObject *b = (PyTupleObject *)bb;
472+485473if (Py_SIZE(b) == 0 && PyTuple_CheckExact(a)) {
486474Py_INCREF(a);
487475return (PyObject *)a;
@@ -492,7 +480,9 @@ tupleconcat(PyTupleObject *a, PyObject *bb)
492480return PyTuple_New(0);
493481 }
494482495-np = tuple_alloc(size);
483+PyInterpreterState *interp = _PyInterpreterState_GET();
484+struct _Py_tuple_state *state = &interp->tuple;
485+np = tuple_alloc(state, size);
496486if (np == NULL) {
497487return NULL;
498488 }
@@ -512,7 +502,6 @@ tupleconcat(PyTupleObject *a, PyObject *bb)
512502 }
513503tuple_gc_track(np);
514504return (PyObject *)np;
515-#undef b
516505}
517506518507static PyObject *
@@ -536,7 +525,9 @@ tuplerepeat(PyTupleObject *a, Py_ssize_t n)
536525if (n > PY_SSIZE_T_MAX / Py_SIZE(a))
537526return PyErr_NoMemory();
538527size = Py_SIZE(a) * n;
539-np = tuple_alloc(size);
528+PyInterpreterState *interp = _PyInterpreterState_GET();
529+struct _Py_tuple_state *state = &interp->tuple;
530+np = tuple_alloc(state, size);
540531if (np == NULL)
541532return NULL;
542533p = np->ob_item;
@@ -801,7 +792,9 @@ tuplesubscript(PyTupleObject* self, PyObject* item)
801792return (PyObject *)self;
802793 }
803794else {
804-PyTupleObject* result = tuple_alloc(slicelength);
795+PyInterpreterState *interp = _PyInterpreterState_GET();
796+struct _Py_tuple_state *state = &interp->tuple;
797+PyTupleObject* result = tuple_alloc(state, slicelength);
805798if (!result) return NULL;
806799807800src = self->ob_item;
@@ -963,13 +956,14 @@ _PyTuple_Resize(PyObject **pv, Py_ssize_t newsize)
963956}
964957965958void
966-_PyTuple_ClearFreeList(void)
959+_PyTuple_ClearFreeList(PyThreadState *tstate)
967960{
968961#if PyTuple_MAXSAVESIZE > 0
962+struct _Py_tuple_state *state = &tstate->interp->tuple;
969963for (Py_ssize_t i = 1; i < PyTuple_MAXSAVESIZE; i++) {
970-PyTupleObject *p = free_list[i];
971-free_list[i] = NULL;
972-numfree[i] = 0;
964+PyTupleObject *p = state->free_list[i];
965+state->free_list[i] = NULL;
966+state->numfree[i] = 0;
973967while (p) {
974968PyTupleObject *q = p;
975969p = (PyTupleObject *)(p->ob_item[0]);
@@ -981,14 +975,15 @@ _PyTuple_ClearFreeList(void)
981975}
982976983977void
984-_PyTuple_Fini(void)
978+_PyTuple_Fini(PyThreadState *tstate)
985979{
986980#if PyTuple_MAXSAVESIZE > 0
981+struct _Py_tuple_state *state = &tstate->interp->tuple;
987982/* empty tuples are used all over the place and applications may
988983 * rely on the fact that an empty tuple is a singleton. */
989-Py_CLEAR(free_list[0]);
984+Py_CLEAR(state->free_list[0]);
990985991-_PyTuple_ClearFreeList();
986+_PyTuple_ClearFreeList(tstate);
992987#endif
993988}
994989