gh-111968: Split _Py_dictkeys_freelist out of _Py_dict_freelist (gh-115505)

This commit is contained in:
Donghee Na 2024-02-16 10:01:36 +09:00 committed by GitHub
parent 454d7963e3
commit 321d13fd2b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 77 additions and 59 deletions

View File

@ -35,7 +35,7 @@ extern "C" {
struct _Py_list_freelist { struct _Py_list_freelist {
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
PyListObject *free_list[PyList_MAXFREELIST]; PyListObject *items[PyList_MAXFREELIST];
int numfree; int numfree;
#endif #endif
}; };
@ -50,7 +50,7 @@ struct _Py_tuple_freelist {
object is used as the linked list node, with its first item object is used as the linked list node, with its first item
(ob_item[0]) pointing to the next node (i.e. the previous head). (ob_item[0]) pointing to the next node (i.e. the previous head).
Each linked list is initially NULL. */ Each linked list is initially NULL. */
PyTupleObject *free_list[PyTuple_NFREELISTS]; PyTupleObject *items[PyTuple_NFREELISTS];
int numfree[PyTuple_NFREELISTS]; int numfree[PyTuple_NFREELISTS];
#else #else
char _unused; // Empty structs are not allowed. char _unused; // Empty structs are not allowed.
@ -63,17 +63,23 @@ struct _Py_float_freelist {
free_list is a singly-linked list of available PyFloatObjects, free_list is a singly-linked list of available PyFloatObjects,
linked via abuse of their ob_type members. */ linked via abuse of their ob_type members. */
int numfree; int numfree;
PyFloatObject *free_list; PyFloatObject *items;
#endif #endif
}; };
struct _Py_dict_freelist { struct _Py_dict_freelist {
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
/* Dictionary reuse scheme to save calls to malloc and free */ /* Dictionary reuse scheme to save calls to malloc and free */
PyDictObject *free_list[PyDict_MAXFREELIST]; PyDictObject *items[PyDict_MAXFREELIST];
PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST]; int numfree;
#endif
};
struct _Py_dictkeys_freelist {
#ifdef WITH_FREELISTS
/* Dictionary keys reuse scheme to save calls to malloc and free */
PyDictKeysObject *items[PyDict_MAXFREELIST];
int numfree; int numfree;
int keys_numfree;
#endif #endif
}; };
@ -88,7 +94,7 @@ struct _Py_slice_freelist {
struct _Py_context_freelist { struct _Py_context_freelist {
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
// List of free PyContext objects // List of free PyContext objects
PyContext *freelist; PyContext *items;
int numfree; int numfree;
#endif #endif
}; };
@ -110,7 +116,7 @@ struct _Py_async_gen_freelist {
struct _PyObjectStackChunk; struct _PyObjectStackChunk;
struct _Py_object_stack_freelist { struct _Py_object_stack_freelist {
struct _PyObjectStackChunk *free_list; struct _PyObjectStackChunk *items;
Py_ssize_t numfree; Py_ssize_t numfree;
}; };
@ -119,6 +125,7 @@ struct _Py_object_freelists {
struct _Py_tuple_freelist tuples; struct _Py_tuple_freelist tuples;
struct _Py_list_freelist lists; struct _Py_list_freelist lists;
struct _Py_dict_freelist dicts; struct _Py_dict_freelist dicts;
struct _Py_dictkeys_freelist dictkeys;
struct _Py_slice_freelist slices; struct _Py_slice_freelist slices;
struct _Py_context_freelist contexts; struct _Py_context_freelist contexts;
struct _Py_async_gen_freelist async_gens; struct _Py_async_gen_freelist async_gens;

View File

@ -276,6 +276,13 @@ get_dict_freelist(void)
struct _Py_object_freelists *freelists = _Py_object_freelists_GET(); struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
return &freelists->dicts; return &freelists->dicts;
} }
static struct _Py_dictkeys_freelist *
get_dictkeys_freelist(void)
{
struct _Py_object_freelists *freelists = _Py_object_freelists_GET();
return &freelists->dictkeys;
}
#endif #endif
@ -283,18 +290,19 @@ void
_PyDict_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization) _PyDict_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalization)
{ {
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
struct _Py_dict_freelist *state = &freelists->dicts; struct _Py_dict_freelist *freelist = &freelists->dicts;
while (state->numfree > 0) { while (freelist->numfree > 0) {
PyDictObject *op = state->free_list[--state->numfree]; PyDictObject *op = freelist->items[--freelist->numfree];
assert(PyDict_CheckExact(op)); assert(PyDict_CheckExact(op));
PyObject_GC_Del(op); PyObject_GC_Del(op);
} }
while (state->keys_numfree > 0) { struct _Py_dictkeys_freelist *keys_freelist = &freelists->dictkeys;
PyMem_Free(state->keys_free_list[--state->keys_numfree]); while (keys_freelist->numfree > 0) {
PyMem_Free(keys_freelist->items[--keys_freelist->numfree]);
} }
if (is_finalization) { if (is_finalization) {
state->numfree = -1; freelist->numfree = -1;
state->keys_numfree = -1; keys_freelist->numfree = -1;
} }
#endif #endif
} }
@ -314,6 +322,9 @@ _PyDict_DebugMallocStats(FILE *out)
struct _Py_dict_freelist *dict_freelist = get_dict_freelist(); struct _Py_dict_freelist *dict_freelist = get_dict_freelist();
_PyDebugAllocatorStats(out, "free PyDictObject", _PyDebugAllocatorStats(out, "free PyDictObject",
dict_freelist->numfree, sizeof(PyDictObject)); dict_freelist->numfree, sizeof(PyDictObject));
struct _Py_dictkeys_freelist *dictkeys_freelist = get_dictkeys_freelist();
_PyDebugAllocatorStats(out, "free PyDictKeysObject",
dictkeys_freelist->numfree, sizeof(PyDictKeysObject));
#endif #endif
} }
@ -663,9 +674,9 @@ new_keys_object(PyInterpreterState *interp, uint8_t log2_size, bool unicode)
} }
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
struct _Py_dict_freelist *dict_freelist = get_dict_freelist(); struct _Py_dictkeys_freelist *freelist = get_dictkeys_freelist();
if (log2_size == PyDict_LOG_MINSIZE && unicode && dict_freelist->keys_numfree > 0) { if (log2_size == PyDict_LOG_MINSIZE && unicode && freelist->numfree > 0) {
dk = dict_freelist->keys_free_list[--dict_freelist->keys_numfree]; dk = freelist->items[--freelist->numfree];
OBJECT_STAT_INC(from_freelist); OBJECT_STAT_INC(from_freelist);
} }
else else
@ -698,12 +709,12 @@ static void
free_keys_object(PyDictKeysObject *keys) free_keys_object(PyDictKeysObject *keys)
{ {
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
struct _Py_dict_freelist *dict_freelist = get_dict_freelist(); struct _Py_dictkeys_freelist *freelist = get_dictkeys_freelist();
if (DK_LOG_SIZE(keys) == PyDict_LOG_MINSIZE if (DK_LOG_SIZE(keys) == PyDict_LOG_MINSIZE
&& dict_freelist->keys_numfree < PyDict_MAXFREELIST && freelist->numfree < PyDict_MAXFREELIST
&& dict_freelist->keys_numfree >= 0 && freelist->numfree >= 0
&& DK_IS_UNICODE(keys)) { && DK_IS_UNICODE(keys)) {
dict_freelist->keys_free_list[dict_freelist->keys_numfree++] = keys; freelist->items[freelist->numfree++] = keys;
OBJECT_STAT_INC(to_freelist); OBJECT_STAT_INC(to_freelist);
return; return;
} }
@ -743,9 +754,9 @@ new_dict(PyInterpreterState *interp,
PyDictObject *mp; PyDictObject *mp;
assert(keys != NULL); assert(keys != NULL);
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
struct _Py_dict_freelist *dict_freelist = get_dict_freelist(); struct _Py_dict_freelist *freelist = get_dict_freelist();
if (dict_freelist->numfree > 0) { if (freelist->numfree > 0) {
mp = dict_freelist->free_list[--dict_freelist->numfree]; mp = freelist->items[--freelist->numfree];
assert (mp != NULL); assert (mp != NULL);
assert (Py_IS_TYPE(mp, &PyDict_Type)); assert (Py_IS_TYPE(mp, &PyDict_Type));
OBJECT_STAT_INC(from_freelist); OBJECT_STAT_INC(from_freelist);
@ -2593,10 +2604,10 @@ dict_dealloc(PyObject *self)
dictkeys_decref(interp, keys); dictkeys_decref(interp, keys);
} }
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
struct _Py_dict_freelist *dict_freelist = get_dict_freelist(); struct _Py_dict_freelist *freelist = get_dict_freelist();
if (dict_freelist->numfree < PyDict_MAXFREELIST && dict_freelist->numfree >=0 && if (freelist->numfree < PyDict_MAXFREELIST && freelist->numfree >=0 &&
Py_IS_TYPE(mp, &PyDict_Type)) { Py_IS_TYPE(mp, &PyDict_Type)) {
dict_freelist->free_list[dict_freelist->numfree++] = mp; freelist->items[freelist->numfree++] = mp;
OBJECT_STAT_INC(to_freelist); OBJECT_STAT_INC(to_freelist);
} }
else else

View File

@ -130,9 +130,9 @@ PyFloat_FromDouble(double fval)
PyFloatObject *op; PyFloatObject *op;
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
struct _Py_float_freelist *float_freelist = get_float_freelist(); struct _Py_float_freelist *float_freelist = get_float_freelist();
op = float_freelist->free_list; op = float_freelist->items;
if (op != NULL) { if (op != NULL) {
float_freelist->free_list = (PyFloatObject *) Py_TYPE(op); float_freelist->items = (PyFloatObject *) Py_TYPE(op);
float_freelist->numfree--; float_freelist->numfree--;
OBJECT_STAT_INC(from_freelist); OBJECT_STAT_INC(from_freelist);
} }
@ -251,8 +251,8 @@ _PyFloat_ExactDealloc(PyObject *obj)
return; return;
} }
float_freelist->numfree++; float_freelist->numfree++;
Py_SET_TYPE(op, (PyTypeObject *)float_freelist->free_list); Py_SET_TYPE(op, (PyTypeObject *)float_freelist->items);
float_freelist->free_list = op; float_freelist->items = op;
OBJECT_STAT_INC(to_freelist); OBJECT_STAT_INC(to_freelist);
#else #else
PyObject_Free(op); PyObject_Free(op);
@ -1994,13 +1994,13 @@ _PyFloat_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalizati
{ {
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
struct _Py_float_freelist *state = &freelists->floats; struct _Py_float_freelist *state = &freelists->floats;
PyFloatObject *f = state->free_list; PyFloatObject *f = state->items;
while (f != NULL) { while (f != NULL) {
PyFloatObject *next = (PyFloatObject*) Py_TYPE(f); PyFloatObject *next = (PyFloatObject*) Py_TYPE(f);
PyObject_Free(f); PyObject_Free(f);
f = next; f = next;
} }
state->free_list = NULL; state->items = NULL;
if (is_finalization) { if (is_finalization) {
state->numfree = -1; state->numfree = -1;
} }

View File

@ -133,7 +133,7 @@ _PyList_ClearFreeList(struct _Py_object_freelists *freelists, int is_finalizatio
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
struct _Py_list_freelist *state = &freelists->lists; struct _Py_list_freelist *state = &freelists->lists;
while (state->numfree > 0) { while (state->numfree > 0) {
PyListObject *op = state->free_list[--state->numfree]; PyListObject *op = state->items[--state->numfree];
assert(PyList_CheckExact(op)); assert(PyList_CheckExact(op));
PyObject_GC_Del(op); PyObject_GC_Del(op);
} }
@ -169,7 +169,7 @@ PyList_New(Py_ssize_t size)
struct _Py_list_freelist *list_freelist = get_list_freelist(); struct _Py_list_freelist *list_freelist = get_list_freelist();
if (PyList_MAXFREELIST && list_freelist->numfree > 0) { if (PyList_MAXFREELIST && list_freelist->numfree > 0) {
list_freelist->numfree--; list_freelist->numfree--;
op = list_freelist->free_list[list_freelist->numfree]; op = list_freelist->items[list_freelist->numfree];
OBJECT_STAT_INC(from_freelist); OBJECT_STAT_INC(from_freelist);
_Py_NewReference((PyObject *)op); _Py_NewReference((PyObject *)op);
} }
@ -401,7 +401,7 @@ list_dealloc(PyObject *self)
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
struct _Py_list_freelist *list_freelist = get_list_freelist(); struct _Py_list_freelist *list_freelist = get_list_freelist();
if (list_freelist->numfree < PyList_MAXFREELIST && list_freelist->numfree >= 0 && PyList_CheckExact(op)) { if (list_freelist->numfree < PyList_MAXFREELIST && list_freelist->numfree >= 0 && PyList_CheckExact(op)) {
list_freelist->free_list[list_freelist->numfree++] = op; list_freelist->items[list_freelist->numfree++] = op;
OBJECT_STAT_INC(to_freelist); OBJECT_STAT_INC(to_freelist);
} }
else else

View File

@ -1134,11 +1134,11 @@ maybe_freelist_pop(Py_ssize_t size)
assert(size > 0); assert(size > 0);
if (size < PyTuple_MAXSAVESIZE) { if (size < PyTuple_MAXSAVESIZE) {
Py_ssize_t index = size - 1; Py_ssize_t index = size - 1;
PyTupleObject *op = TUPLE_FREELIST.free_list[index]; PyTupleObject *op = TUPLE_FREELIST.items[index];
if (op != NULL) { if (op != NULL) {
/* op is the head of a linked list, with the first item /* op is the head of a linked list, with the first item
pointing to the next node. Here we pop off the old head. */ pointing to the next node. Here we pop off the old head. */
TUPLE_FREELIST.free_list[index] = (PyTupleObject *) op->ob_item[0]; TUPLE_FREELIST.items[index] = (PyTupleObject *) op->ob_item[0];
TUPLE_FREELIST.numfree[index]--; TUPLE_FREELIST.numfree[index]--;
/* Inlined _PyObject_InitVar() without _PyType_HasFeature() test */ /* Inlined _PyObject_InitVar() without _PyType_HasFeature() test */
#ifdef Py_TRACE_REFS #ifdef Py_TRACE_REFS
@ -1173,8 +1173,8 @@ maybe_freelist_push(PyTupleObject *op)
{ {
/* op is the head of a linked list, with the first item /* op is the head of a linked list, with the first item
pointing to the next node. Here we set op as the new head. */ pointing to the next node. Here we set op as the new head. */
op->ob_item[0] = (PyObject *) TUPLE_FREELIST.free_list[index]; op->ob_item[0] = (PyObject *) TUPLE_FREELIST.items[index];
TUPLE_FREELIST.free_list[index] = op; TUPLE_FREELIST.items[index] = op;
TUPLE_FREELIST.numfree[index]++; TUPLE_FREELIST.numfree[index]++;
OBJECT_STAT_INC(to_freelist); OBJECT_STAT_INC(to_freelist);
return 1; return 1;
@ -1188,8 +1188,8 @@ maybe_freelist_clear(struct _Py_object_freelists *freelists, int fini)
{ {
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
for (Py_ssize_t i = 0; i < PyTuple_NFREELISTS; i++) { for (Py_ssize_t i = 0; i < PyTuple_NFREELISTS; i++) {
PyTupleObject *p = TUPLE_FREELIST.free_list[i]; PyTupleObject *p = TUPLE_FREELIST.items[i];
TUPLE_FREELIST.free_list[i] = NULL; TUPLE_FREELIST.items[i] = NULL;
TUPLE_FREELIST.numfree[i] = fini ? -1 : 0; TUPLE_FREELIST.numfree[i] = fini ? -1 : 0;
while (p) { while (p) {
PyTupleObject *q = p; PyTupleObject *q = p;

View File

@ -344,8 +344,8 @@ _context_alloc(void)
struct _Py_context_freelist *context_freelist = get_context_freelist(); struct _Py_context_freelist *context_freelist = get_context_freelist();
if (context_freelist->numfree > 0) { if (context_freelist->numfree > 0) {
context_freelist->numfree--; context_freelist->numfree--;
ctx = context_freelist->freelist; ctx = context_freelist->items;
context_freelist->freelist = (PyContext *)ctx->ctx_weakreflist; context_freelist->items = (PyContext *)ctx->ctx_weakreflist;
OBJECT_STAT_INC(from_freelist); OBJECT_STAT_INC(from_freelist);
ctx->ctx_weakreflist = NULL; ctx->ctx_weakreflist = NULL;
_Py_NewReference((PyObject *)ctx); _Py_NewReference((PyObject *)ctx);
@ -471,8 +471,8 @@ context_tp_dealloc(PyContext *self)
struct _Py_context_freelist *context_freelist = get_context_freelist(); struct _Py_context_freelist *context_freelist = get_context_freelist();
if (context_freelist->numfree >= 0 && context_freelist->numfree < PyContext_MAXFREELIST) { if (context_freelist->numfree >= 0 && context_freelist->numfree < PyContext_MAXFREELIST) {
context_freelist->numfree++; context_freelist->numfree++;
self->ctx_weakreflist = (PyObject *)context_freelist->freelist; self->ctx_weakreflist = (PyObject *)context_freelist->items;
context_freelist->freelist = self; context_freelist->items = self;
OBJECT_STAT_INC(to_freelist); OBJECT_STAT_INC(to_freelist);
} }
else else
@ -1272,8 +1272,8 @@ _PyContext_ClearFreeList(struct _Py_object_freelists *freelists, int is_finaliza
#ifdef WITH_FREELISTS #ifdef WITH_FREELISTS
struct _Py_context_freelist *state = &freelists->contexts; struct _Py_context_freelist *state = &freelists->contexts;
for (; state->numfree > 0; state->numfree--) { for (; state->numfree > 0; state->numfree--) {
PyContext *ctx = state->freelist; PyContext *ctx = state->items;
state->freelist = (PyContext *)ctx->ctx_weakreflist; state->items = (PyContext *)ctx->ctx_weakreflist;
ctx->ctx_weakreflist = NULL; ctx->ctx_weakreflist = NULL;
PyObject_GC_Del(ctx); PyObject_GC_Del(ctx);
} }

View File

@ -21,8 +21,8 @@ _PyObjectStackChunk_New(void)
_PyObjectStackChunk *buf; _PyObjectStackChunk *buf;
struct _Py_object_stack_freelist *obj_stack_freelist = get_object_stack_freelist(); struct _Py_object_stack_freelist *obj_stack_freelist = get_object_stack_freelist();
if (obj_stack_freelist->numfree > 0) { if (obj_stack_freelist->numfree > 0) {
buf = obj_stack_freelist->free_list; buf = obj_stack_freelist->items;
obj_stack_freelist->free_list = buf->prev; obj_stack_freelist->items = buf->prev;
obj_stack_freelist->numfree--; obj_stack_freelist->numfree--;
} }
else { else {
@ -47,8 +47,8 @@ _PyObjectStackChunk_Free(_PyObjectStackChunk *buf)
if (obj_stack_freelist->numfree >= 0 && if (obj_stack_freelist->numfree >= 0 &&
obj_stack_freelist->numfree < _PyObjectStackChunk_MAXFREELIST) obj_stack_freelist->numfree < _PyObjectStackChunk_MAXFREELIST)
{ {
buf->prev = obj_stack_freelist->free_list; buf->prev = obj_stack_freelist->items;
obj_stack_freelist->free_list = buf; obj_stack_freelist->items = buf;
obj_stack_freelist->numfree++; obj_stack_freelist->numfree++;
} }
else { else {
@ -97,12 +97,12 @@ _PyObjectStackChunk_ClearFreeList(struct _Py_object_freelists *freelists, int is
return; return;
} }
struct _Py_object_stack_freelist *state = &freelists->object_stacks; struct _Py_object_stack_freelist *freelist = &freelists->object_stacks;
while (state->numfree > 0) { while (freelist->numfree > 0) {
_PyObjectStackChunk *buf = state->free_list; _PyObjectStackChunk *buf = freelist->items;
state->free_list = buf->prev; freelist->items = buf->prev;
state->numfree--; freelist->numfree--;
PyMem_RawFree(buf); PyMem_RawFree(buf);
} }
state->numfree = -1; freelist->numfree = -1;
} }