Skip to content

Commit 8790d4d

Browse files
gh-81057: Move tracemalloc Globals to _PyRuntimeState (gh-100151)
#81057
1 parent 1583c6e commit 8790d4d

File tree

9 files changed

+143
-107
lines changed

9 files changed

+143
-107
lines changed

Include/internal/pycore_pymem.h

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -90,28 +90,6 @@ PyAPI_FUNC(int) _PyMem_GetAllocatorName(
9090
PYMEM_ALLOCATOR_NOT_SET does nothing. */
9191
PyAPI_FUNC(int) _PyMem_SetupAllocators(PyMemAllocatorName allocator);
9292

93-
struct _PyTraceMalloc_Config {
94-
/* Module initialized?
95-
Variable protected by the GIL */
96-
enum {
97-
TRACEMALLOC_NOT_INITIALIZED,
98-
TRACEMALLOC_INITIALIZED,
99-
TRACEMALLOC_FINALIZED
100-
} initialized;
101-
102-
/* Is tracemalloc tracing memory allocations?
103-
Variable protected by the GIL */
104-
int tracing;
105-
106-
/* limit of the number of frames in a traceback, 1 by default.
107-
Variable protected by the GIL. */
108-
int max_nframe;
109-
};
110-
111-
#define _PyTraceMalloc_Config_INIT \
112-
{.initialized = TRACEMALLOC_NOT_INITIALIZED, \
113-
.tracing = 0, \
114-
.max_nframe = 1}
11593

11694
#ifdef __cplusplus
11795
}

Include/internal/pycore_runtime.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ extern "C" {
2323
#include "pycore_pythread.h" // struct _pythread_runtime_state
2424
#include "pycore_obmalloc.h" // struct obmalloc_state
2525
#include "pycore_time.h" // struct _time_runtime_state
26+
#include "pycore_tracemalloc.h" // struct _tracemalloc_runtime_state
2627
#include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_ids
2728

2829
struct _getargs_runtime_state {
@@ -137,11 +138,9 @@ typedef struct pyruntimestate {
137138
struct _ceval_runtime_state ceval;
138139
struct _gilstate_runtime_state gilstate;
139140
struct _getargs_runtime_state getargs;
140-
struct {
141-
struct _PyTraceMalloc_Config config;
142-
} tracemalloc;
143141
struct _dtoa_runtime_state dtoa;
144142
struct _fileutils_state fileutils;
143+
struct _tracemalloc_runtime_state tracemalloc;
145144

146145
PyPreConfig preconfig;
147146

Include/internal/pycore_runtime_init.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,11 @@ extern "C" {
5050
in accordance with the specification. */ \
5151
.autoTSSkey = Py_tss_NEEDS_INIT, \
5252
}, \
53-
.tracemalloc = { \
54-
.config = _PyTraceMalloc_Config_INIT, \
55-
}, \
5653
.dtoa = _dtoa_runtime_state_INIT(runtime), \
5754
.fileutils = { \
5855
.force_ascii = -1, \
5956
}, \
57+
.tracemalloc = _tracemalloc_runtime_state_INIT, \
6058
.float_state = { \
6159
.float_format = _py_float_format_unknown, \
6260
.double_format = _py_float_format_unknown, \

Include/internal/pycore_tracemalloc.h

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
#ifndef Py_INTERNAL_TRACEMALLOC_H
2+
#define Py_INTERNAL_TRACEMALLOC_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_hashtable.h" // _Py_hashtable_t
12+
13+
14+
/* Trace memory blocks allocated by PyMem_RawMalloc() */
15+
#define TRACE_RAW_MALLOC
16+
17+
18+
struct _PyTraceMalloc_Config {
19+
/* Module initialized?
20+
Variable protected by the GIL */
21+
enum {
22+
TRACEMALLOC_NOT_INITIALIZED,
23+
TRACEMALLOC_INITIALIZED,
24+
TRACEMALLOC_FINALIZED
25+
} initialized;
26+
27+
/* Is tracemalloc tracing memory allocations?
28+
Variable protected by the GIL */
29+
int tracing;
30+
31+
/* limit of the number of frames in a traceback, 1 by default.
32+
Variable protected by the GIL. */
33+
int max_nframe;
34+
};
35+
36+
37+
/* Pack the frame_t structure to reduce the memory footprint on 64-bit
38+
architectures: 12 bytes instead of 16. */
39+
struct
40+
#ifdef __GNUC__
41+
__attribute__((packed))
42+
#elif defined(_MSC_VER)
43+
#pragma pack(push, 4)
44+
#endif
45+
tracemalloc_frame {
46+
/* filename cannot be NULL: "<unknown>" is used if the Python frame
47+
filename is NULL */
48+
PyObject *filename;
49+
unsigned int lineno;
50+
};
51+
#ifdef _MSC_VER
52+
#pragma pack(pop)
53+
#endif
54+
55+
struct tracemalloc_traceback {
56+
Py_uhash_t hash;
57+
/* Number of frames stored */
58+
uint16_t nframe;
59+
/* Total number of frames the traceback had */
60+
uint16_t total_nframe;
61+
struct tracemalloc_frame frames[1];
62+
};
63+
64+
65+
struct _tracemalloc_runtime_state {
66+
struct _PyTraceMalloc_Config config;
67+
68+
/* Protected by the GIL */
69+
struct {
70+
PyMemAllocatorEx mem;
71+
PyMemAllocatorEx raw;
72+
PyMemAllocatorEx obj;
73+
} allocators;
74+
75+
#if defined(TRACE_RAW_MALLOC)
76+
PyThread_type_lock tables_lock;
77+
#endif
78+
/* Size in bytes of currently traced memory.
79+
Protected by TABLES_LOCK(). */
80+
size_t traced_memory;
81+
/* Peak size in bytes of traced memory.
82+
Protected by TABLES_LOCK(). */
83+
size_t peak_traced_memory;
84+
/* Hash table used as a set to intern filenames:
85+
PyObject* => PyObject*.
86+
Protected by the GIL */
87+
_Py_hashtable_t *filenames;
88+
/* Buffer to store a new traceback in traceback_new().
89+
Protected by the GIL. */
90+
struct tracemalloc_traceback *traceback;
91+
/* Hash table used as a set to intern tracebacks:
92+
traceback_t* => traceback_t*
93+
Protected by the GIL */
94+
_Py_hashtable_t *tracebacks;
95+
/* pointer (void*) => trace (trace_t*).
96+
Protected by TABLES_LOCK(). */
97+
_Py_hashtable_t *traces;
98+
/* domain (unsigned int) => traces (_Py_hashtable_t).
99+
Protected by TABLES_LOCK(). */
100+
_Py_hashtable_t *domains;
101+
102+
struct tracemalloc_traceback empty_traceback;
103+
104+
Py_tss_t reentrant_key;
105+
};
106+
107+
#define _tracemalloc_runtime_state_INIT \
108+
{ \
109+
.config = { \
110+
.initialized = TRACEMALLOC_NOT_INITIALIZED, \
111+
.tracing = 0, \
112+
.max_nframe = 1, \
113+
}, \
114+
.reentrant_key = Py_tss_NEEDS_INIT, \
115+
}
116+
117+
118+
#ifdef __cplusplus
119+
}
120+
#endif
121+
#endif // !Py_INTERNAL_TRACEMALLOC_H

Makefile.pre.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,6 +1678,7 @@ PYTHON_HEADERS= \
16781678
$(srcdir)/Include/internal/pycore_time.h \
16791679
$(srcdir)/Include/internal/pycore_token.h \
16801680
$(srcdir)/Include/internal/pycore_traceback.h \
1681+
$(srcdir)/Include/internal/pycore_tracemalloc.h \
16811682
$(srcdir)/Include/internal/pycore_tuple.h \
16821683
$(srcdir)/Include/internal/pycore_typeobject.h \
16831684
$(srcdir)/Include/internal/pycore_ucnhash.h \

Modules/_tracemalloc.c

Lines changed: 14 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,6 @@ module _tracemalloc
2020

2121
_Py_DECLARE_STR(anon_unknown, "<unknown>");
2222

23-
/* Trace memory blocks allocated by PyMem_RawMalloc() */
24-
#define TRACE_RAW_MALLOC
25-
2623
/* Forward declaration */
2724
static void tracemalloc_stop(void);
2825
static void* raw_malloc(size_t size);
@@ -35,19 +32,14 @@ static void raw_free(void *ptr);
3532
#define TO_PTR(key) ((const void *)(uintptr_t)(key))
3633
#define FROM_PTR(key) ((uintptr_t)(key))
3734

38-
/* Protected by the GIL */
39-
static struct {
40-
PyMemAllocatorEx mem;
41-
PyMemAllocatorEx raw;
42-
PyMemAllocatorEx obj;
43-
} allocators;
35+
#define allocators _PyRuntime.tracemalloc.allocators
4436

4537

4638
#if defined(TRACE_RAW_MALLOC)
4739
/* This lock is needed because tracemalloc_free() is called without
4840
the GIL held from PyMem_RawFree(). It cannot acquire the lock because it
4941
would introduce a deadlock in _PyThreadState_DeleteCurrent(). */
50-
static PyThread_type_lock tables_lock;
42+
# define tables_lock _PyRuntime.tracemalloc.tables_lock
5143
# define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1)
5244
# define TABLES_UNLOCK() PyThread_release_lock(tables_lock)
5345
#else
@@ -59,33 +51,8 @@ static PyThread_type_lock tables_lock;
5951

6052
#define DEFAULT_DOMAIN 0
6153

62-
/* Pack the frame_t structure to reduce the memory footprint on 64-bit
63-
architectures: 12 bytes instead of 16. */
64-
typedef struct
65-
#ifdef __GNUC__
66-
__attribute__((packed))
67-
#elif defined(_MSC_VER)
68-
#pragma pack(push, 4)
69-
#endif
70-
{
71-
/* filename cannot be NULL: "<unknown>" is used if the Python frame
72-
filename is NULL */
73-
PyObject *filename;
74-
unsigned int lineno;
75-
} frame_t;
76-
#ifdef _MSC_VER
77-
#pragma pack(pop)
78-
#endif
79-
80-
81-
typedef struct {
82-
Py_uhash_t hash;
83-
/* Number of frames stored */
84-
uint16_t nframe;
85-
/* Total number of frames the traceback had */
86-
uint16_t total_nframe;
87-
frame_t frames[1];
88-
} traceback_t;
54+
typedef struct tracemalloc_frame frame_t;
55+
typedef struct tracemalloc_traceback traceback_t;
8956

9057
#define TRACEBACK_SIZE(NFRAME) \
9158
(sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1))
@@ -96,7 +63,8 @@ typedef struct {
9663
static const unsigned long MAX_NFRAME = Py_MIN(UINT16_MAX, ((SIZE_MAX - sizeof(traceback_t)) / sizeof(frame_t) + 1));
9764

9865

99-
static traceback_t tracemalloc_empty_traceback;
66+
#define tracemalloc_empty_traceback _PyRuntime.tracemalloc.empty_traceback
67+
10068

10169
/* Trace of a memory block */
10270
typedef struct {
@@ -108,35 +76,13 @@ typedef struct {
10876
} trace_t;
10977

11078

111-
/* Size in bytes of currently traced memory.
112-
Protected by TABLES_LOCK(). */
113-
static size_t tracemalloc_traced_memory = 0;
114-
115-
/* Peak size in bytes of traced memory.
116-
Protected by TABLES_LOCK(). */
117-
static size_t tracemalloc_peak_traced_memory = 0;
118-
119-
/* Hash table used as a set to intern filenames:
120-
PyObject* => PyObject*.
121-
Protected by the GIL */
122-
static _Py_hashtable_t *tracemalloc_filenames = NULL;
123-
124-
/* Buffer to store a new traceback in traceback_new().
125-
Protected by the GIL. */
126-
static traceback_t *tracemalloc_traceback = NULL;
127-
128-
/* Hash table used as a set to intern tracebacks:
129-
traceback_t* => traceback_t*
130-
Protected by the GIL */
131-
static _Py_hashtable_t *tracemalloc_tracebacks = NULL;
132-
133-
/* pointer (void*) => trace (trace_t*).
134-
Protected by TABLES_LOCK(). */
135-
static _Py_hashtable_t *tracemalloc_traces = NULL;
136-
137-
/* domain (unsigned int) => traces (_Py_hashtable_t).
138-
Protected by TABLES_LOCK(). */
139-
static _Py_hashtable_t *tracemalloc_domains = NULL;
79+
#define tracemalloc_traced_memory _PyRuntime.tracemalloc.traced_memory
80+
#define tracemalloc_peak_traced_memory _PyRuntime.tracemalloc.peak_traced_memory
81+
#define tracemalloc_filenames _PyRuntime.tracemalloc.filenames
82+
#define tracemalloc_traceback _PyRuntime.tracemalloc.traceback
83+
#define tracemalloc_tracebacks _PyRuntime.tracemalloc.tracebacks
84+
#define tracemalloc_traces _PyRuntime.tracemalloc.traces
85+
#define tracemalloc_domains _PyRuntime.tracemalloc.domains
14086

14187

14288
#ifdef TRACE_DEBUG
@@ -157,7 +103,7 @@ tracemalloc_error(const char *format, ...)
157103
#if defined(TRACE_RAW_MALLOC)
158104
#define REENTRANT_THREADLOCAL
159105

160-
static Py_tss_t tracemalloc_reentrant_key = Py_tss_NEEDS_INIT;
106+
#define tracemalloc_reentrant_key _PyRuntime.tracemalloc.reentrant_key
161107

162108
/* Any non-NULL pointer can be used */
163109
#define REENTRANT Py_True

PCbuild/pythoncore.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@
259259
<ClInclude Include="..\Include\internal\pycore_time.h" />
260260
<ClInclude Include="..\Include\internal\pycore_token.h" />
261261
<ClInclude Include="..\Include\internal\pycore_traceback.h" />
262+
<ClInclude Include="..\Include\internal\pycore_tracemalloc.h" />
262263
<ClInclude Include="..\Include\internal\pycore_tuple.h" />
263264
<ClInclude Include="..\Include\internal\pycore_typeobject.h" />
264265
<ClInclude Include="..\Include\internal\pycore_ucnhash.h" />

PCbuild/pythoncore.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,9 @@
678678
<ClInclude Include="..\Include\internal\pycore_traceback.h">
679679
<Filter>Include\internal</Filter>
680680
</ClInclude>
681+
<ClInclude Include="..\Include\internal\pycore_tracemalloc.h">
682+
<Filter>Include\internal</Filter>
683+
</ClInclude>
681684
<ClInclude Include="..\Include\internal\pycore_tuple.h">
682685
<Filter>Include\internal</Filter>
683686
</ClInclude>

Tools/c-analyzer/cpython/globals-to-fix.tsv

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -377,17 +377,6 @@ Modules/faulthandler.c - old_stack -
377377
##-----------------------
378378
## state
379379

380-
Modules/_tracemalloc.c - allocators -
381-
Modules/_tracemalloc.c - tables_lock -
382-
Modules/_tracemalloc.c - tracemalloc_empty_traceback -
383-
Modules/_tracemalloc.c - tracemalloc_traced_memory -
384-
Modules/_tracemalloc.c - tracemalloc_peak_traced_memory -
385-
Modules/_tracemalloc.c - tracemalloc_filenames -
386-
Modules/_tracemalloc.c - tracemalloc_traceback -
387-
Modules/_tracemalloc.c - tracemalloc_tracebacks -
388-
Modules/_tracemalloc.c - tracemalloc_traces -
389-
Modules/_tracemalloc.c - tracemalloc_domains -
390-
Modules/_tracemalloc.c - tracemalloc_reentrant_key -
391380
Modules/faulthandler.c faulthandler_dump_traceback reentrant -
392381
Modules/signalmodule.c - is_tripped -
393382
Modules/signalmodule.c - signal_global_state -

0 commit comments

Comments
 (0)