-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
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-112532: Use separate mimalloc heaps for GC objects #113263
Changes from 2 commits
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 |
---|---|---|
|
@@ -236,6 +236,8 @@ tstate_is_bound(PyThreadState *tstate) | |
static void bind_gilstate_tstate(PyThreadState *); | ||
static void unbind_gilstate_tstate(PyThreadState *); | ||
|
||
static void tstate_mimalloc_bind(PyThreadState *); | ||
|
||
static void | ||
bind_tstate(PyThreadState *tstate) | ||
{ | ||
|
@@ -256,6 +258,9 @@ bind_tstate(PyThreadState *tstate) | |
tstate->native_thread_id = PyThread_get_thread_native_id(); | ||
#endif | ||
|
||
// mimalloc state needs to be initialized from the active thread. | ||
tstate_mimalloc_bind(tstate); | ||
|
||
tstate->_status.bound = 1; | ||
} | ||
|
||
|
@@ -1533,6 +1538,8 @@ PyThreadState_Clear(PyThreadState *tstate) | |
tstate->on_delete(tstate->on_delete_data); | ||
} | ||
|
||
_PyThreadState_ClearMimallocHeaps(tstate); | ||
|
||
tstate->_status.cleared = 1; | ||
|
||
// XXX Call _PyThreadStateSwap(runtime, NULL) here if "current". | ||
|
@@ -2495,3 +2502,51 @@ _PyThreadState_MustExit(PyThreadState *tstate) | |
} | ||
return 1; | ||
} | ||
|
||
/********************/ | ||
/* mimalloc support */ | ||
/********************/ | ||
|
||
static void | ||
tstate_mimalloc_bind(PyThreadState *tstate) | ||
{ | ||
#ifdef Py_GIL_DISABLED | ||
struct _mimalloc_thread_state *mts = &((_PyThreadStateImpl*)tstate)->mimalloc; | ||
|
||
// Initialize the mimalloc thread state. This must be called from the | ||
// same thread that will use the thread state. The "mem" heap doubles as | ||
// the "backing" heap. | ||
mi_tld_t *tld = &mts->tld; | ||
_mi_tld_init(tld, &mts->heaps[_Py_MIMALLOC_HEAP_MEM]); | ||
|
||
// Initialize each heap | ||
for (Py_ssize_t i = 0; i < _Py_MIMALLOC_HEAP_COUNT; i++) { | ||
_mi_heap_init_ex(&mts->heaps[i], tld, _mi_arena_id_none()); | ||
} | ||
|
||
// By default, object allocations use _Py_MIMALLOC_HEAP_OBJECT. | ||
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. I noticed this when looking at some of the later commits in your branch, but 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. @vstinner What do you think about adding a new domain for this vs having some oddness around allocating GC objects? We probably actually need 2 domains though for objects w/ and w/o pre-headers. 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. Some context: all PyObject allocations go through The advantage of adding new memory domains is that it is more explicit and cleaner. The disadvantage is that code (including extensions) that uses |
||
// _PyObject_GC_New() and similar functions temporarily override this to | ||
// use one of the GC heaps. | ||
mts->current_object_heap = &mts->heaps[_Py_MIMALLOC_HEAP_OBJECT]; | ||
#endif | ||
} | ||
|
||
void | ||
_PyThreadState_ClearMimallocHeaps(PyThreadState *tstate) | ||
{ | ||
#ifdef Py_GIL_DISABLED | ||
if (!tstate->_status.bound) { | ||
// The mimalloc heaps are only initialized when the thread is bound. | ||
return; | ||
} | ||
|
||
_PyThreadStateImpl *tstate_impl = (_PyThreadStateImpl *)tstate; | ||
for (Py_ssize_t i = 0; i < _Py_MIMALLOC_HEAP_COUNT; i++) { | ||
// Abandon all segments in use by this thread. This pushes them to | ||
// a shared pool to later be reclaimed by other threads. It's important | ||
// to do this before the thread state is destroyed so that objects | ||
// remain visible to the GC. | ||
_mi_heap_collect_abandon(&tstate_impl->mimalloc.heaps[i]); | ||
} | ||
#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.
It seems like this is only used when
Py_GIL_DISABLED
is defined, so maybe just not define the struct at all if the GIL is enabled?