summaryrefslogtreecommitdiffstats
path: root/Include/internal/pycore_tracemalloc.h
blob: 7ddc5bac5d10af365f8acd55b710325b1a70daa7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#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. */
#if defined(_MSC_VER)
#pragma pack(push, 4)
#endif

struct
#ifdef __GNUC__
__attribute__((packed))
#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, \
    }


// Get the traceback where a memory block was allocated.
//
// Return a tuple of (filename: str, lineno: int) tuples.
//
// Return None if the tracemalloc module is disabled or if the memory block
// is not tracked by tracemalloc.
//
// Raise an exception and return NULL on error.
//
// Export for '_testinternalcapi' shared extension.
PyAPI_FUNC(PyObject*) _PyTraceMalloc_GetTraceback(
    unsigned int domain,
    uintptr_t ptr);

/* Return non-zero if tracemalloc is tracing */
extern int _PyTraceMalloc_IsTracing(void);

/* Clear the tracemalloc traces */
extern void _PyTraceMalloc_ClearTraces(void);

/* Clear the tracemalloc traces */
extern PyObject* _PyTraceMalloc_GetTraces(void);

/* Clear tracemalloc traceback for an object */
extern PyObject* _PyTraceMalloc_GetObjectTraceback(PyObject *obj);

/* Initialize tracemalloc */
extern int _PyTraceMalloc_Init(void);

/* Start tracemalloc */
extern int _PyTraceMalloc_Start(int max_nframe);

/* Stop tracemalloc */
extern void _PyTraceMalloc_Stop(void);

/* Get the tracemalloc traceback limit */
extern int _PyTraceMalloc_GetTracebackLimit(void);

/* Get the memory usage of tracemalloc in bytes */
extern size_t _PyTraceMalloc_GetMemory(void);

/* Get the current size and peak size of traced memory blocks as a 2-tuple */
extern PyObject* _PyTraceMalloc_GetTracedMemory(void);

/* Set the peak size of traced memory blocks to the current size */
extern void _PyTraceMalloc_ResetPeak(void);

#ifdef __cplusplus
}
#endif
#endif  // !Py_INTERNAL_TRACEMALLOC_H