Skip to content

Commit 1a80214

Browse files
authored
gh-126703: Add freelists for list and tuple iterators (GH-128592)
1 parent 41ad2bb commit 1a80214

File tree

5 files changed

+24
-12
lines changed

5 files changed

+24
-12
lines changed

Include/internal/pycore_freelist_state.h

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ extern "C" {
1111
# define PyTuple_MAXSAVESIZE 20 // Largest tuple to save on freelist
1212
# define Py_tuple_MAXFREELIST 2000 // Maximum number of tuples of each size to save
1313
# define Py_lists_MAXFREELIST 80
14+
# define Py_list_iters_MAXFREELIST 10
15+
# define Py_tuple_iters_MAXFREELIST 10
1416
# define Py_dicts_MAXFREELIST 80
1517
# define Py_dictkeys_MAXFREELIST 80
1618
# define Py_floats_MAXFREELIST 100
@@ -40,6 +42,8 @@ struct _Py_freelists {
4042
struct _Py_freelist ints;
4143
struct _Py_freelist tuples[PyTuple_MAXSAVESIZE];
4244
struct _Py_freelist lists;
45+
struct _Py_freelist list_iters;
46+
struct _Py_freelist tuple_iters;
4347
struct _Py_freelist dicts;
4448
struct _Py_freelist dictkeys;
4549
struct _Py_freelist slices;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve performance of iterating over lists and tuples by using a freelist for the iterator objects.

Objects/listobject.c

+9-6
Original file line numberDiff line numberDiff line change
@@ -3903,15 +3903,17 @@ PyTypeObject PyListIter_Type = {
39033903
static PyObject *
39043904
list_iter(PyObject *seq)
39053905
{
3906-
_PyListIterObject *it;
3907-
39083906
if (!PyList_Check(seq)) {
39093907
PyErr_BadInternalCall();
39103908
return NULL;
39113909
}
3912-
it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type);
3913-
if (it == NULL)
3914-
return NULL;
3910+
_PyListIterObject *it = _Py_FREELIST_POP(_PyListIterObject, list_iters);
3911+
if (it == NULL) {
3912+
it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type);
3913+
if (it == NULL) {
3914+
return NULL;
3915+
}
3916+
}
39153917
it->it_index = 0;
39163918
it->it_seq = (PyListObject *)Py_NewRef(seq);
39173919
_PyObject_GC_TRACK(it);
@@ -3924,7 +3926,8 @@ listiter_dealloc(PyObject *self)
39243926
_PyListIterObject *it = (_PyListIterObject *)self;
39253927
_PyObject_GC_UNTRACK(it);
39263928
Py_XDECREF(it->it_seq);
3927-
PyObject_GC_Del(it);
3929+
assert(Py_IS_TYPE(self, &PyListIter_Type));
3930+
_Py_FREELIST_FREE(list_iters, it, PyObject_GC_Del);
39283931
}
39293932

39303933
static int

Objects/object.c

+2
Original file line numberDiff line numberDiff line change
@@ -923,6 +923,8 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization)
923923
clear_freelist(&freelists->tuples[i], is_finalization, free_object);
924924
}
925925
clear_freelist(&freelists->lists, is_finalization, free_object);
926+
clear_freelist(&freelists->list_iters, is_finalization, free_object);
927+
clear_freelist(&freelists->tuple_iters, is_finalization, free_object);
926928
clear_freelist(&freelists->dicts, is_finalization, free_object);
927929
clear_freelist(&freelists->dictkeys, is_finalization, PyMem_Free);
928930
clear_freelist(&freelists->slices, is_finalization, free_object);

Objects/tupleobject.c

+8-6
Original file line numberDiff line numberDiff line change
@@ -993,7 +993,8 @@ tupleiter_dealloc(PyObject *self)
993993
_PyTupleIterObject *it = _PyTupleIterObject_CAST(self);
994994
_PyObject_GC_UNTRACK(it);
995995
Py_XDECREF(it->it_seq);
996-
PyObject_GC_Del(it);
996+
assert(Py_IS_TYPE(self, &PyTupleIter_Type));
997+
_Py_FREELIST_FREE(tuple_iters, it, PyObject_GC_Del);
997998
}
998999

9991000
static int
@@ -1119,15 +1120,16 @@ PyTypeObject PyTupleIter_Type = {
11191120
static PyObject *
11201121
tuple_iter(PyObject *seq)
11211122
{
1122-
_PyTupleIterObject *it;
1123-
11241123
if (!PyTuple_Check(seq)) {
11251124
PyErr_BadInternalCall();
11261125
return NULL;
11271126
}
1128-
it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type);
1129-
if (it == NULL)
1130-
return NULL;
1127+
_PyTupleIterObject *it = _Py_FREELIST_POP(_PyTupleIterObject, tuple_iters);
1128+
if (it == NULL) {
1129+
it = PyObject_GC_New(_PyTupleIterObject, &PyTupleIter_Type);
1130+
if (it == NULL)
1131+
return NULL;
1132+
}
11311133
it->it_index = 0;
11321134
it->it_seq = (PyTupleObject *)Py_NewRef(seq);
11331135
_PyObject_GC_TRACK(it);

0 commit comments

Comments
 (0)