blob: 567571657453e75c22e4d809be463ed9dc70cd26 [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 assert(filename != NULL);
323 if (filename == NULL)
324 return;
325
326 if (!PyUnicode_Check(filename)) {
327#ifdef TRACE_DEBUG
Martin Panter6245cb32016-04-15 02:14:19 +0000328 tracemalloc_error("filename is not a unicode string");
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100329#endif
330 return;
331 }
332 if (!PyUnicode_IS_READY(filename)) {
333 /* Don't make a Unicode string ready to avoid reentrant calls
334 to tracemalloc_malloc() or tracemalloc_realloc() */
335#ifdef TRACE_DEBUG
336 tracemalloc_error("filename is not a ready unicode string");
337#endif
338 return;
339 }
340
341 /* intern the filename */
Victor Stinner8852ad42020-04-29 01:28:13 +0200342 _Py_hashtable_entry_t *entry;
Victor Stinner5b0a3032020-05-13 04:40:30 +0200343 entry = _Py_hashtable_get_entry(tracemalloc_filenames, filename);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100344 if (entry != NULL) {
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200345 filename = (PyObject *)entry->key;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100346 }
347 else {
348 /* tracemalloc_filenames is responsible to keep a reference
349 to the filename */
350 Py_INCREF(filename);
Victor Stinner5b0a3032020-05-13 04:40:30 +0200351 if (_Py_hashtable_set(tracemalloc_filenames, filename, NULL) < 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100352 Py_DECREF(filename);
353#ifdef TRACE_DEBUG
354 tracemalloc_error("failed to intern the filename");
355#endif
356 return;
357 }
358 }
359
360 /* the tracemalloc_filenames table keeps a reference to the filename */
361 frame->filename = filename;
362}
363
Victor Stinnere492ae52016-03-22 12:58:23 +0100364
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100365static Py_uhash_t
366traceback_hash(traceback_t *traceback)
367{
368 /* code based on tuplehash() of Objects/tupleobject.c */
Victor Stinner4d8c29c2013-12-16 23:05:13 +0100369 Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100370 int len = traceback->nframe;
371 Py_uhash_t mult = _PyHASH_MULTIPLIER;
372 frame_t *frame;
373
374 x = 0x345678UL;
375 frame = traceback->frames;
376 while (--len >= 0) {
Victor Stinner4d8c29c2013-12-16 23:05:13 +0100377 y = (Py_uhash_t)PyObject_Hash(frame->filename);
378 y ^= (Py_uhash_t)frame->lineno;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100379 frame++;
380
381 x = (x ^ y) * mult;
382 /* the cast might truncate len; that doesn't change hash stability */
Victor Stinner4d8c29c2013-12-16 23:05:13 +0100383 mult += (Py_uhash_t)(82520UL + len + len);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100384 }
Julien Danjou8d59eb12019-10-15 14:00:16 +0200385 x ^= traceback->total_nframe;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100386 x += 97531UL;
387 return x;
388}
389
Victor Stinnere492ae52016-03-22 12:58:23 +0100390
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100391static void
392traceback_get_frames(traceback_t *traceback)
393{
Victor Stinner4386b902020-04-29 03:01:43 +0200394 PyThreadState *tstate = PyGILState_GetThisThreadState();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100395 if (tstate == NULL) {
396#ifdef TRACE_DEBUG
397 tracemalloc_error("failed to get the current thread state");
398#endif
399 return;
400 }
401
Victor Stinner4386b902020-04-29 03:01:43 +0200402 PyFrameObject *pyframe = PyThreadState_GetFrame(tstate);
Victor Stinner70364772020-04-29 03:28:46 +0200403 for (; pyframe != NULL;) {
Julien Danjou8d59eb12019-10-15 14:00:16 +0200404 if (traceback->nframe < _Py_tracemalloc_config.max_nframe) {
405 tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
406 assert(traceback->frames[traceback->nframe].filename != NULL);
407 traceback->nframe++;
408 }
Victor Stinner70364772020-04-29 03:28:46 +0200409 if (traceback->total_nframe < UINT16_MAX) {
Julien Danjou8d59eb12019-10-15 14:00:16 +0200410 traceback->total_nframe++;
Victor Stinner70364772020-04-29 03:28:46 +0200411 }
412
413 PyFrameObject *back = PyFrame_GetBack(pyframe);
414 Py_DECREF(pyframe);
415 pyframe = back;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100416 }
417}
418
Victor Stinnere492ae52016-03-22 12:58:23 +0100419
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100420static traceback_t *
421traceback_new(void)
422{
Victor Stinnerf28ce602013-11-27 22:27:13 +0100423 traceback_t *traceback;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100424 _Py_hashtable_entry_t *entry;
425
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100426 assert(PyGILState_Check());
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100427
428 /* get frames */
Victor Stinnerf28ce602013-11-27 22:27:13 +0100429 traceback = tracemalloc_traceback;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100430 traceback->nframe = 0;
Julien Danjou8d59eb12019-10-15 14:00:16 +0200431 traceback->total_nframe = 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100432 traceback_get_frames(traceback);
433 if (traceback->nframe == 0)
434 return &tracemalloc_empty_traceback;
435 traceback->hash = traceback_hash(traceback);
436
437 /* intern the traceback */
Victor Stinner5b0a3032020-05-13 04:40:30 +0200438 entry = _Py_hashtable_get_entry(tracemalloc_tracebacks, traceback);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100439 if (entry != NULL) {
Victor Stinnerf9b3b582020-05-13 02:26:02 +0200440 traceback = (traceback_t *)entry->key;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100441 }
442 else {
443 traceback_t *copy;
444 size_t traceback_size;
445
446 traceback_size = TRACEBACK_SIZE(traceback->nframe);
447
448 copy = raw_malloc(traceback_size);
449 if (copy == NULL) {
450#ifdef TRACE_DEBUG
451 tracemalloc_error("failed to intern the traceback: malloc failed");
452#endif
453 return NULL;
454 }
455 memcpy(copy, traceback, traceback_size);
456
Victor Stinner5b0a3032020-05-13 04:40:30 +0200457 if (_Py_hashtable_set(tracemalloc_tracebacks, copy, NULL) < 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100458 raw_free(copy);
459#ifdef TRACE_DEBUG
460 tracemalloc_error("failed to intern the traceback: putdata failed");
461#endif
462 return NULL;
463 }
464 traceback = copy;
465 }
466 return traceback;
467}
468
Victor Stinnere492ae52016-03-22 12:58:23 +0100469
Victor Stinner9e2ca172020-05-13 01:36:47 +0200470static _Py_hashtable_t*
471tracemalloc_create_traces_table(void)
Victor Stinner5e14a382016-03-23 22:03:55 +0100472{
Victor Stinner5b0a3032020-05-13 04:40:30 +0200473 return hashtable_new(_Py_hashtable_hash_ptr,
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200474 _Py_hashtable_compare_direct,
Victor Stinner5b0a3032020-05-13 04:40:30 +0200475 NULL, raw_free);
Victor Stinner5e14a382016-03-23 22:03:55 +0100476}
477
478
Victor Stinner9e2ca172020-05-13 01:36:47 +0200479static _Py_hashtable_t*
480tracemalloc_create_domains_table(void)
Victor Stinner5e14a382016-03-23 22:03:55 +0100481{
Victor Stinner5b0a3032020-05-13 04:40:30 +0200482 return hashtable_new(hashtable_hash_uint,
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200483 _Py_hashtable_compare_direct,
Victor Stinner5b0a3032020-05-13 04:40:30 +0200484 NULL,
485 (_Py_hashtable_destroy_func)_Py_hashtable_destroy);
Victor Stinner9e2ca172020-05-13 01:36:47 +0200486}
487
488
489static _Py_hashtable_t*
490tracemalloc_get_traces_table(unsigned int domain)
491{
492 if (domain == DEFAULT_DOMAIN) {
493 return tracemalloc_traces;
494 }
495 else {
Victor Stinner5b0a3032020-05-13 04:40:30 +0200496 return _Py_hashtable_get(tracemalloc_domains, TO_PTR(domain));
Victor Stinner9e2ca172020-05-13 01:36:47 +0200497 }
498}
499
500
501static void
Victor Stinner5ea4c062017-06-20 17:46:36 +0200502tracemalloc_remove_trace(unsigned int domain, uintptr_t ptr)
Victor Stinnere492ae52016-03-22 12:58:23 +0100503{
Victor Stinner9e00e802018-10-25 13:31:16 +0200504 assert(_Py_tracemalloc_config.tracing);
Victor Stinner10b73e12016-03-22 13:39:05 +0100505
Victor Stinner9e2ca172020-05-13 01:36:47 +0200506 _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
507 if (!traces) {
Victor Stinnere492ae52016-03-22 12:58:23 +0100508 return;
509 }
510
Victor Stinner5b0a3032020-05-13 04:40:30 +0200511 trace_t *trace = _Py_hashtable_steal(traces, TO_PTR(ptr));
512 if (!trace) {
Victor Stinner9e2ca172020-05-13 01:36:47 +0200513 return;
514 }
Victor Stinnerd95bd422020-05-13 03:52:11 +0200515 assert(tracemalloc_traced_memory >= trace->size);
516 tracemalloc_traced_memory -= trace->size;
517 raw_free(trace);
Victor Stinnere492ae52016-03-22 12:58:23 +0100518}
519
520#define REMOVE_TRACE(ptr) \
Benjamin Petersonca470632016-09-06 13:47:26 -0700521 tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr))
Victor Stinnere492ae52016-03-22 12:58:23 +0100522
523
Victor Stinner52968672013-11-24 11:37:15 +0100524static int
Victor Stinner5ea4c062017-06-20 17:46:36 +0200525tracemalloc_add_trace(unsigned int domain, uintptr_t ptr,
Victor Stinner10b73e12016-03-22 13:39:05 +0100526 size_t size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100527{
Victor Stinner9e00e802018-10-25 13:31:16 +0200528 assert(_Py_tracemalloc_config.tracing);
Victor Stinner10b73e12016-03-22 13:39:05 +0100529
Victor Stinner9e2ca172020-05-13 01:36:47 +0200530 traceback_t *traceback = traceback_new();
Victor Stinnere492ae52016-03-22 12:58:23 +0100531 if (traceback == NULL) {
Victor Stinner52968672013-11-24 11:37:15 +0100532 return -1;
Victor Stinnere492ae52016-03-22 12:58:23 +0100533 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100534
Victor Stinner9e2ca172020-05-13 01:36:47 +0200535 _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
536 if (traces == NULL) {
537 traces = tracemalloc_create_traces_table();
538 if (traces == NULL) {
539 return -1;
540 }
541
Victor Stinner5b0a3032020-05-13 04:40:30 +0200542 if (_Py_hashtable_set(tracemalloc_domains, TO_PTR(domain), traces) < 0) {
Victor Stinner9e2ca172020-05-13 01:36:47 +0200543 _Py_hashtable_destroy(traces);
Victor Stinner5e14a382016-03-23 22:03:55 +0100544 return -1;
545 }
546 }
547
Victor Stinner5b0a3032020-05-13 04:40:30 +0200548 trace_t *trace = _Py_hashtable_get(traces, TO_PTR(ptr));
549 if (trace != NULL) {
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100550 /* the memory block is already tracked */
Victor Stinnerd95bd422020-05-13 03:52:11 +0200551 assert(tracemalloc_traced_memory >= trace->size);
552 tracemalloc_traced_memory -= trace->size;
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100553
Victor Stinnerd95bd422020-05-13 03:52:11 +0200554 trace->size = size;
555 trace->traceback = traceback;
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100556 }
557 else {
Victor Stinner5b0a3032020-05-13 04:40:30 +0200558 trace = raw_malloc(sizeof(trace_t));
Victor Stinnerd95bd422020-05-13 03:52:11 +0200559 if (trace == NULL) {
560 return -1;
561 }
562 trace->size = size;
563 trace->traceback = traceback;
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100564
Victor Stinner5b0a3032020-05-13 04:40:30 +0200565 int res = _Py_hashtable_set(traces, TO_PTR(ptr), trace);
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100566 if (res != 0) {
Victor Stinnerd95bd422020-05-13 03:52:11 +0200567 raw_free(trace);
Victor Stinnerca79ccd2016-03-23 09:38:54 +0100568 return res;
569 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100570 }
Victor Stinnere492ae52016-03-22 12:58:23 +0100571
Benjamin Peterson2f8bfef2016-09-07 09:26:18 -0700572 assert(tracemalloc_traced_memory <= SIZE_MAX - size);
Victor Stinnere492ae52016-03-22 12:58:23 +0100573 tracemalloc_traced_memory += size;
Victor Stinner9e2ca172020-05-13 01:36:47 +0200574 if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory) {
Victor Stinnere492ae52016-03-22 12:58:23 +0100575 tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
Victor Stinner9e2ca172020-05-13 01:36:47 +0200576 }
Victor Stinnere492ae52016-03-22 12:58:23 +0100577 return 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100578}
579
Victor Stinnere492ae52016-03-22 12:58:23 +0100580#define ADD_TRACE(ptr, size) \
Benjamin Petersonca470632016-09-06 13:47:26 -0700581 tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size)
Victor Stinnere492ae52016-03-22 12:58:23 +0100582
583
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100584static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200585tracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100586{
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200587 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100588 void *ptr;
589
Benjamin Peterson2f8bfef2016-09-07 09:26:18 -0700590 assert(elsize == 0 || nelem <= SIZE_MAX / elsize);
Victor Stinnerdb067af2014-05-02 22:31:14 +0200591
592 if (use_calloc)
593 ptr = alloc->calloc(alloc->ctx, nelem, elsize);
594 else
595 ptr = alloc->malloc(alloc->ctx, nelem * elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100596 if (ptr == NULL)
597 return NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100598
Victor Stinner88c29872013-12-04 01:47:46 +0100599 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100600 if (ADD_TRACE(ptr, nelem * elsize) < 0) {
Victor Stinner15116802013-12-04 01:29:35 +0100601 /* Failed to allocate a trace for the new memory block */
Victor Stinner88c29872013-12-04 01:47:46 +0100602 TABLES_UNLOCK();
Victor Stinner15116802013-12-04 01:29:35 +0100603 alloc->free(alloc->ctx, ptr);
604 return NULL;
Victor Stinner52968672013-11-24 11:37:15 +0100605 }
Victor Stinner88c29872013-12-04 01:47:46 +0100606 TABLES_UNLOCK();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100607 return ptr;
608}
609
Victor Stinnere492ae52016-03-22 12:58:23 +0100610
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100611static void*
Victor Stinner15116802013-12-04 01:29:35 +0100612tracemalloc_realloc(void *ctx, void *ptr, size_t new_size)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100613{
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200614 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100615 void *ptr2;
616
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100617 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
Victor Stinner15116802013-12-04 01:29:35 +0100618 if (ptr2 == NULL)
619 return NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100620
Victor Stinner15116802013-12-04 01:29:35 +0100621 if (ptr != NULL) {
622 /* an existing memory block has been resized */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100623
Victor Stinner88c29872013-12-04 01:47:46 +0100624 TABLES_LOCK();
Victor Stinner42bcf372016-03-23 09:08:08 +0100625
626 /* tracemalloc_add_trace() updates the trace if there is already
Victor Stinner9e2ca172020-05-13 01:36:47 +0200627 a trace at address ptr2 */
Victor Stinner42bcf372016-03-23 09:08:08 +0100628 if (ptr2 != ptr) {
629 REMOVE_TRACE(ptr);
630 }
Victor Stinner08facd22013-11-24 12:27:59 +0100631
Victor Stinnere492ae52016-03-22 12:58:23 +0100632 if (ADD_TRACE(ptr2, new_size) < 0) {
Victor Stinner15116802013-12-04 01:29:35 +0100633 /* Memory allocation failed. The error cannot be reported to
Raymond Hettinger15f44ab2016-08-30 10:47:49 -0700634 the caller, because realloc() may already have shrunk the
Victor Stinner15116802013-12-04 01:29:35 +0100635 memory block and so removed bytes.
636
Serhiy Storchaka6a7b3a72016-04-17 08:32:47 +0300637 This case is very unlikely: a hash entry has just been
Victor Stinner88c29872013-12-04 01:47:46 +0100638 released, so the hash table should have at least one free entry.
639
640 The GIL and the table lock ensures that only one thread is
641 allocating memory. */
Serhiy Storchakaeebaa9b2020-03-09 20:49:52 +0200642 Py_FatalError("tracemalloc_realloc() failed to allocate a trace");
Victor Stinner52968672013-11-24 11:37:15 +0100643 }
Victor Stinner88c29872013-12-04 01:47:46 +0100644 TABLES_UNLOCK();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100645 }
Victor Stinner15116802013-12-04 01:29:35 +0100646 else {
647 /* new allocation */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100648
Victor Stinner88c29872013-12-04 01:47:46 +0100649 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100650 if (ADD_TRACE(ptr2, new_size) < 0) {
Victor Stinner15116802013-12-04 01:29:35 +0100651 /* Failed to allocate a trace for the new memory block */
Victor Stinner88c29872013-12-04 01:47:46 +0100652 TABLES_UNLOCK();
Victor Stinner15116802013-12-04 01:29:35 +0100653 alloc->free(alloc->ctx, ptr2);
654 return NULL;
655 }
Victor Stinner88c29872013-12-04 01:47:46 +0100656 TABLES_UNLOCK();
Victor Stinner15116802013-12-04 01:29:35 +0100657 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100658 return ptr2;
659}
660
Victor Stinnere492ae52016-03-22 12:58:23 +0100661
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100662static void
663tracemalloc_free(void *ctx, void *ptr)
664{
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200665 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100666
667 if (ptr == NULL)
668 return;
669
670 /* GIL cannot be locked in PyMem_RawFree() because it would introduce
Joannah Nanjekye2bc43cd2019-09-05 13:06:49 -0300671 a deadlock in _PyThreadState_DeleteCurrent(). */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100672
673 alloc->free(alloc->ctx, ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100674
675 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100676 REMOVE_TRACE(ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100677 TABLES_UNLOCK();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100678}
679
Victor Stinnere492ae52016-03-22 12:58:23 +0100680
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100681static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200682tracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100683{
Victor Stinner15116802013-12-04 01:29:35 +0100684 void *ptr;
685
686 if (get_reentrant()) {
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200687 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnerdb067af2014-05-02 22:31:14 +0200688 if (use_calloc)
689 return alloc->calloc(alloc->ctx, nelem, elsize);
690 else
691 return alloc->malloc(alloc->ctx, nelem * elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100692 }
693
694 /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for
695 allocations larger than 512 bytes, don't trace the same memory
696 allocation twice. */
697 set_reentrant(1);
698
Victor Stinnerdb067af2014-05-02 22:31:14 +0200699 ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100700
701 set_reentrant(0);
702 return ptr;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100703}
704
Victor Stinnere492ae52016-03-22 12:58:23 +0100705
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100706static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200707tracemalloc_malloc_gil(void *ctx, size_t size)
708{
709 return tracemalloc_alloc_gil(0, ctx, 1, size);
710}
711
Victor Stinnere492ae52016-03-22 12:58:23 +0100712
Victor Stinnerdb067af2014-05-02 22:31:14 +0200713static void*
714tracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize)
715{
716 return tracemalloc_alloc_gil(1, ctx, nelem, elsize);
717}
718
Victor Stinnere492ae52016-03-22 12:58:23 +0100719
Victor Stinnerdb067af2014-05-02 22:31:14 +0200720static void*
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100721tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
722{
Victor Stinner15116802013-12-04 01:29:35 +0100723 void *ptr2;
724
725 if (get_reentrant()) {
726 /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc().
727 Example: PyMem_RawRealloc() is called internally by pymalloc
728 (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new
729 arena (new_arena()). */
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200730 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinner15116802013-12-04 01:29:35 +0100731
732 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
Victor Stinner88c29872013-12-04 01:47:46 +0100733 if (ptr2 != NULL && ptr != NULL) {
734 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100735 REMOVE_TRACE(ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100736 TABLES_UNLOCK();
737 }
Victor Stinner15116802013-12-04 01:29:35 +0100738 return ptr2;
739 }
740
741 /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for
742 allocations larger than 512 bytes. Don't trace the same memory
743 allocation twice. */
744 set_reentrant(1);
745
746 ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
747
748 set_reentrant(0);
749 return ptr2;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100750}
751
Victor Stinnere492ae52016-03-22 12:58:23 +0100752
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100753#ifdef TRACE_RAW_MALLOC
754static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200755tracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100756{
Victor Stinner15116802013-12-04 01:29:35 +0100757 PyGILState_STATE gil_state;
Victor Stinner15116802013-12-04 01:29:35 +0100758 void *ptr;
759
760 if (get_reentrant()) {
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200761 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinnerdb067af2014-05-02 22:31:14 +0200762 if (use_calloc)
763 return alloc->calloc(alloc->ctx, nelem, elsize);
764 else
765 return alloc->malloc(alloc->ctx, nelem * elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100766 }
767
768 /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
769 indirectly which would call PyGILState_Ensure() if reentrant are not
770 disabled. */
771 set_reentrant(1);
772
Victor Stinner15116802013-12-04 01:29:35 +0100773 gil_state = PyGILState_Ensure();
Victor Stinnerdb067af2014-05-02 22:31:14 +0200774 ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize);
Victor Stinner15116802013-12-04 01:29:35 +0100775 PyGILState_Release(gil_state);
Victor Stinner15116802013-12-04 01:29:35 +0100776
777 set_reentrant(0);
778 return ptr;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100779}
780
Victor Stinnere492ae52016-03-22 12:58:23 +0100781
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100782static void*
Victor Stinnerdb067af2014-05-02 22:31:14 +0200783tracemalloc_raw_malloc(void *ctx, size_t size)
784{
785 return tracemalloc_raw_alloc(0, ctx, 1, size);
786}
787
Victor Stinnere492ae52016-03-22 12:58:23 +0100788
Victor Stinnerdb067af2014-05-02 22:31:14 +0200789static void*
790tracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize)
791{
792 return tracemalloc_raw_alloc(1, ctx, nelem, elsize);
793}
794
Victor Stinnere492ae52016-03-22 12:58:23 +0100795
Victor Stinnerdb067af2014-05-02 22:31:14 +0200796static void*
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100797tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
798{
Victor Stinner15116802013-12-04 01:29:35 +0100799 PyGILState_STATE gil_state;
Victor Stinner15116802013-12-04 01:29:35 +0100800 void *ptr2;
801
802 if (get_reentrant()) {
803 /* Reentrant call to PyMem_RawRealloc(). */
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200804 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx;
Victor Stinner15116802013-12-04 01:29:35 +0100805
806 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
Victor Stinner15116802013-12-04 01:29:35 +0100807
Victor Stinner88c29872013-12-04 01:47:46 +0100808 if (ptr2 != NULL && ptr != NULL) {
809 TABLES_LOCK();
Victor Stinnere492ae52016-03-22 12:58:23 +0100810 REMOVE_TRACE(ptr);
Victor Stinner88c29872013-12-04 01:47:46 +0100811 TABLES_UNLOCK();
812 }
Victor Stinner15116802013-12-04 01:29:35 +0100813 return ptr2;
814 }
815
816 /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
817 indirectly which would call PyGILState_Ensure() if reentrant calls are
818 not disabled. */
819 set_reentrant(1);
820
Victor Stinner15116802013-12-04 01:29:35 +0100821 gil_state = PyGILState_Ensure();
822 ptr2 = tracemalloc_realloc(ctx, ptr, new_size);
823 PyGILState_Release(gil_state);
Victor Stinner15116802013-12-04 01:29:35 +0100824
825 set_reentrant(0);
826 return ptr2;
827}
828#endif /* TRACE_RAW_MALLOC */
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100829
Victor Stinnere492ae52016-03-22 12:58:23 +0100830
Victor Stinner5b0a3032020-05-13 04:40:30 +0200831static void
832tracemalloc_clear_filename(void *value)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100833{
Victor Stinner5b0a3032020-05-13 04:40:30 +0200834 PyObject *filename = (PyObject *)value;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100835 Py_DECREF(filename);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100836}
837
Victor Stinnere492ae52016-03-22 12:58:23 +0100838
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100839/* reentrant flag must be set to call this function and GIL must be held */
840static void
841tracemalloc_clear_traces(void)
842{
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100843 /* The GIL protects variables againt concurrent access */
844 assert(PyGILState_Check());
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100845
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100846 TABLES_LOCK();
847 _Py_hashtable_clear(tracemalloc_traces);
Victor Stinner9e2ca172020-05-13 01:36:47 +0200848 _Py_hashtable_clear(tracemalloc_domains);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100849 tracemalloc_traced_memory = 0;
Victor Stinner3c0481d2013-11-27 21:39:49 +0100850 tracemalloc_peak_traced_memory = 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100851 TABLES_UNLOCK();
852
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100853 _Py_hashtable_clear(tracemalloc_tracebacks);
854
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100855 _Py_hashtable_clear(tracemalloc_filenames);
856}
857
Victor Stinnere492ae52016-03-22 12:58:23 +0100858
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100859static int
860tracemalloc_init(void)
861{
Victor Stinner9e00e802018-10-25 13:31:16 +0200862 if (_Py_tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100863 PyErr_SetString(PyExc_RuntimeError,
864 "the tracemalloc module has been unloaded");
865 return -1;
866 }
867
Victor Stinner9e00e802018-10-25 13:31:16 +0200868 if (_Py_tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100869 return 0;
870
871 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
872
873#ifdef REENTRANT_THREADLOCAL
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900874 if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100875#ifdef MS_WINDOWS
876 PyErr_SetFromWindowsErr(0);
877#else
878 PyErr_SetFromErrno(PyExc_OSError);
879#endif
880 return -1;
881 }
882#endif
883
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200884#if defined(TRACE_RAW_MALLOC)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100885 if (tables_lock == NULL) {
886 tables_lock = PyThread_allocate_lock();
887 if (tables_lock == NULL) {
888 PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock");
889 return -1;
890 }
891 }
892#endif
893
Victor Stinner5b0a3032020-05-13 04:40:30 +0200894 tracemalloc_filenames = hashtable_new(hashtable_hash_pyobject,
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200895 hashtable_compare_unicode,
Victor Stinner5b0a3032020-05-13 04:40:30 +0200896 tracemalloc_clear_filename, NULL);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100897
Victor Stinner5b0a3032020-05-13 04:40:30 +0200898 tracemalloc_tracebacks = hashtable_new(hashtable_hash_traceback,
Victor Stinner2d0a3d62020-05-13 02:50:18 +0200899 hashtable_compare_traceback,
Victor Stinner5b0a3032020-05-13 04:40:30 +0200900 NULL, raw_free);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100901
Victor Stinner9e2ca172020-05-13 01:36:47 +0200902 tracemalloc_traces = tracemalloc_create_traces_table();
903 tracemalloc_domains = tracemalloc_create_domains_table();
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100904
905 if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL
Victor Stinner9e2ca172020-05-13 01:36:47 +0200906 || tracemalloc_traces == NULL || tracemalloc_domains == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100907 PyErr_NoMemory();
908 return -1;
909 }
910
911 unknown_filename = PyUnicode_FromString("<unknown>");
912 if (unknown_filename == NULL)
913 return -1;
914 PyUnicode_InternInPlace(&unknown_filename);
915
916 tracemalloc_empty_traceback.nframe = 1;
Julien Danjou8d59eb12019-10-15 14:00:16 +0200917 tracemalloc_empty_traceback.total_nframe = 1;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100918 /* borrowed reference */
919 tracemalloc_empty_traceback.frames[0].filename = unknown_filename;
920 tracemalloc_empty_traceback.frames[0].lineno = 0;
921 tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback);
922
Victor Stinner9e00e802018-10-25 13:31:16 +0200923 _Py_tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100924 return 0;
925}
926
Victor Stinnere492ae52016-03-22 12:58:23 +0100927
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100928static void
929tracemalloc_deinit(void)
930{
Victor Stinner9e00e802018-10-25 13:31:16 +0200931 if (_Py_tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100932 return;
Victor Stinner9e00e802018-10-25 13:31:16 +0200933 _Py_tracemalloc_config.initialized = TRACEMALLOC_FINALIZED;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100934
935 tracemalloc_stop();
936
937 /* destroy hash tables */
Victor Stinner5b0a3032020-05-13 04:40:30 +0200938 _Py_hashtable_destroy(tracemalloc_domains);
Victor Stinner9e2ca172020-05-13 01:36:47 +0200939 _Py_hashtable_destroy(tracemalloc_traces);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100940 _Py_hashtable_destroy(tracemalloc_tracebacks);
941 _Py_hashtable_destroy(tracemalloc_filenames);
942
Antoine Pitroua6a4dc82017-09-07 18:56:24 +0200943#if defined(TRACE_RAW_MALLOC)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100944 if (tables_lock != NULL) {
945 PyThread_free_lock(tables_lock);
946 tables_lock = NULL;
947 }
948#endif
949
950#ifdef REENTRANT_THREADLOCAL
Masayuki Yamamoto731e1892017-10-06 19:41:34 +0900951 PyThread_tss_delete(&tracemalloc_reentrant_key);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100952#endif
953
954 Py_XDECREF(unknown_filename);
955}
956
Victor Stinnere492ae52016-03-22 12:58:23 +0100957
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100958static int
Victor Stinnerf28ce602013-11-27 22:27:13 +0100959tracemalloc_start(int max_nframe)
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100960{
Victor Stinnerd8f0d922014-06-02 21:57:10 +0200961 PyMemAllocatorEx alloc;
Victor Stinnerf28ce602013-11-27 22:27:13 +0100962 size_t size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100963
Julien Danjou8d59eb12019-10-15 14:00:16 +0200964 if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) {
Victor Stinnera7368ac2017-11-15 18:11:45 -0800965 PyErr_Format(PyExc_ValueError,
Julien Danjou8d59eb12019-10-15 14:00:16 +0200966 "the number of frames must be in range [1; %lu]",
967 MAX_NFRAME);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100968 return -1;
Victor Stinnera7368ac2017-11-15 18:11:45 -0800969 }
970
971 if (tracemalloc_init() < 0) {
972 return -1;
973 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100974
Victor Stinner9e00e802018-10-25 13:31:16 +0200975 if (_Py_tracemalloc_config.tracing) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100976 /* hook already installed: do nothing */
977 return 0;
978 }
979
Victor Stinner9e00e802018-10-25 13:31:16 +0200980 _Py_tracemalloc_config.max_nframe = max_nframe;
Victor Stinnerf28ce602013-11-27 22:27:13 +0100981
982 /* allocate a buffer to store a new traceback */
983 size = TRACEBACK_SIZE(max_nframe);
984 assert(tracemalloc_traceback == NULL);
985 tracemalloc_traceback = raw_malloc(size);
986 if (tracemalloc_traceback == NULL) {
987 PyErr_NoMemory();
988 return -1;
989 }
990
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100991#ifdef TRACE_RAW_MALLOC
992 alloc.malloc = tracemalloc_raw_malloc;
Victor Stinnerdb067af2014-05-02 22:31:14 +0200993 alloc.calloc = tracemalloc_raw_calloc;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100994 alloc.realloc = tracemalloc_raw_realloc;
995 alloc.free = tracemalloc_free;
996
997 alloc.ctx = &allocators.raw;
998 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
999 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
1000#endif
1001
1002 alloc.malloc = tracemalloc_malloc_gil;
Victor Stinnerdb067af2014-05-02 22:31:14 +02001003 alloc.calloc = tracemalloc_calloc_gil;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001004 alloc.realloc = tracemalloc_realloc_gil;
1005 alloc.free = tracemalloc_free;
1006
1007 alloc.ctx = &allocators.mem;
1008 PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
1009 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
1010
1011 alloc.ctx = &allocators.obj;
1012 PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
1013 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc);
1014
1015 /* everything is ready: start tracing Python memory allocations */
Victor Stinner9e00e802018-10-25 13:31:16 +02001016 _Py_tracemalloc_config.tracing = 1;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001017
1018 return 0;
1019}
1020
Victor Stinnere492ae52016-03-22 12:58:23 +01001021
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001022static void
1023tracemalloc_stop(void)
1024{
Victor Stinner9e00e802018-10-25 13:31:16 +02001025 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001026 return;
1027
1028 /* stop tracing Python memory allocations */
Victor Stinner9e00e802018-10-25 13:31:16 +02001029 _Py_tracemalloc_config.tracing = 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001030
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001031 /* unregister the hook on memory allocators */
1032#ifdef TRACE_RAW_MALLOC
1033 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
1034#endif
1035 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
1036 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
1037
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001038 tracemalloc_clear_traces();
Victor Stinner285cf0a2016-03-21 22:00:58 +01001039
1040 /* release memory */
Victor Stinnerf28ce602013-11-27 22:27:13 +01001041 raw_free(tracemalloc_traceback);
1042 tracemalloc_traceback = NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001043}
1044
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001045
Victor Stinnere492ae52016-03-22 12:58:23 +01001046
Serhiy Storchakab451f912017-02-04 12:18:38 +02001047/*[clinic input]
1048_tracemalloc.is_tracing
1049
1050Return True if the tracemalloc module is tracing Python memory allocations.
1051[clinic start generated code]*/
1052
1053static PyObject *
1054_tracemalloc_is_tracing_impl(PyObject *module)
Serhiy Storchaka97353842017-02-05 22:58:46 +02001055/*[clinic end generated code: output=2d763b42601cd3ef input=af104b0a00192f63]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001056{
Victor Stinner9e00e802018-10-25 13:31:16 +02001057 return PyBool_FromLong(_Py_tracemalloc_config.tracing);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001058}
1059
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001060
Serhiy Storchakab451f912017-02-04 12:18:38 +02001061/*[clinic input]
1062_tracemalloc.clear_traces
Victor Stinnere492ae52016-03-22 12:58:23 +01001063
Serhiy Storchakab451f912017-02-04 12:18:38 +02001064Clear traces of memory blocks allocated by Python.
1065[clinic start generated code]*/
1066
1067static PyObject *
1068_tracemalloc_clear_traces_impl(PyObject *module)
1069/*[clinic end generated code: output=a86080ee41b84197 input=0dab5b6c785183a5]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001070{
Victor Stinner9e00e802018-10-25 13:31:16 +02001071 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001072 Py_RETURN_NONE;
1073
1074 set_reentrant(1);
1075 tracemalloc_clear_traces();
1076 set_reentrant(0);
1077
1078 Py_RETURN_NONE;
1079}
1080
Victor Stinnere492ae52016-03-22 12:58:23 +01001081
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001082static PyObject*
1083frame_to_pyobject(frame_t *frame)
1084{
1085 PyObject *frame_obj, *lineno_obj;
1086
1087 frame_obj = PyTuple_New(2);
1088 if (frame_obj == NULL)
1089 return NULL;
1090
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001091 Py_INCREF(frame->filename);
1092 PyTuple_SET_ITEM(frame_obj, 0, frame->filename);
1093
Victor Stinner95283342016-03-15 21:57:02 +01001094 lineno_obj = PyLong_FromUnsignedLong(frame->lineno);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001095 if (lineno_obj == NULL) {
1096 Py_DECREF(frame_obj);
1097 return NULL;
1098 }
1099 PyTuple_SET_ITEM(frame_obj, 1, lineno_obj);
1100
1101 return frame_obj;
1102}
1103
Victor Stinnere492ae52016-03-22 12:58:23 +01001104
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001105static PyObject*
1106traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table)
1107{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001108 PyObject *frames;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001109
1110 if (intern_table != NULL) {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001111 frames = _Py_hashtable_get(intern_table, (const void *)traceback);
1112 if (frames) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001113 Py_INCREF(frames);
1114 return frames;
1115 }
1116 }
1117
1118 frames = PyTuple_New(traceback->nframe);
1119 if (frames == NULL)
1120 return NULL;
1121
Victor Stinner5b0a3032020-05-13 04:40:30 +02001122 for (int i=0; i < traceback->nframe; i++) {
1123 PyObject *frame = frame_to_pyobject(&traceback->frames[i]);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001124 if (frame == NULL) {
1125 Py_DECREF(frames);
1126 return NULL;
1127 }
1128 PyTuple_SET_ITEM(frames, i, frame);
1129 }
1130
1131 if (intern_table != NULL) {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001132 if (_Py_hashtable_set(intern_table, traceback, frames) < 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001133 Py_DECREF(frames);
1134 PyErr_NoMemory();
1135 return NULL;
1136 }
1137 /* intern_table keeps a new reference to frames */
1138 Py_INCREF(frames);
1139 }
1140 return frames;
1141}
1142
Victor Stinnere492ae52016-03-22 12:58:23 +01001143
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001144static PyObject*
Victor Stinner5b0a3032020-05-13 04:40:30 +02001145trace_to_pyobject(unsigned int domain, const trace_t *trace,
Victor Stinnere492ae52016-03-22 12:58:23 +01001146 _Py_hashtable_t *intern_tracebacks)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001147{
1148 PyObject *trace_obj = NULL;
Victor Stinnere492ae52016-03-22 12:58:23 +01001149 PyObject *obj;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001150
Julien Danjou8d59eb12019-10-15 14:00:16 +02001151 trace_obj = PyTuple_New(4);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001152 if (trace_obj == NULL)
1153 return NULL;
1154
Victor Stinnere492ae52016-03-22 12:58:23 +01001155 obj = PyLong_FromSize_t(domain);
1156 if (obj == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001157 Py_DECREF(trace_obj);
1158 return NULL;
1159 }
Victor Stinnere492ae52016-03-22 12:58:23 +01001160 PyTuple_SET_ITEM(trace_obj, 0, obj);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001161
Victor Stinnere492ae52016-03-22 12:58:23 +01001162 obj = PyLong_FromSize_t(trace->size);
1163 if (obj == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001164 Py_DECREF(trace_obj);
1165 return NULL;
1166 }
Victor Stinnere492ae52016-03-22 12:58:23 +01001167 PyTuple_SET_ITEM(trace_obj, 1, obj);
1168
1169 obj = traceback_to_pyobject(trace->traceback, intern_tracebacks);
1170 if (obj == NULL) {
1171 Py_DECREF(trace_obj);
1172 return NULL;
1173 }
1174 PyTuple_SET_ITEM(trace_obj, 2, obj);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001175
Julien Danjou8d59eb12019-10-15 14:00:16 +02001176 obj = PyLong_FromUnsignedLong(trace->traceback->total_nframe);
1177 if (obj == NULL) {
1178 Py_DECREF(trace_obj);
1179 return NULL;
1180 }
1181 PyTuple_SET_ITEM(trace_obj, 3, obj);
1182
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001183 return trace_obj;
1184}
1185
Victor Stinnere492ae52016-03-22 12:58:23 +01001186
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001187typedef struct {
1188 _Py_hashtable_t *traces;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001189 _Py_hashtable_t *domains;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001190 _Py_hashtable_t *tracebacks;
1191 PyObject *list;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001192 unsigned int domain;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001193} get_traces_t;
1194
Victor Stinnerd95bd422020-05-13 03:52:11 +02001195
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001196static int
Victor Stinnerd95bd422020-05-13 03:52:11 +02001197tracemalloc_copy_trace(_Py_hashtable_t *traces,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001198 const void *key, const void *value,
1199 void *user_data)
Victor Stinner9e2ca172020-05-13 01:36:47 +02001200{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001201 _Py_hashtable_t *traces2 = (_Py_hashtable_t *)user_data;
Victor Stinnerd95bd422020-05-13 03:52:11 +02001202
Victor Stinner5b0a3032020-05-13 04:40:30 +02001203 trace_t *trace = (trace_t *)value;
Victor Stinnerd95bd422020-05-13 03:52:11 +02001204
1205 trace_t *trace2 = raw_malloc(sizeof(trace_t));
1206 if (traces2 == NULL) {
1207 return -1;
1208 }
1209 *trace2 = *trace;
Victor Stinner5b0a3032020-05-13 04:40:30 +02001210 if (_Py_hashtable_set(traces2, key, trace2) < 0) {
Victor Stinnerd95bd422020-05-13 03:52:11 +02001211 raw_free(trace2);
1212 return -1;
1213 }
1214 return 0;
1215}
1216
1217
1218static _Py_hashtable_t*
1219tracemalloc_copy_traces(_Py_hashtable_t *traces)
1220{
1221 _Py_hashtable_t *traces2 = tracemalloc_create_traces_table();
1222 if (traces2 == NULL) {
1223 return NULL;
1224 }
1225
1226 int err = _Py_hashtable_foreach(traces,
1227 tracemalloc_copy_trace,
1228 traces2);
1229 if (err) {
1230 _Py_hashtable_destroy(traces2);
1231 return NULL;
1232 }
1233 return traces2;
1234}
1235
1236
1237static int
1238tracemalloc_copy_domain(_Py_hashtable_t *domains,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001239 const void *key, const void *value,
1240 void *user_data)
Victor Stinnerd95bd422020-05-13 03:52:11 +02001241{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001242 _Py_hashtable_t *domains2 = (_Py_hashtable_t *)user_data;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001243
Victor Stinner5b0a3032020-05-13 04:40:30 +02001244 unsigned int domain = (unsigned int)FROM_PTR(key);
1245 _Py_hashtable_t *traces = (_Py_hashtable_t *)value;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001246
Victor Stinnerd95bd422020-05-13 03:52:11 +02001247 _Py_hashtable_t *traces2 = tracemalloc_copy_traces(traces);
Victor Stinner5b0a3032020-05-13 04:40:30 +02001248 if (_Py_hashtable_set(domains2, TO_PTR(domain), traces2) < 0) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001249 _Py_hashtable_destroy(traces2);
1250 return -1;
1251 }
1252 return 0;
1253}
1254
1255
Victor Stinnerd95bd422020-05-13 03:52:11 +02001256static _Py_hashtable_t*
1257tracemalloc_copy_domains(_Py_hashtable_t *domains)
1258{
1259 _Py_hashtable_t *domains2 = tracemalloc_create_domains_table();
1260 if (domains2 == NULL) {
1261 return NULL;
1262 }
1263
1264 int err = _Py_hashtable_foreach(domains,
1265 tracemalloc_copy_domain,
1266 domains2);
1267 if (err) {
1268 _Py_hashtable_destroy(domains2);
1269 return NULL;
1270 }
1271 return domains2;
1272}
1273
1274
Victor Stinner9e2ca172020-05-13 01:36:47 +02001275static int
Victor Stinner5b0a3032020-05-13 04:40:30 +02001276tracemalloc_get_traces_fill(_Py_hashtable_t *traces,
1277 const void *key, const void *value,
Victor Stinner285cf0a2016-03-21 22:00:58 +01001278 void *user_data)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001279{
1280 get_traces_t *get_traces = user_data;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001281
Victor Stinner5b0a3032020-05-13 04:40:30 +02001282 const trace_t *trace = (const trace_t *)value;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001283
Victor Stinner5b0a3032020-05-13 04:40:30 +02001284 PyObject *tuple = trace_to_pyobject(get_traces->domain, trace,
1285 get_traces->tracebacks);
1286 if (tuple == NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001287 return 1;
Victor Stinner5b0a3032020-05-13 04:40:30 +02001288 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001289
Victor Stinner5b0a3032020-05-13 04:40:30 +02001290 int res = PyList_Append(get_traces->list, tuple);
1291 Py_DECREF(tuple);
1292 if (res < 0) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001293 return 1;
Victor Stinner5b0a3032020-05-13 04:40:30 +02001294 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001295
1296 return 0;
1297}
1298
Victor Stinnere492ae52016-03-22 12:58:23 +01001299
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001300static int
Victor Stinner9e2ca172020-05-13 01:36:47 +02001301tracemalloc_get_traces_domain(_Py_hashtable_t *domains,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001302 const void *key, const void *value,
Victor Stinner9e2ca172020-05-13 01:36:47 +02001303 void *user_data)
1304{
1305 get_traces_t *get_traces = user_data;
1306
Victor Stinner5b0a3032020-05-13 04:40:30 +02001307 unsigned int domain = (unsigned int)FROM_PTR(key);
1308 _Py_hashtable_t *traces = (_Py_hashtable_t *)value;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001309
1310 get_traces->domain = domain;
1311 return _Py_hashtable_foreach(traces,
1312 tracemalloc_get_traces_fill,
1313 get_traces);
1314}
1315
1316
Victor Stinner2d0a3d62020-05-13 02:50:18 +02001317static void
Victor Stinner5b0a3032020-05-13 04:40:30 +02001318tracemalloc_pyobject_decref(void *value)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001319{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001320 PyObject *obj = (PyObject *)value;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001321 Py_DECREF(obj);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001322}
1323
Victor Stinnere492ae52016-03-22 12:58:23 +01001324
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001325
Serhiy Storchakab451f912017-02-04 12:18:38 +02001326/*[clinic input]
1327_tracemalloc._get_traces
1328
1329Get traces of all memory blocks allocated by Python.
1330
1331Return a list of (size: int, traceback: tuple) tuples.
1332traceback is a tuple of (filename: str, lineno: int) tuples.
1333
1334Return an empty list if the tracemalloc module is disabled.
1335[clinic start generated code]*/
1336
1337static PyObject *
1338_tracemalloc__get_traces_impl(PyObject *module)
1339/*[clinic end generated code: output=e9929876ced4b5cc input=6c7d2230b24255aa]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001340{
1341 get_traces_t get_traces;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001342 get_traces.domain = DEFAULT_DOMAIN;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001343 get_traces.traces = NULL;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001344 get_traces.domains = NULL;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001345 get_traces.tracebacks = NULL;
1346 get_traces.list = PyList_New(0);
1347 if (get_traces.list == NULL)
1348 goto error;
1349
Victor Stinner9e00e802018-10-25 13:31:16 +02001350 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001351 return get_traces.list;
1352
Victor Stinnerde2f1322013-11-26 00:26:23 +01001353 /* the traceback hash table is used temporarily to intern traceback tuple
1354 of (filename, lineno) tuples */
Victor Stinner5b0a3032020-05-13 04:40:30 +02001355 get_traces.tracebacks = hashtable_new(_Py_hashtable_hash_ptr,
Victor Stinner2d0a3d62020-05-13 02:50:18 +02001356 _Py_hashtable_compare_direct,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001357 NULL, tracemalloc_pyobject_decref);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001358 if (get_traces.tracebacks == NULL) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001359 goto no_memory;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001360 }
1361
Victor Stinner9e2ca172020-05-13 01:36:47 +02001362 // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable
1363 // temporarily tracemalloc which would impact other threads and so would
1364 // miss allocations while get_traces() is called.
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001365 TABLES_LOCK();
Victor Stinnerd95bd422020-05-13 03:52:11 +02001366 get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001367 TABLES_UNLOCK();
1368
1369 if (get_traces.traces == NULL) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001370 goto no_memory;
1371 }
Victor Stinnerd95bd422020-05-13 03:52:11 +02001372
1373 TABLES_LOCK();
1374 get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains);
1375 TABLES_UNLOCK();
1376
1377 if (get_traces.domains == NULL) {
Victor Stinner9e2ca172020-05-13 01:36:47 +02001378 goto no_memory;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001379 }
1380
Victor Stinner9e2ca172020-05-13 01:36:47 +02001381 // Convert traces to a list of tuples
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001382 set_reentrant(1);
Victor Stinnerd95bd422020-05-13 03:52:11 +02001383 int err = _Py_hashtable_foreach(get_traces.traces,
1384 tracemalloc_get_traces_fill,
1385 &get_traces);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001386 if (!err) {
1387 err = _Py_hashtable_foreach(get_traces.domains,
Victor Stinnerd95bd422020-05-13 03:52:11 +02001388 tracemalloc_get_traces_domain,
1389 &get_traces);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001390 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001391 set_reentrant(0);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001392 if (err) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001393 goto error;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001394 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001395
1396 goto finally;
1397
Victor Stinner9e2ca172020-05-13 01:36:47 +02001398no_memory:
1399 PyErr_NoMemory();
1400
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001401error:
1402 Py_CLEAR(get_traces.list);
1403
1404finally:
1405 if (get_traces.tracebacks != NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001406 _Py_hashtable_destroy(get_traces.tracebacks);
1407 }
Victor Stinnerc9553872016-03-22 12:13:01 +01001408 if (get_traces.traces != NULL) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001409 _Py_hashtable_destroy(get_traces.traces);
Victor Stinnerc9553872016-03-22 12:13:01 +01001410 }
Victor Stinner9e2ca172020-05-13 01:36:47 +02001411 if (get_traces.domains != NULL) {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001412 _Py_hashtable_destroy(get_traces.domains);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001413 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001414
1415 return get_traces.list;
1416}
1417
Victor Stinnere492ae52016-03-22 12:58:23 +01001418
Victor Stinner0611c262016-03-15 22:22:13 +01001419static traceback_t*
Victor Stinner5ea4c062017-06-20 17:46:36 +02001420tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr)
Victor Stinner0611c262016-03-15 22:22:13 +01001421{
Victor Stinner0611c262016-03-15 22:22:13 +01001422
Victor Stinner9e00e802018-10-25 13:31:16 +02001423 if (!_Py_tracemalloc_config.tracing)
Victor Stinner0611c262016-03-15 22:22:13 +01001424 return NULL;
1425
Victor Stinner5b0a3032020-05-13 04:40:30 +02001426 trace_t *trace;
Victor Stinner0611c262016-03-15 22:22:13 +01001427 TABLES_LOCK();
Victor Stinner9e2ca172020-05-13 01:36:47 +02001428 _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain);
1429 if (traces) {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001430 trace = _Py_hashtable_get(traces, TO_PTR(ptr));
Victor Stinnere492ae52016-03-22 12:58:23 +01001431 }
1432 else {
Victor Stinner5b0a3032020-05-13 04:40:30 +02001433 trace = NULL;
Victor Stinnere492ae52016-03-22 12:58:23 +01001434 }
Victor Stinner0611c262016-03-15 22:22:13 +01001435 TABLES_UNLOCK();
1436
Victor Stinner5b0a3032020-05-13 04:40:30 +02001437 if (!trace) {
Victor Stinner0611c262016-03-15 22:22:13 +01001438 return NULL;
Victor Stinnerd95bd422020-05-13 03:52:11 +02001439 }
Victor Stinner0611c262016-03-15 22:22:13 +01001440
Victor Stinnerd95bd422020-05-13 03:52:11 +02001441 return trace->traceback;
Victor Stinner0611c262016-03-15 22:22:13 +01001442}
1443
Victor Stinnere492ae52016-03-22 12:58:23 +01001444
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001445
Serhiy Storchakab451f912017-02-04 12:18:38 +02001446/*[clinic input]
1447_tracemalloc._get_object_traceback
1448
1449 obj: object
1450 /
1451
1452Get the traceback where the Python object obj was allocated.
1453
1454Return a tuple of (filename: str, lineno: int) tuples.
1455Return None if the tracemalloc module is disabled or did not
1456trace the allocation of the object.
1457[clinic start generated code]*/
1458
1459static PyObject *
1460_tracemalloc__get_object_traceback(PyObject *module, PyObject *obj)
1461/*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001462{
1463 PyTypeObject *type;
1464 void *ptr;
Victor Stinner0611c262016-03-15 22:22:13 +01001465 traceback_t *traceback;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001466
1467 type = Py_TYPE(obj);
Victor Stinner626bff82018-10-25 17:31:10 +02001468 if (PyType_IS_GC(type)) {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001469 ptr = (void *)((char *)obj - sizeof(PyGC_Head));
Victor Stinner626bff82018-10-25 17:31:10 +02001470 }
1471 else {
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001472 ptr = (void *)obj;
Victor Stinner626bff82018-10-25 17:31:10 +02001473 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001474
Benjamin Petersonca470632016-09-06 13:47:26 -07001475 traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
Victor Stinner0611c262016-03-15 22:22:13 +01001476 if (traceback == NULL)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001477 Py_RETURN_NONE;
1478
Victor Stinner0611c262016-03-15 22:22:13 +01001479 return traceback_to_pyobject(traceback, NULL);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001480}
1481
Victor Stinnere492ae52016-03-22 12:58:23 +01001482
Victor Stinner0611c262016-03-15 22:22:13 +01001483#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str))
1484
1485static void
1486_PyMem_DumpFrame(int fd, frame_t * frame)
1487{
1488 PUTS(fd, " File \"");
1489 _Py_DumpASCII(fd, frame->filename);
1490 PUTS(fd, "\", line ");
1491 _Py_DumpDecimal(fd, frame->lineno);
1492 PUTS(fd, "\n");
1493}
1494
1495/* Dump the traceback where a memory block was allocated into file descriptor
1496 fd. The function may block on TABLES_LOCK() but it is unlikely. */
1497void
1498_PyMem_DumpTraceback(int fd, const void *ptr)
1499{
1500 traceback_t *traceback;
1501 int i;
1502
Victor Stinnerf966e532018-11-13 15:14:58 +01001503 if (!_Py_tracemalloc_config.tracing) {
1504 PUTS(fd, "Enable tracemalloc to get the memory block "
1505 "allocation traceback\n\n");
1506 return;
1507 }
1508
Benjamin Petersonca470632016-09-06 13:47:26 -07001509 traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr);
Victor Stinner0611c262016-03-15 22:22:13 +01001510 if (traceback == NULL)
1511 return;
1512
1513 PUTS(fd, "Memory block allocated at (most recent call first):\n");
1514 for (i=0; i < traceback->nframe; i++) {
1515 _PyMem_DumpFrame(fd, &traceback->frames[i]);
1516 }
1517 PUTS(fd, "\n");
1518}
1519
1520#undef PUTS
1521
Victor Stinnere492ae52016-03-22 12:58:23 +01001522
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001523
Serhiy Storchakab451f912017-02-04 12:18:38 +02001524/*[clinic input]
1525_tracemalloc.start
1526
Victor Stinnera7368ac2017-11-15 18:11:45 -08001527 nframe: int = 1
Serhiy Storchakab451f912017-02-04 12:18:38 +02001528 /
1529
1530Start tracing Python memory allocations.
1531
1532Also set the maximum number of frames stored in the traceback of a
1533trace to nframe.
1534[clinic start generated code]*/
1535
1536static PyObject *
Victor Stinnera7368ac2017-11-15 18:11:45 -08001537_tracemalloc_start_impl(PyObject *module, int nframe)
1538/*[clinic end generated code: output=caae05c23c159d3c input=40d849b5b29d1933]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001539{
Victor Stinnera7368ac2017-11-15 18:11:45 -08001540 if (tracemalloc_start(nframe) < 0) {
Victor Stinner3728d6c2013-11-23 12:37:20 +01001541 return NULL;
1542 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001543 Py_RETURN_NONE;
1544}
1545
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001546
Serhiy Storchakab451f912017-02-04 12:18:38 +02001547/*[clinic input]
1548_tracemalloc.stop
Victor Stinnere492ae52016-03-22 12:58:23 +01001549
Serhiy Storchakab451f912017-02-04 12:18:38 +02001550Stop tracing Python memory allocations.
1551
1552Also clear traces of memory blocks allocated by Python.
1553[clinic start generated code]*/
1554
1555static PyObject *
1556_tracemalloc_stop_impl(PyObject *module)
1557/*[clinic end generated code: output=c3c42ae03e3955cd input=7478f075e51dae18]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001558{
1559 tracemalloc_stop();
1560 Py_RETURN_NONE;
1561}
1562
Victor Stinnere492ae52016-03-22 12:58:23 +01001563
Serhiy Storchakab451f912017-02-04 12:18:38 +02001564/*[clinic input]
1565_tracemalloc.get_traceback_limit
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001566
Serhiy Storchakab451f912017-02-04 12:18:38 +02001567Get the maximum number of frames stored in the traceback of a trace.
1568
1569By default, a trace of an allocated memory block only stores
1570the most recent frame: the limit is 1.
1571[clinic start generated code]*/
1572
1573static PyObject *
1574_tracemalloc_get_traceback_limit_impl(PyObject *module)
1575/*[clinic end generated code: output=d556d9306ba95567 input=da3cd977fc68ae3b]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001576{
Victor Stinner9e00e802018-10-25 13:31:16 +02001577 return PyLong_FromLong(_Py_tracemalloc_config.max_nframe);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001578}
1579
Victor Stinnere492ae52016-03-22 12:58:23 +01001580
Victor Stinner9e2ca172020-05-13 01:36:47 +02001581static int
1582tracemalloc_get_tracemalloc_memory_cb(_Py_hashtable_t *domains,
Victor Stinner5b0a3032020-05-13 04:40:30 +02001583 const void *key, const void *value,
Victor Stinner9e2ca172020-05-13 01:36:47 +02001584 void *user_data)
1585{
Victor Stinner5b0a3032020-05-13 04:40:30 +02001586 const _Py_hashtable_t *traces = value;
Victor Stinner9e2ca172020-05-13 01:36:47 +02001587 size_t *size = (size_t*)user_data;
1588 *size += _Py_hashtable_size(traces);
1589 return 0;
1590}
1591
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001592
Serhiy Storchakab451f912017-02-04 12:18:38 +02001593/*[clinic input]
1594_tracemalloc.get_tracemalloc_memory
1595
1596Get the memory usage in bytes of the tracemalloc module.
1597
1598This memory is used internally to trace memory allocations.
1599[clinic start generated code]*/
1600
1601static PyObject *
1602_tracemalloc_get_tracemalloc_memory_impl(PyObject *module)
1603/*[clinic end generated code: output=e3f14e280a55f5aa input=5d919c0f4d5132ad]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001604{
1605 size_t size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001606
1607 size = _Py_hashtable_size(tracemalloc_tracebacks);
1608 size += _Py_hashtable_size(tracemalloc_filenames);
1609
1610 TABLES_LOCK();
1611 size += _Py_hashtable_size(tracemalloc_traces);
Victor Stinner9e2ca172020-05-13 01:36:47 +02001612 _Py_hashtable_foreach(tracemalloc_domains,
1613 tracemalloc_get_tracemalloc_memory_cb, &size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001614 TABLES_UNLOCK();
1615
Serhiy Storchakab451f912017-02-04 12:18:38 +02001616 return PyLong_FromSize_t(size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001617}
1618
Victor Stinnere492ae52016-03-22 12:58:23 +01001619
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001620
Serhiy Storchakab451f912017-02-04 12:18:38 +02001621/*[clinic input]
1622_tracemalloc.get_traced_memory
1623
1624Get the current size and peak size of memory blocks traced by tracemalloc.
1625
1626Returns a tuple: (current: int, peak: int).
1627[clinic start generated code]*/
1628
1629static PyObject *
1630_tracemalloc_get_traced_memory_impl(PyObject *module)
1631/*[clinic end generated code: output=5b167189adb9e782 input=61ddb5478400ff66]*/
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001632{
Victor Stinner3c0481d2013-11-27 21:39:49 +01001633 Py_ssize_t size, peak_size;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001634
Victor Stinner9e00e802018-10-25 13:31:16 +02001635 if (!_Py_tracemalloc_config.tracing)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001636 return Py_BuildValue("ii", 0, 0);
1637
1638 TABLES_LOCK();
1639 size = tracemalloc_traced_memory;
Victor Stinner3c0481d2013-11-27 21:39:49 +01001640 peak_size = tracemalloc_peak_traced_memory;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001641 TABLES_UNLOCK();
1642
Serhiy Storchakab451f912017-02-04 12:18:38 +02001643 return Py_BuildValue("nn", size, peak_size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001644}
1645
Huon Wilson8b626442020-05-23 00:18:51 +10001646/*[clinic input]
1647_tracemalloc.reset_peak
1648
1649Set the peak size of memory blocks traced by tracemalloc to the current size.
1650
1651Do nothing if the tracemalloc module is not tracing memory allocations.
1652
1653[clinic start generated code]*/
1654
1655static PyObject *
1656_tracemalloc_reset_peak_impl(PyObject *module)
1657/*[clinic end generated code: output=140c2870f691dbb2 input=18afd0635066e9ce]*/
1658{
1659 if (!_Py_tracemalloc_config.tracing) {
1660 Py_RETURN_NONE;
1661 }
1662
1663 TABLES_LOCK();
1664 tracemalloc_peak_traced_memory = tracemalloc_traced_memory;
1665 TABLES_UNLOCK();
1666
1667 Py_RETURN_NONE;
1668}
1669
Victor Stinnere492ae52016-03-22 12:58:23 +01001670
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001671static PyMethodDef module_methods[] = {
Serhiy Storchakab451f912017-02-04 12:18:38 +02001672 _TRACEMALLOC_IS_TRACING_METHODDEF
1673 _TRACEMALLOC_CLEAR_TRACES_METHODDEF
1674 _TRACEMALLOC__GET_TRACES_METHODDEF
1675 _TRACEMALLOC__GET_OBJECT_TRACEBACK_METHODDEF
1676 _TRACEMALLOC_START_METHODDEF
1677 _TRACEMALLOC_STOP_METHODDEF
1678 _TRACEMALLOC_GET_TRACEBACK_LIMIT_METHODDEF
1679 _TRACEMALLOC_GET_TRACEMALLOC_MEMORY_METHODDEF
1680 _TRACEMALLOC_GET_TRACED_MEMORY_METHODDEF
Huon Wilson8b626442020-05-23 00:18:51 +10001681 _TRACEMALLOC_RESET_PEAK_METHODDEF
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001682 /* sentinel */
1683 {NULL, NULL}
1684};
1685
1686PyDoc_STRVAR(module_doc,
1687"Debug module to trace memory blocks allocated by Python.");
1688
1689static struct PyModuleDef module_def = {
1690 PyModuleDef_HEAD_INIT,
1691 "_tracemalloc",
1692 module_doc,
1693 0, /* non-negative size to be able to unload the module */
1694 module_methods,
1695 NULL,
1696};
1697
1698PyMODINIT_FUNC
1699PyInit__tracemalloc(void)
1700{
1701 PyObject *m;
1702 m = PyModule_Create(&module_def);
1703 if (m == NULL)
1704 return NULL;
1705
Brandt Bucherd51a3632019-11-20 02:00:31 -08001706 if (tracemalloc_init() < 0) {
1707 Py_DECREF(m);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001708 return NULL;
Brandt Bucherd51a3632019-11-20 02:00:31 -08001709 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001710
1711 return m;
1712}
1713
Victor Stinnere492ae52016-03-22 12:58:23 +01001714
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001715int
Victor Stinnera7368ac2017-11-15 18:11:45 -08001716_PyTraceMalloc_Init(int nframe)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001717{
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001718 assert(PyGILState_Check());
Victor Stinnera7368ac2017-11-15 18:11:45 -08001719 if (nframe == 0) {
1720 return 0;
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001721 }
Victor Stinnerf28ce602013-11-27 22:27:13 +01001722 return tracemalloc_start(nframe);
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001723}
1724
Victor Stinnere492ae52016-03-22 12:58:23 +01001725
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001726void
1727_PyTraceMalloc_Fini(void)
1728{
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001729 assert(PyGILState_Check());
Victor Stinnerbe0708f2013-12-01 10:03:26 +01001730 tracemalloc_deinit();
1731}
Victor Stinner10b73e12016-03-22 13:39:05 +01001732
1733int
Victor Stinner5ea4c062017-06-20 17:46:36 +02001734PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr,
1735 size_t size)
Victor Stinner10b73e12016-03-22 13:39:05 +01001736{
1737 int res;
Victor Stinner10b73e12016-03-22 13:39:05 +01001738 PyGILState_STATE gil_state;
Victor Stinner10b73e12016-03-22 13:39:05 +01001739
Victor Stinner9e00e802018-10-25 13:31:16 +02001740 if (!_Py_tracemalloc_config.tracing) {
Victor Stinner10b73e12016-03-22 13:39:05 +01001741 /* tracemalloc is not tracing: do nothing */
1742 return -2;
1743 }
1744
Victor Stinner10b73e12016-03-22 13:39:05 +01001745 gil_state = PyGILState_Ensure();
Victor Stinner10b73e12016-03-22 13:39:05 +01001746
1747 TABLES_LOCK();
1748 res = tracemalloc_add_trace(domain, ptr, size);
1749 TABLES_UNLOCK();
1750
Victor Stinner10b73e12016-03-22 13:39:05 +01001751 PyGILState_Release(gil_state);
Victor Stinner10b73e12016-03-22 13:39:05 +01001752 return res;
1753}
1754
1755
1756int
Victor Stinner5ea4c062017-06-20 17:46:36 +02001757PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)
Victor Stinner10b73e12016-03-22 13:39:05 +01001758{
Victor Stinner9e00e802018-10-25 13:31:16 +02001759 if (!_Py_tracemalloc_config.tracing) {
Victor Stinner10b73e12016-03-22 13:39:05 +01001760 /* tracemalloc is not tracing: do nothing */
1761 return -2;
1762 }
1763
1764 TABLES_LOCK();
1765 tracemalloc_remove_trace(domain, ptr);
1766 TABLES_UNLOCK();
1767
1768 return 0;
1769}
1770
1771
Victor Stinner9e00e802018-10-25 13:31:16 +02001772/* If the object memory block is already traced, update its trace
1773 with the current Python traceback.
1774
1775 Do nothing if tracemalloc is not tracing memory allocations
1776 or if the object memory block is not already traced. */
1777int
1778_PyTraceMalloc_NewReference(PyObject *op)
1779{
1780 assert(PyGILState_Check());
1781
1782 if (!_Py_tracemalloc_config.tracing) {
1783 /* tracemalloc is not tracing: do nothing */
1784 return -1;
1785 }
1786
1787 uintptr_t ptr;
1788 PyTypeObject *type = Py_TYPE(op);
1789 if (PyType_IS_GC(type)) {
1790 ptr = (uintptr_t)((char *)op - sizeof(PyGC_Head));
1791 }
1792 else {
1793 ptr = (uintptr_t)op;
1794 }
1795
Victor Stinner9e00e802018-10-25 13:31:16 +02001796 int res = -1;
1797
1798 TABLES_LOCK();
Victor Stinner5b0a3032020-05-13 04:40:30 +02001799 trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr));
1800 if (trace != NULL) {
Victor Stinner9e00e802018-10-25 13:31:16 +02001801 /* update the traceback of the memory block */
1802 traceback_t *traceback = traceback_new();
1803 if (traceback != NULL) {
Victor Stinnerd95bd422020-05-13 03:52:11 +02001804 trace->traceback = traceback;
Victor Stinner9e00e802018-10-25 13:31:16 +02001805 res = 0;
1806 }
1807 }
1808 /* else: cannot track the object, its memory block size is unknown */
1809 TABLES_UNLOCK();
1810
1811 return res;
1812}
1813
1814
Victor Stinner10b73e12016-03-22 13:39:05 +01001815PyObject*
Victor Stinner5ea4c062017-06-20 17:46:36 +02001816_PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr)
Victor Stinner10b73e12016-03-22 13:39:05 +01001817{
1818 traceback_t *traceback;
1819
1820 traceback = tracemalloc_get_traceback(domain, ptr);
1821 if (traceback == NULL)
1822 Py_RETURN_NONE;
1823
1824 return traceback_to_pyobject(traceback, NULL);
1825}