blob: ba0eb738abcbc5de23616db22d18dd24373dd964 [file] [log] [blame]
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001#include "Python.h"
Victor Stinnere560f902020-04-14 18:30:41 +02002#include "pycore_gc.h" // PyGC_Head
3#include "pycore_pymem.h" // _Py_tracemalloc_config
Victor Stinnered488662019-05-20 00:14:57 +02004#include "pycore_traceback.h"
Victor Stinnerb6179932020-05-12 02:42:19 +02005#include "pycore_hashtable.h"
Victor Stinner70364772020-04-29 03:28:46 +02006#include "frameobject.h" // PyFrame_GetBack()
Victor Stinnered3b0bc2013-11-23 12:27:24 +01007
Serhiy Storchakab451f912017-02-04 12:18:38 +02008#include "clinic/_tracemalloc.c.h"
9/*[clinic input]
10module _tracemalloc
11[clinic start generated code]*/
12/*[clinic end generated code: output=da39a3ee5e6b4b0d input=708a98302fc46e5f]*/
13
Victor Stinnered3b0bc2013-11-23 12:27:24 +010014/* Trace memory blocks allocated by PyMem_RawMalloc() */
15#define TRACE_RAW_MALLOC
16
17/* Forward declaration */
18static void tracemalloc_stop(void);
Victor Stinnered3b0bc2013-11-23 12:27:24 +010019static void* raw_malloc(size_t size);
20static void raw_free(void *ptr);
21
22#ifdef Py_DEBUG
23# define TRACE_DEBUG
24#endif
25
Victor Stinner5b0a3032020-05-13 04:40:30 +020026#define TO_PTR(key) ((const void *)(uintptr_t)(key))
27#define FROM_PTR(key) ((uintptr_t)(key))
Victor Stinnerf9b3b582020-05-13 02:26:02 +020028
Victor Stinnered3b0bc2013-11-23 12:27:24 +010029/* Protected by the GIL */
30static struct {
Victor Stinnerd8f0d922014-06-02 21:57:10 +020031 PyMemAllocatorEx mem;
32 PyMemAllocatorEx raw;
33 PyMemAllocatorEx obj;
Victor Stinnered3b0bc2013-11-23 12:27:24 +010034} allocators;
35
Victor Stinnered3b0bc2013-11-23 12:27:24 +010036
Antoine Pitroua6a4dc82017-09-07 18:56:24 +020037#if defined(TRACE_RAW_MALLOC)
Victor Stinnered3b0bc2013-11-23 12:27:24 +010038/* This lock is needed because tracemalloc_free() is called without
39 the GIL held from PyMem_RawFree(). It cannot acquire the lock because it
Joannah Nanjekye2bc43cd2019-09-05 13:06:49 -030040 would introduce a deadlock in _PyThreadState_DeleteCurrent(). */
Victor Stinnered3b0bc2013-11-23 12:27:24 +010041static PyThread_type_lock tables_lock;
42# define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1)
43# define TABLES_UNLOCK() PyThread_release_lock(tables_lock)
44#else
45 /* variables are protected by the GIL */
46# define TABLES_LOCK()
47# define TABLES_UNLOCK()
48#endif
49
Victor Stinnere492ae52016-03-22 12:58:23 +010050
51#define DEFAULT_DOMAIN 0
52
Victor Stinnered3b0bc2013-11-23 12:27:24 +010053/* Pack the frame_t structure to reduce the memory footprint on 64-bit
Victor Stinnere492ae52016-03-22 12:58:23 +010054 architectures: 12 bytes instead of 16. */
Victor Stinnered3b0bc2013-11-23 12:27:24 +010055typedef struct
56#ifdef __GNUC__
57__attribute__((packed))
Victor Stinnerdd382ef2014-02-01 03:43:58 +010058#elif defined(_MSC_VER)
Segev Finer39243772017-07-25 11:47:43 +030059#pragma pack(push, 4)
Victor Stinnered3b0bc2013-11-23 12:27:24 +010060#endif
61{
Victor Stinner7105e9f2016-03-15 14:28:04 +010062 /* filename cannot be NULL: "<unknown>" is used if the Python frame
63 filename is NULL */
Victor Stinnered3b0bc2013-11-23 12:27:24 +010064 PyObject *filename;
Victor Stinner95283342016-03-15 21:57:02 +010065 unsigned int lineno;
Victor Stinnered3b0bc2013-11-23 12:27:24 +010066} frame_t;
Segev Finer39243772017-07-25 11:47:43 +030067#ifdef _MSC_VER
68#pragma pack(pop)
69#endif
Victor Stinnered3b0bc2013-11-23 12:27:24 +010070
Victor Stinnere492ae52016-03-22 12:58:23 +010071
Victor Stinnered3b0bc2013-11-23 12:27:24 +010072typedef struct {
73 Py_uhash_t hash;
Julien Danjou8d59eb12019-10-15 14:00:16 +020074 /* Number of frames stored */
75 uint16_t nframe;
76 /* Total number of frames the traceback had */
77 uint16_t total_nframe;
Victor Stinnered3b0bc2013-11-23 12:27:24 +010078 frame_t frames[1];
79} traceback_t;
80
81#define TRACEBACK_SIZE(NFRAME) \
82 (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1))
Victor Stinnerf28ce602013-11-27 22:27:13 +010083
Julien Danjou8d59eb12019-10-15 14:00:16 +020084/* The maximum number of frames is either:
85 - The maximum number of frames we can store in `traceback_t.nframe`
86 - The maximum memory size_t we can allocate */
87static const unsigned long MAX_NFRAME = Py_MIN(UINT16_MAX, ((SIZE_MAX - sizeof(traceback_t)) / sizeof(frame_t) + 1));
Victor Stinnered3b0bc2013-11-23 12:27:24 +010088
Victor Stinnere492ae52016-03-22 12:58:23 +010089
Victor Stinnered3b0bc2013-11-23 12:27:24 +010090static PyObject *unknown_filename = NULL;
91static traceback_t tracemalloc_empty_traceback;
92
Victor Stinner7a5be142013-11-26 01:06:02 +010093/* Trace of a memory block */
Victor Stinnered3b0bc2013-11-23 12:27:24 +010094typedef struct {
Victor Stinner7a5be142013-11-26 01:06:02 +010095 /* Size of the memory block in bytes */
Victor Stinnered3b0bc2013-11-23 12:27:24 +010096 size_t size;
Victor Stinner7a5be142013-11-26 01:06:02 +010097
98 /* Traceback where the memory block was allocated */
Victor Stinnered3b0bc2013-11-23 12:27:24 +010099 traceback_t *traceback;
100} trace_t;
101
Victor Stinnere492ae52016-03-22 12:58:23 +0100102
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100103/* Size in bytes of currently traced memory.
104 Protected by TABLES_LOCK(). */
105static size_t tracemalloc_traced_memory = 0;
106
Victor Stinner3c0481d2013-11-27 21:39:49 +0100107/* Peak size in bytes of traced memory.
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100108 Protected by TABLES_LOCK(). */
Victor Stinner3c0481d2013-11-27 21:39:49 +0100109static size_t tracemalloc_peak_traced_memory = 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100110
Serhiy Storchaka56a6d852014-12-01 18:28:43 +0200111/* Hash table used as a set to intern filenames:
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100112 PyObject* => PyObject*.
113 Protected by the GIL */
114static _Py_hashtable_t *tracemalloc_filenames = NULL;
115
Victor Stinnerf28ce602013-11-27 22:27:13 +0100116/* Buffer to store a new traceback in traceback_new().
117 Protected by the GIL. */
118static traceback_t *tracemalloc_traceback = NULL;
119
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100120/* Hash table used as a set to intern tracebacks:
121 traceback_t* => traceback_t*
122 Protected by the GIL */
123static _Py_hashtable_t *tracemalloc_tracebacks = NULL;
124
Victor Stinnerd95bd422020-05-13 03:52:11 +0200125/* pointer (void*) => trace (trace_t*).
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100126 Protected by TABLES_LOCK(). */
127static _Py_hashtable_t *tracemalloc_traces = NULL;
128
Victor Stinner9e2ca172020-05-13 01:36:47 +0200129/* domain (unsigned int) => traces (_Py_hashtable_t).
130 Protected by TABLES_LOCK(). */
131static _Py_hashtable_t *tracemalloc_domains = NULL;
132
Victor Stinnere492ae52016-03-22 12:58:23 +0100133
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100134#ifdef TRACE_DEBUG
135static void
136tracemalloc_error(const char *format, ...)
137{
138 va_list ap;
139 fprintf(stderr, "tracemalloc: ");
140 va_start(ap, format);
141 vfprintf(stderr, format, ap);
142 va_end(ap);
143 fprintf(stderr, "\n");
144 fflush(stderr);
145}
146#endif
147
Victor Stinnere492ae52016-03-22 12:58:23 +0100148
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200149#if defined(TRACE_RAW_MALLOC)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100150#define REENTRANT_THREADLOCAL
151
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900152static Py_tss_t tracemalloc_reentrant_key = Py_tss_NEEDS_INIT;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100153
154/* Any non-NULL pointer can be used */
155#define REENTRANT Py_True
156
157static int
158get_reentrant(void)
159{
Victor Stinner4a066472016-03-22 17:45:09 +0100160 void *ptr;
161
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900162 assert(PyThread_tss_is_created(&tracemalloc_reentrant_key));
163 ptr = PyThread_tss_get(&tracemalloc_reentrant_key);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100164 if (ptr != NULL) {
165 assert(ptr == REENTRANT);
166 return 1;
167 }
168 else
169 return 0;
170}
171
172static void
173set_reentrant(int reentrant)
174{
Victor Stinner2ead3d22013-11-26 01:08:53 +0100175 assert(reentrant == 0 || reentrant == 1);
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900176 assert(PyThread_tss_is_created(&tracemalloc_reentrant_key));
Victor Stinner4a066472016-03-22 17:45:09 +0100177
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100178 if (reentrant) {
Victor Stinner0cfc0582016-03-22 17:40:07 +0100179 assert(!get_reentrant());
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900180 PyThread_tss_set(&tracemalloc_reentrant_key, REENTRANT);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100181 }
182 else {
Victor Stinner0cfc0582016-03-22 17:40:07 +0100183 assert(get_reentrant());
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900184 PyThread_tss_set(&tracemalloc_reentrant_key, NULL);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100185 }
186}
187
188#else
189
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200190/* TRACE_RAW_MALLOC not defined: variable protected by the GIL */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100191static int tracemalloc_reentrant = 0;
192
193static int
194get_reentrant(void)
195{
196 return tracemalloc_reentrant;
197}
198
199static void
200set_reentrant(int reentrant)
201{
Victor Stinnerd5871e62016-03-23 00:17:04 +0100202 assert(reentrant != tracemalloc_reentrant);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100203 tracemalloc_reentrant = reentrant;
204}
205#endif
206
Victor Stinnere492ae52016-03-22 12:58:23 +0100207
Victor Stinner285cf0a2016-03-21 22:00:58 +0100208static Py_uhash_t
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200209hashtable_hash_pyobject(const void *key)
Victor Stinner51b846c2016-03-18 21:52:22 +0100210{
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200211 PyObject *obj = (PyObject *)key;
Victor Stinner285cf0a2016-03-21 22:00:58 +0100212 return PyObject_Hash(obj);
213}
214
Victor Stinnere492ae52016-03-22 12:58:23 +0100215
Victor Stinner285cf0a2016-03-21 22:00:58 +0100216static int
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200217hashtable_compare_unicode(const void *key1, const void *key2)
Victor Stinner285cf0a2016-03-21 22:00:58 +0100218{
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200219 PyObject *obj1 = (PyObject *)key1;
220 PyObject *obj2 = (PyObject *)key2;
221 if (obj1 != NULL && obj2 != NULL) {
222 return (PyUnicode_Compare(obj1, obj2) == 0);
223 }
224 else {
225 return obj1 == obj2;
226 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100227}
228
Victor Stinnere492ae52016-03-22 12:58:23 +0100229
230static Py_uhash_t
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200231hashtable_hash_uint(const void *key_raw)
Victor Stinnere492ae52016-03-22 12:58:23 +0100232{
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200233 unsigned int key = (unsigned int)FROM_PTR(key_raw);
Victor Stinner9e2ca172020-05-13 01:36:47 +0200234 return (Py_uhash_t)key;
Victor Stinnere492ae52016-03-22 12:58:23 +0100235}
236
237
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100238static _Py_hashtable_t *
Victor Stinner5b0a3032020-05-13 04:40:30 +0200239hashtable_new(_Py_hashtable_hash_func hash_func,
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200240 _Py_hashtable_compare_func compare_func,
Victor Stinner5b0a3032020-05-13 04:40:30 +0200241 _Py_hashtable_destroy_func key_destroy_func,
242 _Py_hashtable_destroy_func value_destroy_func)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100243{
Victor Stinnerc9553872016-03-22 12:13:01 +0100244 _Py_hashtable_allocator_t hashtable_alloc = {malloc, free};
Victor Stinner5b0a3032020-05-13 04:40:30 +0200245 return _Py_hashtable_new_full(hash_func, compare_func,
246 key_destroy_func, value_destroy_func,
247 &hashtable_alloc);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100248}
249
Victor Stinnere492ae52016-03-22 12:58:23 +0100250
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100251static void*
252raw_malloc(size_t size)
253{
254 return allocators.raw.malloc(allocators.raw.ctx, size);
255}
256
257static void
258raw_free(void *ptr)
259{
260 allocators.raw.free(allocators.raw.ctx, ptr);
261}
262
Victor Stinnere492ae52016-03-22 12:58:23 +0100263
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100264static Py_uhash_t
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200265hashtable_hash_traceback(const void *key)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100266{
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200267 const traceback_t *traceback = (const traceback_t *)key;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100268 return traceback->hash;
269}
270
Victor Stinnere492ae52016-03-22 12:58:23 +0100271
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100272static int
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200273hashtable_compare_traceback(const void *key1, const void *key2)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100274{
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200275 const traceback_t *traceback1 = (const traceback_t *)key1;
276 const traceback_t *traceback2 = (const traceback_t *)key2;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100277
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200278 if (traceback1->nframe != traceback2->nframe) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100279 return 0;
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200280 }
281 if (traceback1->total_nframe != traceback2->total_nframe) {
Julien Danjou8d59eb12019-10-15 14:00:16 +0200282 return 0;
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200283 }
Julien Danjou8d59eb12019-10-15 14:00:16 +0200284
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200285 for (int i=0; i < traceback1->nframe; i++) {
286 const frame_t *frame1 = &traceback1->frames[i];
287 const frame_t *frame2 = &traceback2->frames[i];
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100288
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200289 if (frame1->lineno != frame2->lineno) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100290 return 0;
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200291 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100292 if (frame1->filename != frame2->filename) {
293 assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0);
294 return 0;
295 }
296 }
297 return 1;
298}
299
Victor Stinnere492ae52016-03-22 12:58:23 +0100300
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100301static void
302tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
303{
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100304 frame->filename = unknown_filename;
Victor Stinner8852ad42020-04-29 01:28:13 +0200305 int lineno = PyFrame_GetLineNumber(pyframe);
306 if (lineno < 0) {
Victor Stinner95283342016-03-15 21:57:02 +0100307 lineno = 0;
Victor Stinner8852ad42020-04-29 01:28:13 +0200308 }
Victor Stinner95283342016-03-15 21:57:02 +0100309 frame->lineno = (unsigned int)lineno;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100310
Victor Stinner8852ad42020-04-29 01:28:13 +0200311 PyCodeObject *code = PyFrame_GetCode(pyframe);
312 PyObject *filename = code->co_filename;
313 Py_DECREF(code);
314
315 if (filename == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100316#ifdef TRACE_DEBUG
317 tracemalloc_error("failed to get the filename of the code object");
318#endif
319 return;
320 }
321
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100322 if (!PyUnicode_Check(filename)) {
323#ifdef TRACE_DEBUG
Martin Panter6245cb32016-04-15 02:14:19 +0000324 tracemalloc_error("filename is not a unicode string");
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100325#endif
326 return;
327 }
328 if (!PyUnicode_IS_READY(filename)) {
329 /* Don't make a Unicode string ready to avoid reentrant calls
330 to tracemalloc_malloc() or tracemalloc_realloc() */
331#ifdef TRACE_DEBUG
332 tracemalloc_error("filename is not a ready unicode string");
333#endif
334 return;
335 }
336
337 /* intern the filename */
Victor Stinner8852ad42020-04-29 01:28:13 +0200338 _Py_hashtable_entry_t *entry;
Victor Stinner5b0a3032020-05-13 04:40:30 +0200339 entry = _Py_hashtable_get_entry(tracemalloc_filenames, filename);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100340 if (entry != NULL) {
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200341 filename = (PyObject *)entry->key;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100342 }
343 else {
344 /* tracemalloc_filenames is responsible to keep a reference
345 to the filename */
346 Py_INCREF(filename);
Victor Stinner5b0a3032020-05-13 04:40:30 +0200347 if (_Py_hashtable_set(tracemalloc_filenames, filename, NULL) < 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100348 Py_DECREF(filename);
349#ifdef TRACE_DEBUG
350 tracemalloc_error("failed to intern the filename");
351#endif
352 return;
353 }
354 }
355
356 /* the tracemalloc_filenames table keeps a reference to the filename */
357 frame->filename = filename;
358}
359
Victor Stinnere492ae52016-03-22 12:58:23 +0100360
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100361static Py_uhash_t
362traceback_hash(traceback_t *traceback)
363{
364 /* code based on tuplehash() of Objects/tupleobject.c */
Victor Stinner4d8c29c2013-12-16 23:05:13 +0100365 Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100366 int len = traceback->nframe;
367 Py_uhash_t mult = _PyHASH_MULTIPLIER;
368 frame_t *frame;
369
370 x = 0x345678UL;
371 frame = traceback->frames;
372 while (--len >= 0) {
Victor Stinner4d8c29c2013-12-16 23:05:13 +0100373 y = (Py_uhash_t)PyObject_Hash(frame->filename);
374 y ^= (Py_uhash_t)frame->lineno;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100375 frame++;
376
377 x = (x ^ y) * mult;
378 /* the cast might truncate len; that doesn't change hash stability */
Victor Stinner4d8c29c2013-12-16 23:05:13 +0100379 mult += (Py_uhash_t)(82520UL + len + len);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100380 }
Julien Danjou8d59eb12019-10-15 14:00:16 +0200381 x ^= traceback->total_nframe;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100382 x += 97531UL;
383 return x;
384}
385
Victor Stinnere492ae52016-03-22 12:58:23 +0100386
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100387static void
388traceback_get_frames(traceback_t *traceback)
389{
Victor Stinner4386b902020-04-29 03:01:43 +0200390 PyThreadState *tstate = PyGILState_GetThisThreadState();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100391 if (tstate == NULL) {
392#ifdef TRACE_DEBUG
393 tracemalloc_error("failed to get the current thread state");
394#endif
395 return;
396 }
397
Victor Stinner4386b902020-04-29 03:01:43 +0200398 PyFrameObject *pyframe = PyThreadState_GetFrame(tstate);
Victor Stinner70364772020-04-29 03:28:46 +0200399 for (; pyframe != NULL;) {
Julien Danjou8d59eb12019-10-15 14:00:16 +0200400 if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
401 tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
402 assert(traceback->frames[traceback->nframe].filename != NULL);
403 traceback->nframe++;
404 }
Victor Stinner70364772020-04-29 03:28:46 +0200405 if (traceback->total_nframe < UINT16_MAX) {
Julien Danjou8d59eb12019-10-15 14:00:16 +0200406 traceback->total_nframe++;
Victor Stinner70364772020-04-29 03:28:46 +0200407 }
408
409 PyFrameObject *back = PyFrame_GetBack(pyframe);
410 Py_DECREF(pyframe);
411 pyframe = back;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100412 }
413}
414
Victor Stinnere492ae52016-03-22 12:58:23 +0100415
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100416static traceback_t *
417traceback_new(void)
418{
Victor Stinnerf28ce602013-11-27 22:27:13 +0100419 traceback_t *traceback;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100420 _Py_hashtable_entry_t *entry;
421
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100422 assert(PyGILState_Check());
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100423
424 /* get frames */
Victor Stinnerf28ce602013-11-27 22:27:13 +0100425 traceback = tracemalloc_traceback;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100426 traceback->nframe = 0;
Julien Danjou8d59eb12019-10-15 14:00:16 +0200427 traceback->total_nframe = 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100428 traceback_get_frames(traceback);
429 if (traceback->nframe == 0)
430 return &tracemalloc_empty_traceback;
431 traceback->hash = traceback_hash(traceback);
432
433 /* intern the traceback */
Victor Stinner5b0a3032020-05-13 04:40:30 +0200434 entry = _Py_hashtable_get_entry(tracemalloc_tracebacks, traceback);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100435 if (entry != NULL) {
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200436 traceback = (traceback_t *)entry->key;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100437 }
438 else {
439 traceback_t *copy;
440 size_t traceback_size;
441
442 traceback_size = TRACEBACK_SIZE(traceback->nframe);
443
444 copy = raw_malloc(traceback_size);
445 if (copy == NULL) {
446#ifdef TRACE_DEBUG
447 tracemalloc_error("failed to intern the traceback: malloc failed");
448#endif
449 return NULL;
450 }
451 memcpy(copy, traceback, traceback_size);
452
Victor Stinner5b0a3032020-05-13 04:40:30 +0200453 if (_Py_hashtable_set(tracemalloc_tracebacks, copy, NULL) < 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100454 raw_free(copy);
455#ifdef TRACE_DEBUG
456 tracemalloc_error("failed to intern the traceback: putdata failed");
457#endif
458 return NULL;
459 }
460 traceback = copy;
461 }
462 return traceback;
463}
464
Victor Stinnere492ae52016-03-22 12:58:23 +0100465
Victor Stinner9e2ca172020-05-13 01:36:47 +0200466static _Py_hashtable_t*
467tracemalloc_create_traces_table(void)
Victor Stinner5e14a382016-03-23 22:03:55 +0100468{
Victor Stinner5b0a3032020-05-13 04:40:30 +0200469 return hashtable_new(_Py_hashtable_hash_ptr,
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200470 _Py_hashtable_compare_direct,
Victor Stinner5b0a3032020-05-13 04:40:30 +0200471 NULL, raw_free);
Victor Stinner5e14a382016-03-23 22:03:55 +0100472}
473
474
Victor Stinner9e2ca172020-05-13 01:36:47 +0200475static _Py_hashtable_t*
476tracemalloc_create_domains_table(void)
Victor Stinner5e14a382016-03-23 22:03:55 +0100477{
Victor Stinner5b0a3032020-05-13 04:40:30 +0200478 return hashtable_new(hashtable_hash_uint,
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200479 _Py_hashtable_compare_direct,
Victor Stinner5b0a3032020-05-13 04:40:30 +0200480 NULL,
481 (_Py_hashtable_destroy_func)_Py_hashtable_destroy);
Victor Stinner9e2ca172020-05-13 01:36:47 +0200482}
483
484
485static _Py_hashtable_t*
486tracemalloc_get_traces_table(unsigned int domain)
487{
488 if (domain == DEFAULT_DOMAIN) {
489 return tracemalloc_traces;
490 }
491 else {
Victor Stinner5b0a3032020-05-13 04:40:30 +0200492 return _Py_hashtable_get(tracemalloc_domains, TO_PTR(domain));
Victor Stinner9e2ca172020-05-13 01:36:47 +0200493 }
494}
495
496
497static void
Victor Stinner5ea4c062017-06-20 17:46:36 +0200498tracemalloc_remove_trace(unsigned int domain, uintptr_t ptr)
Victor Stinnere492ae52016-03-22 12:58:23 +0100499{
Victor Stinner9e00e802018-10-25 13:31:16 +0200500 assert(_Py_tracemalloc_config.tracing);
Victor Stinner10b73e12016-03-22 13:39:05 +0100501
Victor Stinner9e2ca172020-05-13 01:36:47 +0200502 _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
503 if (!traces) {
Victor Stinnere492ae52016-03-22 12:58:23 +0100504 return;
505 }
506
Victor Stinner5b0a3032020-05-13 04:40:30 +0200507 trace_t *trace = _Py_hashtable_steal(traces, TO_PTR(ptr));
508 if (!trace) {
Victor Stinner9e2ca172020-05-13 01:36:47 +0200509 return;
510 }
Victor Stinnerd95bd422020-05-13 03:52:11 +0200511 assert(tracemalloc_traced_memory >= trace->size);
512 tracemalloc_traced_memory -= trace->size;
513 raw_free(trace);
Victor Stinnere492ae52016-03-22 12:58:23 +0100514}
515
516#define REMOVE_TRACE(ptr) \
Benjamin Petersonca470632016-09-06 13:47:26 -0700517 tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr))
Victor Stinnere492ae52016-03-22 12:58:23 +0100518
519
Victor Stinner52968672013-11-24 11:37:15 +0100520static int
Victor Stinner5ea4c062017-06-20 17:46:36 +0200521tracemalloc_add_trace(unsigned int domain, uintptr_t ptr,
Victor Stinner10b73e12016-03-22 13:39:05 +0100522 size_t size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100523{
Victor Stinner9e00e802018-10-25 13:31:16 +0200524 assert(_Py_tracemalloc_config.tracing);
Victor Stinner10b73e12016-03-22 13:39:05 +0100525
Victor Stinner9e2ca172020-05-13 01:36:47 +0200526 traceback_t *traceback = traceback_new();
Victor Stinnere492ae52016-03-22 12:58:23 +0100527 if (traceback == NULL) {
Victor Stinner52968672013-11-24 11:37:15 +0100528 return -1;
Victor Stinnere492ae52016-03-22 12:58:23 +0100529 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100530
Victor Stinner9e2ca172020-05-13 01:36:47 +0200531 _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
532 if (traces == NULL) {
533 traces = tracemalloc_create_traces_table();
534 if (traces == NULL) {
535 return -1;
536 }
537
Victor Stinner5b0a3032020-05-13 04:40:30 +0200538 if (_Py_hashtable_set(tracemalloc_domains, TO_PTR(domain), traces) < 0) {
Victor Stinner9e2ca172020-05-13 01:36:47 +0200539 _Py_hashtable_destroy(traces);
Victor Stinner5e14a382016-03-23 22:03:55 +0100540 return -1;
541 }
542 }
543
Victor Stinner5b0a3032020-05-13 04:40:30 +0200544 trace_t *trace = _Py_hashtable_get(traces, TO_PTR(ptr));
545 if (trace != NULL) {
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100546 /* the memory block is already tracked */
Victor Stinnerd95bd422020-05-13 03:52:11 +0200547 assert(tracemalloc_traced_memory >= trace->size);
548 tracemalloc_traced_memory -= trace->size;
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100549
Victor Stinnerd95bd422020-05-13 03:52:11 +0200550 trace->size = size;
551 trace->traceback = traceback;
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100552 }
553 else {
Victor Stinner5b0a3032020-05-13 04:40:30 +0200554 trace = raw_malloc(sizeof(trace_t));
Victor Stinnerd95bd422020-05-13 03:52:11 +0200555 if (trace == NULL) {
556 return -1;
557 }
558 trace->size = size;
559 trace->traceback = traceback;
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100560
Victor Stinner5b0a3032020-05-13 04:40:30 +0200561 int res = _Py_hashtable_set(traces, TO_PTR(ptr), trace);
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100562 if (res != 0) {
Victor Stinnerd95bd422020-05-13 03:52:11 +0200563 raw_free(trace);
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100564 return res;
565 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100566 }
Victor Stinnere492ae52016-03-22 12:58:23 +0100567
Benjamin Peterson2f8bfef2016-09-07 09:26:18 -0700568 assert(tracemalloc_traced_memory <= SIZE_MAX - size);
Victor Stinnere492ae52016-03-22 12:58:23 +0100569 tracemalloc_traced_memory += size;
Victor Stinner9e2ca172020-05-13 01:36:47 +0200570 if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory) {
Victor Stinnere492ae52016-03-22 12:58:23 +0100571 tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
Victor Stinner9e2ca172020-05-13 01:36:47 +0200572 }
Victor Stinnere492ae52016-03-22 12:58:23 +0100573 return 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100574}
575
Victor Stinnere492ae52016-03-22 12:58:23 +0100576#define ADD_TRACE(ptr, size) \
Benjamin Petersonca470632016-09-06 13:47:26 -0700577 tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size)
Victor Stinnere492ae52016-03-22 12:58:23 +0100578
579
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100580static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200581tracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100582{
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200583 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100584 void *ptr;
585
Benjamin Peterson2f8bfef2016-09-07 09:26:18 -0700586 assert(elsize == 0 || nelem <= SIZE_MAX / elsize);
Victor Stinnerdb067af2014-05-02 22:31:14 +0200587
588 if (use_calloc)
589 ptr = alloc->calloc(alloc->ctx, nelem, elsize);
590 else
591 ptr = alloc->malloc(alloc->ctx, nelem * elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100592 if (ptr == NULL)
593 return NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100594
Victor Stinner88c29872013-12-04 01:47:46 +0100595 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100596 if (ADD_TRACE(ptr, nelem * elsize) < 0) {
Victor Stinner15116802013-12-04 01:29:35 +0100597 /* Failed to allocate a trace for the new memory block */
Victor Stinner88c29872013-12-04 01:47:46 +0100598 TABLES_UNLOCK();
Victor Stinner15116802013-12-04 01:29:35 +0100599 alloc->free(alloc->ctx, ptr);
600 return NULL;
Victor Stinner52968672013-11-24 11:37:15 +0100601 }
Victor Stinner88c29872013-12-04 01:47:46 +0100602 TABLES_UNLOCK();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100603 return ptr;
604}
605
Victor Stinnere492ae52016-03-22 12:58:23 +0100606
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100607static void*
Victor Stinner15116802013-12-04 01:29:35 +0100608tracemalloc_realloc(void *ctx, void *ptr, size_t new_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100609{
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200610 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100611 void *ptr2;
612
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100613 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
Victor Stinner15116802013-12-04 01:29:35 +0100614 if (ptr2 == NULL)
615 return NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100616
Victor Stinner15116802013-12-04 01:29:35 +0100617 if (ptr != NULL) {
618 /* an existing memory block has been resized */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100619
Victor Stinner88c29872013-12-04 01:47:46 +0100620 TABLES_LOCK();
Victor Stinner42bcf372016-03-23 09:08:08 +0100621
622 /* tracemalloc_add_trace() updates the trace if there is already
Victor Stinner9e2ca172020-05-13 01:36:47 +0200623 a trace at address ptr2 */
Victor Stinner42bcf372016-03-23 09:08:08 +0100624 if (ptr2 != ptr) {
625 REMOVE_TRACE(ptr);
626 }
Victor Stinner08facd22013-11-24 12:27:59 +0100627
Victor Stinnere492ae52016-03-22 12:58:23 +0100628 if (ADD_TRACE(ptr2, new_size) < 0) {
Victor Stinner15116802013-12-04 01:29:35 +0100629 /* Memory allocation failed. The error cannot be reported to
Raymond Hettinger15f44ab2016-08-30 10:47:49 -0700630 the caller, because realloc() may already have shrunk the
Victor Stinner15116802013-12-04 01:29:35 +0100631 memory block and so removed bytes.
632
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300633 This case is very unlikely: a hash entry has just been
Victor Stinner88c29872013-12-04 01:47:46 +0100634 released, so the hash table should have at least one free entry.
635
636 The GIL and the table lock ensures that only one thread is
637 allocating memory. */
Serhiy Storchakaeebaa9b2020-03-09 20:49:52 +0200638 Py_FatalError("tracemalloc_realloc() failed to allocate a trace");
Victor Stinner52968672013-11-24 11:37:15 +0100639 }
Victor Stinner88c29872013-12-04 01:47:46 +0100640 TABLES_UNLOCK();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100641 }
Victor Stinner15116802013-12-04 01:29:35 +0100642 else {
643 /* new allocation */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100644
Victor Stinner88c29872013-12-04 01:47:46 +0100645 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100646 if (ADD_TRACE(ptr2, new_size) < 0) {
Victor Stinner15116802013-12-04 01:29:35 +0100647 /* Failed to allocate a trace for the new memory block */
Victor Stinner88c29872013-12-04 01:47:46 +0100648 TABLES_UNLOCK();
Victor Stinner15116802013-12-04 01:29:35 +0100649 alloc->free(alloc->ctx, ptr2);
650 return NULL;
651 }
Victor Stinner88c29872013-12-04 01:47:46 +0100652 TABLES_UNLOCK();
Victor Stinner15116802013-12-04 01:29:35 +0100653 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100654 return ptr2;
655}
656
Victor Stinnere492ae52016-03-22 12:58:23 +0100657
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100658static void
659tracemalloc_free(void *ctx, void *ptr)
660{
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200661 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100662
663 if (ptr == NULL)
664 return;
665
666 /* GIL cannot be locked in PyMem_RawFree() because it would introduce
Joannah Nanjekye2bc43cd2019-09-05 13:06:49 -0300667 a deadlock in _PyThreadState_DeleteCurrent(). */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100668
669 alloc->free(alloc->ctx, ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100670
671 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100672 REMOVE_TRACE(ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100673 TABLES_UNLOCK();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100674}
675
Victor Stinnere492ae52016-03-22 12:58:23 +0100676
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100677static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200678tracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100679{
Victor Stinner15116802013-12-04 01:29:35 +0100680 void *ptr;
681
682 if (get_reentrant()) {
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200683 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnerdb067af2014-05-02 22:31:14 +0200684 if (use_calloc)
685 return alloc->calloc(alloc->ctx, nelem, elsize);
686 else
687 return alloc->malloc(alloc->ctx, nelem * elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100688 }
689
690 /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for
691 allocations larger than 512 bytes, don't trace the same memory
692 allocation twice. */
693 set_reentrant(1);
694
Victor Stinnerdb067af2014-05-02 22:31:14 +0200695 ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100696
697 set_reentrant(0);
698 return ptr;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100699}
700
Victor Stinnere492ae52016-03-22 12:58:23 +0100701
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100702static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200703tracemalloc_malloc_gil(void *ctx, size_t size)
704{
705 return tracemalloc_alloc_gil(0, ctx, 1, size);
706}
707
Victor Stinnere492ae52016-03-22 12:58:23 +0100708
Victor Stinnerdb067af2014-05-02 22:31:14 +0200709static void*
710tracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize)
711{
712 return tracemalloc_alloc_gil(1, ctx, nelem, elsize);
713}
714
Victor Stinnere492ae52016-03-22 12:58:23 +0100715
Victor Stinnerdb067af2014-05-02 22:31:14 +0200716static void*
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100717tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
718{
Victor Stinner15116802013-12-04 01:29:35 +0100719 void *ptr2;
720
721 if (get_reentrant()) {
722 /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc().
723 Example: PyMem_RawRealloc() is called internally by pymalloc
724 (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new
725 arena (new_arena()). */
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200726 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinner15116802013-12-04 01:29:35 +0100727
728 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
Victor Stinner88c29872013-12-04 01:47:46 +0100729 if (ptr2 != NULL && ptr != NULL) {
730 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100731 REMOVE_TRACE(ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100732 TABLES_UNLOCK();
733 }
Victor Stinner15116802013-12-04 01:29:35 +0100734 return ptr2;
735 }
736
737 /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for
738 allocations larger than 512 bytes. Don't trace the same memory
739 allocation twice. */
740 set_reentrant(1);
741
742 ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
743
744 set_reentrant(0);
745 return ptr2;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100746}
747
Victor Stinnere492ae52016-03-22 12:58:23 +0100748
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100749#ifdef TRACE_RAW_MALLOC
750static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200751tracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100752{
Victor Stinner15116802013-12-04 01:29:35 +0100753 PyGILState_STATE gil_state;
Victor Stinner15116802013-12-04 01:29:35 +0100754 void *ptr;
755
756 if (get_reentrant()) {
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200757 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnerdb067af2014-05-02 22:31:14 +0200758 if (use_calloc)
759 return alloc->calloc(alloc->ctx, nelem, elsize);
760 else
761 return alloc->malloc(alloc->ctx, nelem * elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100762 }
763
764 /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
765 indirectly which would call PyGILState_Ensure() if reentrant are not
766 disabled. */
767 set_reentrant(1);
768
Victor Stinner15116802013-12-04 01:29:35 +0100769 gil_state = PyGILState_Ensure();
Victor Stinnerdb067af2014-05-02 22:31:14 +0200770 ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100771 PyGILState_Release(gil_state);
Victor Stinner15116802013-12-04 01:29:35 +0100772
773 set_reentrant(0);
774 return ptr;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100775}
776
Victor Stinnere492ae52016-03-22 12:58:23 +0100777
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100778static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200779tracemalloc_raw_malloc(void *ctx, size_t size)
780{
781 return tracemalloc_raw_alloc(0, ctx, 1, size);
782}
783
Victor Stinnere492ae52016-03-22 12:58:23 +0100784
Victor Stinnerdb067af2014-05-02 22:31:14 +0200785static void*
786tracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize)
787{
788 return tracemalloc_raw_alloc(1, ctx, nelem, elsize);
789}
790
Victor Stinnere492ae52016-03-22 12:58:23 +0100791
Victor Stinnerdb067af2014-05-02 22:31:14 +0200792static void*
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100793tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
794{
Victor Stinner15116802013-12-04 01:29:35 +0100795 PyGILState_STATE gil_state;
Victor Stinner15116802013-12-04 01:29:35 +0100796 void *ptr2;
797
798 if (get_reentrant()) {
799 /* Reentrant call to PyMem_RawRealloc(). */
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200800 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinner15116802013-12-04 01:29:35 +0100801
802 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
Victor Stinner15116802013-12-04 01:29:35 +0100803
Victor Stinner88c29872013-12-04 01:47:46 +0100804 if (ptr2 != NULL && ptr != NULL) {
805 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100806 REMOVE_TRACE(ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100807 TABLES_UNLOCK();
808 }
Victor Stinner15116802013-12-04 01:29:35 +0100809 return ptr2;
810 }
811
812 /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
813 indirectly which would call PyGILState_Ensure() if reentrant calls are
814 not disabled. */
815 set_reentrant(1);
816
Victor Stinner15116802013-12-04 01:29:35 +0100817 gil_state = PyGILState_Ensure();
818 ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
819 PyGILState_Release(gil_state);
Victor Stinner15116802013-12-04 01:29:35 +0100820
821 set_reentrant(0);
822 return ptr2;
823}
824#endif /* TRACE_RAW_MALLOC */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100825
Victor Stinnere492ae52016-03-22 12:58:23 +0100826
Victor Stinner5b0a3032020-05-13 04:40:30 +0200827static void
828tracemalloc_clear_filename(void *value)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100829{
Victor Stinner5b0a3032020-05-13 04:40:30 +0200830 PyObject *filename = (PyObject *)value;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100831 Py_DECREF(filename);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100832}
833
Victor Stinnere492ae52016-03-22 12:58:23 +0100834
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100835/* reentrant flag must be set to call this function and GIL must be held */
836static void
837tracemalloc_clear_traces(void)
838{
Miss Islington (bot)5afc5bb2021-10-07 01:55:18 -0700839 /* The GIL protects variables against concurrent access */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100840 assert(PyGILState_Check());
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100841
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100842 TABLES_LOCK();
843 _Py_hashtable_clear(tracemalloc_traces);
Victor Stinner9e2ca172020-05-13 01:36:47 +0200844 _Py_hashtable_clear(tracemalloc_domains);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100845 tracemalloc_traced_memory = 0;
Victor Stinner3c0481d2013-11-27 21:39:49 +0100846 tracemalloc_peak_traced_memory = 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100847 TABLES_UNLOCK();
848
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100849 _Py_hashtable_clear(tracemalloc_tracebacks);
850
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100851 _Py_hashtable_clear(tracemalloc_filenames);
852}
853
Victor Stinnere492ae52016-03-22 12:58:23 +0100854
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100855static int
856tracemalloc_init(void)
857{
Victor Stinner9e00e802018-10-25 13:31:16 +0200858 if (_Py_tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100859 PyErr_SetString(PyExc_RuntimeError,
860 "the tracemalloc module has been unloaded");
861 return -1;
862 }
863
Victor Stinner9e00e802018-10-25 13:31:16 +0200864 if (_Py_tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100865 return 0;
866
867 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
868
869#ifdef REENTRANT_THREADLOCAL
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900870 if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100871#ifdef MS_WINDOWS
872 PyErr_SetFromWindowsErr(0);
873#else
874 PyErr_SetFromErrno(PyExc_OSError);
875#endif
876 return -1;
877 }
878#endif
879
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200880#if defined(TRACE_RAW_MALLOC)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100881 if (tables_lock == NULL) {
882 tables_lock = PyThread_allocate_lock();
883 if (tables_lock == NULL) {
884 PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock");
885 return -1;
886 }
887 }
888#endif
889
Victor Stinner5b0a3032020-05-13 04:40:30 +0200890 tracemalloc_filenames = hashtable_new(hashtable_hash_pyobject,
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200891 hashtable_compare_unicode,
Victor Stinner5b0a3032020-05-13 04:40:30 +0200892 tracemalloc_clear_filename, NULL);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100893
Victor Stinner5b0a3032020-05-13 04:40:30 +0200894 tracemalloc_tracebacks = hashtable_new(hashtable_hash_traceback,
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200895 hashtable_compare_traceback,
Victor Stinner5b0a3032020-05-13 04:40:30 +0200896 NULL, raw_free);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100897
Victor Stinner9e2ca172020-05-13 01:36:47 +0200898 tracemalloc_traces = tracemalloc_create_traces_table();
899 tracemalloc_domains = tracemalloc_create_domains_table();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100900
901 if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL
Victor Stinner9e2ca172020-05-13 01:36:47 +0200902 || tracemalloc_traces == NULL || tracemalloc_domains == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100903 PyErr_NoMemory();
904 return -1;
905 }
906
907 unknown_filename = PyUnicode_FromString("<unknown>");
908 if (unknown_filename == NULL)
909 return -1;
910 PyUnicode_InternInPlace(&unknown_filename);
911
912 tracemalloc_empty_traceback.nframe = 1;
Julien Danjou8d59eb12019-10-15 14:00:16 +0200913 tracemalloc_empty_traceback.total_nframe = 1;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100914 /* borrowed reference */
915 tracemalloc_empty_traceback.frames[0].filename = unknown_filename;
916 tracemalloc_empty_traceback.frames[0].lineno = 0;
917 tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback);
918
Victor Stinner9e00e802018-10-25 13:31:16 +0200919 _Py_tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100920 return 0;
921}
922
Victor Stinnere492ae52016-03-22 12:58:23 +0100923
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100924static void
925tracemalloc_deinit(void)
926{
Victor Stinner9e00e802018-10-25 13:31:16 +0200927 if (_Py_tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100928 return;
Victor Stinner9e00e802018-10-25 13:31:16 +0200929 _Py_tracemalloc_config.initialized = TRACEMALLOC_FINALIZED;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100930
931 tracemalloc_stop();
932
933 /* destroy hash tables */
Victor Stinner5b0a3032020-05-13 04:40:30 +0200934 _Py_hashtable_destroy(tracemalloc_domains);
Victor Stinner9e2ca172020-05-13 01:36:47 +0200935 _Py_hashtable_destroy(tracemalloc_traces);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100936 _Py_hashtable_destroy(tracemalloc_tracebacks);
937 _Py_hashtable_destroy(tracemalloc_filenames);
938
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200939#if defined(TRACE_RAW_MALLOC)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100940 if (tables_lock != NULL) {
941 PyThread_free_lock(tables_lock);
942 tables_lock = NULL;
943 }
944#endif
945
946#ifdef REENTRANT_THREADLOCAL
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900947 PyThread_tss_delete(&tracemalloc_reentrant_key);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100948#endif
949
950 Py_XDECREF(unknown_filename);
951}
952
Victor Stinnere492ae52016-03-22 12:58:23 +0100953
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100954static int
Victor Stinnerf28ce602013-11-27 22:27:13 +0100955tracemalloc_start(int max_nframe)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100956{
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200957 PyMemAllocatorEx alloc;
Victor Stinnerf28ce602013-11-27 22:27:13 +0100958 size_t size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100959
Julien Danjou8d59eb12019-10-15 14:00:16 +0200960 if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) {
Victor Stinnera7368ac2017-11-15 18:11:45 -0800961 PyErr_Format(PyExc_ValueError,
Julien Danjou8d59eb12019-10-15 14:00:16 +0200962 "the number of frames must be in range [1; %lu]",
963 MAX_NFRAME);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100964 return -1;
Victor Stinnera7368ac2017-11-15 18:11:45 -0800965 }
966
967 if (tracemalloc_init() < 0) {
968 return -1;
969 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100970
Victor Stinner9e00e802018-10-25 13:31:16 +0200971 if (_Py_tracemalloc_config.tracing) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100972 /* hook already installed: do nothing */
973 return 0;
974 }
975
Victor Stinner9e00e802018-10-25 13:31:16 +0200976 _Py_tracemalloc_config.max_nframe = max_nframe;
Victor Stinnerf28ce602013-11-27 22:27:13 +0100977
978 /* allocate a buffer to store a new traceback */
979 size = TRACEBACK_SIZE(max_nframe);
980 assert(tracemalloc_traceback == NULL);
981 tracemalloc_traceback = raw_malloc(size);
982 if (tracemalloc_traceback == NULL) {
983 PyErr_NoMemory();
984 return -1;
985 }
986
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100987#ifdef TRACE_RAW_MALLOC
988 alloc.malloc = tracemalloc_raw_malloc;
Victor Stinnerdb067af2014-05-02 22:31:14 +0200989 alloc.calloc = tracemalloc_raw_calloc;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100990 alloc.realloc = tracemalloc_raw_realloc;
991 alloc.free = tracemalloc_free;
992
993 alloc.ctx = &allocators.raw;
994 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
995 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
996#endif
997
998 alloc.malloc = tracemalloc_malloc_gil;
Victor Stinnerdb067af2014-05-02 22:31:14 +0200999 alloc.calloc = tracemalloc_calloc_gil;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001000 alloc.realloc = tracemalloc_realloc_gil;
1001 alloc.free = tracemalloc_free;
1002
1003 alloc.ctx = &allocators.mem;
1004 PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
1005 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
1006
1007 alloc.ctx = &allocators.obj;
1008 PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
1009 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc);
1010
1011 /* everything is ready: start tracing Python memory allocations */
Victor Stinner9e00e802018-10-25 13:31:16 +02001012 _Py_tracemalloc_config.tracing = 1;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001013
1014 return 0;
1015}
1016
Victor Stinnere492ae52016-03-22 12:58:23 +01001017
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001018static void
1019tracemalloc_stop(void)
1020{
Victor Stinner9e00e802018-10-25 13:31:16 +02001021 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001022 return;
1023
1024 /* stop tracing Python memory allocations */
Victor Stinner9e00e802018-10-25 13:31:16 +02001025 _Py_tracemalloc_config.tracing = 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001026
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001027 /* unregister the hook on memory allocators */
1028#ifdef TRACE_RAW_MALLOC
1029 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
1030#endif
1031 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
1032 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
1033
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001034 tracemalloc_clear_traces();
Victor Stinner285cf0a2016-03-21 22:00:58 +01001035
1036 /* release memory */
Victor Stinnerf28ce602013-11-27 22:27:13 +01001037 raw_free(tracemalloc_traceback);
1038 tracemalloc_traceback = NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001039}
1040
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001041
Victor Stinnere492ae52016-03-22 12:58:23 +01001042
Serhiy Storchakab451f912017-02-04 12:18:38 +02001043/*[clinic input]
1044_tracemalloc.is_tracing
1045
1046Return True if the tracemalloc module is tracing Python memory allocations.
1047[clinic start generated code]*/
1048
1049static PyObject *
1050_tracemalloc_is_tracing_impl(PyObject *module)
Serhiy Storchaka97353842017-02-05 22:58:46 +02001051/*[clinic end generated code: output=2d763b42601cd3ef input=af104b0a00192f63]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001052{
Victor Stinner9e00e802018-10-25 13:31:16 +02001053 return PyBool_FromLong(_Py_tracemalloc_config.tracing);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001054}
1055
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001056
Serhiy Storchakab451f912017-02-04 12:18:38 +02001057/*[clinic input]
1058_tracemalloc.clear_traces
Victor Stinnere492ae52016-03-22 12:58:23 +01001059
Serhiy Storchakab451f912017-02-04 12:18:38 +02001060Clear traces of memory blocks allocated by Python.
1061[clinic start generated code]*/
1062
1063static PyObject *
1064_tracemalloc_clear_traces_impl(PyObject *module)
1065/*[clinic end generated code: output=a86080ee41b84197 input=0dab5b6c785183a5]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001066{
Victor Stinner9e00e802018-10-25 13:31:16 +02001067 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001068 Py_RETURN_NONE;
1069
1070 set_reentrant(1);
1071 tracemalloc_clear_traces();
1072 set_reentrant(0);
1073
1074 Py_RETURN_NONE;
1075}
1076
Victor Stinnere492ae52016-03-22 12:58:23 +01001077
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001078static PyObject*
1079frame_to_pyobject(frame_t *frame)
1080{
1081 PyObject *frame_obj, *lineno_obj;
1082
1083 frame_obj = PyTuple_New(2);
1084 if (frame_obj == NULL)
1085 return NULL;
1086
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001087 Py_INCREF(frame->filename);
1088 PyTuple_SET_ITEM(frame_obj, 0, frame->filename);
1089
Victor Stinner95283342016-03-15 21:57:02 +01001090 lineno_obj = PyLong_FromUnsignedLong(frame->lineno);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001091 if (lineno_obj == NULL) {
1092 Py_DECREF(frame_obj);
1093 return NULL;
1094 }
1095 PyTuple_SET_ITEM(frame_obj, 1, lineno_obj);
1096
1097 return frame_obj;
1098}
1099
Victor Stinnere492ae52016-03-22 12:58:23 +01001100
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001101static PyObject*
1102traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table)
1103{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001104 PyObject *frames;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001105
1106 if (intern_table != NULL) {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001107 frames = _Py_hashtable_get(intern_table, (const void *)traceback);
1108 if (frames) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001109 Py_INCREF(frames);
1110 return frames;
1111 }
1112 }
1113
1114 frames = PyTuple_New(traceback->nframe);
1115 if (frames == NULL)
1116 return NULL;
1117
Victor Stinner5b0a3032020-05-13 04:40:30 +02001118 for (int i=0; i < traceback->nframe; i++) {
1119 PyObject *frame = frame_to_pyobject(&traceback->frames[i]);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001120 if (frame == NULL) {
1121 Py_DECREF(frames);
1122 return NULL;
1123 }
1124 PyTuple_SET_ITEM(frames, i, frame);
1125 }
1126
1127 if (intern_table != NULL) {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001128 if (_Py_hashtable_set(intern_table, traceback, frames) < 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001129 Py_DECREF(frames);
1130 PyErr_NoMemory();
1131 return NULL;
1132 }
1133 /* intern_table keeps a new reference to frames */
1134 Py_INCREF(frames);
1135 }
1136 return frames;
1137}
1138
Victor Stinnere492ae52016-03-22 12:58:23 +01001139
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001140static PyObject*
Victor Stinner5b0a3032020-05-13 04:40:30 +02001141trace_to_pyobject(unsigned int domain, const trace_t *trace,
Victor Stinnere492ae52016-03-22 12:58:23 +01001142 _Py_hashtable_t *intern_tracebacks)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001143{
1144 PyObject *trace_obj = NULL;
Victor Stinnere492ae52016-03-22 12:58:23 +01001145 PyObject *obj;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001146
Julien Danjou8d59eb12019-10-15 14:00:16 +02001147 trace_obj = PyTuple_New(4);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001148 if (trace_obj == NULL)
1149 return NULL;
1150
Victor Stinnere492ae52016-03-22 12:58:23 +01001151 obj = PyLong_FromSize_t(domain);
1152 if (obj == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001153 Py_DECREF(trace_obj);
1154 return NULL;
1155 }
Victor Stinnere492ae52016-03-22 12:58:23 +01001156 PyTuple_SET_ITEM(trace_obj, 0, obj);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001157
Victor Stinnere492ae52016-03-22 12:58:23 +01001158 obj = PyLong_FromSize_t(trace->size);
1159 if (obj == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001160 Py_DECREF(trace_obj);
1161 return NULL;
1162 }
Victor Stinnere492ae52016-03-22 12:58:23 +01001163 PyTuple_SET_ITEM(trace_obj, 1, obj);
1164
1165 obj = traceback_to_pyobject(trace->traceback, intern_tracebacks);
1166 if (obj == NULL) {
1167 Py_DECREF(trace_obj);
1168 return NULL;
1169 }
1170 PyTuple_SET_ITEM(trace_obj, 2, obj);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001171
Julien Danjou8d59eb12019-10-15 14:00:16 +02001172 obj = PyLong_FromUnsignedLong(trace->traceback->total_nframe);
1173 if (obj == NULL) {
1174 Py_DECREF(trace_obj);
1175 return NULL;
1176 }
1177 PyTuple_SET_ITEM(trace_obj, 3, obj);
1178
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001179 return trace_obj;
1180}
1181
Victor Stinnere492ae52016-03-22 12:58:23 +01001182
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001183typedef struct {
1184 _Py_hashtable_t *traces;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001185 _Py_hashtable_t *domains;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001186 _Py_hashtable_t *tracebacks;
1187 PyObject *list;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001188 unsigned int domain;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001189} get_traces_t;
1190
Victor Stinnerd95bd422020-05-13 03:52:11 +02001191
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001192static int
Victor Stinnerd95bd422020-05-13 03:52:11 +02001193tracemalloc_copy_trace(_Py_hashtable_t *traces,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001194 const void *key, const void *value,
1195 void *user_data)
Victor Stinner9e2ca172020-05-13 01:36:47 +02001196{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001197 _Py_hashtable_t *traces2 = (_Py_hashtable_t *)user_data;
Victor Stinnerd95bd422020-05-13 03:52:11 +02001198
Victor Stinner5b0a3032020-05-13 04:40:30 +02001199 trace_t *trace = (trace_t *)value;
Victor Stinnerd95bd422020-05-13 03:52:11 +02001200
1201 trace_t *trace2 = raw_malloc(sizeof(trace_t));
Yunlongs66c28f52020-10-13 14:46:31 +08001202 if (trace2 == NULL) {
Victor Stinnerd95bd422020-05-13 03:52:11 +02001203 return -1;
1204 }
1205 *trace2 = *trace;
Victor Stinner5b0a3032020-05-13 04:40:30 +02001206 if (_Py_hashtable_set(traces2, key, trace2) < 0) {
Victor Stinnerd95bd422020-05-13 03:52:11 +02001207 raw_free(trace2);
1208 return -1;
1209 }
1210 return 0;
1211}
1212
1213
1214static _Py_hashtable_t*
1215tracemalloc_copy_traces(_Py_hashtable_t *traces)
1216{
1217 _Py_hashtable_t *traces2 = tracemalloc_create_traces_table();
1218 if (traces2 == NULL) {
1219 return NULL;
1220 }
1221
1222 int err = _Py_hashtable_foreach(traces,
1223 tracemalloc_copy_trace,
1224 traces2);
1225 if (err) {
1226 _Py_hashtable_destroy(traces2);
1227 return NULL;
1228 }
1229 return traces2;
1230}
1231
1232
1233static int
1234tracemalloc_copy_domain(_Py_hashtable_t *domains,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001235 const void *key, const void *value,
1236 void *user_data)
Victor Stinnerd95bd422020-05-13 03:52:11 +02001237{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001238 _Py_hashtable_t *domains2 = (_Py_hashtable_t *)user_data;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001239
Victor Stinner5b0a3032020-05-13 04:40:30 +02001240 unsigned int domain = (unsigned int)FROM_PTR(key);
1241 _Py_hashtable_t *traces = (_Py_hashtable_t *)value;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001242
Victor Stinnerd95bd422020-05-13 03:52:11 +02001243 _Py_hashtable_t *traces2 = tracemalloc_copy_traces(traces);
Miss Islington (bot)86d18012022-01-13 20:32:40 -08001244 if (traces2 == NULL) {
1245 return -1;
1246 }
Victor Stinner5b0a3032020-05-13 04:40:30 +02001247 if (_Py_hashtable_set(domains2, TO_PTR(domain), traces2) < 0) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001248 _Py_hashtable_destroy(traces2);
1249 return -1;
1250 }
1251 return 0;
1252}
1253
1254
Victor Stinnerd95bd422020-05-13 03:52:11 +02001255static _Py_hashtable_t*
1256tracemalloc_copy_domains(_Py_hashtable_t *domains)
1257{
1258 _Py_hashtable_t *domains2 = tracemalloc_create_domains_table();
1259 if (domains2 == NULL) {
1260 return NULL;
1261 }
1262
1263 int err = _Py_hashtable_foreach(domains,
1264 tracemalloc_copy_domain,
1265 domains2);
1266 if (err) {
1267 _Py_hashtable_destroy(domains2);
1268 return NULL;
1269 }
1270 return domains2;
1271}
1272
1273
Victor Stinner9e2ca172020-05-13 01:36:47 +02001274static int
Victor Stinner5b0a3032020-05-13 04:40:30 +02001275tracemalloc_get_traces_fill(_Py_hashtable_t *traces,
1276 const void *key, const void *value,
Victor Stinner285cf0a2016-03-21 22:00:58 +01001277 void *user_data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001278{
1279 get_traces_t *get_traces = user_data;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001280
Victor Stinner5b0a3032020-05-13 04:40:30 +02001281 const trace_t *trace = (const trace_t *)value;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001282
Victor Stinner5b0a3032020-05-13 04:40:30 +02001283 PyObject *tuple = trace_to_pyobject(get_traces->domain, trace,
1284 get_traces->tracebacks);
1285 if (tuple == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001286 return 1;
Victor Stinner5b0a3032020-05-13 04:40:30 +02001287 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001288
Victor Stinner5b0a3032020-05-13 04:40:30 +02001289 int res = PyList_Append(get_traces->list, tuple);
1290 Py_DECREF(tuple);
1291 if (res < 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001292 return 1;
Victor Stinner5b0a3032020-05-13 04:40:30 +02001293 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001294
1295 return 0;
1296}
1297
Victor Stinnere492ae52016-03-22 12:58:23 +01001298
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001299static int
Victor Stinner9e2ca172020-05-13 01:36:47 +02001300tracemalloc_get_traces_domain(_Py_hashtable_t *domains,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001301 const void *key, const void *value,
Victor Stinner9e2ca172020-05-13 01:36:47 +02001302 void *user_data)
1303{
1304 get_traces_t *get_traces = user_data;
1305
Victor Stinner5b0a3032020-05-13 04:40:30 +02001306 unsigned int domain = (unsigned int)FROM_PTR(key);
1307 _Py_hashtable_t *traces = (_Py_hashtable_t *)value;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001308
1309 get_traces->domain = domain;
1310 return _Py_hashtable_foreach(traces,
1311 tracemalloc_get_traces_fill,
1312 get_traces);
1313}
1314
1315
Victor Stinner2d0a3d62020-05-13 02:50:18 +02001316static void
Victor Stinner5b0a3032020-05-13 04:40:30 +02001317tracemalloc_pyobject_decref(void *value)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001318{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001319 PyObject *obj = (PyObject *)value;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001320 Py_DECREF(obj);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001321}
1322
Victor Stinnere492ae52016-03-22 12:58:23 +01001323
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001324
Serhiy Storchakab451f912017-02-04 12:18:38 +02001325/*[clinic input]
1326_tracemalloc._get_traces
1327
1328Get traces of all memory blocks allocated by Python.
1329
1330Return a list of (size: int, traceback: tuple) tuples.
1331traceback is a tuple of (filename: str, lineno: int) tuples.
1332
1333Return an empty list if the tracemalloc module is disabled.
1334[clinic start generated code]*/
1335
1336static PyObject *
1337_tracemalloc__get_traces_impl(PyObject *module)
1338/*[clinic end generated code: output=e9929876ced4b5cc input=6c7d2230b24255aa]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001339{
1340 get_traces_t get_traces;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001341 get_traces.domain = DEFAULT_DOMAIN;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001342 get_traces.traces = NULL;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001343 get_traces.domains = NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001344 get_traces.tracebacks = NULL;
1345 get_traces.list = PyList_New(0);
1346 if (get_traces.list == NULL)
1347 goto error;
1348
Victor Stinner9e00e802018-10-25 13:31:16 +02001349 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001350 return get_traces.list;
1351
Victor Stinnerde2f1322013-11-26 00:26:23 +01001352 /* the traceback hash table is used temporarily to intern traceback tuple
1353 of (filename, lineno) tuples */
Victor Stinner5b0a3032020-05-13 04:40:30 +02001354 get_traces.tracebacks = hashtable_new(_Py_hashtable_hash_ptr,
Victor Stinner2d0a3d62020-05-13 02:50:18 +02001355 _Py_hashtable_compare_direct,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001356 NULL, tracemalloc_pyobject_decref);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001357 if (get_traces.tracebacks == NULL) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001358 goto no_memory;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001359 }
1360
Victor Stinner9e2ca172020-05-13 01:36:47 +02001361 // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable
1362 // temporarily tracemalloc which would impact other threads and so would
1363 // miss allocations while get_traces() is called.
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001364 TABLES_LOCK();
Victor Stinnerd95bd422020-05-13 03:52:11 +02001365 get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001366 TABLES_UNLOCK();
1367
1368 if (get_traces.traces == NULL) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001369 goto no_memory;
1370 }
Victor Stinnerd95bd422020-05-13 03:52:11 +02001371
1372 TABLES_LOCK();
1373 get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains);
1374 TABLES_UNLOCK();
1375
1376 if (get_traces.domains == NULL) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001377 goto no_memory;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001378 }
1379
Victor Stinner9e2ca172020-05-13 01:36:47 +02001380 // Convert traces to a list of tuples
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001381 set_reentrant(1);
Victor Stinnerd95bd422020-05-13 03:52:11 +02001382 int err = _Py_hashtable_foreach(get_traces.traces,
1383 tracemalloc_get_traces_fill,
1384 &get_traces);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001385 if (!err) {
1386 err = _Py_hashtable_foreach(get_traces.domains,
Victor Stinnerd95bd422020-05-13 03:52:11 +02001387 tracemalloc_get_traces_domain,
1388 &get_traces);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001389 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001390 set_reentrant(0);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001391 if (err) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001392 goto error;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001393 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001394
1395 goto finally;
1396
Victor Stinner9e2ca172020-05-13 01:36:47 +02001397no_memory:
1398 PyErr_NoMemory();
1399
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001400error:
1401 Py_CLEAR(get_traces.list);
1402
1403finally:
1404 if (get_traces.tracebacks != NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001405 _Py_hashtable_destroy(get_traces.tracebacks);
1406 }
Victor Stinnerc9553872016-03-22 12:13:01 +01001407 if (get_traces.traces != NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001408 _Py_hashtable_destroy(get_traces.traces);
Victor Stinnerc9553872016-03-22 12:13:01 +01001409 }
Victor Stinner9e2ca172020-05-13 01:36:47 +02001410 if (get_traces.domains != NULL) {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001411 _Py_hashtable_destroy(get_traces.domains);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001412 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001413
1414 return get_traces.list;
1415}
1416
Victor Stinnere492ae52016-03-22 12:58:23 +01001417
Victor Stinner0611c262016-03-15 22:22:13 +01001418static traceback_t*
Victor Stinner5ea4c062017-06-20 17:46:36 +02001419tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr)
Victor Stinner0611c262016-03-15 22:22:13 +01001420{
Victor Stinner0611c262016-03-15 22:22:13 +01001421
Victor Stinner9e00e802018-10-25 13:31:16 +02001422 if (!_Py_tracemalloc_config.tracing)
Victor Stinner0611c262016-03-15 22:22:13 +01001423 return NULL;
1424
Victor Stinner5b0a3032020-05-13 04:40:30 +02001425 trace_t *trace;
Victor Stinner0611c262016-03-15 22:22:13 +01001426 TABLES_LOCK();
Victor Stinner9e2ca172020-05-13 01:36:47 +02001427 _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
1428 if (traces) {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001429 trace = _Py_hashtable_get(traces, TO_PTR(ptr));
Victor Stinnere492ae52016-03-22 12:58:23 +01001430 }
1431 else {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001432 trace = NULL;
Victor Stinnere492ae52016-03-22 12:58:23 +01001433 }
Victor Stinner0611c262016-03-15 22:22:13 +01001434 TABLES_UNLOCK();
1435
Victor Stinner5b0a3032020-05-13 04:40:30 +02001436 if (!trace) {
Victor Stinner0611c262016-03-15 22:22:13 +01001437 return NULL;
Victor Stinnerd95bd422020-05-13 03:52:11 +02001438 }
Victor Stinner0611c262016-03-15 22:22:13 +01001439
Victor Stinnerd95bd422020-05-13 03:52:11 +02001440 return trace->traceback;
Victor Stinner0611c262016-03-15 22:22:13 +01001441}
1442
Victor Stinnere492ae52016-03-22 12:58:23 +01001443
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001444
Serhiy Storchakab451f912017-02-04 12:18:38 +02001445/*[clinic input]
1446_tracemalloc._get_object_traceback
1447
1448 obj: object
1449 /
1450
1451Get the traceback where the Python object obj was allocated.
1452
1453Return a tuple of (filename: str, lineno: int) tuples.
1454Return None if the tracemalloc module is disabled or did not
1455trace the allocation of the object.
1456[clinic start generated code]*/
1457
1458static PyObject *
1459_tracemalloc__get_object_traceback(PyObject *module, PyObject *obj)
1460/*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001461{
1462 PyTypeObject *type;
1463 void *ptr;
Victor Stinner0611c262016-03-15 22:22:13 +01001464 traceback_t *traceback;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001465
1466 type = Py_TYPE(obj);
Victor Stinner626bff82018-10-25 17:31:10 +02001467 if (PyType_IS_GC(type)) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001468 ptr = (void *)((char *)obj - sizeof(PyGC_Head));
Victor Stinner626bff82018-10-25 17:31:10 +02001469 }
1470 else {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001471 ptr = (void *)obj;
Victor Stinner626bff82018-10-25 17:31:10 +02001472 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001473
Benjamin Petersonca470632016-09-06 13:47:26 -07001474 traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
Victor Stinner0611c262016-03-15 22:22:13 +01001475 if (traceback == NULL)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001476 Py_RETURN_NONE;
1477
Victor Stinner0611c262016-03-15 22:22:13 +01001478 return traceback_to_pyobject(traceback, NULL);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001479}
1480
Victor Stinnere492ae52016-03-22 12:58:23 +01001481
Victor Stinner0611c262016-03-15 22:22:13 +01001482#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
1483
1484static void
1485_PyMem_DumpFrame(int fd, frame_t * frame)
1486{
1487 PUTS(fd, " File \"");
1488 _Py_DumpASCII(fd, frame->filename);
1489 PUTS(fd, "\", line ");
1490 _Py_DumpDecimal(fd, frame->lineno);
1491 PUTS(fd, "\n");
1492}
1493
1494/* Dump the traceback where a memory block was allocated into file descriptor
1495 fd. The function may block on TABLES_LOCK() but it is unlikely. */
1496void
1497_PyMem_DumpTraceback(int fd, const void *ptr)
1498{
1499 traceback_t *traceback;
1500 int i;
1501
Victor Stinnerf966e532018-11-13 15:14:58 +01001502 if (!_Py_tracemalloc_config.tracing) {
1503 PUTS(fd, "Enable tracemalloc to get the memory block "
1504 "allocation traceback\n\n");
1505 return;
1506 }
1507
Benjamin Petersonca470632016-09-06 13:47:26 -07001508 traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
Victor Stinner0611c262016-03-15 22:22:13 +01001509 if (traceback == NULL)
1510 return;
1511
1512 PUTS(fd, "Memory block allocated at (most recent call first):\n");
1513 for (i=0; i < traceback->nframe; i++) {
1514 _PyMem_DumpFrame(fd, &traceback->frames[i]);
1515 }
1516 PUTS(fd, "\n");
1517}
1518
1519#undef PUTS
1520
Victor Stinnere492ae52016-03-22 12:58:23 +01001521
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001522
Serhiy Storchakab451f912017-02-04 12:18:38 +02001523/*[clinic input]
1524_tracemalloc.start
1525
Victor Stinnera7368ac2017-11-15 18:11:45 -08001526 nframe: int = 1
Serhiy Storchakab451f912017-02-04 12:18:38 +02001527 /
1528
1529Start tracing Python memory allocations.
1530
1531Also set the maximum number of frames stored in the traceback of a
1532trace to nframe.
1533[clinic start generated code]*/
1534
1535static PyObject *
Victor Stinnera7368ac2017-11-15 18:11:45 -08001536_tracemalloc_start_impl(PyObject *module, int nframe)
1537/*[clinic end generated code: output=caae05c23c159d3c input=40d849b5b29d1933]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001538{
Victor Stinnera7368ac2017-11-15 18:11:45 -08001539 if (tracemalloc_start(nframe) < 0) {
Victor Stinner3728d6c2013-11-23 12:37:20 +01001540 return NULL;
1541 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001542 Py_RETURN_NONE;
1543}
1544
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001545
Serhiy Storchakab451f912017-02-04 12:18:38 +02001546/*[clinic input]
1547_tracemalloc.stop
Victor Stinnere492ae52016-03-22 12:58:23 +01001548
Serhiy Storchakab451f912017-02-04 12:18:38 +02001549Stop tracing Python memory allocations.
1550
1551Also clear traces of memory blocks allocated by Python.
1552[clinic start generated code]*/
1553
1554static PyObject *
1555_tracemalloc_stop_impl(PyObject *module)
1556/*[clinic end generated code: output=c3c42ae03e3955cd input=7478f075e51dae18]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001557{
1558 tracemalloc_stop();
1559 Py_RETURN_NONE;
1560}
1561
Victor Stinnere492ae52016-03-22 12:58:23 +01001562
Serhiy Storchakab451f912017-02-04 12:18:38 +02001563/*[clinic input]
1564_tracemalloc.get_traceback_limit
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001565
Serhiy Storchakab451f912017-02-04 12:18:38 +02001566Get the maximum number of frames stored in the traceback of a trace.
1567
1568By default, a trace of an allocated memory block only stores
1569the most recent frame: the limit is 1.
1570[clinic start generated code]*/
1571
1572static PyObject *
1573_tracemalloc_get_traceback_limit_impl(PyObject *module)
1574/*[clinic end generated code: output=d556d9306ba95567 input=da3cd977fc68ae3b]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001575{
Victor Stinner9e00e802018-10-25 13:31:16 +02001576 return PyLong_FromLong(_Py_tracemalloc_config.max_nframe);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001577}
1578
Victor Stinnere492ae52016-03-22 12:58:23 +01001579
Victor Stinner9e2ca172020-05-13 01:36:47 +02001580static int
1581tracemalloc_get_tracemalloc_memory_cb(_Py_hashtable_t *domains,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001582 const void *key, const void *value,
Victor Stinner9e2ca172020-05-13 01:36:47 +02001583 void *user_data)
1584{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001585 const _Py_hashtable_t *traces = value;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001586 size_t *size = (size_t*)user_data;
1587 *size += _Py_hashtable_size(traces);
1588 return 0;
1589}
1590
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001591
Serhiy Storchakab451f912017-02-04 12:18:38 +02001592/*[clinic input]
1593_tracemalloc.get_tracemalloc_memory
1594
1595Get the memory usage in bytes of the tracemalloc module.
1596
1597This memory is used internally to trace memory allocations.
1598[clinic start generated code]*/
1599
1600static PyObject *
1601_tracemalloc_get_tracemalloc_memory_impl(PyObject *module)
1602/*[clinic end generated code: output=e3f14e280a55f5aa input=5d919c0f4d5132ad]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001603{
1604 size_t size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001605
1606 size = _Py_hashtable_size(tracemalloc_tracebacks);
1607 size += _Py_hashtable_size(tracemalloc_filenames);
1608
1609 TABLES_LOCK();
1610 size += _Py_hashtable_size(tracemalloc_traces);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001611 _Py_hashtable_foreach(tracemalloc_domains,
1612 tracemalloc_get_tracemalloc_memory_cb, &size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001613 TABLES_UNLOCK();
1614
Serhiy Storchakab451f912017-02-04 12:18:38 +02001615 return PyLong_FromSize_t(size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001616}
1617
Victor Stinnere492ae52016-03-22 12:58:23 +01001618
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001619
Serhiy Storchakab451f912017-02-04 12:18:38 +02001620/*[clinic input]
1621_tracemalloc.get_traced_memory
1622
1623Get the current size and peak size of memory blocks traced by tracemalloc.
1624
1625Returns a tuple: (current: int, peak: int).
1626[clinic start generated code]*/
1627
1628static PyObject *
1629_tracemalloc_get_traced_memory_impl(PyObject *module)
1630/*[clinic end generated code: output=5b167189adb9e782 input=61ddb5478400ff66]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001631{
Victor Stinner3c0481d2013-11-27 21:39:49 +01001632 Py_ssize_t size, peak_size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001633
Victor Stinner9e00e802018-10-25 13:31:16 +02001634 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001635 return Py_BuildValue("ii", 0, 0);
1636
1637 TABLES_LOCK();
1638 size = tracemalloc_traced_memory;
Victor Stinner3c0481d2013-11-27 21:39:49 +01001639 peak_size = tracemalloc_peak_traced_memory;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001640 TABLES_UNLOCK();
1641
Serhiy Storchakab451f912017-02-04 12:18:38 +02001642 return Py_BuildValue("nn", size, peak_size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001643}
1644
Huon Wilson8b626442020-05-23 00:18:51 +10001645/*[clinic input]
1646_tracemalloc.reset_peak
1647
1648Set the peak size of memory blocks traced by tracemalloc to the current size.
1649
1650Do nothing if the tracemalloc module is not tracing memory allocations.
1651
1652[clinic start generated code]*/
1653
1654static PyObject *
1655_tracemalloc_reset_peak_impl(PyObject *module)
1656/*[clinic end generated code: output=140c2870f691dbb2 input=18afd0635066e9ce]*/
1657{
1658 if (!_Py_tracemalloc_config.tracing) {
1659 Py_RETURN_NONE;
1660 }
1661
1662 TABLES_LOCK();
1663 tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
1664 TABLES_UNLOCK();
1665
1666 Py_RETURN_NONE;
1667}
1668
Victor Stinnere492ae52016-03-22 12:58:23 +01001669
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001670static PyMethodDef module_methods[] = {
Serhiy Storchakab451f912017-02-04 12:18:38 +02001671 _TRACEMALLOC_IS_TRACING_METHODDEF
1672 _TRACEMALLOC_CLEAR_TRACES_METHODDEF
1673 _TRACEMALLOC__GET_TRACES_METHODDEF
1674 _TRACEMALLOC__GET_OBJECT_TRACEBACK_METHODDEF
1675 _TRACEMALLOC_START_METHODDEF
1676 _TRACEMALLOC_STOP_METHODDEF
1677 _TRACEMALLOC_GET_TRACEBACK_LIMIT_METHODDEF
1678 _TRACEMALLOC_GET_TRACEMALLOC_MEMORY_METHODDEF
1679 _TRACEMALLOC_GET_TRACED_MEMORY_METHODDEF
Huon Wilson8b626442020-05-23 00:18:51 +10001680 _TRACEMALLOC_RESET_PEAK_METHODDEF
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001681 /* sentinel */
1682 {NULL, NULL}
1683};
1684
1685PyDoc_STRVAR(module_doc,
1686"Debug module to trace memory blocks allocated by Python.");
1687
1688static struct PyModuleDef module_def = {
1689 PyModuleDef_HEAD_INIT,
1690 "_tracemalloc",
1691 module_doc,
1692 0, /* non-negative size to be able to unload the module */
1693 module_methods,
1694 NULL,
1695};
1696
1697PyMODINIT_FUNC
1698PyInit__tracemalloc(void)
1699{
1700 PyObject *m;
1701 m = PyModule_Create(&module_def);
1702 if (m == NULL)
1703 return NULL;
1704
Brandt Bucherd51a3632019-11-20 02:00:31 -08001705 if (tracemalloc_init() < 0) {
1706 Py_DECREF(m);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001707 return NULL;
Brandt Bucherd51a3632019-11-20 02:00:31 -08001708 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001709
1710 return m;
1711}
1712
Victor Stinnere492ae52016-03-22 12:58:23 +01001713
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001714int
Victor Stinnera7368ac2017-11-15 18:11:45 -08001715_PyTraceMalloc_Init(int nframe)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001716{
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001717 assert(PyGILState_Check());
Victor Stinnera7368ac2017-11-15 18:11:45 -08001718 if (nframe == 0) {
1719 return 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001720 }
Victor Stinnerf28ce602013-11-27 22:27:13 +01001721 return tracemalloc_start(nframe);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001722}
1723
Victor Stinnere492ae52016-03-22 12:58:23 +01001724
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001725void
1726_PyTraceMalloc_Fini(void)
1727{
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001728 assert(PyGILState_Check());
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001729 tracemalloc_deinit();
1730}
Victor Stinner10b73e12016-03-22 13:39:05 +01001731
1732int
Victor Stinner5ea4c062017-06-20 17:46:36 +02001733PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr,
1734 size_t size)
Victor Stinner10b73e12016-03-22 13:39:05 +01001735{
1736 int res;
Victor Stinner10b73e12016-03-22 13:39:05 +01001737 PyGILState_STATE gil_state;
Victor Stinner10b73e12016-03-22 13:39:05 +01001738
Victor Stinner9e00e802018-10-25 13:31:16 +02001739 if (!_Py_tracemalloc_config.tracing) {
Victor Stinner10b73e12016-03-22 13:39:05 +01001740 /* tracemalloc is not tracing: do nothing */
1741 return -2;
1742 }
1743
Victor Stinner10b73e12016-03-22 13:39:05 +01001744 gil_state = PyGILState_Ensure();
Victor Stinner10b73e12016-03-22 13:39:05 +01001745
1746 TABLES_LOCK();
1747 res = tracemalloc_add_trace(domain, ptr, size);
1748 TABLES_UNLOCK();
1749
Victor Stinner10b73e12016-03-22 13:39:05 +01001750 PyGILState_Release(gil_state);
Victor Stinner10b73e12016-03-22 13:39:05 +01001751 return res;
1752}
1753
1754
1755int
Victor Stinner5ea4c062017-06-20 17:46:36 +02001756PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)
Victor Stinner10b73e12016-03-22 13:39:05 +01001757{
Victor Stinner9e00e802018-10-25 13:31:16 +02001758 if (!_Py_tracemalloc_config.tracing) {
Victor Stinner10b73e12016-03-22 13:39:05 +01001759 /* tracemalloc is not tracing: do nothing */
1760 return -2;
1761 }
1762
1763 TABLES_LOCK();
1764 tracemalloc_remove_trace(domain, ptr);
1765 TABLES_UNLOCK();
1766
1767 return 0;
1768}
1769
1770
Victor Stinner9e00e802018-10-25 13:31:16 +02001771/* If the object memory block is already traced, update its trace
1772 with the current Python traceback.
1773
1774 Do nothing if tracemalloc is not tracing memory allocations
1775 or if the object memory block is not already traced. */
1776int
1777_PyTraceMalloc_NewReference(PyObject *op)
1778{
1779 assert(PyGILState_Check());
1780
1781 if (!_Py_tracemalloc_config.tracing) {
1782 /* tracemalloc is not tracing: do nothing */
1783 return -1;
1784 }
1785
1786 uintptr_t ptr;
1787 PyTypeObject *type = Py_TYPE(op);
1788 if (PyType_IS_GC(type)) {
1789 ptr = (uintptr_t)((char *)op - sizeof(PyGC_Head));
1790 }
1791 else {
1792 ptr = (uintptr_t)op;
1793 }
1794
Victor Stinner9e00e802018-10-25 13:31:16 +02001795 int res = -1;
1796
1797 TABLES_LOCK();
Victor Stinner5b0a3032020-05-13 04:40:30 +02001798 trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr));
1799 if (trace != NULL) {
Victor Stinner9e00e802018-10-25 13:31:16 +02001800 /* update the traceback of the memory block */
1801 traceback_t *traceback = traceback_new();
1802 if (traceback != NULL) {
Victor Stinnerd95bd422020-05-13 03:52:11 +02001803 trace->traceback = traceback;
Victor Stinner9e00e802018-10-25 13:31:16 +02001804 res = 0;
1805 }
1806 }
1807 /* else: cannot track the object, its memory block size is unknown */
1808 TABLES_UNLOCK();
1809
1810 return res;
1811}
1812
1813
Victor Stinner10b73e12016-03-22 13:39:05 +01001814PyObject*
Victor Stinner5ea4c062017-06-20 17:46:36 +02001815_PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr)
Victor Stinner10b73e12016-03-22 13:39:05 +01001816{
1817 traceback_t *traceback;
1818
1819 traceback = tracemalloc_get_traceback(domain, ptr);
1820 if (traceback == NULL)
1821 Py_RETURN_NONE;
1822
1823 return traceback_to_pyobject(traceback, NULL);
1824}