From cb834902f6ffd45ec4c442bfac281614810f1453 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Fri, 8 Nov 2024 12:43:03 +0100 Subject: [PATCH 1/9] Use freelist for range object --- Include/internal/pycore_freelist_state.h | 2 ++ Objects/rangeobject.c | 15 ++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index a1a94c1f2dc880..daeebf35900a38 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -16,6 +16,7 @@ extern "C" { # define Py_floats_MAXFREELIST 100 # define Py_ints_MAXFREELIST 100 # define Py_slices_MAXFREELIST 1 +# define Py_ranges_MAXFREELIST 10 # define Py_contexts_MAXFREELIST 255 # define Py_async_gens_MAXFREELIST 80 # define Py_async_gen_asends_MAXFREELIST 80 @@ -42,6 +43,7 @@ struct _Py_freelists { struct _Py_freelist dicts; struct _Py_freelist dictkeys; struct _Py_freelist slices; + struct _Py_freelist ranges; struct _Py_freelist contexts; struct _Py_freelist async_gens; struct _Py_freelist async_gen_asends; diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 2942ab624edf72..959b4f91733aed 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" // _Py_FREELIST_FREE(), _Py_FREELIST_POP() #include "pycore_long.h" // _PyLong_GetZero() #include "pycore_modsupport.h" // _PyArg_NoKwnames() #include "pycore_range.h" @@ -51,16 +52,20 @@ 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; + } + } else { + //printf("rangeobject from freelist!\n"); } obj->start = start; obj->stop = stop; @@ -170,7 +175,7 @@ range_dealloc(rangeobject *r) 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 From 6adf31c33f1576e130917269cb4703fa79c73997 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Fri, 8 Nov 2024 12:59:25 +0100 Subject: [PATCH 2/9] Use freelist for rangeiter object --- Include/internal/pycore_freelist_state.h | 2 ++ Objects/rangeobject.c | 17 +++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index daeebf35900a38..873bd0623a2a2f 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -17,6 +17,7 @@ extern "C" { # define Py_ints_MAXFREELIST 100 # define Py_slices_MAXFREELIST 1 # define Py_ranges_MAXFREELIST 10 +# define Py_rangeiters_MAXFREELIST 10 # define Py_contexts_MAXFREELIST 255 # define Py_async_gens_MAXFREELIST 80 # define Py_async_gen_asends_MAXFREELIST 80 @@ -44,6 +45,7 @@ struct _Py_freelists { struct _Py_freelist dictkeys; struct _Py_freelist slices; struct _Py_freelist ranges; + struct _Py_freelist rangeiters; struct _Py_freelist contexts; struct _Py_freelist async_gens; struct _Py_freelist async_gen_asends; diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 959b4f91733aed..8df6d95df22047 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -885,6 +885,12 @@ rangeiter_setstate(_PyRangeIterObject *r, PyObject *state) Py_RETURN_NONE; } +static void +rangeiter_dealloc(_PyRangeIterObject *r) +{ + _Py_FREELIST_FREE(rangeiters, r, PyObject_Free); +} + PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); PyDoc_STRVAR(setstate_doc, "Set state information for unpickling."); @@ -904,7 +910,7 @@ PyTypeObject PyRangeIter_Type = { sizeof(_PyRangeIterObject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ - (destructor)PyObject_Free, /* tp_dealloc */ + (destructor)rangeiter_dealloc, /* tp_dealloc */ 0, /* tp_vectorcall_offset */ 0, /* tp_getattr */ 0, /* tp_setattr */ @@ -965,9 +971,12 @@ 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, rangeiters); + if (it == NULL) { + it = PyObject_New(_PyRangeIterObject, &PyRangeIter_Type); + if (it == NULL) + return NULL; + } it->start = start; it->step = step; it->len = len; From 94cbc7c988653a99a574f2195e541f9effd2e81f Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Mon, 11 Nov 2024 22:26:34 +0100 Subject: [PATCH 3/9] cleanup debug code --- Objects/rangeobject.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 8df6d95df22047..f6627abfbded64 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -64,8 +64,6 @@ make_range_object(PyTypeObject *type, PyObject *start, Py_DECREF(length); return NULL; } - } else { - //printf("rangeobject from freelist!\n"); } obj->start = start; obj->stop = stop; From 17100c09debfa6aadc1ac5e747aa16a96688c74c Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 12 Dec 2024 22:50:45 +0100 Subject: [PATCH 4/9] set types --- Include/internal/pycore_freelist.h | 1 + Include/internal/pycore_freelist_state.h | 4 ++-- Objects/listobject.c | 16 ++++++++++------ Objects/rangeobject.c | 7 +++++-- Objects/tupleobject.c | 15 +++++++++++---- Objects/typeobject.c | 1 + 6 files changed, 30 insertions(+), 14 deletions(-) diff --git a/Include/internal/pycore_freelist.h b/Include/internal/pycore_freelist.h index 84a5ab30f3eeea..54b472189f1796 100644 --- a/Include/internal/pycore_freelist.h +++ b/Include/internal/pycore_freelist.h @@ -40,6 +40,7 @@ _Py_freelists_GET(void) #define _Py_FREELIST_POP(TYPE, NAME) \ _Py_CAST(TYPE*, _PyFreeList_Pop(&_Py_freelists_GET()->NAME)) + // Pops a non-PyObject data structure from the freelist, returns NULL if the // freelist is empty. #define _Py_FREELIST_POP_MEM(NAME) \ diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index 873bd0623a2a2f..db8363aa8c75ce 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -17,7 +17,7 @@ extern "C" { # define Py_ints_MAXFREELIST 100 # define Py_slices_MAXFREELIST 1 # define Py_ranges_MAXFREELIST 10 -# define Py_rangeiters_MAXFREELIST 10 +# define Py_shared_iters_MAXFREELIST 24 # define Py_contexts_MAXFREELIST 255 # define Py_async_gens_MAXFREELIST 80 # define Py_async_gen_asends_MAXFREELIST 80 @@ -45,7 +45,7 @@ struct _Py_freelists { struct _Py_freelist dictkeys; struct _Py_freelist slices; struct _Py_freelist ranges; - struct _Py_freelist rangeiters; + struct _Py_freelist shared_iters; struct _Py_freelist contexts; struct _Py_freelist async_gens; struct _Py_freelist async_gen_asends; diff --git a/Objects/listobject.c b/Objects/listobject.c index a877bad66be45f..c91ebe42a0f638 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -3910,15 +3910,19 @@ PyTypeObject PyListIter_Type = { static PyObject * list_iter(PyObject *seq) { - _PyListIterObject *it; - if (!PyList_Check(seq)) { PyErr_BadInternalCall(); return NULL; } - it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type); - if (it == NULL) - return NULL; + _PyListIterObject *it = _Py_FREELIST_POP(_PyListIterObject, shared_iters); + if (it == NULL) { + it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type); + if (it == NULL) { + return NULL; + } + } else { + Py_SET_TYPE(it, &PyListIter_Type); + } it->it_index = 0; it->it_seq = (PyListObject *)Py_NewRef(seq); _PyObject_GC_TRACK(it); @@ -3931,7 +3935,7 @@ listiter_dealloc(PyObject *self) _PyListIterObject *it = (_PyListIterObject *)self; _PyObject_GC_UNTRACK(it); Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); + _Py_FREELIST_FREE(shared_iters, it, PyObject_GC_Del); } static int diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index f6627abfbded64..529525e106b3c6 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -886,7 +886,7 @@ rangeiter_setstate(_PyRangeIterObject *r, PyObject *state) static void rangeiter_dealloc(_PyRangeIterObject *r) { - _Py_FREELIST_FREE(rangeiters, r, PyObject_Free); + _Py_FREELIST_FREE(shared_iters, r, PyObject_Free); } PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); @@ -969,12 +969,15 @@ 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 = _Py_FREELIST_POP(_PyRangeIterObject, rangeiters); + _PyRangeIterObject *it = _Py_FREELIST_POP(_PyRangeIterObject, shared_iters); if (it == NULL) { it = PyObject_New(_PyRangeIterObject, &PyRangeIter_Type); if (it == NULL) return NULL; } + else { + Py_SET_TYPE(it, &PyRangeIter_Type); + } it->start = start; it->step = step; it->len = len; diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 49977726eadca9..d2a18f8f7ac11b 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -994,7 +994,8 @@ tupleiter_dealloc(_PyTupleIterObject *it) { _PyObject_GC_UNTRACK(it); Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); + assert(sizeof(_PyTupleIterObject)==sizeof(_PyListIterObject)); + _Py_FREELIST_FREE(shared_iters, it, PyObject_GC_Del); } static int @@ -1122,9 +1123,15 @@ tuple_iter(PyObject *seq) PyErr_BadInternalCall(); return NULL; } - it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type); - if (it == NULL) - return NULL; + it = _Py_FREELIST_POP(_PyTupleIterObject, shared_iters); + + if (it == NULL) { + it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type); + if (it == NULL) + return NULL; + } else { + Py_SET_TYPE(it, &PyTupleIter_Type); + } it->it_index = 0; it->it_seq = (PyTupleObject *)Py_NewRef(seq); _PyObject_GC_TRACK(it); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 7f95b519561e68..4b4cf993395b9e 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6,6 +6,7 @@ #include "pycore_code.h" // CO_FAST_FREE #include "pycore_dict.h" // _PyDict_KeysSize() #include "pycore_frame.h" // _PyInterpreterFrame +#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP() #include "pycore_lock.h" // _PySeqLock_* #include "pycore_long.h" // _PyLong_IsNegative(), _PyLong_GetOne() #include "pycore_memoryobject.h" // _PyMemoryView_FromBufferProc() From ea98fa1477d27539089c927d64e149c94e9ddbb1 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Mon, 30 Dec 2024 23:11:14 +0100 Subject: [PATCH 5/9] add more freelists --- Include/internal/pycore_freelist.h | 1 - Include/internal/pycore_freelist_state.h | 2 ++ Objects/classobject.c | 11 ++++++++--- Objects/iterobject.c | 17 +++++++++++++---- Objects/typeobject.c | 1 - 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/Include/internal/pycore_freelist.h b/Include/internal/pycore_freelist.h index 54b472189f1796..84a5ab30f3eeea 100644 --- a/Include/internal/pycore_freelist.h +++ b/Include/internal/pycore_freelist.h @@ -40,7 +40,6 @@ _Py_freelists_GET(void) #define _Py_FREELIST_POP(TYPE, NAME) \ _Py_CAST(TYPE*, _PyFreeList_Pop(&_Py_freelists_GET()->NAME)) - // Pops a non-PyObject data structure from the freelist, returns NULL if the // freelist is empty. #define _Py_FREELIST_POP_MEM(NAME) \ diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index db8363aa8c75ce..dfbb5105292642 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -18,6 +18,7 @@ extern "C" { # define Py_slices_MAXFREELIST 1 # define Py_ranges_MAXFREELIST 10 # define Py_shared_iters_MAXFREELIST 24 +# define Py_class_method_MAXFREELIST 10 # define Py_contexts_MAXFREELIST 255 # define Py_async_gens_MAXFREELIST 80 # define Py_async_gen_asends_MAXFREELIST 80 @@ -46,6 +47,7 @@ struct _Py_freelists { struct _Py_freelist slices; struct _Py_freelist ranges; struct _Py_freelist shared_iters; + struct _Py_freelist class_method; struct _Py_freelist contexts; struct _Py_freelist async_gens; struct _Py_freelist async_gen_asends; diff --git a/Objects/classobject.c b/Objects/classobject.c index 775894ad5a7166..408fcdab9e25b5 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -3,6 +3,7 @@ #include "Python.h" #include "pycore_call.h" // _PyObject_VectorcallTstate() #include "pycore_ceval.h" // _PyEval_GetBuiltin() +#include "pycore_freelist.h" #include "pycore_object.h" #include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyThreadState_GET() @@ -112,9 +113,13 @@ PyMethod_New(PyObject *func, PyObject *self) PyErr_BadInternalCall(); return NULL; } - PyMethodObject *im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); + + PyMethodObject *im = _Py_FREELIST_POP(PyMethodObject, class_method); if (im == NULL) { - return NULL; + im = PyObject_GC_New(PyMethodObject, &PyMethod_Type); + if (im == NULL) { + return NULL; + } } im->im_weakreflist = NULL; im->im_func = Py_NewRef(func); @@ -245,7 +250,7 @@ method_dealloc(PyObject *self) PyObject_ClearWeakRefs((PyObject *)im); Py_DECREF(im->im_func); Py_XDECREF(im->im_self); - PyObject_GC_Del(im); + _Py_FREELIST_FREE(class_method, (PyObject *)im, PyObject_GC_Del); } static PyObject * diff --git a/Objects/iterobject.c b/Objects/iterobject.c index 135ced9ea1f268..3bd3a26968df5f 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -4,6 +4,7 @@ #include "pycore_abstract.h" // _PyObject_HasLen() #include "pycore_call.h" // _PyObject_CallNoArgs() #include "pycore_ceval.h" // _PyEval_GetBuiltin() +#include "pycore_freelist.h" // _Py_FREELIST_PUSH(), _Py_FREELIST_POP() #include "pycore_object.h" // _PyObject_GC_TRACK() typedef struct { @@ -21,9 +22,16 @@ PySeqIter_New(PyObject *seq) PyErr_BadInternalCall(); return NULL; } - it = PyObject_GC_New(seqiterobject, &PySeqIter_Type); - if (it == NULL) - return NULL; + + it = _Py_FREELIST_POP(seqiterobject, shared_iters); + if (it == NULL) { + it = PyObject_GC_New(seqiterobject, &PySeqIter_Type); + if (it == NULL) + return NULL; + } + else { + Py_SET_TYPE(it, &PySeqIter_Type); + } it->it_index = 0; it->it_seq = Py_NewRef(seq); _PyObject_GC_TRACK(it); @@ -35,7 +43,8 @@ iter_dealloc(seqiterobject *it) { _PyObject_GC_UNTRACK(it); Py_XDECREF(it->it_seq); - PyObject_GC_Del(it); + assert(sizeof(seqiterobject)==sizeof(_PyListIterObject)); + _Py_FREELIST_FREE(shared_iters, (PyObject *)it, PyObject_GC_Del); } static int diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 4b4cf993395b9e..7f95b519561e68 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -6,7 +6,6 @@ #include "pycore_code.h" // CO_FAST_FREE #include "pycore_dict.h" // _PyDict_KeysSize() #include "pycore_frame.h" // _PyInterpreterFrame -#include "pycore_freelist.h" // _Py_FREELIST_FREE(), _Py_FREELIST_POP() #include "pycore_lock.h" // _PySeqLock_* #include "pycore_long.h" // _PyLong_IsNegative(), _PyLong_GetOne() #include "pycore_memoryobject.h" // _PyMemoryView_FromBufferProc() From 64be6c4ac1e02ca28029816d4f2fc2ee7d36318f Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Wed, 1 Jan 2025 20:16:20 +0100 Subject: [PATCH 6/9] clear freelists --- Objects/object.c | 3 +++ Objects/rangeobject.c | 1 + 2 files changed, 4 insertions(+) diff --git a/Objects/object.c b/Objects/object.c index d584414c559b9d..81df7dd41aa60f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -937,6 +937,9 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) } clear_freelist(&freelists->unicode_writers, is_finalization, PyMem_Free); clear_freelist(&freelists->ints, is_finalization, free_object); + clear_freelist(&freelists->shared_iters, is_finalization, free_object); + clear_freelist(&freelists->ranges, is_finalization, free_object); + clear_freelist(&freelists->class_method, is_finalization, free_object); } /* diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 529525e106b3c6..40916c641d4695 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -977,6 +977,7 @@ fast_range_iter(long start, long stop, long step, long len) } else { Py_SET_TYPE(it, &PyRangeIter_Type); + //_PyObject_GC_TRACK(it); // need to track with GC again } it->start = start; it->step = step; From 2551f2988b761ca8f84d64994ccbfb1c89d6c820 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Wed, 1 Jan 2025 20:44:03 +0100 Subject: [PATCH 7/9] freelist for range iterators --- Include/internal/pycore_freelist_state.h | 2 ++ Objects/iterobject.c | 2 +- Objects/listobject.c | 2 +- Objects/object.c | 1 + Objects/rangeobject.c | 5 ++--- Objects/tupleobject.c | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index dfbb5105292642..dd5cc21cf45729 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -17,6 +17,7 @@ extern "C" { # define Py_ints_MAXFREELIST 100 # define Py_slices_MAXFREELIST 1 # define Py_ranges_MAXFREELIST 10 +# define Py_range_iters_MAXFREELIST 10 # define Py_shared_iters_MAXFREELIST 24 # define Py_class_method_MAXFREELIST 10 # define Py_contexts_MAXFREELIST 255 @@ -46,6 +47,7 @@ struct _Py_freelists { struct _Py_freelist dictkeys; struct _Py_freelist slices; struct _Py_freelist ranges; + struct _Py_freelist range_iters; struct _Py_freelist shared_iters; struct _Py_freelist class_method; struct _Py_freelist contexts; diff --git a/Objects/iterobject.c b/Objects/iterobject.c index 3bd3a26968df5f..de452092e90553 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -23,7 +23,7 @@ PySeqIter_New(PyObject *seq) return NULL; } - it = _Py_FREELIST_POP(seqiterobject, shared_iters); + it = 0; //_Py_FREELIST_POP(seqiterobject, shared_iters); if (it == NULL) { it = PyObject_GC_New(seqiterobject, &PySeqIter_Type); if (it == NULL) diff --git a/Objects/listobject.c b/Objects/listobject.c index c91ebe42a0f638..c72143655befef 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -3914,7 +3914,7 @@ list_iter(PyObject *seq) PyErr_BadInternalCall(); return NULL; } - _PyListIterObject *it = _Py_FREELIST_POP(_PyListIterObject, shared_iters); + _PyListIterObject *it = 0; //_Py_FREELIST_POP(_PyListIterObject, shared_iters); if (it == NULL) { it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type); if (it == NULL) { diff --git a/Objects/object.c b/Objects/object.c index 81df7dd41aa60f..6ce38c4566f501 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -939,6 +939,7 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) clear_freelist(&freelists->ints, is_finalization, free_object); clear_freelist(&freelists->shared_iters, is_finalization, free_object); clear_freelist(&freelists->ranges, is_finalization, free_object); + clear_freelist(&freelists->range_iters, is_finalization, free_object); clear_freelist(&freelists->class_method, is_finalization, free_object); } diff --git a/Objects/rangeobject.c b/Objects/rangeobject.c index 40916c641d4695..a64522d19b7ded 100644 --- a/Objects/rangeobject.c +++ b/Objects/rangeobject.c @@ -886,7 +886,7 @@ rangeiter_setstate(_PyRangeIterObject *r, PyObject *state) static void rangeiter_dealloc(_PyRangeIterObject *r) { - _Py_FREELIST_FREE(shared_iters, r, PyObject_Free); + _Py_FREELIST_FREE(range_iters, r, PyObject_Free); } PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); @@ -969,7 +969,7 @@ 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 = _Py_FREELIST_POP(_PyRangeIterObject, shared_iters); + _PyRangeIterObject *it = _Py_FREELIST_POP(_PyRangeIterObject, range_iters); if (it == NULL) { it = PyObject_New(_PyRangeIterObject, &PyRangeIter_Type); if (it == NULL) @@ -977,7 +977,6 @@ fast_range_iter(long start, long stop, long step, long len) } else { Py_SET_TYPE(it, &PyRangeIter_Type); - //_PyObject_GC_TRACK(it); // need to track with GC again } it->start = start; it->step = step; diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index d2a18f8f7ac11b..0ae0a45a0737ed 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -1123,7 +1123,7 @@ tuple_iter(PyObject *seq) PyErr_BadInternalCall(); return NULL; } - it = _Py_FREELIST_POP(_PyTupleIterObject, shared_iters); + it = 0; // _Py_FREELIST_POP(_PyTupleIterObject, shared_iters); if (it == NULL) { it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type); From fce4651fca7fa1d97ea5cdcce1baf97296375e67 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Wed, 1 Jan 2025 21:10:28 +0100 Subject: [PATCH 8/9] enable all freelists again --- Objects/iterobject.c | 2 +- Objects/listobject.c | 2 +- Objects/tupleobject.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Objects/iterobject.c b/Objects/iterobject.c index de452092e90553..3bd3a26968df5f 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -23,7 +23,7 @@ PySeqIter_New(PyObject *seq) return NULL; } - it = 0; //_Py_FREELIST_POP(seqiterobject, shared_iters); + it = _Py_FREELIST_POP(seqiterobject, shared_iters); if (it == NULL) { it = PyObject_GC_New(seqiterobject, &PySeqIter_Type); if (it == NULL) diff --git a/Objects/listobject.c b/Objects/listobject.c index c72143655befef..c91ebe42a0f638 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -3914,7 +3914,7 @@ list_iter(PyObject *seq) PyErr_BadInternalCall(); return NULL; } - _PyListIterObject *it = 0; //_Py_FREELIST_POP(_PyListIterObject, shared_iters); + _PyListIterObject *it = _Py_FREELIST_POP(_PyListIterObject, shared_iters); if (it == NULL) { it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type); if (it == NULL) { diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c index 0ae0a45a0737ed..d2a18f8f7ac11b 100644 --- a/Objects/tupleobject.c +++ b/Objects/tupleobject.c @@ -1123,7 +1123,7 @@ tuple_iter(PyObject *seq) PyErr_BadInternalCall(); return NULL; } - it = 0; // _Py_FREELIST_POP(_PyTupleIterObject, shared_iters); + it = _Py_FREELIST_POP(_PyTupleIterObject, shared_iters); if (it == NULL) { it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type); From 5d13675cd8f2add3984ec7250e47120f93d4bd5b Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Wed, 1 Jan 2025 22:39:01 +0100 Subject: [PATCH 9/9] add PyCFunctionObject --- Include/internal/pycore_freelist_state.h | 4 ++++ Objects/methodobject.c | 26 +++++++++++++++++------- Objects/object.c | 2 ++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index dd5cc21cf45729..5b95485a1ae63c 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -16,6 +16,8 @@ extern "C" { # define Py_floats_MAXFREELIST 100 # define Py_ints_MAXFREELIST 100 # define Py_slices_MAXFREELIST 1 +# define Py_pycfunctionobject_MAXFREELIST 40 +# define Py_pycmethodobject_MAXFREELIST 40 # define Py_ranges_MAXFREELIST 10 # define Py_range_iters_MAXFREELIST 10 # define Py_shared_iters_MAXFREELIST 24 @@ -46,6 +48,8 @@ struct _Py_freelists { struct _Py_freelist dicts; struct _Py_freelist dictkeys; struct _Py_freelist slices; + struct _Py_freelist pycfunctionobject; + struct _Py_freelist pycmethodobject; struct _Py_freelist ranges; struct _Py_freelist range_iters; struct _Py_freelist shared_iters; diff --git a/Objects/methodobject.c b/Objects/methodobject.c index 345da4607423cf..362b46c9b66b75 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -4,6 +4,7 @@ #include "Python.h" #include "pycore_call.h" // _Py_CheckFunctionResult() #include "pycore_ceval.h" // _Py_EnterRecursiveCallTstate() +#include "pycore_freelist.h" #include "pycore_object.h" #include "pycore_pyerrors.h" #include "pycore_pystate.h" // _PyThreadState_GET() @@ -85,10 +86,13 @@ PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *c "flag but no class"); return NULL; } - PyCMethodObject *om = PyObject_GC_New(PyCMethodObject, &PyCMethod_Type); - if (om == NULL) { - return NULL; - } + PyCMethodObject *om = _Py_FREELIST_POP(PyCMethodObject, pycmethodobject); + if (om == NULL) { + om = PyObject_GC_New(PyCMethodObject, &PyCMethod_Type); + if (om == NULL) { + return NULL; + } + } om->mm_class = (PyTypeObject*)Py_NewRef(cls); op = (PyCFunctionObject *)om; } else { @@ -98,9 +102,12 @@ PyCMethod_New(PyMethodDef *ml, PyObject *self, PyObject *module, PyTypeObject *c "but no METH_METHOD flag"); return NULL; } - op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type); + op = _Py_FREELIST_POP(PyCFunctionObject, pycfunctionobject); if (op == NULL) { - return NULL; + op = PyObject_GC_New(PyCFunctionObject, &PyCFunction_Type); + if (op == NULL) { + return NULL; + } } } @@ -171,7 +178,12 @@ meth_dealloc(PyObject *self) Py_XDECREF(PyCFunction_GET_CLASS(m)); Py_XDECREF(m->m_self); Py_XDECREF(m->m_module); - PyObject_GC_Del(m); + if (m->m_ml->ml_flags & METH_METHOD) { + _Py_FREELIST_FREE(pycmethodobject, m, PyObject_GC_Del); + } + else { + _Py_FREELIST_FREE(pycfunctionobject, m, PyObject_GC_Del); + } Py_TRASHCAN_END; } diff --git a/Objects/object.c b/Objects/object.c index 6ce38c4566f501..49be7628e04752 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -938,6 +938,8 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) clear_freelist(&freelists->unicode_writers, is_finalization, PyMem_Free); clear_freelist(&freelists->ints, is_finalization, free_object); clear_freelist(&freelists->shared_iters, is_finalization, free_object); + clear_freelist(&freelists->pycfunctionobject, is_finalization, PyObject_GC_Del); + clear_freelist(&freelists->pycmethodobject, is_finalization, PyObject_GC_Del); clear_freelist(&freelists->ranges, is_finalization, free_object); clear_freelist(&freelists->range_iters, is_finalization, free_object); clear_freelist(&freelists->class_method, is_finalization, free_object);