Skip to content

Commit 7627b90

Browse files
Yhg1smeta-codesync[bot]
authored andcommitted
Cache one datachunk per tstate to prevent alloc/dealloc thrashing
Summary: Cache one datachunk per tstate to prevent alloc/dealloc thrashing when repeatedly hitting the same call depth at exactly the wrong boundary. Upstream issue: python/cpython#142183 Upstream PR: python/cpython#145789 Reviewed By: itamaro Differential Revision: D96052502 fbshipit-source-id: 883f6148568b6cca5a71dd7d754eb206fbb56f90
1 parent 743d728 commit 7627b90

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

Include/cpython/pystate.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ struct _ts {
208208
*/
209209
PyObject *threading_local_sentinel;
210210
_PyRemoteDebuggerSupport remote_debugger_support;
211+
_PyStackChunk *datastack_cached_chunk;
211212
};
212213

213214
/* other API */

Python/pystate.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1596,6 +1596,7 @@ init_threadstate(_PyThreadStateImpl *_tstate,
15961596
tstate->datastack_chunk = NULL;
15971597
tstate->datastack_top = NULL;
15981598
tstate->datastack_limit = NULL;
1599+
tstate->datastack_cached_chunk = NULL;
15991600
tstate->what_event = -1;
16001601
tstate->current_executor = NULL;
16011602
tstate->dict_global_version = 0;
@@ -1735,6 +1736,11 @@ clear_datastack(PyThreadState *tstate)
17351736
_PyObject_VirtualFree(chunk, chunk->size);
17361737
chunk = prev;
17371738
}
1739+
if (tstate->datastack_cached_chunk != NULL) {
1740+
_PyObject_VirtualFree(tstate->datastack_cached_chunk,
1741+
tstate->datastack_cached_chunk->size);
1742+
tstate->datastack_cached_chunk = NULL;
1743+
}
17381744
}
17391745

17401746
void
@@ -3050,9 +3056,20 @@ push_chunk(PyThreadState *tstate, int size)
30503056
while (allocate_size < (int)sizeof(PyObject*)*(size + MINIMUM_OVERHEAD)) {
30513057
allocate_size *= 2;
30523058
}
3053-
_PyStackChunk *new = allocate_chunk(allocate_size, tstate->datastack_chunk);
3054-
if (new == NULL) {
3055-
return NULL;
3059+
_PyStackChunk *new;
3060+
if (tstate->datastack_cached_chunk != NULL
3061+
&& (size_t)allocate_size <= tstate->datastack_cached_chunk->size)
3062+
{
3063+
new = tstate->datastack_cached_chunk;
3064+
tstate->datastack_cached_chunk = NULL;
3065+
new->previous = tstate->datastack_chunk;
3066+
new->top = 0;
3067+
}
3068+
else {
3069+
new = allocate_chunk(allocate_size, tstate->datastack_chunk);
3070+
if (new == NULL) {
3071+
return NULL;
3072+
}
30563073
}
30573074
if (tstate->datastack_chunk) {
30583075
tstate->datastack_chunk->top = tstate->datastack_top -
@@ -3088,12 +3105,17 @@ _PyThreadState_PopFrame(PyThreadState *tstate, _PyInterpreterFrame * frame)
30883105
if (base == &tstate->datastack_chunk->data[0]) {
30893106
_PyStackChunk *chunk = tstate->datastack_chunk;
30903107
_PyStackChunk *previous = chunk->previous;
3108+
_PyStackChunk *cached = tstate->datastack_cached_chunk;
30913109
// push_chunk ensures that the root chunk is never popped:
30923110
assert(previous);
30933111
tstate->datastack_top = &previous->data[previous->top];
30943112
tstate->datastack_chunk = previous;
3095-
_PyObject_VirtualFree(chunk, chunk->size);
30963113
tstate->datastack_limit = (PyObject **)(((char *)previous) + previous->size);
3114+
chunk->previous = NULL;
3115+
if (cached != NULL) {
3116+
_PyObject_VirtualFree(cached, cached->size);
3117+
}
3118+
tstate->datastack_cached_chunk = chunk;
30973119
}
30983120
else {
30993121
assert(tstate->datastack_top);

0 commit comments

Comments
 (0)