Skip to content

Commit 3ccb908

Browse files
committed
Add freelist for ints with small number of digits
1 parent 75b628a commit 3ccb908

File tree

3 files changed

+32
-11
lines changed

3 files changed

+32
-11
lines changed

Include/internal/pycore_freelist_state.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ extern "C" {
1717
# define Py_dictkeys_MAXFREELIST 80
1818
# define Py_floats_MAXFREELIST 100
1919
# define Py_ints_MAXFREELIST 100
20+
# define PyLong_MAXSAVESIZE 8 // Keep freelists for all ints with less than this number of digits
2021
# define Py_slices_MAXFREELIST 1
2122
# define Py_contexts_MAXFREELIST 255
2223
# define Py_async_gens_MAXFREELIST 80
@@ -39,8 +40,8 @@ struct _Py_freelist {
3940

4041
struct _Py_freelists {
4142
struct _Py_freelist floats;
42-
struct _Py_freelist ints;
4343
struct _Py_freelist tuples[PyTuple_MAXSAVESIZE];
44+
struct _Py_freelist ints[PyLong_MAXSAVESIZE];
4445
struct _Py_freelist lists;
4546
struct _Py_freelist list_iters;
4647
struct _Py_freelist tuple_iters;

Objects/longobject.c

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,22 @@ long_normalize(PyLongObject *v)
152152
# define MAX_LONG_DIGITS ((INT64_MAX-1) / PyLong_SHIFT)
153153
#endif
154154

155+
static inline int
156+
maybe_freelist_push(PyObject *self)
157+
{
158+
assert(PyLong_CheckExact(self));
159+
assert(Py_IS_TYPE(self, &PyLong_Type));
160+
161+
PyLongObject *op = (PyLongObject *)self;
162+
Py_ssize_t ndigits = _PyLong_DigitCount(op);
163+
164+
if (ndigits < PyLong_MAXSAVESIZE) {
165+
return _Py_FREELIST_PUSH(ints[ndigits], self, Py_ints_MAXFREELIST);
166+
}
167+
return 0;
168+
}
169+
170+
155171
static PyLongObject *
156172
long_alloc(Py_ssize_t size)
157173
{
@@ -166,8 +182,8 @@ long_alloc(Py_ssize_t size)
166182
* assume that there is always at least one digit present. */
167183
Py_ssize_t ndigits = size ? size : 1;
168184

169-
if (ndigits == 1) {
170-
result = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints);
185+
if (ndigits < PyLong_MAXSAVESIZE ) {
186+
result = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints[ndigits]);
171187
}
172188
if (result == NULL) {
173189
/* Number of bytes needed is: offsetof(PyLongObject, ob_digit) +
@@ -247,7 +263,7 @@ _PyLong_FromMedium(sdigit x)
247263
assert(!IS_SMALL_INT(x));
248264
assert(is_medium_int(x));
249265

250-
PyLongObject *v = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints);
266+
PyLongObject *v = (PyLongObject *)_Py_FREELIST_POP(PyLongObject, ints[1]);
251267
if (v == NULL) {
252268
v = PyObject_Malloc(sizeof(PyLongObject));
253269
if (v == NULL) {
@@ -3669,11 +3685,10 @@ _PyLong_ExactDealloc(PyObject *self)
36693685
_Py_SetImmortal(self);
36703686
return;
36713687
}
3672-
if (_PyLong_IsCompact((PyLongObject *)self)) {
3673-
_Py_FREELIST_FREE(ints, self, PyObject_Free);
3674-
return;
3688+
3689+
if (!maybe_freelist_push(self)) {
3690+
PyObject_Free(self);
36753691
}
3676-
PyObject_Free(self);
36773692
}
36783693

36793694
static void
@@ -3689,10 +3704,13 @@ long_dealloc(PyObject *self)
36893704
_Py_SetImmortal(self);
36903705
return;
36913706
}
3692-
if (PyLong_CheckExact(self) && _PyLong_IsCompact((PyLongObject *)self)) {
3693-
_Py_FREELIST_FREE(ints, self, PyObject_Free);
3707+
if (PyLong_CheckExact(self)) {
3708+
if (!maybe_freelist_push(self)) {
3709+
PyObject_Free(self);
3710+
}
36943711
return;
36953712
}
3713+
36963714
Py_TYPE(self)->tp_free(self);
36973715
}
36983716

Objects/object.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,9 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization)
922922
for (Py_ssize_t i = 0; i < PyTuple_MAXSAVESIZE; i++) {
923923
clear_freelist(&freelists->tuples[i], is_finalization, free_object);
924924
}
925+
for (Py_ssize_t i = 0; i < PyLong_MAXSAVESIZE; i++) {
926+
clear_freelist(&freelists->ints[i], is_finalization, free_object);
927+
}
925928
clear_freelist(&freelists->lists, is_finalization, free_object);
926929
clear_freelist(&freelists->list_iters, is_finalization, free_object);
927930
clear_freelist(&freelists->tuple_iters, is_finalization, free_object);
@@ -938,7 +941,6 @@ _PyObject_ClearFreeLists(struct _Py_freelists *freelists, int is_finalization)
938941
clear_freelist(&freelists->object_stack_chunks, 1, PyMem_RawFree);
939942
}
940943
clear_freelist(&freelists->unicode_writers, is_finalization, PyMem_Free);
941-
clear_freelist(&freelists->ints, is_finalization, free_object);
942944
clear_freelist(&freelists->pymethodobjects, is_finalization, free_object);
943945
}
944946

0 commit comments

Comments
 (0)