gh-111968: Use per-thread slice_cache in free-threading by corona10 · Pull Request #113972 · python/cpython · GitHub
Skip to content
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
9 changes: 9 additions & 0 deletions Include/internal/pycore_freelist.h
1 change: 1 addition & 0 deletions Include/internal/pycore_gc.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ extern void _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization);
extern void _PyTuple_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PyFloat_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization);
extern void _PySlice_ClearCache(_PyFreeListState *state);
extern void _PyDict_ClearFreeList(PyInterpreterState *interp);
extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp);
extern void _PyContext_ClearFreeList(PyInterpreterState *interp);
Expand Down
3 changes: 0 additions & 3 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,6 @@ struct _is {
struct _Py_long_state long_state;
struct _dtoa_state dtoa;
struct _py_func_state func_state;
/* Using a cache is very effective since typically only a single slice is
created and then deleted again. */
PySliceObject *slice_cache;

struct _Py_tuple_state tuple;
struct _Py_dict_state dict_state;
Expand Down
2 changes: 1 addition & 1 deletion Include/internal/pycore_sliceobject.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ extern "C" {

/* runtime lifecycle */

extern void _PySlice_Fini(PyInterpreterState *);
extern void _PySlice_Fini(_PyFreeListState *);

extern PyObject *
_PyBuildSlice_ConsumeRefs(PyObject *start, PyObject *stop);
Expand Down
26 changes: 15 additions & 11 deletions Objects/sliceobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -103,16 +103,20 @@ PyObject _Py_EllipsisObject = _PyObject_HEAD_INIT(&PyEllipsis_Type);

/* Slice object implementation */


void _PySlice_Fini(PyInterpreterState *interp)
void _PySlice_ClearCache(_PyFreeListState *state)
{
PySliceObject *obj = interp->slice_cache;
PySliceObject *obj = state->slice_state.slice_cache;
if (obj != NULL) {
interp->slice_cache = NULL;
state->slice_state.slice_cache = NULL;
PyObject_GC_Del(obj);
}
}

void _PySlice_Fini(_PyFreeListState *state)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is identical to _PySlice_ClearCache. Do we need both functions? If you want to keep both names, maybe have one call the other.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep both names; I don't want to confuse people who work on the default build.

{
_PySlice_ClearCache(state);
}

/* start, stop, and step are python objects with None indicating no
index is present.
*/
Expand All @@ -122,11 +126,11 @@ _PyBuildSlice_Consume2(PyObject *start, PyObject *stop, PyObject *step)
{
assert(start != NULL && stop != NULL && step != NULL);

PyInterpreterState *interp = _PyInterpreterState_GET();
_PyFreeListState *state = _PyFreeListState_GET();
PySliceObject *obj;
if (interp->slice_cache != NULL) {
obj = interp->slice_cache;
interp->slice_cache = NULL;
if (state->slice_state.slice_cache != NULL) {
obj = state->slice_state.slice_cache;
state->slice_state.slice_cache = NULL;
_Py_NewReference((PyObject *)obj);
}
else {
Expand Down Expand Up @@ -354,13 +358,13 @@ 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();
_PyFreeListState *state = _PyFreeListState_GET();
_PyObject_GC_UNTRACK(r);
Py_DECREF(r->step);
Py_DECREF(r->start);
Py_DECREF(r->stop);
if (interp->slice_cache == NULL) {
interp->slice_cache = r;
if (state->slice_state.slice_cache == NULL) {
state->slice_state.slice_cache = r;
}
else {
PyObject_GC_Del(r);
Expand Down
4 changes: 1 addition & 3 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -1752,15 +1752,13 @@ finalize_interp_types(PyInterpreterState *interp)
_PyUnicode_ClearInterned(interp);

_PyDict_Fini(interp);

_PySlice_Fini(interp);

_PyUnicode_Fini(interp);

_PyFreeListState *state = _PyFreeListState_GET();
_PyTuple_Fini(state);
_PyList_Fini(state);
_PyFloat_Fini(state);
_PySlice_Fini(state);

#ifdef Py_DEBUG
_PyStaticObjects_CheckRefcnt(interp);
Expand Down
1 change: 1 addition & 0 deletions Python/pystate.c