bpo-40521: Make slice cache per-interpreter (GH-20637)

Each interpreter now has its own slice cache:

* Move slice cache into PyInterpreterState.
* Add tstate parameter to _PySlice_Fini().
This commit is contained in:
Victor Stinner 2020-06-05 01:14:40 +02:00 committed by GitHub
parent 2ba59370c3
commit 7daba6f221
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 24 additions and 18 deletions

View file

@ -187,6 +187,10 @@ struct _is {
#endif #endif
struct _Py_tuple_state tuple; struct _Py_tuple_state tuple;
struct _Py_float_state float_state; struct _Py_float_state float_state;
/* Using a cache is very effective since typically only a single slice is
created and then deleted again. */
PySliceObject *slice_cache;
}; };
/* Used by _PyImport_Cleanup() */ /* Used by _PyImport_Cleanup() */

View file

@ -65,7 +65,7 @@ extern void _PyList_Fini(void);
extern void _PySet_Fini(void); extern void _PySet_Fini(void);
extern void _PyBytes_Fini(void); extern void _PyBytes_Fini(void);
extern void _PyFloat_Fini(PyThreadState *tstate); extern void _PyFloat_Fini(PyThreadState *tstate);
extern void _PySlice_Fini(void); extern void _PySlice_Fini(PyThreadState *tstate);
extern void _PyAsyncGen_Fini(void); extern void _PyAsyncGen_Fini(void);
extern void PyOS_FiniInterrupts(void); extern void PyOS_FiniInterrupts(void);

View file

@ -1,2 +1,3 @@
Tuple free lists, empty tuple singleton, and float free list are no longer The tuple free lists, the empty tuple singleton, the float free list, and the
shared by all interpreters: each interpreter now its own free lists. slice cache are no longer shared by all interpreters: each interpreter now has
its own free lists and caches.

View file

@ -15,7 +15,7 @@ this type and there is exactly one in existence.
#include "Python.h" #include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_abstract.h" // _PyIndex_Check()
#include "pycore_object.h" #include "pycore_object.h" // _PyObject_GC_TRACK()
#include "structmember.h" // PyMemberDef #include "structmember.h" // PyMemberDef
static PyObject * static PyObject *
@ -95,16 +95,13 @@ PyObject _Py_EllipsisObject = {
/* Slice object implementation */ /* Slice object implementation */
/* Using a cache is very effective since typically only a single slice is
* created and then deleted again
*/
static PySliceObject *slice_cache = NULL;
void _PySlice_Fini(void) void _PySlice_Fini(PyThreadState *tstate)
{ {
PySliceObject *obj = slice_cache; PyInterpreterState *interp = tstate->interp;
PySliceObject *obj = interp->slice_cache;
if (obj != NULL) { if (obj != NULL) {
slice_cache = NULL; interp->slice_cache = NULL;
PyObject_GC_Del(obj); PyObject_GC_Del(obj);
} }
} }
@ -116,10 +113,11 @@ void _PySlice_Fini(void)
PyObject * PyObject *
PySlice_New(PyObject *start, PyObject *stop, PyObject *step) PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
{ {
PyInterpreterState *interp = _PyInterpreterState_GET();
PySliceObject *obj; PySliceObject *obj;
if (slice_cache != NULL) { if (interp->slice_cache != NULL) {
obj = slice_cache; obj = interp->slice_cache;
slice_cache = NULL; interp->slice_cache = NULL;
_Py_NewReference((PyObject *)obj); _Py_NewReference((PyObject *)obj);
} else { } else {
obj = PyObject_GC_New(PySliceObject, &PySlice_Type); obj = PyObject_GC_New(PySliceObject, &PySlice_Type);
@ -324,14 +322,17 @@ Create a slice object. This is used for extended slicing (e.g. a[0:10:2]).");
static void static void
slice_dealloc(PySliceObject *r) slice_dealloc(PySliceObject *r)
{ {
PyInterpreterState *interp = _PyInterpreterState_GET();
_PyObject_GC_UNTRACK(r); _PyObject_GC_UNTRACK(r);
Py_DECREF(r->step); Py_DECREF(r->step);
Py_DECREF(r->start); Py_DECREF(r->start);
Py_DECREF(r->stop); Py_DECREF(r->stop);
if (slice_cache == NULL) if (interp->slice_cache == NULL) {
slice_cache = r; interp->slice_cache = r;
else }
else {
PyObject_GC_Del(r); PyObject_GC_Del(r);
}
} }
static PyObject * static PyObject *

View file

@ -1265,9 +1265,9 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp)
if (is_main_interp) { if (is_main_interp) {
_PyDict_Fini(); _PyDict_Fini();
_PySlice_Fini();
} }
_PySlice_Fini(tstate);
_PyWarnings_Fini(tstate->interp); _PyWarnings_Fini(tstate->interp);
if (is_main_interp) { if (is_main_interp) {