From 578468ff732b8de0f3cd2844958238a8255b3d3d Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 28 Oct 2024 17:53:46 -0400 Subject: [PATCH 1/7] Use a thread-local freelist for thread states. --- Python/pystate.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Python/pystate.c b/Python/pystate.c index 36b31f3b9e4200..9e16af863332d9 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1390,10 +1390,19 @@ allocate_chunk(int size_in_bytes, _PyStackChunk* previous) return res; } +_Py_thread_local struct _Py_freelist thread_states = { 0 }; + static _PyThreadStateImpl * alloc_threadstate(void) { - return PyMem_RawCalloc(1, sizeof(_PyThreadStateImpl)); + _PyThreadStateImpl *impl = _PyFreeList_PopMem(&thread_states); + if (impl == NULL) + { + return PyMem_RawCalloc(1, sizeof(_PyThreadStateImpl)); + } + // Zero-out the allocation again. + memset(impl, 0, sizeof(_PyThreadStateImpl)); + return impl; } static void @@ -1408,7 +1417,7 @@ free_threadstate(_PyThreadStateImpl *tstate) sizeof(*tstate)); } else { - PyMem_RawFree(tstate); + _PyFreeList_Free(&thread_states, tstate, 100, PyMem_RawFree); } } From 4bbbc928a189106c3f749ce2d75d8e9b699543a6 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 28 Oct 2024 19:06:09 -0400 Subject: [PATCH 2/7] Don't use it on systems that don't support thread locals. --- Python/pystate.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Python/pystate.c b/Python/pystate.c index 9e16af863332d9..7e669d1a3688fc 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1390,11 +1390,14 @@ allocate_chunk(int size_in_bytes, _PyStackChunk* previous) return res; } +#ifdef HAVE_THREAD_LOCAL _Py_thread_local struct _Py_freelist thread_states = { 0 }; +#endif static _PyThreadStateImpl * alloc_threadstate(void) { +#ifdef HAVE_THREAD_LOCAL _PyThreadStateImpl *impl = _PyFreeList_PopMem(&thread_states); if (impl == NULL) { @@ -1403,6 +1406,9 @@ alloc_threadstate(void) // Zero-out the allocation again. memset(impl, 0, sizeof(_PyThreadStateImpl)); return impl; +#else + return PyMem_RawCalloc(1, sizeof(_PyThreadStateImpl)); +#endif } static void @@ -1417,7 +1423,12 @@ free_threadstate(_PyThreadStateImpl *tstate) sizeof(*tstate)); } else { +#ifdef HAVE_THREAD_LOCAL + // Maximum of 100 thread states in the freelist _PyFreeList_Free(&thread_states, tstate, 100, PyMem_RawFree); +#else + PyMem_RawFree(tstate); +#endif } } From 26621db16deec07df648ae60bd5431c1ade9cf72 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 28 Oct 2024 19:13:58 -0400 Subject: [PATCH 3/7] Add blurb. --- .../2024-10-28-19-13-52.gh-issue-126096.3x4spF.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2024-10-28-19-13-52.gh-issue-126096.3x4spF.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-28-19-13-52.gh-issue-126096.3x4spF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-28-19-13-52.gh-issue-126096.3x4spF.rst new file mode 100644 index 00000000000000..1e67a8ccefa1f7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-28-19-13-52.gh-issue-126096.3x4spF.rst @@ -0,0 +1 @@ +Optimized switching between interpreters via a freelist. From ec1d7c3fd75042674a964ef16d714538c503d994 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 28 Oct 2024 19:21:35 -0400 Subject: [PATCH 4/7] Add const to shut the analyzer up. --- Python/pystate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index 7e669d1a3688fc..cfbf2aa5fa19f6 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1391,7 +1391,7 @@ allocate_chunk(int size_in_bytes, _PyStackChunk* previous) } #ifdef HAVE_THREAD_LOCAL -_Py_thread_local struct _Py_freelist thread_states = { 0 }; +const _Py_thread_local struct _Py_freelist thread_states = { 0 }; #endif static _PyThreadStateImpl * From c0b8536ed440f881ba0233be689130703a0e179f Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 28 Oct 2024 19:25:07 -0400 Subject: [PATCH 5/7] Fix compiler warnings. --- Python/pystate.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Python/pystate.c b/Python/pystate.c index cfbf2aa5fa19f6..9b1ca74e92ab30 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1391,14 +1391,15 @@ allocate_chunk(int size_in_bytes, _PyStackChunk* previous) } #ifdef HAVE_THREAD_LOCAL -const _Py_thread_local struct _Py_freelist thread_states = { 0 }; +_Py_thread_local const struct _Py_freelist thread_states = { 0 }; +#define _PyThreadState_FREELIST() ((struct _Py_freelist *) &thread_states) #endif static _PyThreadStateImpl * alloc_threadstate(void) { #ifdef HAVE_THREAD_LOCAL - _PyThreadStateImpl *impl = _PyFreeList_PopMem(&thread_states); + _PyThreadStateImpl *impl = _PyFreeList_PopMem(_PyThreadState_FREELIST()); if (impl == NULL) { return PyMem_RawCalloc(1, sizeof(_PyThreadStateImpl)); @@ -1425,7 +1426,7 @@ free_threadstate(_PyThreadStateImpl *tstate) else { #ifdef HAVE_THREAD_LOCAL // Maximum of 100 thread states in the freelist - _PyFreeList_Free(&thread_states, tstate, 100, PyMem_RawFree); + _PyFreeList_Free(_PyThreadState_FREELIST(), tstate, 100, PyMem_RawFree); #else PyMem_RawFree(tstate); #endif From 6e5961825b15c213ad64495e0b5e2db6fc9561b8 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 28 Oct 2024 19:35:35 -0400 Subject: [PATCH 6/7] Use a static declaration as well. --- Python/pystate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Python/pystate.c b/Python/pystate.c index 9b1ca74e92ab30..f031d7dcd1af0c 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1391,7 +1391,7 @@ allocate_chunk(int size_in_bytes, _PyStackChunk* previous) } #ifdef HAVE_THREAD_LOCAL -_Py_thread_local const struct _Py_freelist thread_states = { 0 }; +_Py_thread_local static const struct _Py_freelist thread_states = { 0 }; #define _PyThreadState_FREELIST() ((struct _Py_freelist *) &thread_states) #endif From 7fdc3da1df6e96a80fa236158e066c2e79f07c49 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Mon, 28 Oct 2024 19:37:49 -0400 Subject: [PATCH 7/7] Fix the analyzer (again). --- Python/pystate.c | 4 ++-- Tools/c-analyzer/cpython/ignored.tsv | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Python/pystate.c b/Python/pystate.c index f031d7dcd1af0c..662480cb2f2098 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -1391,8 +1391,8 @@ allocate_chunk(int size_in_bytes, _PyStackChunk* previous) } #ifdef HAVE_THREAD_LOCAL -_Py_thread_local static const struct _Py_freelist thread_states = { 0 }; -#define _PyThreadState_FREELIST() ((struct _Py_freelist *) &thread_states) +_Py_thread_local static const struct _Py_freelist _Py_tss_tstates_freelist = { 0 }; +#define _PyThreadState_FREELIST() ((struct _Py_freelist *) &_Py_tss_tstates_freelist) #endif static _PyThreadStateImpl * diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv index 2605825d3d0078..664559d0fef054 100644 --- a/Tools/c-analyzer/cpython/ignored.tsv +++ b/Tools/c-analyzer/cpython/ignored.tsv @@ -185,6 +185,7 @@ Python/pyfpe.c - PyFPE_counter - Python/import.c - pkgcontext - Python/pystate.c - _Py_tss_tstate - +Python/pystate.c - _Py_tss_tstates_freelist - ##----------------------- ## should be const