bpo-40521: Make dict free lists per-interpreter (GH-20645) · python/cpython@b4e85ca
@@ -247,58 +247,47 @@ static uint64_t pydict_global_version = 0;
247247248248#define DICT_NEXT_VERSION() (++pydict_global_version)
249249250-/* Dictionary reuse scheme to save calls to malloc and free */
251-#ifndef PyDict_MAXFREELIST
252-#define PyDict_MAXFREELIST 80
253-#endif
254-255-/* bpo-40521: dict free lists are shared by all interpreters. */
256-#ifdef EXPERIMENTAL_ISOLATED_SUBINTERPRETERS
257-# undef PyDict_MAXFREELIST
258-# define PyDict_MAXFREELIST 0
259-#endif
260-261-#if PyDict_MAXFREELIST > 0
262-static PyDictObject *free_list[PyDict_MAXFREELIST];
263-static int numfree = 0;
264-static PyDictKeysObject *keys_free_list[PyDict_MAXFREELIST];
265-static int numfreekeys = 0;
266-#endif
267-268250#include "clinic/dictobject.c.h"
269251270252void
271-_PyDict_ClearFreeList(void)
253+_PyDict_ClearFreeList(PyThreadState *tstate)
272254{
273-#if PyDict_MAXFREELIST > 0
274-while (numfree) {
275-PyDictObject *op = free_list[--numfree];
255+ struct _Py_dict_state *state = &tstate->interp->dict_state;
256+while (state->numfree) {
257+PyDictObject *op = state->free_list[--state->numfree];
276258assert(PyDict_CheckExact(op));
277259PyObject_GC_Del(op);
278260 }
279-while (numfreekeys) {
280-PyObject_FREE(keys_free_list[--numfreekeys]);
261+while (state->keys_numfree) {
262+PyObject_FREE(state->keys_free_list[--state->keys_numfree]);
281263 }
282-#endif
283264}
284265285-/* Print summary info about the state of the optimized allocator */
266+286267void
287-_PyDict_DebugMallocStats(FILE *out)
268+_PyDict_Fini(PyThreadState *tstate)
288269{
289-#if PyDict_MAXFREELIST > 0
290-_PyDebugAllocatorStats(out,
291-"free PyDictObject", numfree, sizeof(PyDictObject));
270+_PyDict_ClearFreeList(tstate);
271+#ifdef Py_DEBUG
272+PyInterpreterState *interp = _PyInterpreterState_GET();
273+struct _Py_dict_state *state = &interp->dict_state;
274+state->numfree = -1;
275+state->keys_numfree = -1;
292276#endif
293277}
294278295279280+/* Print summary info about the state of the optimized allocator */
296281void
297-_PyDict_Fini(void)
282+_PyDict_DebugMallocStats(FILE *out)
298283{
299-_PyDict_ClearFreeList();
284+PyInterpreterState *interp = _PyInterpreterState_GET();
285+struct _Py_dict_state *state = &interp->dict_state;
286+_PyDebugAllocatorStats(out, "free PyDictObject",
287+state->numfree, sizeof(PyDictObject));
300288}
301289290+302291#define DK_SIZE(dk) ((dk)->dk_size)
303292#if SIZEOF_VOID_P > 4
304293#define DK_IXSIZE(dk) \
@@ -543,7 +532,8 @@ _PyDict_CheckConsistency(PyObject *op, int check_content)
543532}
544533545534546-static PyDictKeysObject *new_keys_object(Py_ssize_t size)
535+static PyDictKeysObject*
536+new_keys_object(Py_ssize_t size)
547537{
548538PyDictKeysObject *dk;
549539Py_ssize_t es, usable;
@@ -567,12 +557,16 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size)
567557es = sizeof(Py_ssize_t);
568558 }
569559570-#if PyDict_MAXFREELIST > 0
571-if (size == PyDict_MINSIZE && numfreekeys > 0) {
572-dk = keys_free_list[--numfreekeys];
560+PyInterpreterState *interp = _PyInterpreterState_GET();
561+struct _Py_dict_state *state = &interp->dict_state;
562+#ifdef Py_DEBUG
563+// new_keys_object() must not be called after _PyDict_Fini()
564+assert(state->keys_numfree != -1);
565+#endif
566+if (size == PyDict_MINSIZE && state->keys_numfree > 0) {
567+dk = state->keys_free_list[--state->keys_numfree];
573568 }
574569else
575-#endif
576570 {
577571dk = PyObject_MALLOC(sizeof(PyDictKeysObject)
578572+ es * size
@@ -604,12 +598,16 @@ free_keys_object(PyDictKeysObject *keys)
604598Py_XDECREF(entries[i].me_key);
605599Py_XDECREF(entries[i].me_value);
606600 }
607-#if PyDict_MAXFREELIST > 0
608-if (keys->dk_size == PyDict_MINSIZE && numfreekeys < PyDict_MAXFREELIST) {
609-keys_free_list[numfreekeys++] = keys;
601+PyInterpreterState *interp = _PyInterpreterState_GET();
602+struct _Py_dict_state *state = &interp->dict_state;
603+#ifdef Py_DEBUG
604+// free_keys_object() must not be called after _PyDict_Fini()
605+assert(state->keys_numfree != -1);
606+#endif
607+if (keys->dk_size == PyDict_MINSIZE && state->keys_numfree < PyDict_MAXFREELIST) {
608+state->keys_free_list[state->keys_numfree++] = keys;
610609return;
611610 }
612-#endif
613611PyObject_FREE(keys);
614612}
615613@@ -622,16 +620,19 @@ new_dict(PyDictKeysObject *keys, PyObject **values)
622620{
623621PyDictObject *mp;
624622assert(keys != NULL);
625-#if PyDict_MAXFREELIST > 0
626-if (numfree) {
627-mp = free_list[--numfree];
623+PyInterpreterState *interp = _PyInterpreterState_GET();
624+struct _Py_dict_state *state = &interp->dict_state;
625+#ifdef Py_DEBUG
626+// new_dict() must not be called after _PyDict_Fini()
627+assert(state->numfree != -1);
628+#endif
629+if (state->numfree) {
630+mp = state->free_list[--state->numfree];
628631assert (mp != NULL);
629632assert (Py_IS_TYPE(mp, &PyDict_Type));
630633_Py_NewReference((PyObject *)mp);
631634 }
632-else
633-#endif
634- {
635+else {
635636mp = PyObject_GC_New(PyDictObject, &PyDict_Type);
636637if (mp == NULL) {
637638dictkeys_decref(keys);
@@ -1280,15 +1281,18 @@ dictresize(PyDictObject *mp, Py_ssize_t minsize)
12801281#ifdef Py_REF_DEBUG
12811282_Py_RefTotal--;
12821283#endif
1283-#if PyDict_MAXFREELIST > 0
1284+PyInterpreterState *interp = _PyInterpreterState_GET();
1285+struct _Py_dict_state *state = &interp->dict_state;
1286+#ifdef Py_DEBUG
1287+// dictresize() must not be called after _PyDict_Fini()
1288+assert(state->keys_numfree != -1);
1289+#endif
12841290if (oldkeys->dk_size == PyDict_MINSIZE &&
1285-numfreekeys < PyDict_MAXFREELIST)
1291+state->keys_numfree < PyDict_MAXFREELIST)
12861292 {
1287-keys_free_list[numfreekeys++] = oldkeys;
1293+state->keys_free_list[state->keys_numfree++] = oldkeys;
12881294 }
1289-else
1290-#endif
1291- {
1295+else {
12921296PyObject_FREE(oldkeys);
12931297 }
12941298 }
@@ -2028,13 +2032,16 @@ dict_dealloc(PyDictObject *mp)
20282032assert(keys->dk_refcnt == 1);
20292033dictkeys_decref(keys);
20302034 }
2031-#if PyDict_MAXFREELIST > 0
2032-if (numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) {
2033- free_list[numfree++] = mp;
2034-}
2035-else
2035+ PyInterpreterState *interp = _PyInterpreterState_GET();
2036+struct _Py_dict_state *state = &interp->dict_state;
2037+#ifdef Py_DEBUG
2038+// new_dict() must not be called after _PyDict_Fini()
2039+assert(state->numfree != -1);
20362040#endif
2037- {
2041+if (state->numfree < PyDict_MAXFREELIST && Py_IS_TYPE(mp, &PyDict_Type)) {
2042+state->free_list[state->numfree++] = mp;
2043+ }
2044+else {
20382045Py_TYPE(mp)->tp_free((PyObject *)mp);
20392046 }
20402047Py_TRASHCAN_END