From f799722b4e28b0c5f324ba0af51395ca69f044ed Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Fri, 7 Feb 2025 15:28:44 +0100 Subject: [PATCH 01/12] Create freelist for small lists --- Include/internal/pycore_freelist_state.h | 3 + Objects/listobject.c | 95 ++++++++++++++++++------ Objects/object.c | 5 ++ 3 files changed, 82 insertions(+), 21 deletions(-) diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index 7c252f5b570c13..8c2991c55359c0 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -10,6 +10,8 @@ extern "C" { # define PyTuple_MAXSAVESIZE 20 // Largest tuple to save on freelist # define Py_tuple_MAXFREELIST 2000 // Maximum number of tuples of each size to save +# define PyList_MAXSAVESIZE 10 // Largest list size to save on freelist (minus one) +# define Py_small_lists_MAXFREELIST 40 # define Py_lists_MAXFREELIST 80 # define Py_list_iters_MAXFREELIST 10 # define Py_tuple_iters_MAXFREELIST 10 @@ -41,6 +43,7 @@ struct _Py_freelists { struct _Py_freelist floats; struct _Py_freelist ints; struct _Py_freelist tuples[PyTuple_MAXSAVESIZE]; + struct _Py_freelist small_lists[PyList_MAXSAVESIZE]; struct _Py_freelist lists; struct _Py_freelist list_iters; struct _Py_freelist tuple_iters; diff --git a/Objects/listobject.c b/Objects/listobject.c index 84faa5a32a1f2a..57ded918070735 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -228,6 +228,27 @@ _PyList_DebugMallocStats(FILE *out) sizeof(PyListObject)); } + +static inline int +maybe_small_list_freelist_push(PyObject *self) +{ + assert(PyList_CheckExact(self)); + assert(0); + + PyListObject *op = (PyListObject *)self; + PyObject **ob_item = _Py_atomic_load_ptr(&op->ob_item); + + + Py_ssize_t cap = op->allocated; // what is the difference between allocated and capacity in the FT build? + + printf("maybe_small_list_freelist_push: cap %d\n", cap); + if (cap < PyList_MAXSAVESIZE) { + return _Py_FREELIST_PUSH(small_lists[cap], self, Py_small_lists_MAXFREELIST); + } + return 0; +} + + PyObject * PyList_New(Py_ssize_t size) { @@ -236,35 +257,49 @@ PyList_New(Py_ssize_t size) return NULL; } - PyListObject *op = _Py_FREELIST_POP(PyListObject, lists); - if (op == NULL) { - op = PyObject_GC_New(PyListObject, &PyList_Type); - if (op == NULL) { - return NULL; - } + PyListObject *op; + + if (size < PyList_MAXSAVESIZE ) { + op = 0; + //op = (PyListObject *)_Py_FREELIST_POP(PyLongObject, small_lists[size]); } - if (size <= 0) { - op->ob_item = NULL; + if (op) { + // allocated with ob_item still allocated. we do need to set to zero? + if ( size>0) { + memset(&op->ob_item, 0, size * sizeof(PyObject *)); + } } else { -#ifdef Py_GIL_DISABLED - _PyListArray *array = list_allocate_array(size); - if (array == NULL) { - Py_DECREF(op); - return PyErr_NoMemory(); + op = _Py_FREELIST_POP(PyListObject, lists); + if (op == NULL) { + op = PyObject_GC_New(PyListObject, &PyList_Type); + if (op == NULL) { + return NULL; + } + } + if (size <= 0) { + op->ob_item = NULL; } - memset(&array->ob_item, 0, size * sizeof(PyObject *)); - op->ob_item = array->ob_item; + else { +#ifdef Py_GIL_DISABLED + _PyListArray *array = list_allocate_array(size); + if (array == NULL) { + Py_DECREF(op); + return PyErr_NoMemory(); + } + memset(&array->ob_item, 0, size * sizeof(PyObject *)); + op->ob_item = array->ob_item; #else - op->ob_item = (PyObject **) PyMem_Calloc(size, sizeof(PyObject *)); + op->ob_item = (PyObject **) PyMem_Calloc(size, sizeof(PyObject *)); + if (op->ob_item == NULL) { + Py_DECREF(op); + return PyErr_NoMemory(); + } #endif - if (op->ob_item == NULL) { - Py_DECREF(op); - return PyErr_NoMemory(); } + Py_SET_SIZE(op, size); + op->allocated = size; } - Py_SET_SIZE(op, size); - op->allocated = size; _PyObject_GC_TRACK(op); return (PyObject *) op; } @@ -516,6 +551,18 @@ PyList_Append(PyObject *op, PyObject *newitem) /* Methods */ +void small_list_freelist_free(PyObject *self) +{ + assert(0); + printf("small_list_freelist_free\n"); + assert(PyLong_CheckExact(self)); + PyListObject *op = (PyListObject *)self; + if (op->ob_item != NULL) { + free_list_items(op->ob_item, false); + } + PyObject_GC_Del(op); +} + static void list_dealloc(PyObject *self) { @@ -532,6 +579,12 @@ list_dealloc(PyObject *self) while (--i >= 0) { Py_XDECREF(op->ob_item[i]); } + } + if (0 && maybe_small_list_freelist_push(self) ) { + return; + } + + if (op->ob_item != NULL) { free_list_items(op->ob_item, false); } if (PyList_CheckExact(op)) { diff --git a/Objects/object.c b/Objects/object.c index b3309bac7afdee..d6ce3850b57c11 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -914,6 +914,8 @@ free_object(void *obj) Py_DECREF(tp); } +extern void small_list_freelist_free(PyObject *); + void _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) { @@ -923,6 +925,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 < PyList_MAXSAVESIZE; i++) { + clear_freelist(&freelists->small_lists[i], is_finalization, small_list_freelist_free); + } 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); From 32f1a36ff56f098e4f4114361ea21dcef6b1ca13 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Fri, 7 Feb 2025 21:19:51 +0100 Subject: [PATCH 02/12] working version --- Include/internal/pycore_freelist_state.h | 2 +- Objects/listobject.c | 55 +++++++++++++----------- Objects/object.c | 2 +- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index 8c2991c55359c0..7deef9666051f9 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -10,7 +10,7 @@ extern "C" { # define PyTuple_MAXSAVESIZE 20 // Largest tuple to save on freelist # define Py_tuple_MAXFREELIST 2000 // Maximum number of tuples of each size to save -# define PyList_MAXSAVESIZE 10 // Largest list size to save on freelist (minus one) +# define PyList_MAXSAVESIZE 13 // Largest list size to save on freelist (minus one) # define Py_small_lists_MAXFREELIST 40 # define Py_lists_MAXFREELIST 80 # define Py_list_iters_MAXFREELIST 10 diff --git a/Objects/listobject.c b/Objects/listobject.c index 57ded918070735..a5dce8695916ff 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -233,17 +233,14 @@ static inline int maybe_small_list_freelist_push(PyObject *self) { assert(PyList_CheckExact(self)); - assert(0); PyListObject *op = (PyListObject *)self; PyObject **ob_item = _Py_atomic_load_ptr(&op->ob_item); - - Py_ssize_t cap = op->allocated; // what is the difference between allocated and capacity in the FT build? - - printf("maybe_small_list_freelist_push: cap %d\n", cap); - if (cap < PyList_MAXSAVESIZE) { - return _Py_FREELIST_PUSH(small_lists[cap], self, Py_small_lists_MAXFREELIST); + Py_ssize_t allocated = op->allocated; + if (allocated < PyList_MAXSAVESIZE) { + return _Py_FREELIST_PUSH(small_lists[allocated], self, Py_small_lists_MAXFREELIST); + //printf("maybe_small_list_freelist_push: allocated %d (mod %d), size %d, id %p\n", (int)allocated, op->allocated, (int)PyList_Size(self), (void *)self); } return 0; } @@ -257,19 +254,23 @@ PyList_New(Py_ssize_t size) return NULL; } - PyListObject *op; + PyListObject *op=0; - if (size < PyList_MAXSAVESIZE ) { - op = 0; - //op = (PyListObject *)_Py_FREELIST_POP(PyLongObject, small_lists[size]); - } - if (op) { - // allocated with ob_item still allocated. we do need to set to zero? - if ( size>0) { - memset(&op->ob_item, 0, size * sizeof(PyObject *)); + if (size < PyList_MAXSAVESIZE) { + op = (PyListObject *)_Py_FREELIST_POP(PyLongObject, small_lists[size]); + if (op) { + // allocated with ob_item still allocated, but we need to set the other fields + Py_SET_SIZE(op, size); + if ( size>0) { + memset(op->ob_item, 0, size * sizeof(PyObject *)); + } + //printf("obtained list from small_lists[%d] (id %p, op->allocated %d, size %d, PyList_Size %d)\n", (int) size, op, (int)op->allocated, (int)size, (int)PyList_Size( (PyObject*)op)); + assert (op->allocated >= size); } + op=0; } - else { + if (!op) { + // do we still need this freelist? if so, we could store it at small_lists[PyList_MAXSAVESIZE-1] with some special casing op = _Py_FREELIST_POP(PyListObject, lists); if (op == NULL) { op = PyObject_GC_New(PyListObject, &PyList_Type); @@ -551,12 +552,13 @@ PyList_Append(PyObject *op, PyObject *newitem) /* Methods */ -void small_list_freelist_free(PyObject *self) +void small_list_freelist_free(void *obj) { - assert(0); - printf("small_list_freelist_free\n"); - assert(PyLong_CheckExact(self)); + PyObject *self = (PyObject *)obj; + + assert(PyList_CheckExact(self)); PyListObject *op = (PyListObject *)self; + //printf("small_list_freelist_free: (op->allocated %d, size %d)\n", (int)op->allocated, (int)PyList_Size(self)); if (op->ob_item != NULL) { free_list_items(op->ob_item, false); } @@ -580,19 +582,22 @@ list_dealloc(PyObject *self) Py_XDECREF(op->ob_item[i]); } } - if (0 && maybe_small_list_freelist_push(self) ) { - return; + if (PyList_CheckExact(op)) { + if( maybe_small_list_freelist_push(self) ) { + goto end; + } } - if (op->ob_item != NULL) { free_list_items(op->ob_item, false); } if (PyList_CheckExact(op)) { - _Py_FREELIST_FREE(lists, op, PyObject_GC_Del); + _Py_FREELIST_FREE(lists, op, PyObject_GC_Del); } else { PyObject_GC_Del(op); } + + end: Py_TRASHCAN_END } diff --git a/Objects/object.c b/Objects/object.c index d6ce3850b57c11..ac1b29a83046ed 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -914,7 +914,7 @@ free_object(void *obj) Py_DECREF(tp); } -extern void small_list_freelist_free(PyObject *); +extern void small_list_freelist_free(void *); void _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) From 1feab3733f44f25b3b0ad9612006a26f472682ff Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Sun, 9 Feb 2025 19:52:27 +0100 Subject: [PATCH 03/12] comments --- Objects/listobject.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index a5dce8695916ff..1b4e1d9969dfa8 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -232,11 +232,10 @@ _PyList_DebugMallocStats(FILE *out) static inline int maybe_small_list_freelist_push(PyObject *self) { + // todo: in the resizing there are some alignments on the allocation. can we use that here? assert(PyList_CheckExact(self)); PyListObject *op = (PyListObject *)self; - PyObject **ob_item = _Py_atomic_load_ptr(&op->ob_item); - Py_ssize_t allocated = op->allocated; if (allocated < PyList_MAXSAVESIZE) { return _Py_FREELIST_PUSH(small_lists[allocated], self, Py_small_lists_MAXFREELIST); @@ -267,9 +266,9 @@ PyList_New(Py_ssize_t size) //printf("obtained list from small_lists[%d] (id %p, op->allocated %d, size %d, PyList_Size %d)\n", (int) size, op, (int)op->allocated, (int)size, (int)PyList_Size( (PyObject*)op)); assert (op->allocated >= size); } - op=0; + //op=0; } - if (!op) { + if (op == NULL) { // do we still need this freelist? if so, we could store it at small_lists[PyList_MAXSAVESIZE-1] with some special casing op = _Py_FREELIST_POP(PyListObject, lists); if (op == NULL) { From e9fe6b6ae0882f48dbeba44017bd79ae793941e7 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Sun, 9 Feb 2025 22:45:51 +0100 Subject: [PATCH 04/12] clear debugging code --- Objects/listobject.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 1b4e1d9969dfa8..21460fb1fe9b00 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -239,7 +239,6 @@ maybe_small_list_freelist_push(PyObject *self) Py_ssize_t allocated = op->allocated; if (allocated < PyList_MAXSAVESIZE) { return _Py_FREELIST_PUSH(small_lists[allocated], self, Py_small_lists_MAXFREELIST); - //printf("maybe_small_list_freelist_push: allocated %d (mod %d), size %d, id %p\n", (int)allocated, op->allocated, (int)PyList_Size(self), (void *)self); } return 0; } @@ -263,13 +262,12 @@ PyList_New(Py_ssize_t size) if ( size>0) { memset(op->ob_item, 0, size * sizeof(PyObject *)); } - //printf("obtained list from small_lists[%d] (id %p, op->allocated %d, size %d, PyList_Size %d)\n", (int) size, op, (int)op->allocated, (int)size, (int)PyList_Size( (PyObject*)op)); assert (op->allocated >= size); } //op=0; } if (op == NULL) { - // do we still need this freelist? if so, we could store it at small_lists[PyList_MAXSAVESIZE-1] with some special casing + // do we still need this freelist? if so, we could store it at small_lists[0] with some special casing op = _Py_FREELIST_POP(PyListObject, lists); if (op == NULL) { op = PyObject_GC_New(PyListObject, &PyList_Type); @@ -308,6 +306,15 @@ static PyObject * list_new_prealloc(Py_ssize_t size) { assert(size > 0); + if (size < PyList_MAXSAVESIZE) { + PyListObject *op = (PyListObject *)_Py_FREELIST_POP(PyLongObject, small_lists[size]); + if (op) { + // allocated with ob_item still allocated, but we need to set the other fields + assert (op->allocated >= size); + return op; + } + } + PyListObject *op = (PyListObject *) PyList_New(0); if (op == NULL) { return NULL; @@ -557,7 +564,6 @@ void small_list_freelist_free(void *obj) assert(PyList_CheckExact(self)); PyListObject *op = (PyListObject *)self; - //printf("small_list_freelist_free: (op->allocated %d, size %d)\n", (int)op->allocated, (int)PyList_Size(self)); if (op->ob_item != NULL) { free_list_items(op->ob_item, false); } From b81c62f73463039bde8511ef922cc39163d371cd Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Mon, 10 Feb 2025 14:33:31 +0100 Subject: [PATCH 05/12] ci --- Objects/listobject.c | 7 +++++-- Objects/object.c | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 21460fb1fe9b00..4bfc7257c11215 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -261,6 +261,9 @@ PyList_New(Py_ssize_t size) Py_SET_SIZE(op, size); if ( size>0) { memset(op->ob_item, 0, size * sizeof(PyObject *)); + } else { + // might be relatex later + op->ob_item = NULL; } assert (op->allocated >= size); } @@ -311,7 +314,7 @@ list_new_prealloc(Py_ssize_t size) if (op) { // allocated with ob_item still allocated, but we need to set the other fields assert (op->allocated >= size); - return op; + return (PyObject *) op; } } @@ -558,7 +561,7 @@ PyList_Append(PyObject *op, PyObject *newitem) /* Methods */ -void small_list_freelist_free(void *obj) +void _Py_small_list_freelist_free(void *obj) { PyObject *self = (PyObject *)obj; diff --git a/Objects/object.c b/Objects/object.c index ac1b29a83046ed..7fded260487299 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -914,7 +914,7 @@ free_object(void *obj) Py_DECREF(tp); } -extern void small_list_freelist_free(void *); +extern void _Py_small_list_freelist_free(void *); void _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) @@ -926,7 +926,7 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization) clear_freelist(&freelists->tuples[i], is_finalization, free_object); } for (Py_ssize_t i = 0; i < PyList_MAXSAVESIZE; i++) { - clear_freelist(&freelists->small_lists[i], is_finalization, small_list_freelist_free); + clear_freelist(&freelists->small_lists[i], is_finalization, _Py_small_list_freelist_free); } clear_freelist(&freelists->lists, is_finalization, free_object); clear_freelist(&freelists->list_iters, is_finalization, free_object); From 958ff12dd426f329412b1272b2eaee091793adb9 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Sun, 30 Mar 2025 20:56:16 +0200 Subject: [PATCH 06/12] fix test --- Lib/test/test_list.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_list.py b/Lib/test/test_list.py index 725e07f3ad023f..ebfcbe92d84a49 100644 --- a/Lib/test/test_list.py +++ b/Lib/test/test_list.py @@ -319,8 +319,9 @@ def test_no_memory(self): import_module("_testcapi") code = textwrap.dedent(""" import _testcapi, sys - # Prime the freelist - l = [None] + # Prime the freelist, size needs to larger than the small list freelists + l = [None, None, None, None, None, None, None, None, None, None, None, + None, None, None, None, None, None, None, None, None,] del l _testcapi.set_nomemory(0) l = [None] From 0fd64a7886386ead8473c3180afa5105e42a64c5 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 3 Apr 2025 23:15:49 +0200 Subject: [PATCH 07/12] increase size used to that of the tuples --- Include/internal/pycore_freelist_state.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index 7deef9666051f9..ef7af2d04a53d6 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -10,7 +10,7 @@ extern "C" { # define PyTuple_MAXSAVESIZE 20 // Largest tuple to save on freelist # define Py_tuple_MAXFREELIST 2000 // Maximum number of tuples of each size to save -# define PyList_MAXSAVESIZE 13 // Largest list size to save on freelist (minus one) +# define PyList_MAXSAVESIZE 21 // Largest list size to save on freelist (minus one) # define Py_small_lists_MAXFREELIST 40 # define Py_lists_MAXFREELIST 80 # define Py_list_iters_MAXFREELIST 10 From f1ada9643915dedef92b1bdb7639871baf81ee2c Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Thu, 3 Apr 2025 23:21:21 +0200 Subject: [PATCH 08/12] revert size increase --- Include/internal/pycore_freelist_state.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_freelist_state.h b/Include/internal/pycore_freelist_state.h index ef7af2d04a53d6..7deef9666051f9 100644 --- a/Include/internal/pycore_freelist_state.h +++ b/Include/internal/pycore_freelist_state.h @@ -10,7 +10,7 @@ extern "C" { # define PyTuple_MAXSAVESIZE 20 // Largest tuple to save on freelist # define Py_tuple_MAXFREELIST 2000 // Maximum number of tuples of each size to save -# define PyList_MAXSAVESIZE 21 // Largest list size to save on freelist (minus one) +# define PyList_MAXSAVESIZE 13 // Largest list size to save on freelist (minus one) # define Py_small_lists_MAXFREELIST 40 # define Py_lists_MAXFREELIST 80 # define Py_list_iters_MAXFREELIST 10 From 519ea7b54032f74c3df53beb68d5b12a0fc41651 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 21:23:08 +0000 Subject: [PATCH 09/12] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-04-03-21-23-05.gh-issue-126703.6JpmrR.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-04-03-21-23-05.gh-issue-126703.6JpmrR.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-03-21-23-05.gh-issue-126703.6JpmrR.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-03-21-23-05.gh-issue-126703.6JpmrR.rst new file mode 100644 index 00000000000000..2890b782cfdd48 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-03-21-23-05.gh-issue-126703.6JpmrR.rst @@ -0,0 +1 @@ +Improve performance of :class:`list` by using dedicated freelists for small sizes. From 42c7abbfe9ac98872eae38073a9146a57b18102f Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Sun, 6 Apr 2025 22:38:45 +0200 Subject: [PATCH 10/12] cleanup --- Objects/listobject.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index dd4c87223e88b6..24ddcdc341ccf1 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -234,7 +234,6 @@ _PyList_DebugMallocStats(FILE *out) static inline int maybe_small_list_freelist_push(PyObject *self) { - // todo: in the resizing there are some alignments on the allocation. can we use that here? assert(PyList_CheckExact(self)); PyListObject *op = (PyListObject *)self; @@ -259,17 +258,15 @@ PyList_New(Py_ssize_t size) if (size < PyList_MAXSAVESIZE) { op = (PyListObject *)_Py_FREELIST_POP(PyLongObject, small_lists[size]); if (op) { + assert (op->allocated >= size); // allocated with ob_item still allocated, but we need to set the other fields Py_SET_SIZE(op, size); if ( size>0) { memset(op->ob_item, 0, size * sizeof(PyObject *)); } else { - // might be relatex later op->ob_item = NULL; } - assert (op->allocated >= size); } - //op=0; } if (op == NULL) { // do we still need this freelist? if so, we could store it at small_lists[0] with some special casing From 5baec9429b074618e204ce9b1e7f23b80ee3c971 Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Tue, 8 Apr 2025 22:47:57 +0200 Subject: [PATCH 11/12] update comment --- Objects/listobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 24ddcdc341ccf1..9de853589f2a7e 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -269,7 +269,7 @@ PyList_New(Py_ssize_t size) } } if (op == NULL) { - // do we still need this freelist? if so, we could store it at small_lists[0] with some special casing + // the size based freelist was empty, so we try the general freelist op = _Py_FREELIST_POP(PyListObject, lists); if (op == NULL) { op = PyObject_GC_New(PyListObject, &PyList_Type); From 77f3e29227a612bf9c583d741ae91793e86de0ae Mon Sep 17 00:00:00 2001 From: Pieter Eendebak Date: Tue, 8 Apr 2025 22:49:01 +0200 Subject: [PATCH 12/12] update comment --- Objects/listobject.c | 1 - 1 file changed, 1 deletion(-) diff --git a/Objects/listobject.c b/Objects/listobject.c index 9de853589f2a7e..b4d749d7255971 100644 --- a/Objects/listobject.c +++ b/Objects/listobject.c @@ -311,7 +311,6 @@ list_new_prealloc(Py_ssize_t size) if (size < PyList_MAXSAVESIZE) { PyListObject *op = (PyListObject *)_Py_FREELIST_POP(PyLongObject, small_lists[size]); if (op) { - // allocated with ob_item still allocated, but we need to set the other fields assert (op->allocated >= size); return (PyObject *) op; }