Skip to content

Commit 3744ed2

Browse files
authored
bpo-40521: Make frame free list per-interpreter (GH-20638)
Each interpreter now has its own frame free list: * Move frame free list into PyInterpreterState. * Add _Py_frame_state structure. * Add tstate parameter to _PyFrame_ClearFreeList() and _PyFrame_Fini(). * Remove "#if PyFrame_MAXFREELIST > 0". * Remove "#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS".
1 parent 7daba6f commit 3744ed2

File tree

7 files changed

+51
-59
lines changed

7 files changed

+51
-59
lines changed

Include/internal/pycore_gc.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ PyAPI_FUNC(void) _PyGC_InitState(struct _gc_runtime_state *);
165165

166166

167167
// Functions to clear types free lists
168-
extern void _PyFrame_ClearFreeList(void);
168+
extern void _PyFrame_ClearFreeList(PyThreadState *tstate);
169169
extern void _PyTuple_ClearFreeList(PyThreadState *tstate);
170170
extern void _PyFloat_ClearFreeList(PyThreadState *tstate);
171171
extern void _PyList_ClearFreeList(void);

Include/internal/pycore_interp.h

+7
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ struct _Py_float_state {
9292
PyFloatObject *free_list;
9393
};
9494

95+
struct _Py_frame_state {
96+
PyFrameObject *free_list;
97+
/* number of frames currently in free_list */
98+
int numfree;
99+
};
100+
95101

96102
/* interpreter state */
97103

@@ -187,6 +193,7 @@ struct _is {
187193
#endif
188194
struct _Py_tuple_state tuple;
189195
struct _Py_float_state float_state;
196+
struct _Py_frame_state frame;
190197

191198
/* Using a cache is very effective since typically only a single slice is
192199
created and then deleted again. */

Include/internal/pycore_pylifecycle.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ extern PyStatus _PyGC_Init(PyThreadState *tstate);
5858

5959
/* Various internal finalizers */
6060

61-
extern void _PyFrame_Fini(void);
61+
extern void _PyFrame_Fini(PyThreadState *tstate);
6262
extern void _PyDict_Fini(void);
6363
extern void _PyTuple_Fini(PyThreadState *tstate);
6464
extern void _PyList_Fini(void);
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
The tuple free lists, the empty tuple singleton, the float free list, and the
2-
slice cache are no longer shared by all interpreters: each interpreter now has
3-
its own free lists and caches.
1+
The tuple free lists, the empty tuple singleton, the float free list, the slice
2+
cache, and the frame free list are no longer shared by all interpreters: each
3+
interpreter now its has own free lists and caches.

Modules/gcmodule.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1026,7 +1026,7 @@ static void
10261026
clear_freelists(void)
10271027
{
10281028
PyThreadState *tstate = _PyThreadState_GET();
1029-
_PyFrame_ClearFreeList();
1029+
_PyFrame_ClearFreeList(tstate);
10301030
_PyTuple_ClearFreeList(tstate);
10311031
_PyFloat_ClearFreeList(tstate);
10321032
_PyList_ClearFreeList();

Objects/frameobject.c

+37-49
Original file line numberDiff line numberDiff line change
@@ -561,36 +561,25 @@ static PyGetSetDef frame_getsetlist[] = {
561561
/* max value for numfree */
562562
#define PyFrame_MAXFREELIST 200
563563

564-
/* bpo-40521: frame free lists are shared by all interpreters. */
565-
#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
566-
# undef PyFrame_MAXFREELIST
567-
# define PyFrame_MAXFREELIST 0
568-
#endif
569-
570-
#if PyFrame_MAXFREELIST > 0
571-
static PyFrameObject *free_list = NULL;
572-
static int numfree = 0; /* number of frames currently in free_list */
573-
#endif
574-
575564
static void _Py_HOT_FUNCTION
576565
frame_dealloc(PyFrameObject *f)
577566
{
578-
PyObject **p, **valuestack;
579-
PyCodeObject *co;
580-
581-
if (_PyObject_GC_IS_TRACKED(f))
567+
if (_PyObject_GC_IS_TRACKED(f)) {
582568
_PyObject_GC_UNTRACK(f);
569+
}
583570

584571
Py_TRASHCAN_SAFE_BEGIN(f)
585572
/* Kill all local variables */
586-
valuestack = f->f_valuestack;
587-
for (p = f->f_localsplus; p < valuestack; p++)
573+
PyObject **valuestack = f->f_valuestack;
574+
for (PyObject **p = f->f_localsplus; p < valuestack; p++) {
588575
Py_CLEAR(*p);
576+
}
589577

590578
/* Free stack */
591579
if (f->f_stacktop != NULL) {
592-
for (p = valuestack; p < f->f_stacktop; p++)
580+
for (PyObject **p = valuestack; p < f->f_stacktop; p++) {
593581
Py_XDECREF(*p);
582+
}
594583
}
595584

596585
Py_XDECREF(f->f_back);
@@ -599,19 +588,21 @@ frame_dealloc(PyFrameObject *f)
599588
Py_CLEAR(f->f_locals);
600589
Py_CLEAR(f->f_trace);
601590

602-
co = f->f_code;
591+
PyCodeObject *co = f->f_code;
603592
if (co->co_zombieframe == NULL) {
604593
co->co_zombieframe = f;
605594
}
606-
#if PyFrame_MAXFREELIST > 0
607-
else if (numfree < PyFrame_MAXFREELIST) {
608-
++numfree;
609-
f->f_back = free_list;
610-
free_list = f;
611-
}
612-
#endif
613595
else {
614-
PyObject_GC_Del(f);
596+
PyInterpreterState *interp = _PyInterpreterState_GET();
597+
struct _Py_frame_state *state = &interp->frame;
598+
if (state->numfree < PyFrame_MAXFREELIST) {
599+
++state->numfree;
600+
f->f_back = state->free_list;
601+
state->free_list = f;
602+
}
603+
else {
604+
PyObject_GC_Del(f);
605+
}
615606
}
616607

617608
Py_DECREF(co);
@@ -789,21 +780,20 @@ frame_alloc(PyCodeObject *code)
789780
Py_ssize_t ncells = PyTuple_GET_SIZE(code->co_cellvars);
790781
Py_ssize_t nfrees = PyTuple_GET_SIZE(code->co_freevars);
791782
Py_ssize_t extras = code->co_stacksize + code->co_nlocals + ncells + nfrees;
792-
#if PyFrame_MAXFREELIST > 0
793-
if (free_list == NULL)
794-
#endif
783+
PyInterpreterState *interp = _PyInterpreterState_GET();
784+
struct _Py_frame_state *state = &interp->frame;
785+
if (state->free_list == NULL)
795786
{
796787
f = PyObject_GC_NewVar(PyFrameObject, &PyFrame_Type, extras);
797788
if (f == NULL) {
798789
return NULL;
799790
}
800791
}
801-
#if PyFrame_MAXFREELIST > 0
802792
else {
803-
assert(numfree > 0);
804-
--numfree;
805-
f = free_list;
806-
free_list = free_list->f_back;
793+
assert(state->numfree > 0);
794+
--state->numfree;
795+
f = state->free_list;
796+
state->free_list = state->free_list->f_back;
807797
if (Py_SIZE(f) < extras) {
808798
PyFrameObject *new_f = PyObject_GC_Resize(PyFrameObject, f, extras);
809799
if (new_f == NULL) {
@@ -814,7 +804,6 @@ frame_alloc(PyCodeObject *code)
814804
}
815805
_Py_NewReference((PyObject *)f);
816806
}
817-
#endif
818807

819808
f->f_code = code;
820809
extras = code->co_nlocals + ncells + nfrees;
@@ -1183,34 +1172,33 @@ PyFrame_LocalsToFast(PyFrameObject *f, int clear)
11831172

11841173
/* Clear out the free list */
11851174
void
1186-
_PyFrame_ClearFreeList(void)
1175+
_PyFrame_ClearFreeList(PyThreadState *tstate)
11871176
{
1188-
#if PyFrame_MAXFREELIST > 0
1189-
while (free_list != NULL) {
1190-
PyFrameObject *f = free_list;
1191-
free_list = free_list->f_back;
1177+
struct _Py_frame_state *state = &tstate->interp->frame;
1178+
while (state->free_list != NULL) {
1179+
PyFrameObject *f = state->free_list;
1180+
state->free_list = state->free_list->f_back;
11921181
PyObject_GC_Del(f);
1193-
--numfree;
1182+
--state->numfree;
11941183
}
1195-
assert(numfree == 0);
1196-
#endif
1184+
assert(state->numfree == 0);
11971185
}
11981186

11991187
void
1200-
_PyFrame_Fini(void)
1188+
_PyFrame_Fini(PyThreadState *tstate)
12011189
{
1202-
_PyFrame_ClearFreeList();
1190+
_PyFrame_ClearFreeList(tstate);
12031191
}
12041192

12051193
/* Print summary info about the state of the optimized allocator */
12061194
void
12071195
_PyFrame_DebugMallocStats(FILE *out)
12081196
{
1209-
#if PyFrame_MAXFREELIST > 0
1197+
PyInterpreterState *interp = _PyInterpreterState_GET();
1198+
struct _Py_frame_state *state = &interp->frame;
12101199
_PyDebugAllocatorStats(out,
12111200
"free PyFrameObject",
1212-
numfree, sizeof(PyFrameObject));
1213-
#endif
1201+
state->numfree, sizeof(PyFrameObject));
12141202
}
12151203

12161204

Python/pylifecycle.c

+1-4
Original file line numberDiff line numberDiff line change
@@ -1249,10 +1249,7 @@ flush_std_files(void)
12491249
static void
12501250
finalize_interp_types(PyThreadState *tstate, int is_main_interp)
12511251
{
1252-
if (is_main_interp) {
1253-
/* Sundry finalizers */
1254-
_PyFrame_Fini();
1255-
}
1252+
_PyFrame_Fini(tstate);
12561253
_PyTuple_Fini(tstate);
12571254
if (is_main_interp) {
12581255
_PyList_Fini();

0 commit comments

Comments
 (0)