Skip to content

bpo-40521: Make slice cache per-interpreter #20637

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 4, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ struct _is {
#endif
struct _Py_tuple_state tuple;
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() */
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ extern void _PyList_Fini(void);
extern void _PySet_Fini(void);
extern void _PyBytes_Fini(void);
extern void _PyFloat_Fini(PyThreadState *tstate);
extern void _PySlice_Fini(void);
extern void _PySlice_Fini(PyThreadState *tstate);
extern void _PyAsyncGen_Fini(void);

extern void PyOS_FiniInterrupts(void);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
Tuple free lists, empty tuple singleton, and float free list are no longer
shared by all interpreters: each interpreter now its own free lists.
The tuple free lists, the empty tuple singleton, the float free list, and the
slice cache are no longer shared by all interpreters: each interpreter now has
its own free lists and caches.
29 changes: 15 additions & 14 deletions Objects/sliceobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ this type and there is exactly one in existence.

#include "Python.h"
#include "pycore_abstract.h" // _PyIndex_Check()
#include "pycore_object.h"
#include "pycore_object.h" // _PyObject_GC_TRACK()
#include "structmember.h" // PyMemberDef

static PyObject *
Expand Down Expand Up @@ -95,16 +95,13 @@ PyObject _Py_EllipsisObject = {

/* 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) {
slice_cache = NULL;
interp->slice_cache = NULL;
PyObject_GC_Del(obj);
}
}
Expand All @@ -116,10 +113,11 @@ void _PySlice_Fini(void)
PyObject *
PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
PySliceObject *obj;
if (slice_cache != NULL) {
obj = slice_cache;
slice_cache = NULL;
if (interp->slice_cache != NULL) {
obj = interp->slice_cache;
interp->slice_cache = NULL;
_Py_NewReference((PyObject *)obj);
} else {
obj = PyObject_GC_New(PySliceObject, &PySlice_Type);
Expand Down Expand Up @@ -324,14 +322,17 @@ Create a slice object. This is used for extended slicing (e.g. a[0:10:2]).");
static void
slice_dealloc(PySliceObject *r)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
_PyObject_GC_UNTRACK(r);
Py_DECREF(r->step);
Py_DECREF(r->start);
Py_DECREF(r->stop);
if (slice_cache == NULL)
slice_cache = r;
else
if (interp->slice_cache == NULL) {
interp->slice_cache = r;
}
else {
PyObject_GC_Del(r);
}
}

static PyObject *
Expand Down
2 changes: 1 addition & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -1265,9 +1265,9 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp)

if (is_main_interp) {
_PyDict_Fini();
_PySlice_Fini();
}

_PySlice_Fini(tstate);
_PyWarnings_Fini(tstate->interp);

if (is_main_interp) {
Expand Down