diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index 46e2a82ea03456..01a04bf59d0c2c 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -18,6 +18,7 @@ extern "C" { # define Py_floats_MAXFREELIST 100 # define Py_complexes_MAXFREELIST 100 # define Py_ints_MAXFREELIST 100 +# define PyLong_MAXSAVESIZE 8 // Keep freelists for all ints with less than this number of digits # define Py_slices_MAXFREELIST 1 # define Py_ranges_MAXFREELIST 6 # define Py_range_iters_MAXFREELIST 6 @@ -46,8 +47,8 @@ struct _Py_freelist { struct _Py_freelists { struct _Py_freelist floats; struct _Py_freelist complexes; - struct _Py_freelist ints; struct _Py_freelist tuples[PyTuple_MAXSAVESIZE]; + struct _Py_freelist ints[PyLong_MAXSAVESIZE]; struct _Py_freelist lists; struct _Py_freelist list_iters; struct _Py_freelist tuple_iters; diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-02-04-10-53-18.gh-issue-126703.RpjKez.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-04-10-53-18.gh-issue-126703.RpjKez.rst new file mode 100644 index 00000000000000..ede383deb4ad31 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-04-10-53-18.gh-issue-126703.RpjKez.rst @@ -0,0 +1 @@ +Increase usage of freelist for :class:`int` allocation. diff --git a/Objects/longobject.c b/Objects/longobject.c index 5eb4063f861f7a..9f2539de086cf7 100644 --- a/Objects/longobject.c +++ b/Objects/longobject.c @@ -154,6 +154,21 @@ long_normalize(PyLongObject *v) # define MAX_LONG_DIGITS ((INT64_MAX-1) / PyLong_SHIFT) #endif +static inline int +maybe_freelist_push(PyObject *self) +{ + assert(PyLong_CheckExact(self)); + + PyLongObject *op = (PyLongObject *)self; + Py_ssize_t ndigits = _PyLong_DigitCount(op); + + if (ndigits < PyLong_MAXSAVESIZE) { + return _Py_FREELIST_PUSH(ints[ndigits], self, Py_ints_MAXFREELIST); + } + return 0; +} + + static PyLongObject * long_alloc(Py_ssize_t size) { @@ -168,8 +183,8 @@ long_alloc(Py_ssize_t size) * assume that there is always at least one digit present. */ Py_ssize_t ndigits = size ? size : 1; - if (ndigits == 1) { - result = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints); + if (ndigits < PyLong_MAXSAVESIZE ) { + result = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints[ndigits]); } if (result == NULL) { /* Number of bytes needed is: offsetof(PyLongObject, ob_digit) + @@ -249,7 +264,7 @@ _PyLong_FromMedium(sdigit x) assert(!IS_SMALL_INT(x)); assert(is_medium_int(x)); - PyLongObject *v = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints); + PyLongObject *v = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints[1]); if (v == NULL) { v = PyObject_Malloc(sizeof(PyLongObject)); if (v == NULL) { @@ -3641,11 +3656,10 @@ _PyLong_ExactDealloc(PyObject *self) _Py_SetImmortal(self); return; } - if (_PyLong_IsCompact((PyLongObject *)self)) { - _Py_FREELIST_FREE(ints, self, PyObject_Free); - return; + + if (!maybe_freelist_push(self)) { + PyObject_Free(self); } - PyObject_Free(self); } static void @@ -3661,10 +3675,13 @@ long_dealloc(PyObject *self) _Py_SetImmortal(self); return; } - if (PyLong_CheckExact(self) && _PyLong_IsCompact((PyLongObject *)self)) { - _Py_FREELIST_FREE(ints, self, PyObject_Free); + if (PyLong_CheckExact(self)) { + if (!maybe_freelist_push(self)) { + PyObject_Free(self); + } return; } + Py_TYPE(self)->tp_free(self); } diff --git a/Objects/object.c b/Objects/object.c index 0540112d7d2acf..7d6329ccfbbbb0 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -927,6 +927,9 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) for (Py_ssize_t i = 0; i < PyTuple_MAXSAVESIZE; i++) { clear_freelist(&freelists->tuples[i], is_finalization, free_object); } + for (Py_ssize_t i = 0; i < PyLong_MAXSAVESIZE; i++) { + clear_freelist(&freelists->ints[i], is_finalization, free_object); + } clear_freelist(&freelists->lists, is_finalization, free_object); clear_freelist(&freelists->list_iters, is_finalization, free_object); clear_freelist(&freelists->tuple_iters, is_finalization, free_object);