Skip to content

Commit f728f72

Browse files
authored
gh-111968: Use per-thread freelists for float in free-threading (gh-113886)
1 parent a0c9cf9 commit f728f72

File tree

9 files changed

+43
-59
lines changed

9 files changed

+43
-59
lines changed

Diff for: Include/internal/pycore_floatobject.h

+2-19
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11-
11+
#include "pycore_freelist.h" // _PyFreeListState
1212
#include "pycore_unicodeobject.h" // _PyUnicodeWriter
1313

1414
/* runtime lifecycle */
1515

1616
extern void _PyFloat_InitState(PyInterpreterState *);
1717
extern PyStatus _PyFloat_InitTypes(PyInterpreterState *);
18-
extern void _PyFloat_Fini(PyInterpreterState *);
18+
extern void _PyFloat_Fini(_PyFreeListState *);
1919
extern void _PyFloat_FiniType(PyInterpreterState *);
2020

2121

@@ -33,24 +33,7 @@ struct _Py_float_runtime_state {
3333
};
3434

3535

36-
#ifndef WITH_FREELISTS
37-
// without freelists
38-
# define PyFloat_MAXFREELIST 0
39-
#endif
40-
41-
#ifndef PyFloat_MAXFREELIST
42-
# define PyFloat_MAXFREELIST 100
43-
#endif
4436

45-
struct _Py_float_state {
46-
#if PyFloat_MAXFREELIST > 0
47-
/* Special free list
48-
free_list is a singly-linked list of available PyFloatObjects,
49-
linked via abuse of their ob_type members. */
50-
int numfree;
51-
PyFloatObject *free_list;
52-
#endif
53-
};
5437

5538
void _PyFloat_ExactDealloc(PyObject *op);
5639

Diff for: Include/internal/pycore_freelist.h

+18-8
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,34 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11-
#ifndef WITH_FREELISTS
12-
// without freelists
13-
# define PyList_MAXFREELIST 0
14-
#endif
15-
16-
/* Empty list reuse scheme to save calls to malloc and free */
17-
#ifndef PyList_MAXFREELIST
11+
#ifdef WITH_FREELISTS
12+
// with freelists
1813
# define PyList_MAXFREELIST 80
14+
# define PyFloat_MAXFREELIST 100
15+
#else
16+
# define PyList_MAXFREELIST 0
17+
# define PyFloat_MAXFREELIST 0
1918
#endif
2019

2120
struct _Py_list_state {
22-
#if PyList_MAXFREELIST > 0
21+
#ifdef WITH_FREELISTS
2322
PyListObject *free_list[PyList_MAXFREELIST];
2423
int numfree;
2524
#endif
2625
};
2726

27+
struct _Py_float_state {
28+
#ifdef WITH_FREELISTS
29+
/* Special free list
30+
free_list is a singly-linked list of available PyFloatObjects,
31+
linked via abuse of their ob_type members. */
32+
int numfree;
33+
PyFloatObject *free_list;
34+
#endif
35+
};
36+
2837
typedef struct _Py_freelist_state {
38+
struct _Py_float_state float_state;
2939
struct _Py_list_state list;
3040
} _PyFreeListState;
3141

Diff for: Include/internal/pycore_gc.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ extern PyObject *_PyGC_GetReferrers(PyInterpreterState *interp, PyObject *objs);
243243
extern void _PyGC_ClearAllFreeLists(PyInterpreterState *interp);
244244
extern void _Py_ClearFreeLists(_PyFreeListState *state, int is_finalization);
245245
extern void _PyTuple_ClearFreeList(PyInterpreterState *interp);
246-
extern void _PyFloat_ClearFreeList(PyInterpreterState *interp);
246+
extern void _PyFloat_ClearFreeList(_PyFreeListState *state, int is_finalization);
247247
extern void _PyList_ClearFreeList(_PyFreeListState *state, int is_finalization);
248248
extern void _PyDict_ClearFreeList(PyInterpreterState *interp);
249249
extern void _PyAsyncGen_ClearFreeLists(PyInterpreterState *interp);

Diff for: Include/internal/pycore_interp.h

-1
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,6 @@ struct _is {
184184
#endif
185185
struct _py_object_state object_state;
186186
struct _Py_unicode_state unicode;
187-
struct _Py_float_state float_state;
188187
struct _Py_long_state long_state;
189188
struct _dtoa_state dtoa;
190189
struct _py_func_state func_state;

Diff for: Objects/floatobject.c

+20-27
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,13 @@ class float "PyObject *" "&PyFloat_Type"
2626

2727
#include "clinic/floatobject.c.h"
2828

29-
#ifndef PyFloat_MAXFREELIST
30-
# define PyFloat_MAXFREELIST 100
31-
#endif
32-
33-
34-
#if PyFloat_MAXFREELIST > 0
29+
#ifdef WITH_FREELISTS
3530
static struct _Py_float_state *
3631
get_float_state(void)
3732
{
38-
PyInterpreterState *interp = _PyInterpreterState_GET();
39-
return &interp->float_state;
33+
_PyFreeListState *state = _PyFreeListState_GET();
34+
assert(state != NULL);
35+
return &state->float_state;
4036
}
4137
#endif
4238

@@ -132,7 +128,7 @@ PyObject *
132128
PyFloat_FromDouble(double fval)
133129
{
134130
PyFloatObject *op;
135-
#if PyFloat_MAXFREELIST > 0
131+
#ifdef WITH_FREELISTS
136132
struct _Py_float_state *state = get_float_state();
137133
op = state->free_list;
138134
if (op != NULL) {
@@ -252,13 +248,9 @@ _PyFloat_ExactDealloc(PyObject *obj)
252248
{
253249
assert(PyFloat_CheckExact(obj));
254250
PyFloatObject *op = (PyFloatObject *)obj;
255-
#if PyFloat_MAXFREELIST > 0
251+
#ifdef WITH_FREELISTS
256252
struct _Py_float_state *state = get_float_state();
257-
#ifdef Py_DEBUG
258-
// float_dealloc() must not be called after _PyFloat_Fini()
259-
assert(state->numfree != -1);
260-
#endif
261-
if (state->numfree >= PyFloat_MAXFREELIST) {
253+
if (state->numfree >= PyFloat_MAXFREELIST || state->numfree < 0) {
262254
PyObject_Free(op);
263255
return;
264256
}
@@ -275,7 +267,7 @@ static void
275267
float_dealloc(PyObject *op)
276268
{
277269
assert(PyFloat_Check(op));
278-
#if PyFloat_MAXFREELIST > 0
270+
#ifdef WITH_FREELISTS
279271
if (PyFloat_CheckExact(op)) {
280272
_PyFloat_ExactDealloc(op);
281273
}
@@ -2002,29 +1994,30 @@ _PyFloat_InitTypes(PyInterpreterState *interp)
20021994
}
20031995

20041996
void
2005-
_PyFloat_ClearFreeList(PyInterpreterState *interp)
1997+
_PyFloat_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization)
20061998
{
2007-
#if PyFloat_MAXFREELIST > 0
2008-
struct _Py_float_state *state = &interp->float_state;
1999+
#ifdef WITH_FREELISTS
2000+
struct _Py_float_state *state = &freelist_state->float_state;
20092001
PyFloatObject *f = state->free_list;
20102002
while (f != NULL) {
20112003
PyFloatObject *next = (PyFloatObject*) Py_TYPE(f);
20122004
PyObject_Free(f);
20132005
f = next;
20142006
}
20152007
state->free_list = NULL;
2016-
state->numfree = 0;
2008+
if (is_finalization) {
2009+
state->numfree = -1;
2010+
}
2011+
else {
2012+
state->numfree = 0;
2013+
}
20172014
#endif
20182015
}
20192016

20202017
void
2021-
_PyFloat_Fini(PyInterpreterState *interp)
2018+
_PyFloat_Fini(_PyFreeListState *state)
20222019
{
2023-
_PyFloat_ClearFreeList(interp);
2024-
#if defined(Py_DEBUG) && PyFloat_MAXFREELIST > 0
2025-
struct _Py_float_state *state = &interp->float_state;
2026-
state->numfree = -1;
2027-
#endif
2020+
_PyFloat_ClearFreeList(state, 1);
20282021
}
20292022

20302023
void
@@ -2037,7 +2030,7 @@ _PyFloat_FiniType(PyInterpreterState *interp)
20372030
void
20382031
_PyFloat_DebugMallocStats(FILE *out)
20392032
{
2040-
#if PyFloat_MAXFREELIST > 0
2033+
#ifdef WITH_FREELISTS
20412034
struct _Py_float_state *state = get_float_state();
20422035
_PyDebugAllocatorStats(out,
20432036
"free PyFloatObject",

Diff for: Python/gc_free_threading.c

-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ void
1515
_PyGC_ClearAllFreeLists(PyInterpreterState *interp)
1616
{
1717
_PyTuple_ClearFreeList(interp);
18-
_PyFloat_ClearFreeList(interp);
1918
_PyDict_ClearFreeList(interp);
2019
_PyAsyncGen_ClearFreeLists(interp);
2120
_PyContext_ClearFreeList(interp);

Diff for: Python/gc_gil.c

-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ void
1212
_PyGC_ClearAllFreeLists(PyInterpreterState *interp)
1313
{
1414
_PyTuple_ClearFreeList(interp);
15-
_PyFloat_ClearFreeList(interp);
1615
_PyDict_ClearFreeList(interp);
1716
_PyAsyncGen_ClearFreeLists(interp);
1817
_PyContext_ClearFreeList(interp);

Diff for: Python/pylifecycle.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -1757,10 +1757,10 @@ finalize_interp_types(PyInterpreterState *interp)
17571757
_PySlice_Fini(interp);
17581758

17591759
_PyUnicode_Fini(interp);
1760-
_PyFloat_Fini(interp);
17611760

17621761
_PyFreeListState *state = _PyFreeListState_GET();
17631762
_PyList_Fini(state);
1763+
_PyFloat_Fini(state);
17641764

17651765
#ifdef Py_DEBUG
17661766
_PyStaticObjects_CheckRefcnt(interp);

Diff for: Python/pystate.c

+1
Original file line numberDiff line numberDiff line change
@@ -1458,6 +1458,7 @@ clear_datastack(PyThreadState *tstate)
14581458
void
14591459
_Py_ClearFreeLists(_PyFreeListState *state, int is_finalization)
14601460
{
1461+
_PyFloat_ClearFreeList(state, is_finalization);
14611462
_PyList_ClearFreeList(state, is_finalization);
14621463
}
14631464

0 commit comments

Comments
 (0)