Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 100072e

Browse files
committedJan 10, 2024
pythongh-111968: Use per-thread freelists for float in free-threading
1 parent 57bdc6c commit 100072e

9 files changed

+37
-48
lines changed
 

‎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

‎Include/internal/pycore_freelist.h

+19-8
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,38 @@ 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

42+
3243
#ifdef __cplusplus
3344
}
3445
#endif

‎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);

‎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;

‎Objects/floatobject.c

+13-16
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-
3429
#if PyFloat_MAXFREELIST > 0
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

@@ -2002,29 +1998,30 @@ _PyFloat_InitTypes(PyInterpreterState *interp)
20021998
}
20031999

20042000
void
2005-
_PyFloat_ClearFreeList(PyInterpreterState *interp)
2001+
_PyFloat_ClearFreeList(_PyFreeListState *freelist_state, int is_finalization)
20062002
{
20072003
#if PyFloat_MAXFREELIST > 0
2008-
struct _Py_float_state *state = &interp->float_state;
2004+
struct _Py_float_state *state = &freelist_state->float_state;
20092005
PyFloatObject *f = state->free_list;
20102006
while (f != NULL) {
20112007
PyFloatObject *next = (PyFloatObject*) Py_TYPE(f);
20122008
PyObject_Free(f);
20132009
f = next;
20142010
}
20152011
state->free_list = NULL;
2016-
state->numfree = 0;
2012+
if (is_finalization) {
2013+
state->numfree = -1;
2014+
}
2015+
else {
2016+
state->numfree = 0;
2017+
}
20172018
#endif
20182019
}
20192020

20202021
void
2021-
_PyFloat_Fini(PyInterpreterState *interp)
2022+
_PyFloat_Fini(_PyFreeListState *state)
20222023
{
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
2024+
_PyFloat_ClearFreeList(state, 1);
20282025
}
20292026

20302027
void

‎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);

‎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);

‎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);

‎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)
Please sign in to comment.