[Python-checkins] gh-81057: Move tracemalloc Globals to _PyRuntimeState (gh-100151)

ericsnowcurrently webhook-mailer at python.org
Mon Dec 12 10:44:31 EST 2022


https://github.com/python/cpython/commit/8790d4d31fcd3abaccf31d27f72a8684adfc9dee
commit: 8790d4d31fcd3abaccf31d27f72a8684adfc9dee
branch: main
author: Eric Snow <ericsnowcurrently at gmail.com>
committer: ericsnowcurrently <ericsnowcurrently at gmail.com>
date: 2022-12-12T08:44:23-07:00
summary:

gh-81057: Move tracemalloc Globals to _PyRuntimeState (gh-100151)

https://github.com/python/cpython/issues/81057

files:
A Include/internal/pycore_tracemalloc.h
M Include/internal/pycore_pymem.h
M Include/internal/pycore_runtime.h
M Include/internal/pycore_runtime_init.h
M Makefile.pre.in
M Modules/_tracemalloc.c
M PCbuild/pythoncore.vcxproj
M PCbuild/pythoncore.vcxproj.filters
M Tools/c-analyzer/cpython/globals-to-fix.tsv

diff --git a/Include/internal/pycore_pymem.h b/Include/internal/pycore_pymem.h
index 5749af7465f6..4cc953d8d779 100644
--- a/Include/internal/pycore_pymem.h
+++ b/Include/internal/pycore_pymem.h
@@ -90,28 +90,6 @@ PyAPI_FUNC(int) _PyMem_GetAllocatorName(
    PYMEM_ALLOCATOR_NOT_SET does nothing. */
 PyAPI_FUNC(int) _PyMem_SetupAllocators(PyMemAllocatorName allocator);
 
-struct _PyTraceMalloc_Config {
-    /* Module initialized?
-       Variable protected by the GIL */
-    enum {
-        TRACEMALLOC_NOT_INITIALIZED,
-        TRACEMALLOC_INITIALIZED,
-        TRACEMALLOC_FINALIZED
-    } initialized;
-
-    /* Is tracemalloc tracing memory allocations?
-       Variable protected by the GIL */
-    int tracing;
-
-    /* limit of the number of frames in a traceback, 1 by default.
-       Variable protected by the GIL. */
-    int max_nframe;
-};
-
-#define _PyTraceMalloc_Config_INIT \
-    {.initialized = TRACEMALLOC_NOT_INITIALIZED, \
-     .tracing = 0, \
-     .max_nframe = 1}
 
 #ifdef __cplusplus
 }
diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h
index fe2de5feb47a..99ec6fc8862b 100644
--- a/Include/internal/pycore_runtime.h
+++ b/Include/internal/pycore_runtime.h
@@ -23,6 +23,7 @@ extern "C" {
 #include "pycore_pythread.h"        // struct _pythread_runtime_state
 #include "pycore_obmalloc.h"        // struct obmalloc_state
 #include "pycore_time.h"            // struct _time_runtime_state
+#include "pycore_tracemalloc.h"     // struct _tracemalloc_runtime_state
 #include "pycore_unicodeobject.h"   // struct _Py_unicode_runtime_ids
 
 struct _getargs_runtime_state {
@@ -137,11 +138,9 @@ typedef struct pyruntimestate {
     struct _ceval_runtime_state ceval;
     struct _gilstate_runtime_state gilstate;
     struct _getargs_runtime_state getargs;
-    struct {
-        struct _PyTraceMalloc_Config config;
-    } tracemalloc;
     struct _dtoa_runtime_state dtoa;
     struct _fileutils_state fileutils;
+    struct _tracemalloc_runtime_state tracemalloc;
 
     PyPreConfig preconfig;
 
diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h
index b569e5833f1d..029357dedf3e 100644
--- a/Include/internal/pycore_runtime_init.h
+++ b/Include/internal/pycore_runtime_init.h
@@ -50,13 +50,11 @@ extern "C" {
                in accordance with the specification. */ \
             .autoTSSkey = Py_tss_NEEDS_INIT, \
         }, \
-        .tracemalloc = { \
-            .config = _PyTraceMalloc_Config_INIT, \
-        }, \
         .dtoa = _dtoa_runtime_state_INIT(runtime), \
         .fileutils = { \
             .force_ascii = -1, \
         }, \
+        .tracemalloc = _tracemalloc_runtime_state_INIT, \
         .float_state = { \
             .float_format = _py_float_format_unknown, \
             .double_format = _py_float_format_unknown, \
diff --git a/Include/internal/pycore_tracemalloc.h b/Include/internal/pycore_tracemalloc.h
new file mode 100644
index 000000000000..08d7d1096c78
--- /dev/null
+++ b/Include/internal/pycore_tracemalloc.h
@@ -0,0 +1,121 @@
+#ifndef Py_INTERNAL_TRACEMALLOC_H
+#define Py_INTERNAL_TRACEMALLOC_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+#  error "this header requires Py_BUILD_CORE define"
+#endif
+
+#include "pycore_hashtable.h"     // _Py_hashtable_t
+
+
+/* Trace memory blocks allocated by PyMem_RawMalloc() */
+#define TRACE_RAW_MALLOC
+
+
+struct _PyTraceMalloc_Config {
+    /* Module initialized?
+       Variable protected by the GIL */
+    enum {
+        TRACEMALLOC_NOT_INITIALIZED,
+        TRACEMALLOC_INITIALIZED,
+        TRACEMALLOC_FINALIZED
+    } initialized;
+
+    /* Is tracemalloc tracing memory allocations?
+       Variable protected by the GIL */
+    int tracing;
+
+    /* limit of the number of frames in a traceback, 1 by default.
+       Variable protected by the GIL. */
+    int max_nframe;
+};
+
+
+/* Pack the frame_t structure to reduce the memory footprint on 64-bit
+   architectures: 12 bytes instead of 16. */
+struct
+#ifdef __GNUC__
+__attribute__((packed))
+#elif defined(_MSC_VER)
+#pragma pack(push, 4)
+#endif
+tracemalloc_frame {
+    /* filename cannot be NULL: "<unknown>" is used if the Python frame
+       filename is NULL */
+    PyObject *filename;
+    unsigned int lineno;
+};
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif
+
+struct tracemalloc_traceback {
+    Py_uhash_t hash;
+    /* Number of frames stored */
+    uint16_t nframe;
+    /* Total number of frames the traceback had */
+    uint16_t total_nframe;
+    struct tracemalloc_frame frames[1];
+};
+
+
+struct _tracemalloc_runtime_state {
+    struct _PyTraceMalloc_Config config;
+
+    /* Protected by the GIL */
+    struct {
+        PyMemAllocatorEx mem;
+        PyMemAllocatorEx raw;
+        PyMemAllocatorEx obj;
+    } allocators;
+
+#if defined(TRACE_RAW_MALLOC)
+    PyThread_type_lock tables_lock;
+#endif
+    /* Size in bytes of currently traced memory.
+       Protected by TABLES_LOCK(). */
+    size_t traced_memory;
+    /* Peak size in bytes of traced memory.
+       Protected by TABLES_LOCK(). */
+    size_t peak_traced_memory;
+    /* Hash table used as a set to intern filenames:
+       PyObject* => PyObject*.
+       Protected by the GIL */
+    _Py_hashtable_t *filenames;
+    /* Buffer to store a new traceback in traceback_new().
+       Protected by the GIL. */
+    struct tracemalloc_traceback *traceback;
+    /* Hash table used as a set to intern tracebacks:
+       traceback_t* => traceback_t*
+       Protected by the GIL */
+    _Py_hashtable_t *tracebacks;
+    /* pointer (void*) => trace (trace_t*).
+       Protected by TABLES_LOCK(). */
+    _Py_hashtable_t *traces;
+    /* domain (unsigned int) => traces (_Py_hashtable_t).
+       Protected by TABLES_LOCK(). */
+    _Py_hashtable_t *domains;
+
+    struct tracemalloc_traceback empty_traceback;
+
+    Py_tss_t reentrant_key;
+};
+
+#define _tracemalloc_runtime_state_INIT \
+    { \
+        .config = { \
+            .initialized = TRACEMALLOC_NOT_INITIALIZED, \
+            .tracing = 0, \
+            .max_nframe = 1, \
+        }, \
+        .reentrant_key = Py_tss_NEEDS_INIT, \
+    }
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif  // !Py_INTERNAL_TRACEMALLOC_H
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 815df69ad48c..9577f9dee6da 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1678,6 +1678,7 @@ PYTHON_HEADERS= \
 		$(srcdir)/Include/internal/pycore_time.h \
 		$(srcdir)/Include/internal/pycore_token.h \
 		$(srcdir)/Include/internal/pycore_traceback.h \
+		$(srcdir)/Include/internal/pycore_tracemalloc.h \
 		$(srcdir)/Include/internal/pycore_tuple.h \
 		$(srcdir)/Include/internal/pycore_typeobject.h \
 		$(srcdir)/Include/internal/pycore_ucnhash.h \
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index 0d70f0cf34c8..ac16626f2101 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -20,9 +20,6 @@ module _tracemalloc
 
 _Py_DECLARE_STR(anon_unknown, "<unknown>");
 
-/* Trace memory blocks allocated by PyMem_RawMalloc() */
-#define TRACE_RAW_MALLOC
-
 /* Forward declaration */
 static void tracemalloc_stop(void);
 static void* raw_malloc(size_t size);
@@ -35,19 +32,14 @@ static void raw_free(void *ptr);
 #define TO_PTR(key) ((const void *)(uintptr_t)(key))
 #define FROM_PTR(key) ((uintptr_t)(key))
 
-/* Protected by the GIL */
-static struct {
-    PyMemAllocatorEx mem;
-    PyMemAllocatorEx raw;
-    PyMemAllocatorEx obj;
-} allocators;
+#define allocators _PyRuntime.tracemalloc.allocators
 
 
 #if defined(TRACE_RAW_MALLOC)
 /* This lock is needed because tracemalloc_free() is called without
    the GIL held from PyMem_RawFree(). It cannot acquire the lock because it
    would introduce a deadlock in _PyThreadState_DeleteCurrent(). */
-static PyThread_type_lock tables_lock;
+#  define tables_lock _PyRuntime.tracemalloc.tables_lock
 #  define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1)
 #  define TABLES_UNLOCK() PyThread_release_lock(tables_lock)
 #else
@@ -59,33 +51,8 @@ static PyThread_type_lock tables_lock;
 
 #define DEFAULT_DOMAIN 0
 
-/* Pack the frame_t structure to reduce the memory footprint on 64-bit
-   architectures: 12 bytes instead of 16. */
-typedef struct
-#ifdef __GNUC__
-__attribute__((packed))
-#elif defined(_MSC_VER)
-#pragma pack(push, 4)
-#endif
-{
-    /* filename cannot be NULL: "<unknown>" is used if the Python frame
-       filename is NULL */
-    PyObject *filename;
-    unsigned int lineno;
-} frame_t;
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif
-
-
-typedef struct {
-    Py_uhash_t hash;
-    /* Number of frames stored */
-    uint16_t nframe;
-    /* Total number of frames the traceback had */
-    uint16_t total_nframe;
-    frame_t frames[1];
-} traceback_t;
+typedef struct tracemalloc_frame frame_t;
+typedef struct tracemalloc_traceback traceback_t;
 
 #define TRACEBACK_SIZE(NFRAME) \
         (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1))
@@ -96,7 +63,8 @@ typedef struct {
 static const unsigned long MAX_NFRAME = Py_MIN(UINT16_MAX, ((SIZE_MAX - sizeof(traceback_t)) / sizeof(frame_t) + 1));
 
 
-static traceback_t tracemalloc_empty_traceback;
+#define tracemalloc_empty_traceback _PyRuntime.tracemalloc.empty_traceback
+
 
 /* Trace of a memory block */
 typedef struct {
@@ -108,35 +76,13 @@ typedef struct {
 } trace_t;
 
 
-/* Size in bytes of currently traced memory.
-   Protected by TABLES_LOCK(). */
-static size_t tracemalloc_traced_memory = 0;
-
-/* Peak size in bytes of traced memory.
-   Protected by TABLES_LOCK(). */
-static size_t tracemalloc_peak_traced_memory = 0;
-
-/* Hash table used as a set to intern filenames:
-   PyObject* => PyObject*.
-   Protected by the GIL */
-static _Py_hashtable_t *tracemalloc_filenames = NULL;
-
-/* Buffer to store a new traceback in traceback_new().
-   Protected by the GIL. */
-static traceback_t *tracemalloc_traceback = NULL;
-
-/* Hash table used as a set to intern tracebacks:
-   traceback_t* => traceback_t*
-   Protected by the GIL */
-static _Py_hashtable_t *tracemalloc_tracebacks = NULL;
-
-/* pointer (void*) => trace (trace_t*).
-   Protected by TABLES_LOCK(). */
-static _Py_hashtable_t *tracemalloc_traces = NULL;
-
-/* domain (unsigned int) => traces (_Py_hashtable_t).
-   Protected by TABLES_LOCK(). */
-static _Py_hashtable_t *tracemalloc_domains = NULL;
+#define tracemalloc_traced_memory _PyRuntime.tracemalloc.traced_memory
+#define tracemalloc_peak_traced_memory _PyRuntime.tracemalloc.peak_traced_memory
+#define tracemalloc_filenames _PyRuntime.tracemalloc.filenames
+#define tracemalloc_traceback _PyRuntime.tracemalloc.traceback
+#define tracemalloc_tracebacks _PyRuntime.tracemalloc.tracebacks
+#define tracemalloc_traces _PyRuntime.tracemalloc.traces
+#define tracemalloc_domains _PyRuntime.tracemalloc.domains
 
 
 #ifdef TRACE_DEBUG
@@ -157,7 +103,7 @@ tracemalloc_error(const char *format, ...)
 #if defined(TRACE_RAW_MALLOC)
 #define REENTRANT_THREADLOCAL
 
-static Py_tss_t tracemalloc_reentrant_key = Py_tss_NEEDS_INIT;
+#define tracemalloc_reentrant_key _PyRuntime.tracemalloc.reentrant_key
 
 /* Any non-NULL pointer can be used */
 #define REENTRANT Py_True
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index 35fbff320f46..25572d6ebcd5 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -259,6 +259,7 @@
     <ClInclude Include="..\Include\internal\pycore_time.h" />
     <ClInclude Include="..\Include\internal\pycore_token.h" />
     <ClInclude Include="..\Include\internal\pycore_traceback.h" />
+    <ClInclude Include="..\Include\internal\pycore_tracemalloc.h" />
     <ClInclude Include="..\Include\internal\pycore_tuple.h" />
     <ClInclude Include="..\Include\internal\pycore_typeobject.h" />
     <ClInclude Include="..\Include\internal\pycore_ucnhash.h" />
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index 19cb5cf1c807..d45b50c5d62d 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -678,6 +678,9 @@
     <ClInclude Include="..\Include\internal\pycore_traceback.h">
       <Filter>Include\internal</Filter>
     </ClInclude>
+    <ClInclude Include="..\Include\internal\pycore_tracemalloc.h">
+      <Filter>Include\internal</Filter>
+    </ClInclude>
     <ClInclude Include="..\Include\internal\pycore_tuple.h">
       <Filter>Include\internal</Filter>
     </ClInclude>
diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv
index 94e9831db1fd..5dcd396c5487 100644
--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv
+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv
@@ -377,17 +377,6 @@ Modules/faulthandler.c	-	old_stack	-
 ##-----------------------
 ## state
 
-Modules/_tracemalloc.c	-	allocators	-
-Modules/_tracemalloc.c	-	tables_lock	-
-Modules/_tracemalloc.c	-	tracemalloc_empty_traceback	-
-Modules/_tracemalloc.c	-	tracemalloc_traced_memory	-
-Modules/_tracemalloc.c	-	tracemalloc_peak_traced_memory	-
-Modules/_tracemalloc.c	-	tracemalloc_filenames	-
-Modules/_tracemalloc.c	-	tracemalloc_traceback	-
-Modules/_tracemalloc.c	-	tracemalloc_tracebacks	-
-Modules/_tracemalloc.c	-	tracemalloc_traces	-
-Modules/_tracemalloc.c	-	tracemalloc_domains	-
-Modules/_tracemalloc.c	-	tracemalloc_reentrant_key	-
 Modules/faulthandler.c	faulthandler_dump_traceback	reentrant	-
 Modules/signalmodule.c	-	is_tripped	-
 Modules/signalmodule.c	-	signal_global_state	-



More information about the Python-checkins mailing list