https://github.com/python/cpython/commit/706fd4ec08acbf1b1def3630017ebe55d224adfa
commit: 706fd4ec08acbf1b1def3630017ebe55d224adfa
branch: main
author: T. Wouters <[email protected]>
committer: Yhg1s <[email protected]>
date: 2026-03-11T15:46:16+01:00
summary:
gh-142183: Cache one datachunk per tstate to prevent alloc/dealloc thrashing
(#145789)
Cache one datachunk per tstate to prevent alloc/dealloc thrashing when
repeatedly hitting the same call depth at exactly the wrong boundary.
---------
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-03-11-00-13-59.gh-issue-142183.2iVhJH.rst
M Include/cpython/pystate.h
M Python/pystate.c
diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index 22df26bd37a5c5..1c56ad5af8072f 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -198,6 +198,7 @@ struct _ts {
_PyStackChunk *datastack_chunk;
PyObject **datastack_top;
PyObject **datastack_limit;
+ _PyStackChunk *datastack_cached_chunk;
/* XXX signal handlers should also be here */
/* The following fields are here to avoid allocation during init.
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-03-11-00-13-59.gh-issue-142183.2iVhJH.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-11-00-13-59.gh-issue-142183.2iVhJH.rst
new file mode 100644
index 00000000000000..827224dc71e827
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-03-11-00-13-59.gh-issue-142183.2iVhJH.rst
@@ -0,0 +1 @@
+Avoid a pathological case where repeated calls at a specific stack depth could
be significantly slower.
diff --git a/Python/pystate.c b/Python/pystate.c
index a8f37bedc81247..17b8430b19c188 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1564,6 +1564,7 @@ init_threadstate(_PyThreadStateImpl *_tstate,
tstate->datastack_chunk = NULL;
tstate->datastack_top = NULL;
tstate->datastack_limit = NULL;
+ tstate->datastack_cached_chunk = NULL;
tstate->what_event = -1;
tstate->current_executor = NULL;
tstate->jit_exit = NULL;
@@ -1714,6 +1715,11 @@ clear_datastack(PyThreadState *tstate)
_PyObject_VirtualFree(chunk, chunk->size);
chunk = prev;
}
+ if (tstate->datastack_cached_chunk != NULL) {
+ _PyObject_VirtualFree(tstate->datastack_cached_chunk,
+ tstate->datastack_cached_chunk->size);
+ tstate->datastack_cached_chunk = NULL;
+ }
}
void
@@ -3045,9 +3051,20 @@ push_chunk(PyThreadState *tstate, int size)
while (allocate_size < (int)sizeof(PyObject*)*(size + MINIMUM_OVERHEAD)) {
allocate_size *= 2;
}
- _PyStackChunk *new = allocate_chunk(allocate_size,
tstate->datastack_chunk);
- if (new == NULL) {
- return NULL;
+ _PyStackChunk *new;
+ if (tstate->datastack_cached_chunk != NULL
+ && (size_t)allocate_size <= tstate->datastack_cached_chunk->size)
+ {
+ new = tstate->datastack_cached_chunk;
+ tstate->datastack_cached_chunk = NULL;
+ new->previous = tstate->datastack_chunk;
+ new->top = 0;
+ }
+ else {
+ new = allocate_chunk(allocate_size, tstate->datastack_chunk);
+ if (new == NULL) {
+ return NULL;
+ }
}
if (tstate->datastack_chunk) {
tstate->datastack_chunk->top = tstate->datastack_top -
@@ -3083,12 +3100,17 @@ _PyThreadState_PopFrame(PyThreadState *tstate,
_PyInterpreterFrame * frame)
if (base == &tstate->datastack_chunk->data[0]) {
_PyStackChunk *chunk = tstate->datastack_chunk;
_PyStackChunk *previous = chunk->previous;
+ _PyStackChunk *cached = tstate->datastack_cached_chunk;
// push_chunk ensures that the root chunk is never popped:
assert(previous);
tstate->datastack_top = &previous->data[previous->top];
tstate->datastack_chunk = previous;
- _PyObject_VirtualFree(chunk, chunk->size);
tstate->datastack_limit = (PyObject **)(((char *)previous) +
previous->size);
+ chunk->previous = NULL;
+ if (cached != NULL) {
+ _PyObject_VirtualFree(cached, cached->size);
+ }
+ tstate->datastack_cached_chunk = chunk;
}
else {
assert(tstate->datastack_top);
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]