blob: fc91622d3925b8424880b48bdd8f0f3a411fad9c [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{
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100839 /* The GIL protects variables againt concurrent access */
840 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));
1202 if (traces2 == NULL) {
1203 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);
Victor Stinner5b0a3032020-05-13 04:40:30 +02001244 if (_Py_hashtable_set(domains2, TO_PTR(domain), traces2) < 0) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001245 _Py_hashtable_destroy(traces2);
1246 return -1;
1247 }
1248 return 0;
1249}
1250
1251
Victor Stinnerd95bd422020-05-13 03:52:11 +02001252static _Py_hashtable_t*
1253tracemalloc_copy_domains(_Py_hashtable_t *domains)
1254{
1255 _Py_hashtable_t *domains2 = tracemalloc_create_domains_table();
1256 if (domains2 == NULL) {
1257 return NULL;
1258 }
1259
1260 int err = _Py_hashtable_foreach(domains,
1261 tracemalloc_copy_domain,
1262 domains2);
1263 if (err) {
1264 _Py_hashtable_destroy(domains2);
1265 return NULL;
1266 }
1267 return domains2;
1268}
1269
1270
Victor Stinner9e2ca172020-05-13 01:36:47 +02001271static int
Victor Stinner5b0a3032020-05-13 04:40:30 +02001272tracemalloc_get_traces_fill(_Py_hashtable_t *traces,
1273 const void *key, const void *value,
Victor Stinner285cf0a2016-03-21 22:00:58 +01001274 void *user_data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001275{
1276 get_traces_t *get_traces = user_data;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001277
Victor Stinner5b0a3032020-05-13 04:40:30 +02001278 const trace_t *trace = (const trace_t *)value;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001279
Victor Stinner5b0a3032020-05-13 04:40:30 +02001280 PyObject *tuple = trace_to_pyobject(get_traces->domain, trace,
1281 get_traces->tracebacks);
1282 if (tuple == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001283 return 1;
Victor Stinner5b0a3032020-05-13 04:40:30 +02001284 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001285
Victor Stinner5b0a3032020-05-13 04:40:30 +02001286 int res = PyList_Append(get_traces->list, tuple);
1287 Py_DECREF(tuple);
1288 if (res < 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001289 return 1;
Victor Stinner5b0a3032020-05-13 04:40:30 +02001290 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001291
1292 return 0;
1293}
1294
Victor Stinnere492ae52016-03-22 12:58:23 +01001295
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001296static int
Victor Stinner9e2ca172020-05-13 01:36:47 +02001297tracemalloc_get_traces_domain(_Py_hashtable_t *domains,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001298 const void *key, const void *value,
Victor Stinner9e2ca172020-05-13 01:36:47 +02001299 void *user_data)
1300{
1301 get_traces_t *get_traces = user_data;
1302
Victor Stinner5b0a3032020-05-13 04:40:30 +02001303 unsigned int domain = (unsigned int)FROM_PTR(key);
1304 _Py_hashtable_t *traces = (_Py_hashtable_t *)value;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001305
1306 get_traces->domain = domain;
1307 return _Py_hashtable_foreach(traces,
1308 tracemalloc_get_traces_fill,
1309 get_traces);
1310}
1311
1312
Victor Stinner2d0a3d62020-05-13 02:50:18 +02001313static void
Victor Stinner5b0a3032020-05-13 04:40:30 +02001314tracemalloc_pyobject_decref(void *value)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001315{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001316 PyObject *obj = (PyObject *)value;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001317 Py_DECREF(obj);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001318}
1319
Victor Stinnere492ae52016-03-22 12:58:23 +01001320
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001321
Serhiy Storchakab451f912017-02-04 12:18:38 +02001322/*[clinic input]
1323_tracemalloc._get_traces
1324
1325Get traces of all memory blocks allocated by Python.
1326
1327Return a list of (size: int, traceback: tuple) tuples.
1328traceback is a tuple of (filename: str, lineno: int) tuples.
1329
1330Return an empty list if the tracemalloc module is disabled.
1331[clinic start generated code]*/
1332
1333static PyObject *
1334_tracemalloc__get_traces_impl(PyObject *module)
1335/*[clinic end generated code: output=e9929876ced4b5cc input=6c7d2230b24255aa]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001336{
1337 get_traces_t get_traces;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001338 get_traces.domain = DEFAULT_DOMAIN;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001339 get_traces.traces = NULL;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001340 get_traces.domains = NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001341 get_traces.tracebacks = NULL;
1342 get_traces.list = PyList_New(0);
1343 if (get_traces.list == NULL)
1344 goto error;
1345
Victor Stinner9e00e802018-10-25 13:31:16 +02001346 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001347 return get_traces.list;
1348
Victor Stinnerde2f1322013-11-26 00:26:23 +01001349 /* the traceback hash table is used temporarily to intern traceback tuple
1350 of (filename, lineno) tuples */
Victor Stinner5b0a3032020-05-13 04:40:30 +02001351 get_traces.tracebacks = hashtable_new(_Py_hashtable_hash_ptr,
Victor Stinner2d0a3d62020-05-13 02:50:18 +02001352 _Py_hashtable_compare_direct,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001353 NULL, tracemalloc_pyobject_decref);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001354 if (get_traces.tracebacks == NULL) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001355 goto no_memory;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001356 }
1357
Victor Stinner9e2ca172020-05-13 01:36:47 +02001358 // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable
1359 // temporarily tracemalloc which would impact other threads and so would
1360 // miss allocations while get_traces() is called.
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001361 TABLES_LOCK();
Victor Stinnerd95bd422020-05-13 03:52:11 +02001362 get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001363 TABLES_UNLOCK();
1364
1365 if (get_traces.traces == NULL) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001366 goto no_memory;
1367 }
Victor Stinnerd95bd422020-05-13 03:52:11 +02001368
1369 TABLES_LOCK();
1370 get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains);
1371 TABLES_UNLOCK();
1372
1373 if (get_traces.domains == NULL) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001374 goto no_memory;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001375 }
1376
Victor Stinner9e2ca172020-05-13 01:36:47 +02001377 // Convert traces to a list of tuples
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001378 set_reentrant(1);
Victor Stinnerd95bd422020-05-13 03:52:11 +02001379 int err = _Py_hashtable_foreach(get_traces.traces,
1380 tracemalloc_get_traces_fill,
1381 &get_traces);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001382 if (!err) {
1383 err = _Py_hashtable_foreach(get_traces.domains,
Victor Stinnerd95bd422020-05-13 03:52:11 +02001384 tracemalloc_get_traces_domain,
1385 &get_traces);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001386 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001387 set_reentrant(0);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001388 if (err) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001389 goto error;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001390 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001391
1392 goto finally;
1393
Victor Stinner9e2ca172020-05-13 01:36:47 +02001394no_memory:
1395 PyErr_NoMemory();
1396
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001397error:
1398 Py_CLEAR(get_traces.list);
1399
1400finally:
1401 if (get_traces.tracebacks != NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001402 _Py_hashtable_destroy(get_traces.tracebacks);
1403 }
Victor Stinnerc9553872016-03-22 12:13:01 +01001404 if (get_traces.traces != NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001405 _Py_hashtable_destroy(get_traces.traces);
Victor Stinnerc9553872016-03-22 12:13:01 +01001406 }
Victor Stinner9e2ca172020-05-13 01:36:47 +02001407 if (get_traces.domains != NULL) {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001408 _Py_hashtable_destroy(get_traces.domains);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001409 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001410
1411 return get_traces.list;
1412}
1413
Victor Stinnere492ae52016-03-22 12:58:23 +01001414
Victor Stinner0611c262016-03-15 22:22:13 +01001415static traceback_t*
Victor Stinner5ea4c062017-06-20 17:46:36 +02001416tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr)
Victor Stinner0611c262016-03-15 22:22:13 +01001417{
Victor Stinner0611c262016-03-15 22:22:13 +01001418
Victor Stinner9e00e802018-10-25 13:31:16 +02001419 if (!_Py_tracemalloc_config.tracing)
Victor Stinner0611c262016-03-15 22:22:13 +01001420 return NULL;
1421
Victor Stinner5b0a3032020-05-13 04:40:30 +02001422 trace_t *trace;
Victor Stinner0611c262016-03-15 22:22:13 +01001423 TABLES_LOCK();
Victor Stinner9e2ca172020-05-13 01:36:47 +02001424 _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
1425 if (traces) {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001426 trace = _Py_hashtable_get(traces, TO_PTR(ptr));
Victor Stinnere492ae52016-03-22 12:58:23 +01001427 }
1428 else {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001429 trace = NULL;
Victor Stinnere492ae52016-03-22 12:58:23 +01001430 }
Victor Stinner0611c262016-03-15 22:22:13 +01001431 TABLES_UNLOCK();
1432
Victor Stinner5b0a3032020-05-13 04:40:30 +02001433 if (!trace) {
Victor Stinner0611c262016-03-15 22:22:13 +01001434 return NULL;
Victor Stinnerd95bd422020-05-13 03:52:11 +02001435 }
Victor Stinner0611c262016-03-15 22:22:13 +01001436
Victor Stinnerd95bd422020-05-13 03:52:11 +02001437 return trace->traceback;
Victor Stinner0611c262016-03-15 22:22:13 +01001438}
1439
Victor Stinnere492ae52016-03-22 12:58:23 +01001440
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001441
Serhiy Storchakab451f912017-02-04 12:18:38 +02001442/*[clinic input]
1443_tracemalloc._get_object_traceback
1444
1445 obj: object
1446 /
1447
1448Get the traceback where the Python object obj was allocated.
1449
1450Return a tuple of (filename: str, lineno: int) tuples.
1451Return None if the tracemalloc module is disabled or did not
1452trace the allocation of the object.
1453[clinic start generated code]*/
1454
1455static PyObject *
1456_tracemalloc__get_object_traceback(PyObject *module, PyObject *obj)
1457/*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001458{
1459 PyTypeObject *type;
1460 void *ptr;
Victor Stinner0611c262016-03-15 22:22:13 +01001461 traceback_t *traceback;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001462
1463 type = Py_TYPE(obj);
Victor Stinner626bff82018-10-25 17:31:10 +02001464 if (PyType_IS_GC(type)) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001465 ptr = (void *)((char *)obj - sizeof(PyGC_Head));
Victor Stinner626bff82018-10-25 17:31:10 +02001466 }
1467 else {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001468 ptr = (void *)obj;
Victor Stinner626bff82018-10-25 17:31:10 +02001469 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001470
Benjamin Petersonca470632016-09-06 13:47:26 -07001471 traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
Victor Stinner0611c262016-03-15 22:22:13 +01001472 if (traceback == NULL)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001473 Py_RETURN_NONE;
1474
Victor Stinner0611c262016-03-15 22:22:13 +01001475 return traceback_to_pyobject(traceback, NULL);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001476}
1477
Victor Stinnere492ae52016-03-22 12:58:23 +01001478
Victor Stinner0611c262016-03-15 22:22:13 +01001479#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
1480
1481static void
1482_PyMem_DumpFrame(int fd, frame_t * frame)
1483{
1484 PUTS(fd, " File \"");
1485 _Py_DumpASCII(fd, frame->filename);
1486 PUTS(fd, "\", line ");
1487 _Py_DumpDecimal(fd, frame->lineno);
1488 PUTS(fd, "\n");
1489}
1490
1491/* Dump the traceback where a memory block was allocated into file descriptor
1492 fd. The function may block on TABLES_LOCK() but it is unlikely. */
1493void
1494_PyMem_DumpTraceback(int fd, const void *ptr)
1495{
1496 traceback_t *traceback;
1497 int i;
1498
Victor Stinnerf966e532018-11-13 15:14:58 +01001499 if (!_Py_tracemalloc_config.tracing) {
1500 PUTS(fd, "Enable tracemalloc to get the memory block "
1501 "allocation traceback\n\n");
1502 return;
1503 }
1504
Benjamin Petersonca470632016-09-06 13:47:26 -07001505 traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
Victor Stinner0611c262016-03-15 22:22:13 +01001506 if (traceback == NULL)
1507 return;
1508
1509 PUTS(fd, "Memory block allocated at (most recent call first):\n");
1510 for (i=0; i < traceback->nframe; i++) {
1511 _PyMem_DumpFrame(fd, &traceback->frames[i]);
1512 }
1513 PUTS(fd, "\n");
1514}
1515
1516#undef PUTS
1517
Victor Stinnere492ae52016-03-22 12:58:23 +01001518
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001519
Serhiy Storchakab451f912017-02-04 12:18:38 +02001520/*[clinic input]
1521_tracemalloc.start
1522
Victor Stinnera7368ac2017-11-15 18:11:45 -08001523 nframe: int = 1
Serhiy Storchakab451f912017-02-04 12:18:38 +02001524 /
1525
1526Start tracing Python memory allocations.
1527
1528Also set the maximum number of frames stored in the traceback of a
1529trace to nframe.
1530[clinic start generated code]*/
1531
1532static PyObject *
Victor Stinnera7368ac2017-11-15 18:11:45 -08001533_tracemalloc_start_impl(PyObject *module, int nframe)
1534/*[clinic end generated code: output=caae05c23c159d3c input=40d849b5b29d1933]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001535{
Victor Stinnera7368ac2017-11-15 18:11:45 -08001536 if (tracemalloc_start(nframe) < 0) {
Victor Stinner3728d6c2013-11-23 12:37:20 +01001537 return NULL;
1538 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001539 Py_RETURN_NONE;
1540}
1541
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001542
Serhiy Storchakab451f912017-02-04 12:18:38 +02001543/*[clinic input]
1544_tracemalloc.stop
Victor Stinnere492ae52016-03-22 12:58:23 +01001545
Serhiy Storchakab451f912017-02-04 12:18:38 +02001546Stop tracing Python memory allocations.
1547
1548Also clear traces of memory blocks allocated by Python.
1549[clinic start generated code]*/
1550
1551static PyObject *
1552_tracemalloc_stop_impl(PyObject *module)
1553/*[clinic end generated code: output=c3c42ae03e3955cd input=7478f075e51dae18]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001554{
1555 tracemalloc_stop();
1556 Py_RETURN_NONE;
1557}
1558
Victor Stinnere492ae52016-03-22 12:58:23 +01001559
Serhiy Storchakab451f912017-02-04 12:18:38 +02001560/*[clinic input]
1561_tracemalloc.get_traceback_limit
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001562
Serhiy Storchakab451f912017-02-04 12:18:38 +02001563Get the maximum number of frames stored in the traceback of a trace.
1564
1565By default, a trace of an allocated memory block only stores
1566the most recent frame: the limit is 1.
1567[clinic start generated code]*/
1568
1569static PyObject *
1570_tracemalloc_get_traceback_limit_impl(PyObject *module)
1571/*[clinic end generated code: output=d556d9306ba95567 input=da3cd977fc68ae3b]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001572{
Victor Stinner9e00e802018-10-25 13:31:16 +02001573 return PyLong_FromLong(_Py_tracemalloc_config.max_nframe);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001574}
1575
Victor Stinnere492ae52016-03-22 12:58:23 +01001576
Victor Stinner9e2ca172020-05-13 01:36:47 +02001577static int
1578tracemalloc_get_tracemalloc_memory_cb(_Py_hashtable_t *domains,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001579 const void *key, const void *value,
Victor Stinner9e2ca172020-05-13 01:36:47 +02001580 void *user_data)
1581{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001582 const _Py_hashtable_t *traces = value;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001583 size_t *size = (size_t*)user_data;
1584 *size += _Py_hashtable_size(traces);
1585 return 0;
1586}
1587
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001588
Serhiy Storchakab451f912017-02-04 12:18:38 +02001589/*[clinic input]
1590_tracemalloc.get_tracemalloc_memory
1591
1592Get the memory usage in bytes of the tracemalloc module.
1593
1594This memory is used internally to trace memory allocations.
1595[clinic start generated code]*/
1596
1597static PyObject *
1598_tracemalloc_get_tracemalloc_memory_impl(PyObject *module)
1599/*[clinic end generated code: output=e3f14e280a55f5aa input=5d919c0f4d5132ad]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001600{
1601 size_t size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001602
1603 size = _Py_hashtable_size(tracemalloc_tracebacks);
1604 size += _Py_hashtable_size(tracemalloc_filenames);
1605
1606 TABLES_LOCK();
1607 size += _Py_hashtable_size(tracemalloc_traces);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001608 _Py_hashtable_foreach(tracemalloc_domains,
1609 tracemalloc_get_tracemalloc_memory_cb, &size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001610 TABLES_UNLOCK();
1611
Serhiy Storchakab451f912017-02-04 12:18:38 +02001612 return PyLong_FromSize_t(size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001613}
1614
Victor Stinnere492ae52016-03-22 12:58:23 +01001615
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001616
Serhiy Storchakab451f912017-02-04 12:18:38 +02001617/*[clinic input]
1618_tracemalloc.get_traced_memory
1619
1620Get the current size and peak size of memory blocks traced by tracemalloc.
1621
1622Returns a tuple: (current: int, peak: int).
1623[clinic start generated code]*/
1624
1625static PyObject *
1626_tracemalloc_get_traced_memory_impl(PyObject *module)
1627/*[clinic end generated code: output=5b167189adb9e782 input=61ddb5478400ff66]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001628{
Victor Stinner3c0481d2013-11-27 21:39:49 +01001629 Py_ssize_t size, peak_size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001630
Victor Stinner9e00e802018-10-25 13:31:16 +02001631 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001632 return Py_BuildValue("ii", 0, 0);
1633
1634 TABLES_LOCK();
1635 size = tracemalloc_traced_memory;
Victor Stinner3c0481d2013-11-27 21:39:49 +01001636 peak_size = tracemalloc_peak_traced_memory;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001637 TABLES_UNLOCK();
1638
Serhiy Storchakab451f912017-02-04 12:18:38 +02001639 return Py_BuildValue("nn", size, peak_size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001640}
1641
Huon Wilson3c7609a2020-06-02 03:26:22 +10001642/*[clinic input]
1643_tracemalloc.reset_peak
1644
1645Set the peak size of memory blocks traced by tracemalloc to the current size.
1646
1647Do nothing if the tracemalloc module is not tracing memory allocations.
1648
1649[clinic start generated code]*/
1650
1651static PyObject *
1652_tracemalloc_reset_peak_impl(PyObject *module)
1653/*[clinic end generated code: output=140c2870f691dbb2 input=18afd0635066e9ce]*/
1654{
1655 if (!_Py_tracemalloc_config.tracing) {
1656 Py_RETURN_NONE;
1657 }
1658
1659 TABLES_LOCK();
1660 tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
1661 TABLES_UNLOCK();
1662
1663 Py_RETURN_NONE;
1664}
1665
Victor Stinnere492ae52016-03-22 12:58:23 +01001666
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001667static PyMethodDef module_methods[] = {
Serhiy Storchakab451f912017-02-04 12:18:38 +02001668 _TRACEMALLOC_IS_TRACING_METHODDEF
1669 _TRACEMALLOC_CLEAR_TRACES_METHODDEF
1670 _TRACEMALLOC__GET_TRACES_METHODDEF
1671 _TRACEMALLOC__GET_OBJECT_TRACEBACK_METHODDEF
1672 _TRACEMALLOC_START_METHODDEF
1673 _TRACEMALLOC_STOP_METHODDEF
1674 _TRACEMALLOC_GET_TRACEBACK_LIMIT_METHODDEF
1675 _TRACEMALLOC_GET_TRACEMALLOC_MEMORY_METHODDEF
1676 _TRACEMALLOC_GET_TRACED_MEMORY_METHODDEF
Huon Wilson3c7609a2020-06-02 03:26:22 +10001677 _TRACEMALLOC_RESET_PEAK_METHODDEF
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001678 /* sentinel */
1679 {NULL, NULL}
1680};
1681
1682PyDoc_STRVAR(module_doc,
1683"Debug module to trace memory blocks allocated by Python.");
1684
1685static struct PyModuleDef module_def = {
1686 PyModuleDef_HEAD_INIT,
1687 "_tracemalloc",
1688 module_doc,
1689 0, /* non-negative size to be able to unload the module */
1690 module_methods,
1691 NULL,
1692};
1693
1694PyMODINIT_FUNC
1695PyInit__tracemalloc(void)
1696{
1697 PyObject *m;
1698 m = PyModule_Create(&module_def);
1699 if (m == NULL)
1700 return NULL;
1701
Brandt Bucherd51a3632019-11-20 02:00:31 -08001702 if (tracemalloc_init() < 0) {
1703 Py_DECREF(m);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001704 return NULL;
Brandt Bucherd51a3632019-11-20 02:00:31 -08001705 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001706
1707 return m;
1708}
1709
Victor Stinnere492ae52016-03-22 12:58:23 +01001710
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001711int
Victor Stinnera7368ac2017-11-15 18:11:45 -08001712_PyTraceMalloc_Init(int nframe)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001713{
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001714 assert(PyGILState_Check());
Victor Stinnera7368ac2017-11-15 18:11:45 -08001715 if (nframe == 0) {
1716 return 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001717 }
Victor Stinnerf28ce602013-11-27 22:27:13 +01001718 return tracemalloc_start(nframe);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001719}
1720
Victor Stinnere492ae52016-03-22 12:58:23 +01001721
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001722void
1723_PyTraceMalloc_Fini(void)
1724{
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001725 assert(PyGILState_Check());
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001726 tracemalloc_deinit();
1727}
Victor Stinner10b73e12016-03-22 13:39:05 +01001728
1729int
Victor Stinner5ea4c062017-06-20 17:46:36 +02001730PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr,
1731 size_t size)
Victor Stinner10b73e12016-03-22 13:39:05 +01001732{
1733 int res;
Victor Stinner10b73e12016-03-22 13:39:05 +01001734 PyGILState_STATE gil_state;
Victor Stinner10b73e12016-03-22 13:39:05 +01001735
Victor Stinner9e00e802018-10-25 13:31:16 +02001736 if (!_Py_tracemalloc_config.tracing) {
Victor Stinner10b73e12016-03-22 13:39:05 +01001737 /* tracemalloc is not tracing: do nothing */
1738 return -2;
1739 }
1740
Victor Stinner10b73e12016-03-22 13:39:05 +01001741 gil_state = PyGILState_Ensure();
Victor Stinner10b73e12016-03-22 13:39:05 +01001742
1743 TABLES_LOCK();
1744 res = tracemalloc_add_trace(domain, ptr, size);
1745 TABLES_UNLOCK();
1746
Victor Stinner10b73e12016-03-22 13:39:05 +01001747 PyGILState_Release(gil_state);
Victor Stinner10b73e12016-03-22 13:39:05 +01001748 return res;
1749}
1750
1751
1752int
Victor Stinner5ea4c062017-06-20 17:46:36 +02001753PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)
Victor Stinner10b73e12016-03-22 13:39:05 +01001754{
Victor Stinner9e00e802018-10-25 13:31:16 +02001755 if (!_Py_tracemalloc_config.tracing) {
Victor Stinner10b73e12016-03-22 13:39:05 +01001756 /* tracemalloc is not tracing: do nothing */
1757 return -2;
1758 }
1759
1760 TABLES_LOCK();
1761 tracemalloc_remove_trace(domain, ptr);
1762 TABLES_UNLOCK();
1763
1764 return 0;
1765}
1766
1767
Victor Stinner9e00e802018-10-25 13:31:16 +02001768/* If the object memory block is already traced, update its trace
1769 with the current Python traceback.
1770
1771 Do nothing if tracemalloc is not tracing memory allocations
1772 or if the object memory block is not already traced. */
1773int
1774_PyTraceMalloc_NewReference(PyObject *op)
1775{
1776 assert(PyGILState_Check());
1777
1778 if (!_Py_tracemalloc_config.tracing) {
1779 /* tracemalloc is not tracing: do nothing */
1780 return -1;
1781 }
1782
1783 uintptr_t ptr;
1784 PyTypeObject *type = Py_TYPE(op);
1785 if (PyType_IS_GC(type)) {
1786 ptr = (uintptr_t)((char *)op - sizeof(PyGC_Head));
1787 }
1788 else {
1789 ptr = (uintptr_t)op;
1790 }
1791
Victor Stinner9e00e802018-10-25 13:31:16 +02001792 int res = -1;
1793
1794 TABLES_LOCK();
Victor Stinner5b0a3032020-05-13 04:40:30 +02001795 trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr));
1796 if (trace != NULL) {
Victor Stinner9e00e802018-10-25 13:31:16 +02001797 /* update the traceback of the memory block */
1798 traceback_t *traceback = traceback_new();
1799 if (traceback != NULL) {
Victor Stinnerd95bd422020-05-13 03:52:11 +02001800 trace->traceback = traceback;
Victor Stinner9e00e802018-10-25 13:31:16 +02001801 res = 0;
1802 }
1803 }
1804 /* else: cannot track the object, its memory block size is unknown */
1805 TABLES_UNLOCK();
1806
1807 return res;
1808}
1809
1810
Victor Stinner10b73e12016-03-22 13:39:05 +01001811PyObject*
Victor Stinner5ea4c062017-06-20 17:46:36 +02001812_PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr)
Victor Stinner10b73e12016-03-22 13:39:05 +01001813{
1814 traceback_t *traceback;
1815
1816 traceback = tracemalloc_get_traceback(domain, ptr);
1817 if (traceback == NULL)
1818 Py_RETURN_NONE;
1819
1820 return traceback_to_pyobject(traceback, NULL);
1821}