10000 gh-126703: Add freelists for small size lists by eendebakpt · Pull Request #129921 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

gh-126703: Add freelists for small size lists #129921

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
working version
  • Loading branch information
eendebakpt committed Mar 4, 2025
commit 32f1a36ff56f098e4f4114361ea21dcef6b1ca13
2 changes: 1 addition & 1 deletion Include/internal/pycore_freelist_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
55 changes: 30 additions & 25 deletions Objects/listobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
Expand All @@ -580,19 +582,22 @@ list_dealloc(PyObject *self)
Py_XDECREF(op->ob_item[i]);
}
}
if (0 && maybe_small_list_freelist_push(self) ) {
return;
CB2E 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
}

Expand Down
2 changes: 1 addition & 1 deletion Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
0