-
-
Notifications
You must be signed in to change notification settings - Fork 30.4k
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
gh-111968: Introduce _PyFreeListState and _PyFreeListState_GET API #113584
Changes from 43 commits
cd4863c
333873d
8b7e261
dd0afa2
f0d55de
5e8e3b4
7aa956a
908ef13
0096383
bc8dd4a
40bad6b
1b0f370
3d6042e
09403db
c05491e
d5f9559
3dd3c3f
0d8ea53
e9d8138
07e0536
6c8ba67
8a80970
6d2f2d4
887bacf
e65952f
25a6714
3fd9baa
e175b61
295a292
5836c4b
7cb261f
01bbc7a
b08f65f
65cedee
9a40708
af86a20
4e84130
7ffa64c
d6a2feb
458aadb
b105bda
18e9216
5bb8d3f
2811a12
a5f494d
837ae60
08c8613
b5eb472
0d8dc3d
fe859e1
c284061
a8e39b3
99ac375
0c331c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,35 @@ | ||||||||||||||||||||||||||||||||||
#ifndef Py_INTERNAL_FREELIST_H | ||||||||||||||||||||||||||||||||||
#define Py_INTERNAL_FREELIST_H | ||||||||||||||||||||||||||||||||||
#ifdef __cplusplus | ||||||||||||||||||||||||||||||||||
extern "C" { | ||||||||||||||||||||||||||||||||||
#endif | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#ifndef Py_BUILD_CORE | ||||||||||||||||||||||||||||||||||
# error "this header requires Py_BUILD_CORE define" | ||||||||||||||||||||||||||||||||||
#endif | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#ifndef WITH_FREELISTS | ||||||||||||||||||||||||||||||||||
// without freelists | ||||||||||||||||||||||||||||||||||
# define PyList_MAXFREELIST 0 | ||||||||||||||||||||||||||||||||||
#endif | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
/* Empty list reuse scheme to save calls to malloc and free */ | ||||||||||||||||||||||||||||||||||
#ifndef PyList_MAXFREELIST | ||||||||||||||||||||||||||||||||||
# define PyList_MAXFREELIST 80 | ||||||||||||||||||||||||||||||||||
#endif | ||||||||||||||||||||||||||||||||||
Comment on lines
+11
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can be improved better way to only depend on cpython/Include/internal/pycore_list.h Lines 23 to 38 in 3aadb95
|
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
struct _Py_list_state { | ||||||||||||||||||||||||||||||||||
#if PyList_MAXFREELIST > 0 | ||||||||||||||||||||||||||||||||||
PyListObject *free_list[PyList_MAXFREELIST]; | ||||||||||||||||||||||||||||||||||
int numfree; | ||||||||||||||||||||||||||||||||||
#endif | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
typedef struct _Py_freelist_state { | ||||||||||||||||||||||||||||||||||
struct _Py_list_state list; | ||||||||||||||||||||||||||||||||||
} _PyFreeListState; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#ifdef __cplusplus | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
#endif | ||||||||||||||||||||||||||||||||||
#endif /* !Py_INTERNAL_FREELIST_H */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,8 @@ extern "C" { | |
# error "this header requires Py_BUILD_CORE define" | ||
#endif | ||
|
||
#include "pycore_freelist.h" // _PyFreeListState | ||
|
||
/* GC information is stored BEFORE the object structure. */ | ||
typedef struct { | ||
// Pointer to next object in the list. | ||
|
@@ -238,14 +240,16 @@ extern PyObject *_PyGC_GetObjects(PyInterpreterState *interp, Py_ssize_t generat | |
extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs); | ||
|
||
// Functions to clear types free lists | ||
extern void _Py_ClearFreeLists(_PyFreeListState *state); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hummm, I find this asymmetry a bit odd. Wouldn't be better to keep all functions receiving That way the code of the caller will be also cleaner and doesn't need to deal with where the freelist is stored. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the free-threaded builds, we want to clear the free-lists for a specific thread (not all threads). Passing |
||
extern void _PyTuple_ClearFreeList(PyInterpreterState *interp); | ||
extern void _PyFloat_ClearFreeList(PyInterpreterState *interp); | ||
extern void _PyList_ClearFreeList(PyInterpreterState *interp); | ||
extern void _PyList_ClearFreeList(_PyFreeListState *state); | ||
extern void _PyDict_ClearFreeList(PyInterpreterState *interp); | ||
extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp); | ||
extern void _PyContext_ClearFreeList(PyInterpreterState *interp); | ||
extern void _Py_ScheduleGC(PyInterpreterState *interp); | ||
extern void _Py_RunGC(PyThreadState *tstate); | ||
extern void _PyGC_Clear_FreeList(PyInterpreterState *interp); | ||
|
||
#ifdef __cplusplus | ||
} | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,30 @@ | ||||||
#ifdef Py_GIL_DISABLED | ||||||
|
||||||
#include "Python.h" | ||||||
#include "pycore_pystate.h" // _PyFreeListState_GET() | ||||||
#include "pycore_tstate.h" // _PyThreadStateImpl | ||||||
|
||||||
/* Clear all free lists | ||||||
* All free lists are cleared during the collection of the highest generation. | ||||||
* Allocated items in the free list may keep a pymalloc arena occupied. | ||||||
* Clearing the free lists may give back memory to the OS earlier. | ||||||
*/ | ||||||
void | ||||||
_PyGC_Clear_FreeList(PyInterpreterState *interp) | ||||||
{ | ||||||
_PyTuple_ClearFreeList(interp); | ||||||
_PyFloat_ClearFreeList(interp); | ||||||
_PyDict_ClearFreeList(interp); | ||||||
_PyAsyncGen_ClearFreeLists(interp); | ||||||
_PyContext_ClearFreeList(interp); | ||||||
|
||||||
HEAD_LOCK(&_PyRuntime); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This locks interpreters creation, but not thread creation, no? Is it possible that this races with thread creation/destruction? I am missing something? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This part looks okay to me. The Lines 1370 to 1371 in ace4d7f
Modification of the free-lists themselves is protected by the "stop-the-world" pause (or the GIL), which is not yet implemented. |
||||||
_PyThreadStateImpl *tstate = (_PyThreadStateImpl *)interp->threads.head; | ||||||
while (tstate != NULL) { | ||||||
_Py_ClearFreeLists(&tstate->freelist_state); | ||||||
tstate = tstate->base.next; | ||||||
} | ||||||
HEAD_UNLOCK(&_PyRuntime); | ||||||
} | ||||||
|
||||||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
#ifndef Py_GIL_DISABLED | ||
|
||
#include "Python.h" | ||
#include "pycore_pystate.h" // _Py_ClearFreeLists() | ||
|
||
/* Clear all free lists | ||
* All free lists are cleared during the collection of the highest generation. | ||
* Allocated items in the free list may keep a pymalloc arena occupied. | ||
* Clearing the free lists may give back memory to the OS earlier. | ||
*/ | ||
void | ||
_PyGC_Clear_FreeList(PyInterpreterState *interp) | ||
{ | ||
_PyTuple_ClearFreeList(interp); | ||
_PyFloat_ClearFreeList(interp); | ||
_PyDict_ClearFreeList(interp); | ||
_PyAsyncGen_ClearFreeLists(interp); | ||
_PyContext_ClearFreeList(interp); | ||
|
||
_Py_ClearFreeLists(&interp->freelist_state); | ||
Check failure on line 20 in Python/gc_gil.c GitHub Actions / Windows (free-threading) / build and test (x64)
Check failure on line 20 in Python/gc_gil.c GitHub Actions / Windows (free-threading) / build and test (x64)
Check failure on line 20 in Python/gc_gil.c GitHub Actions / Windows (free-threading) / build (arm64)
Check failure on line 20 in Python/gc_gil.c GitHub Actions / Windows (free-threading) / build (arm64)
|
||
} | ||
|
||
#endif |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All freelist related domains will be moved here.