Skip to content

Commit

Permalink
gh-81057: Move tracemalloc Globals to _PyRuntimeState (gh-100151)
Browse files Browse the repository at this point in the history
  • Loading branch information
ericsnowcurrently committed Dec 12, 2022
1 parent 1583c6e commit 8790d4d
Show file tree
Hide file tree
Showing 9 changed files with 143 additions and 107 deletions.
22 changes: 0 additions & 22 deletions Include/internal/pycore_pymem.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
5 changes: 2 additions & 3 deletions Include/internal/pycore_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down
4 changes: 1 addition & 3 deletions Include/internal/pycore_runtime_init.h
Original file line number Diff line number Diff line change
Expand Up @@ -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, \
Expand Down
121 changes: 121 additions & 0 deletions Include/internal/pycore_tracemalloc.h
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
82 changes: 14 additions & 68 deletions Modules/_tracemalloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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
Expand All @@ -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))
Expand All @@ -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 {
Expand All @@ -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
Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions PCbuild/pythoncore.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -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" />
Expand Down
3 changes: 3 additions & 0 deletions PCbuild/pythoncore.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
11 changes: 0 additions & 11 deletions Tools/c-analyzer/cpython/globals-to-fix.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -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 -
Expand Down

0 comments on commit 8790d4d

Please sign in to comment.