https://github.com/python/cpython/commit/dff8bcfa3cb2daf0aa0d3f4717fd77948d3b2b2f commit: dff8bcfa3cb2daf0aa0d3f4717fd77948d3b2b2f branch: main author: Pieter Eendebak <pieter.eende...@gmail.com> committer: Fidget-Spinner <kenjin4...@gmail.com> date: 2025-04-07T04:40:52+08:00 summary:
gh-126703: Add freelist for range and range_iter objects (GH-128619) files: A Misc/NEWS.d/next/Core_and_Builtins/2025-01-08-09-41-25.gh-issue-126703.djs9e_.rst M Include/internal/pycore_freelist_state.h M Objects/object.c M Objects/rangeobject.c diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index 54415b22fd41ef..4828dfd948f70a 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -18,6 +18,8 @@ extern "C" { # define Py_floats_MAXFREELIST 100 # define Py_ints_MAXFREELIST 100 # define Py_slices_MAXFREELIST 1 +# define Py_ranges_MAXFREELIST 6 +# define Py_range_iters_MAXFREELIST 6 # define Py_contexts_MAXFREELIST 255 # define Py_async_gens_MAXFREELIST 80 # define Py_async_gen_asends_MAXFREELIST 80 @@ -49,6 +51,8 @@ struct _Py_freelists { struct _Py_freelist dicts; struct _Py_freelist dictkeys; struct _Py_freelist slices; + struct _Py_freelist ranges; + struct _Py_freelist range_iters; struct _Py_freelist contexts; struct _Py_freelist async_gens; struct _Py_freelist async_gen_asends; diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-01-08-09-41-25.gh-issue-126703.djs9e_.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-08-09-41-25.gh-issue-126703.djs9e_.rst new file mode 100644 index 00000000000000..2fb44568b12168 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-01-08-09-41-25.gh-issue-126703.djs9e_.rst @@ -0,0 +1 @@ +Improve performance of :class:`range` by using a freelist. diff --git a/Objects/object.c b/Objects/object.c index 42ac3a1c2baa7b..99bb1d9c0bfad5 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -931,6 +931,8 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) clear_freelist(&freelists->dicts, is_finalization, free_object); clear_freelist(&freelists->dictkeys, is_finalization, PyMem_Free); clear_freelist(&freelists->slices, is_finalization, free_object); + clear_freelist(&freelists->ranges, is_finalization, free_object); + clear_freelist(&freelists->range_iters, is_finalization, free_object); clear_freelist(&freelists->contexts, is_finalization, free_object); clear_freelist(&freelists->async_gens, is_finalization, free_object); clear_freelist(&freelists->async_gen_asends, is_finalization, free_object); diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 24f9ce807fd24e..f8cdfe68a6435e 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_abstract.h" // _PyIndex_Check() #include "pycore_ceval.h" // _PyEval_GetBuiltin() +#include "pycore_freelist.h" #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_range.h" @@ -51,16 +52,18 @@ static rangeobject * make_range_object(PyTypeObject *type, PyObject *start, PyObject *stop, PyObject *step) { - rangeobject *obj = NULL; PyObject *length; length = compute_range_length(start, stop, step); if (length == NULL) { return NULL; } - obj = PyObject_New(rangeobject, type); + rangeobject *obj = _Py_FREELIST_POP(rangeobject, ranges); if (obj == NULL) { - Py_DECREF(length); - return NULL; + obj = PyObject_New(rangeobject, type); + if (obj == NULL) { + Py_DECREF(length); + return NULL; + } } obj->start = start; obj->stop = stop; @@ -171,7 +174,7 @@ range_dealloc(PyObject *op) Py_DECREF(r->stop); Py_DECREF(r->step); Py_DECREF(r->length); - PyObject_Free(r); + _Py_FREELIST_FREE(ranges, r, PyObject_Free); } static unsigned long @@ -895,6 +898,12 @@ rangeiter_setstate(PyObject *op, PyObject *state) Py_RETURN_NONE; } +static void +rangeiter_dealloc(PyObject *self) +{ + _Py_FREELIST_FREE(range_iters, (_PyRangeIterObject *)self, PyObject_Free); +} + PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); @@ -911,7 +920,7 @@ PyTypeObject PyRangeIter_Type = { sizeof(_PyRangeIterObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - 0, /* tp_dealloc */ + rangeiter_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -972,9 +981,14 @@ get_len_of_range(long lo, long hi, long step) static PyObject * fast_range_iter(long start, long stop, long step, long len) { - _PyRangeIterObject *it = PyObject_New(_PyRangeIterObject, &PyRangeIter_Type); - if (it == NULL) - return NULL; + _PyRangeIterObject *it = _Py_FREELIST_POP(_PyRangeIterObject, range_iters); + if (it == NULL) { + it = PyObject_New(_PyRangeIterObject, &PyRangeIter_Type); + if (it == NULL) { + return NULL; + } + } + assert(Py_IS_TYPE(it, &PyRangeIter_Type)); it->start = start; it->step = step; it->len = len; _______________________________________________ Python-checkins mailing list -- python-checkins@python.org To unsubscribe send an email to python-checkins-le...@python.org https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: arch...@mail-archive.com