mirror of
https://github.com/python/cpython.git
synced 2026-05-06 12:49:07 -04:00
[3.13] gh-142183: Cache one datachunk per tstate to prevent alloc/dealloc thrashing (GH-145789) (#146123)
* gh-142183: Cache one datachunk per tstate to prevent alloc/dealloc thrashing (GH-145789) (#145828) Cache one datachunk per tstate to prevent alloc/dealloc thrashing when repeatedly hitting the same call depth at exactly the wrong boundary. Move new _ts member to the end to not mess up remote debuggers' ideas of the struct's layout. (The struct is only created by the runtime, and the new field only used by the runtime, so it should be safe.) (cherry picked from commit706fd4ec08) (cherry picked from commit19cbcc0f85) Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com> Co-authored-by: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
This commit is contained in:
+634
-631
File diff suppressed because it is too large
Load Diff
@@ -200,6 +200,8 @@ struct _ts {
|
||||
The PyThreadObject must hold the only reference to this value.
|
||||
*/
|
||||
PyObject *threading_local_sentinel;
|
||||
|
||||
_PyStackChunk *datastack_cached_chunk;
|
||||
};
|
||||
|
||||
#ifdef Py_DEBUG
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Avoid a pathological case where repeated calls at a specific stack depth could be significantly slower.
|
||||
+26
-4
@@ -1521,6 +1521,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->previous_executor = NULL;
|
||||
tstate->dict_global_version = 0;
|
||||
@@ -1655,6 +1656,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
|
||||
@@ -2934,9 +2940,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 -
|
||||
@@ -2972,12 +2989,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);
|
||||
|
||||
Reference in New Issue
Block a user