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"

269251270252

void

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];

276258

assert(PyDict_CheckExact(op));

277259

PyObject_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+286267

void

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 */

296281

void

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

{

548538

PyDictKeysObject *dk;

549539

Py_ssize_t es, usable;

@@ -567,12 +557,16 @@ static PyDictKeysObject *new_keys_object(Py_ssize_t size)

567557

es = 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

}

574569

else

575-

#endif

576570

{

577571

dk = PyObject_MALLOC(sizeof(PyDictKeysObject)

578572

+ es * size

@@ -604,12 +598,16 @@ free_keys_object(PyDictKeysObject *keys)

604598

Py_XDECREF(entries[i].me_key);

605599

Py_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;

610609

return;

611610

}

612-

#endif

613611

PyObject_FREE(keys);

614612

}

615613

@@ -622,16 +620,19 @@ new_dict(PyDictKeysObject *keys, PyObject **values)

622620

{

623621

PyDictObject *mp;

624622

assert(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];

628631

assert (mp != NULL);

629632

assert (Py_IS_TYPE(mp, &PyDict_Type));

630633

_Py_NewReference((PyObject *)mp);

631634

}

632-

else

633-

#endif

634-

{

635+

else {

635636

mp = PyObject_GC_New(PyDictObject, &PyDict_Type);

636637

if (mp == NULL) {

637638

dictkeys_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

12841290

if (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 {

12921296

PyObject_FREE(oldkeys);

12931297

}

12941298

}

@@ -2028,13 +2032,16 @@ dict_dealloc(PyDictObject *mp)

20282032

assert(keys->dk_refcnt == 1);

20292033

dictkeys_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 {

20382045

Py_TYPE(mp)->tp_free((PyObject *)mp);

20392046

}

20402047

Py_TRASHCAN_END