Skip to content

Commit 67807cf

Browse files
gh-81057: Move the Allocators to _PyRuntimeState (gh-99217)
The global allocators were stored in 3 static global variables: _PyMem_Raw, _PyMem, and _PyObject. State for the "small block" allocator was stored in another 13. That makes a total of 16 global variables. We are moving all 16 to the _PyRuntimeState struct as part of the work for gh-81057. (If PEP 684 is accepted then we will follow up by moving them all to PyInterpreterState.) #81057
1 parent 55c96e8 commit 67807cf

14 files changed

+1104
-900
lines changed

Include/internal/pycore_obmalloc.h

+689
Large diffs are not rendered by default.
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#ifndef Py_INTERNAL_OBMALLOC_INIT_H
2+
#define Py_INTERNAL_OBMALLOC_INIT_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#ifndef Py_BUILD_CORE
8+
# error "this header requires Py_BUILD_CORE define"
9+
#endif
10+
11+
12+
/****************************************************/
13+
/* the default object allocator's state initializer */
14+
15+
#define PTA(pools, x) \
16+
((poolp )((uint8_t *)&(pools.used[2*(x)]) - 2*sizeof(pymem_block *)))
17+
#define PT(p, x) PTA(p, x), PTA(p, x)
18+
19+
#define PT_8(p, start) \
20+
PT(p, start), \
21+
PT(p, start+1), \
22+
PT(p, start+2), \
23+
PT(p, start+3), \
24+
PT(p, start+4), \
25+
PT(p, start+5), \
26+
PT(p, start+6), \
27+
PT(p, start+7)
28+
29+
#if NB_SMALL_SIZE_CLASSES <= 8
30+
# define _obmalloc_pools_INIT(p) \
31+
{ PT_8(p, 0) }
32+
#elif NB_SMALL_SIZE_CLASSES <= 16
33+
# define _obmalloc_pools_INIT(p) \
34+
{ PT_8(p, 0), PT_8(p, 8) }
35+
#elif NB_SMALL_SIZE_CLASSES <= 24
36+
# define _obmalloc_pools_INIT(p) \
37+
{ PT_8(p, 0), PT_8(p, 8), PT_8(p, 16) }
38+
#elif NB_SMALL_SIZE_CLASSES <= 32
39+
# define _obmalloc_pools_INIT(p) \
40+
{ PT_8(p, 0), PT_8(p, 8), PT_8(p, 16), PT_8(p, 24) }
41+
#elif NB_SMALL_SIZE_CLASSES <= 40
42+
# define _obmalloc_pools_INIT(p) \
43+
{ PT_8(p, 0), PT_8(p, 8), PT_8(p, 16), PT_8(p, 24), PT_8(p, 32) }
44+
#elif NB_SMALL_SIZE_CLASSES <= 48
45+
# define _obmalloc_pools_INIT(p) \
46+
{ PT_8(p, 0), PT_8(p, 8), PT_8(p, 16), PT_8(p, 24), PT_8(p, 32), PT_8(p, 40) }
47+
#elif NB_SMALL_SIZE_CLASSES <= 56
48+
# define _obmalloc_pools_INIT(p) \
49+
{ PT_8(p, 0), PT_8(p, 8), PT_8(p, 16), PT_8(p, 24), PT_8(p, 32), PT_8(p, 40), PT_8(p, 48) }
50+
#elif NB_SMALL_SIZE_CLASSES <= 64
51+
# define _obmalloc_pools_INIT(p) \
52+
{ PT_8(p, 0), PT_8(p, 8), PT_8(p, 16), PT_8(p, 24), PT_8(p, 32), PT_8(p, 40), PT_8(p, 48), PT_8(p, 56) }
53+
#else
54+
# error "NB_SMALL_SIZE_CLASSES should be less than 64"
55+
#endif
56+
57+
#define _obmalloc_state_INIT(obmalloc) \
58+
{ \
59+
.pools = { \
60+
.used = _obmalloc_pools_INIT(obmalloc.pools), \
61+
}, \
62+
}
63+
64+
65+
#ifdef __cplusplus
66+
}
67+
#endif
68+
#endif // !Py_INTERNAL_OBMALLOC_INIT_H

Include/internal/pycore_pymem.h

+21-14
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,27 @@ extern "C" {
1111
#include "pymem.h" // PyMemAllocatorName
1212

1313

14+
typedef struct {
15+
/* We tag each block with an API ID in order to tag API violations */
16+
char api_id;
17+
PyMemAllocatorEx alloc;
18+
} debug_alloc_api_t;
19+
20+
struct _pymem_allocators {
21+
struct {
22+
PyMemAllocatorEx raw;
23+
PyMemAllocatorEx mem;
24+
PyMemAllocatorEx obj;
25+
} standard;
26+
struct {
27+
debug_alloc_api_t raw;
28+
debug_alloc_api_t mem;
29+
debug_alloc_api_t obj;
30+
} debug;
31+
PyObjectArenaAllocator obj_arena;
32+
};
33+
34+
1435
/* Set the memory allocator of the specified domain to the default.
1536
Save the old allocator into *old_alloc if it's non-NULL.
1637
Return on success, or return -1 if the domain is unknown. */
@@ -94,20 +115,6 @@ struct _PyTraceMalloc_Config {
94115

95116
PyAPI_DATA(struct _PyTraceMalloc_Config) _Py_tracemalloc_config;
96117

97-
/* Allocate memory directly from the O/S virtual memory system,
98-
* where supported. Otherwise fallback on malloc */
99-
void *_PyObject_VirtualAlloc(size_t size);
100-
void _PyObject_VirtualFree(void *, size_t size);
101-
102-
/* This function returns the number of allocated memory blocks, regardless of size */
103-
PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void);
104-
105-
/* Macros */
106-
#ifdef WITH_PYMALLOC
107-
// Export the symbol for the 3rd party guppy3 project
108-
PyAPI_FUNC(int) _PyObject_DebugMallocStats(FILE *out);
109-
#endif
110-
111118
#ifdef __cplusplus
112119
}
113120
#endif

Include/internal/pycore_pymem_init.h

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#ifndef Py_INTERNAL_PYMEM_INIT_H
2+
#define Py_INTERNAL_PYMEM_INIT_H
3+
#ifdef __cplusplus
4+
extern "C" {
5+
#endif
6+
7+
#ifndef Py_BUILD_CORE
8+
# error "this header requires Py_BUILD_CORE define"
9+
#endif
10+
11+
#include "pycore_pymem.h"
12+
13+
14+
/********************************/
15+
/* the allocators' initializers */
16+
17+
extern void * _PyMem_RawMalloc(void *, size_t);
18+
extern void * _PyMem_RawCalloc(void *, size_t, size_t);
19+
extern void * _PyMem_RawRealloc(void *, void *, size_t);
20+
extern void _PyMem_RawFree(void *, void *);
21+
#define PYRAW_ALLOC {NULL, _PyMem_RawMalloc, _PyMem_RawCalloc, _PyMem_RawRealloc, _PyMem_RawFree}
22+
23+
#ifdef WITH_PYMALLOC
24+
extern void* _PyObject_Malloc(void *, size_t);
25+
extern void* _PyObject_Calloc(void *, size_t, size_t);
26+
extern void _PyObject_Free(void *, void *);
27+
extern void* _PyObject_Realloc(void *, void *, size_t);
28+
# define PYOBJ_ALLOC {NULL, _PyObject_Malloc, _PyObject_Calloc, _PyObject_Realloc, _PyObject_Free}
29+
#else
30+
# define PYOBJ_ALLOC PYRAW_ALLOC
31+
#endif // WITH_PYMALLOC
32+
33+
#define PYMEM_ALLOC PYOBJ_ALLOC
34+
35+
extern void* _PyMem_DebugRawMalloc(void *, size_t);
36+
extern void* _PyMem_DebugRawCalloc(void *, size_t, size_t);
37+
extern void* _PyMem_DebugRawRealloc(void *, void *, size_t);
38+
extern void _PyMem_DebugRawFree(void *, void *);
39+
40+
extern void* _PyMem_DebugMalloc(void *, size_t);
41+
extern void* _PyMem_DebugCalloc(void *, size_t, size_t);
42+
extern void* _PyMem_DebugRealloc(void *, void *, size_t);
43+
extern void _PyMem_DebugFree(void *, void *);
44+
45+
#define PYDBGRAW_ALLOC(runtime) \
46+
{&(runtime).allocators.debug.raw, _PyMem_DebugRawMalloc, _PyMem_DebugRawCalloc, _PyMem_DebugRawRealloc, _PyMem_DebugRawFree}
47+
#define PYDBGMEM_ALLOC(runtime) \
48+
{&(runtime).allocators.debug.mem, _PyMem_DebugMalloc, _PyMem_DebugCalloc, _PyMem_DebugRealloc, _PyMem_DebugFree}
49+
#define PYDBGOBJ_ALLOC(runtime) \
50+
{&(runtime).allocators.debug.obj, _PyMem_DebugMalloc, _PyMem_DebugCalloc, _PyMem_DebugRealloc, _PyMem_DebugFree}
51+
52+
extern void * _PyMem_ArenaAlloc(void *, size_t);
53+
extern void _PyMem_ArenaFree(void *, void *, size_t);
54+
55+
#ifdef Py_DEBUG
56+
# define _pymem_allocators_standard_INIT(runtime) \
57+
{ \
58+
PYDBGRAW_ALLOC(runtime), \
59+
PYDBGMEM_ALLOC(runtime), \
60+
PYDBGOBJ_ALLOC(runtime), \
61+
}
62+
#else
63+
# define _pymem_allocators_standard_INIT(runtime) \
64+
{ \
65+
PYRAW_ALLOC, \
66+
PYMEM_ALLOC, \
67+
PYOBJ_ALLOC, \
68+
}
69+
#endif
70+
71+
#define _pymem_allocators_debug_INIT \
72+
{ \
73+
{'r', PYRAW_ALLOC}, \
74+
{'m', PYMEM_ALLOC}, \
75+
{'o', PYOBJ_ALLOC}, \
76+
}
77+
78+
# define _pymem_allocators_obj_arena_INIT \
79+
{ NULL, _PyMem_ArenaAlloc, _PyMem_ArenaFree }
80+
81+
82+
#ifdef __cplusplus
83+
}
84+
#endif
85+
#endif // !Py_INTERNAL_PYMEM_INIT_H

Include/internal/pycore_runtime.h

+5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ extern "C" {
1313
#include "pycore_global_objects.h" // struct _Py_global_objects
1414
#include "pycore_import.h" // struct _import_runtime_state
1515
#include "pycore_interp.h" // PyInterpreterState
16+
#include "pycore_pymem.h" // struct _pymem_allocators
17+
#include "pycore_obmalloc.h" // struct obmalloc_state
1618
#include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_ids
1719

1820
struct _getargs_runtime_state {
@@ -86,6 +88,9 @@ typedef struct pyruntimestate {
8688
to access it, don't access it directly. */
8789
_Py_atomic_address _finalizing;
8890

91+
struct _pymem_allocators allocators;
92+
struct _obmalloc_state obmalloc;
93+
8994
struct pyinterpreters {
9095
PyThread_type_lock mutex;
9196
/* The linked list of interpreters, newest first. */

Include/internal/pycore_runtime_init.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,28 @@ extern "C" {
99
#endif
1010

1111
#include "pycore_object.h"
12+
#include "pycore_pymem_init.h"
13+
#include "pycore_obmalloc_init.h"
1214

1315

1416
/* The static initializers defined here should only be used
1517
in the runtime init code (in pystate.c and pylifecycle.c). */
1618

1719

18-
#define _PyRuntimeState_INIT \
20+
#define _PyRuntimeState_INIT(runtime) \
1921
{ \
2022
.gilstate = { \
2123
.check_enabled = 1, \
2224
/* A TSS key must be initialized with Py_tss_NEEDS_INIT \
2325
in accordance with the specification. */ \
2426
.autoTSSkey = Py_tss_NEEDS_INIT, \
2527
}, \
28+
.allocators = { \
29+
_pymem_allocators_standard_INIT(runtime), \
30+
_pymem_allocators_debug_INIT, \
31+
_pymem_allocators_obj_arena_INIT, \
32+
}, \
33+
.obmalloc = _obmalloc_state_INIT(runtime.obmalloc), \
2634
.interpreters = { \
2735
/* This prevents interpreters from getting created \
2836
until _PyInterpreterState_Enable() is called. */ \

Makefile.pre.in

+3
Original file line numberDiff line numberDiff line change
@@ -1650,12 +1650,15 @@ PYTHON_HEADERS= \
16501650
$(srcdir)/Include/internal/pycore_moduleobject.h \
16511651
$(srcdir)/Include/internal/pycore_namespace.h \
16521652
$(srcdir)/Include/internal/pycore_object.h \
1653+
$(srcdir)/Include/internal/pycore_obmalloc.h \
1654+
$(srcdir)/Include/internal/pycore_obmalloc_init.h \
16531655
$(srcdir)/Include/internal/pycore_pathconfig.h \
16541656
$(srcdir)/Include/internal/pycore_pyarena.h \
16551657
$(srcdir)/Include/internal/pycore_pyerrors.h \
16561658
$(srcdir)/Include/internal/pycore_pyhash.h \
16571659
$(srcdir)/Include/internal/pycore_pylifecycle.h \
16581660
$(srcdir)/Include/internal/pycore_pymem.h \
1661+
$(srcdir)/Include/internal/pycore_pymem_init.h \
16591662
$(srcdir)/Include/internal/pycore_pystate.h \
16601663
$(srcdir)/Include/internal/pycore_range.h \
16611664
$(srcdir)/Include/internal/pycore_runtime.h \
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The 18 global C variables holding the state of the allocators have been
2+
moved to ``_PyRuntimeState``. This is a strictly internal change with no
3+
change in behavior.

0 commit comments

Comments
 (0)