blob: 22ec5ddf2a28240468098815c3d66cb5404406c8 [file] [log] [blame]
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001#include "Python.h"
2#include "hashtable.h"
3#include "frameobject.h"
4#include "pythread.h"
5#include "osdefs.h"
6
7/* Trace memory blocks allocated by PyMem_RawMalloc() */
8#define TRACE_RAW_MALLOC
9
10/* Forward declaration */
11static void tracemalloc_stop(void);
12static int tracemalloc_atexit_register(void);
13static void* raw_malloc(size_t size);
14static void raw_free(void *ptr);
15
16#ifdef Py_DEBUG
17# define TRACE_DEBUG
18#endif
19
20#define _STR(VAL) #VAL
21#define STR(VAL) _STR(VAL)
22
23/* Protected by the GIL */
24static struct {
25 PyMemAllocator mem;
26 PyMemAllocator raw;
27 PyMemAllocator obj;
28} allocators;
29
30/* Arbitrary limit of the number of frames in a traceback. The value was chosen
31 to not allocate too much memory on the stack (see TRACEBACK_STACK_SIZE
32 below). */
33#define MAX_NFRAME 100
34
35static struct {
36 /* Module initialized?
37 Variable protected by the GIL */
38 enum {
39 TRACEMALLOC_NOT_INITIALIZED,
40 TRACEMALLOC_INITIALIZED,
41 TRACEMALLOC_FINALIZED
42 } initialized;
43
44 /* atexit handler registered? */
45 int atexit_registered;
46
47 /* Is tracemalloc tracing memory allocations?
48 Variable protected by the GIL */
49 int tracing;
50
51 /* limit of the number of frames in a traceback, 1 by default.
52 Variable protected by the GIL. */
53 int max_nframe;
54} tracemalloc_config = {TRACEMALLOC_NOT_INITIALIZED, 0, 0, 1};
55
56#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
57/* This lock is needed because tracemalloc_free() is called without
58 the GIL held from PyMem_RawFree(). It cannot acquire the lock because it
59 would introduce a deadlock in PyThreadState_DeleteCurrent(). */
60static PyThread_type_lock tables_lock;
61# define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1)
62# define TABLES_UNLOCK() PyThread_release_lock(tables_lock)
63#else
64 /* variables are protected by the GIL */
65# define TABLES_LOCK()
66# define TABLES_UNLOCK()
67#endif
68
69/* Pack the frame_t structure to reduce the memory footprint on 64-bit
70 architectures: 12 bytes instead of 16. This optimization might produce
71 SIGBUS on architectures not supporting unaligned memory accesses (64-bit
72 IPS CPU?): on such architecture, the structure must not be packed. */
73#pragma pack(4)
74typedef struct
75#ifdef __GNUC__
76__attribute__((packed))
77#endif
78{
79 PyObject *filename;
80 int lineno;
81} frame_t;
82
83typedef struct {
84 Py_uhash_t hash;
85 int nframe;
86 frame_t frames[1];
87} traceback_t;
88
89#define TRACEBACK_SIZE(NFRAME) \
90 (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1))
91#define TRACEBACK_STACK_SIZE TRACEBACK_SIZE(MAX_NFRAME)
92
93static PyObject *unknown_filename = NULL;
94static traceback_t tracemalloc_empty_traceback;
95
96typedef struct {
97 size_t size;
98 traceback_t *traceback;
99} trace_t;
100
101/* Size in bytes of currently traced memory.
102 Protected by TABLES_LOCK(). */
103static size_t tracemalloc_traced_memory = 0;
104
105/* Maximum size in bytes of traced memory.
106 Protected by TABLES_LOCK(). */
107static size_t tracemalloc_max_traced_memory = 0;
108
109/* Hash table used as a set to to intern filenames:
110 PyObject* => PyObject*.
111 Protected by the GIL */
112static _Py_hashtable_t *tracemalloc_filenames = NULL;
113
114/* Hash table used as a set to intern tracebacks:
115 traceback_t* => traceback_t*
116 Protected by the GIL */
117static _Py_hashtable_t *tracemalloc_tracebacks = NULL;
118
119/* pointer (void*) => trace (trace_t).
120 Protected by TABLES_LOCK(). */
121static _Py_hashtable_t *tracemalloc_traces = NULL;
122
123#ifdef TRACE_DEBUG
124static void
125tracemalloc_error(const char *format, ...)
126{
127 va_list ap;
128 fprintf(stderr, "tracemalloc: ");
129 va_start(ap, format);
130 vfprintf(stderr, format, ap);
131 va_end(ap);
132 fprintf(stderr, "\n");
133 fflush(stderr);
134}
135#endif
136
137#if defined(WITH_THREAD) && defined(TRACE_RAW_MALLOC)
138#define REENTRANT_THREADLOCAL
139
140/* If your OS does not provide native thread local storage, you can implement
141 it manually using a lock. Functions of thread.c cannot be used because
142 they use PyMem_RawMalloc() which leads to a reentrant call. */
143#if !(defined(_POSIX_THREADS) || defined(NT_THREADS))
144# error "need native thread local storage (TLS)"
145#endif
146
147static int tracemalloc_reentrant_key;
148
149/* Any non-NULL pointer can be used */
150#define REENTRANT Py_True
151
152static int
153get_reentrant(void)
154{
155 void *ptr = PyThread_get_key_value(tracemalloc_reentrant_key);
156 if (ptr != NULL) {
157 assert(ptr == REENTRANT);
158 return 1;
159 }
160 else
161 return 0;
162}
163
164static void
165set_reentrant(int reentrant)
166{
167 if (reentrant) {
168 assert(PyThread_get_key_value(tracemalloc_reentrant_key) == NULL);
169 PyThread_set_key_value(tracemalloc_reentrant_key,
170 REENTRANT);
171 }
172 else {
173 /* FIXME: PyThread_set_key_value() cannot be used to set the flag
174 to zero, because it does nothing if the variable has already
175 a value set. */
176 PyThread_delete_key_value(tracemalloc_reentrant_key);
177 }
178}
179
180#else
181
182/* WITH_THREAD not defined: Python compiled without threads,
183 or TRACE_RAW_MALLOC not defined: variable protected by the GIL */
184static int tracemalloc_reentrant = 0;
185
186static int
187get_reentrant(void)
188{
189 return tracemalloc_reentrant;
190}
191
192static void
193set_reentrant(int reentrant)
194{
195 assert(!reentrant || !get_reentrant());
196 tracemalloc_reentrant = reentrant;
197}
198#endif
199
200static int
201hashtable_compare_unicode(const void *key, const _Py_hashtable_entry_t *entry)
202{
203 if (key != NULL && entry->key != NULL)
204 return (PyUnicode_Compare((PyObject *)key, (PyObject *)entry->key) == 0);
205 else
206 return key == entry->key;
207}
208
209static _Py_hashtable_allocator_t hashtable_alloc = {malloc, free};
210
211static _Py_hashtable_t *
212hashtable_new(size_t data_size,
213 _Py_hashtable_hash_func hash_func,
214 _Py_hashtable_compare_func compare_func)
215{
216 return _Py_hashtable_new_full(data_size, 0,
217 hash_func, compare_func,
218 NULL, NULL, NULL, &hashtable_alloc);
219}
220
221static void*
222raw_malloc(size_t size)
223{
224 return allocators.raw.malloc(allocators.raw.ctx, size);
225}
226
227static void
228raw_free(void *ptr)
229{
230 allocators.raw.free(allocators.raw.ctx, ptr);
231}
232
233static Py_uhash_t
234hashtable_hash_traceback(const void *key)
235{
236 const traceback_t *traceback = key;
237 return traceback->hash;
238}
239
240static int
241hashtable_compare_traceback(const traceback_t *traceback1,
242 const _Py_hashtable_entry_t *he)
243{
244 const traceback_t *traceback2 = he->key;
245 const frame_t *frame1, *frame2;
246 int i;
247
248 if (traceback1->nframe != traceback2->nframe)
249 return 0;
250
251 for (i=0; i < traceback1->nframe; i++) {
252 frame1 = &traceback1->frames[i];
253 frame2 = &traceback2->frames[i];
254
255 if (frame1->lineno != frame2->lineno)
256 return 0;
257
258 if (frame1->filename != frame2->filename) {
259 assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0);
260 return 0;
261 }
262 }
263 return 1;
264}
265
266static void
267tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame)
268{
269 PyCodeObject *code;
270 PyObject *filename;
271 _Py_hashtable_entry_t *entry;
272
273 frame->filename = unknown_filename;
274 frame->lineno = PyFrame_GetLineNumber(pyframe);
275 assert(frame->lineno >= 0);
276 if (frame->lineno < 0)
277 frame->lineno = 0;
278
279 code = pyframe->f_code;
280 if (code == NULL) {
281#ifdef TRACE_DEBUG
282 tracemalloc_error("failed to get the code object of the a frame");
283#endif
284 return;
285 }
286
287 if (code->co_filename == NULL) {
288#ifdef TRACE_DEBUG
289 tracemalloc_error("failed to get the filename of the code object");
290#endif
291 return;
292 }
293
294 filename = code->co_filename;
295 assert(filename != NULL);
296 if (filename == NULL)
297 return;
298
299 if (!PyUnicode_Check(filename)) {
300#ifdef TRACE_DEBUG
301 tracemalloc_error("filename is not an unicode string");
302#endif
303 return;
304 }
305 if (!PyUnicode_IS_READY(filename)) {
306 /* Don't make a Unicode string ready to avoid reentrant calls
307 to tracemalloc_malloc() or tracemalloc_realloc() */
308#ifdef TRACE_DEBUG
309 tracemalloc_error("filename is not a ready unicode string");
310#endif
311 return;
312 }
313
314 /* intern the filename */
315 entry = _Py_hashtable_get_entry(tracemalloc_filenames, filename);
316 if (entry != NULL) {
317 filename = (PyObject *)entry->key;
318 }
319 else {
320 /* tracemalloc_filenames is responsible to keep a reference
321 to the filename */
322 Py_INCREF(filename);
323 if (_Py_hashtable_set(tracemalloc_filenames, filename, NULL, 0) < 0) {
324 Py_DECREF(filename);
325#ifdef TRACE_DEBUG
326 tracemalloc_error("failed to intern the filename");
327#endif
328 return;
329 }
330 }
331
332 /* the tracemalloc_filenames table keeps a reference to the filename */
333 frame->filename = filename;
334}
335
336static Py_uhash_t
337traceback_hash(traceback_t *traceback)
338{
339 /* code based on tuplehash() of Objects/tupleobject.c */
340 Py_uhash_t x; /* Unsigned for defined overflow behavior. */
341 Py_hash_t y;
342 int len = traceback->nframe;
343 Py_uhash_t mult = _PyHASH_MULTIPLIER;
344 frame_t *frame;
345
346 x = 0x345678UL;
347 frame = traceback->frames;
348 while (--len >= 0) {
349 y = PyObject_Hash(frame->filename);
350 y ^= frame->lineno;
351 frame++;
352
353 x = (x ^ y) * mult;
354 /* the cast might truncate len; that doesn't change hash stability */
355 mult += (Py_hash_t)(82520UL + len + len);
356 }
357 x += 97531UL;
358 return x;
359}
360
361static void
362traceback_get_frames(traceback_t *traceback)
363{
364 PyThreadState *tstate;
365 PyFrameObject *pyframe;
366
367#ifdef WITH_THREAD
368 tstate = PyGILState_GetThisThreadState();
369#else
370 tstate = PyThreadState_Get();
371#endif
372 if (tstate == NULL) {
373#ifdef TRACE_DEBUG
374 tracemalloc_error("failed to get the current thread state");
375#endif
376 return;
377 }
378
379 for (pyframe = tstate->frame; pyframe != NULL; pyframe = pyframe->f_back) {
380 tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]);
381 assert(traceback->frames[traceback->nframe].filename != NULL);
382 assert(traceback->frames[traceback->nframe].lineno >= 0);
383 traceback->nframe++;
384 if (traceback->nframe == tracemalloc_config.max_nframe)
385 break;
386 }
387}
388
389static traceback_t *
390traceback_new(void)
391{
392 char stack_buffer[TRACEBACK_STACK_SIZE];
393 traceback_t *traceback = (traceback_t *)stack_buffer;
394 _Py_hashtable_entry_t *entry;
395
396#ifdef WITH_THREAD
397 assert(PyGILState_Check());
398#endif
399
400 /* get frames */
401 traceback->nframe = 0;
402 traceback_get_frames(traceback);
403 if (traceback->nframe == 0)
404 return &tracemalloc_empty_traceback;
405 traceback->hash = traceback_hash(traceback);
406
407 /* intern the traceback */
408 entry = _Py_hashtable_get_entry(tracemalloc_tracebacks, traceback);
409 if (entry != NULL) {
410 traceback = (traceback_t *)entry->key;
411 }
412 else {
413 traceback_t *copy;
414 size_t traceback_size;
415
416 traceback_size = TRACEBACK_SIZE(traceback->nframe);
417
418 copy = raw_malloc(traceback_size);
419 if (copy == NULL) {
420#ifdef TRACE_DEBUG
421 tracemalloc_error("failed to intern the traceback: malloc failed");
422#endif
423 return NULL;
424 }
425 memcpy(copy, traceback, traceback_size);
426
427 if (_Py_hashtable_set(tracemalloc_tracebacks, copy, NULL, 0) < 0) {
428 raw_free(copy);
429#ifdef TRACE_DEBUG
430 tracemalloc_error("failed to intern the traceback: putdata failed");
431#endif
432 return NULL;
433 }
434 traceback = copy;
435 }
436 return traceback;
437}
438
Victor Stinner52968672013-11-24 11:37:15 +0100439static int
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100440tracemalloc_log_alloc(void *ptr, size_t size)
441{
442 traceback_t *traceback;
443 trace_t trace;
Victor Stinner52968672013-11-24 11:37:15 +0100444 int res;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100445
446#ifdef WITH_THREAD
447 assert(PyGILState_Check());
448#endif
449
450 traceback = traceback_new();
Victor Stinner52968672013-11-24 11:37:15 +0100451 if (traceback == NULL)
452 return -1;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100453
454 trace.size = size;
455 trace.traceback = traceback;
456
457 TABLES_LOCK();
Victor Stinner52968672013-11-24 11:37:15 +0100458 res = _Py_HASHTABLE_SET(tracemalloc_traces, ptr, trace);
459 if (res == 0) {
Victor Stinnerd606ba72013-11-24 11:28:20 +0100460 assert(tracemalloc_traced_memory <= PY_SIZE_MAX - size);
461 tracemalloc_traced_memory += size;
462 if (tracemalloc_traced_memory > tracemalloc_max_traced_memory)
463 tracemalloc_max_traced_memory = tracemalloc_traced_memory;
464 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100465 TABLES_UNLOCK();
Victor Stinner52968672013-11-24 11:37:15 +0100466
467 return res;
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100468}
469
470static void
471tracemalloc_log_free(void *ptr)
472{
473 trace_t trace;
474
475 TABLES_LOCK();
476 if (_Py_hashtable_pop(tracemalloc_traces, ptr, &trace, sizeof(trace))) {
477 assert(tracemalloc_traced_memory >= trace.size);
478 tracemalloc_traced_memory -= trace.size;
479 }
480 TABLES_UNLOCK();
481}
482
483static void*
484tracemalloc_malloc(void *ctx, size_t size, int gil_held)
485{
486 PyMemAllocator *alloc = (PyMemAllocator *)ctx;
487#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
488 PyGILState_STATE gil_state;
489#endif
490 void *ptr;
491
492 if (get_reentrant()) {
493 return alloc->malloc(alloc->ctx, size);
494 }
495
496 /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc()
497 for allocations larger than 512 bytes. PyGILState_Ensure() may call
498 PyMem_RawMalloc() indirectly which would call PyGILState_Ensure() if
499 reentrant are not disabled. */
500 set_reentrant(1);
501#ifdef WITH_THREAD
502#ifdef TRACE_RAW_MALLOC
503 if (!gil_held)
504 gil_state = PyGILState_Ensure();
505#else
506 assert(gil_held);
507#endif
508#endif
509 ptr = alloc->malloc(alloc->ctx, size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100510
Victor Stinner52968672013-11-24 11:37:15 +0100511 if (ptr != NULL) {
512 if (tracemalloc_log_alloc(ptr, size) < 0) {
513 /* Memory allocation failed */
514 alloc->free(alloc->ctx, ptr);
515 ptr = NULL;
516 }
517 }
518 set_reentrant(0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100519
520#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
521 if (!gil_held)
522 PyGILState_Release(gil_state);
523#endif
524
525 return ptr;
526}
527
528static void*
529tracemalloc_realloc(void *ctx, void *ptr, size_t new_size, int gil_held)
530{
531 PyMemAllocator *alloc = (PyMemAllocator *)ctx;
532#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
533 PyGILState_STATE gil_state;
534#endif
535 void *ptr2;
536
537 if (get_reentrant()) {
538 /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc().
539 Example: PyMem_RawRealloc() is called internally by pymalloc
540 (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new
541 arena (new_arena()). */
542 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
543
544 if (ptr2 != NULL && ptr != NULL)
545 tracemalloc_log_free(ptr);
546
547 return ptr2;
548 }
549
550 /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for
551 allocations larger than 512 bytes. PyGILState_Ensure() may call
552 PyMem_RawMalloc() indirectly which would call PyGILState_Ensure() if
553 reentrant are not disabled. */
554 set_reentrant(1);
555#ifdef WITH_THREAD
556#ifdef TRACE_RAW_MALLOC
557 if (!gil_held)
558 gil_state = PyGILState_Ensure();
559#else
560 assert(gil_held);
561#endif
562#endif
563 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100564
565 if (ptr2 != NULL) {
566 if (ptr != NULL)
567 tracemalloc_log_free(ptr);
568
Victor Stinner52968672013-11-24 11:37:15 +0100569 if (tracemalloc_log_alloc(ptr2, new_size) < 0) {
570 if (ptr == NULL) {
571 /* Memory allocation failed */
572 alloc->free(alloc->ctx, ptr2);
573 ptr2 = NULL;
574 }
575 else {
576 /* Memory allocation failed. The error cannot be reported to
577 the caller, because realloc() may already have shrinked the
578 memory block and so removed bytes. */
579 }
580 }
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100581 }
Victor Stinner52968672013-11-24 11:37:15 +0100582 set_reentrant(0);
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100583
584#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
585 if (!gil_held)
586 PyGILState_Release(gil_state);
587#endif
588
589 return ptr2;
590}
591
592static void
593tracemalloc_free(void *ctx, void *ptr)
594{
595 PyMemAllocator *alloc = (PyMemAllocator *)ctx;
596
597 if (ptr == NULL)
598 return;
599
600 /* GIL cannot be locked in PyMem_RawFree() because it would introduce
601 a deadlock in PyThreadState_DeleteCurrent(). */
602
603 alloc->free(alloc->ctx, ptr);
604 tracemalloc_log_free(ptr);
605}
606
607static void*
608tracemalloc_malloc_gil(void *ctx, size_t size)
609{
610 return tracemalloc_malloc(ctx, size, 1);
611}
612
613static void*
614tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
615{
616 return tracemalloc_realloc(ctx, ptr, new_size, 1);
617}
618
619#ifdef TRACE_RAW_MALLOC
620static void*
621tracemalloc_raw_malloc(void *ctx, size_t size)
622{
623 return tracemalloc_malloc(ctx, size, 0);
624}
625
626static void*
627tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
628{
629 return tracemalloc_realloc(ctx, ptr, new_size, 0);
630}
631#endif
632
633static int
634tracemalloc_clear_filename(_Py_hashtable_entry_t *entry, void *user_data)
635{
636 PyObject *filename = (PyObject *)entry->key;
637 Py_DECREF(filename);
638 return 0;
639}
640
641static int
642traceback_free_traceback(_Py_hashtable_entry_t *entry, void *user_data)
643{
644 traceback_t *traceback = (traceback_t *)entry->key;
645 raw_free(traceback);
646 return 0;
647}
648
649/* reentrant flag must be set to call this function and GIL must be held */
650static void
651tracemalloc_clear_traces(void)
652{
653#ifdef WITH_THREAD
654 /* The GIL protects variables againt concurrent access */
655 assert(PyGILState_Check());
656#endif
657
658 /* Disable also reentrant calls to tracemalloc_malloc() to not add a new
659 trace while we are clearing traces */
660 assert(get_reentrant());
661
662 TABLES_LOCK();
663 _Py_hashtable_clear(tracemalloc_traces);
664 tracemalloc_traced_memory = 0;
665 tracemalloc_max_traced_memory = 0;
666 TABLES_UNLOCK();
667
668 _Py_hashtable_foreach(tracemalloc_tracebacks, traceback_free_traceback, NULL);
669 _Py_hashtable_clear(tracemalloc_tracebacks);
670
671 _Py_hashtable_foreach(tracemalloc_filenames, tracemalloc_clear_filename, NULL);
672 _Py_hashtable_clear(tracemalloc_filenames);
673}
674
675static int
676tracemalloc_init(void)
677{
678 if (tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) {
679 PyErr_SetString(PyExc_RuntimeError,
680 "the tracemalloc module has been unloaded");
681 return -1;
682 }
683
684 if (tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED)
685 return 0;
686
687 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
688
689#ifdef REENTRANT_THREADLOCAL
690 tracemalloc_reentrant_key = PyThread_create_key();
691 if (tracemalloc_reentrant_key == -1) {
692#ifdef MS_WINDOWS
693 PyErr_SetFromWindowsErr(0);
694#else
695 PyErr_SetFromErrno(PyExc_OSError);
696#endif
697 return -1;
698 }
699#endif
700
701#if defined(WITH_THREAD) && defined(TRACE_RAW_MALLOC)
702 if (tables_lock == NULL) {
703 tables_lock = PyThread_allocate_lock();
704 if (tables_lock == NULL) {
705 PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock");
706 return -1;
707 }
708 }
709#endif
710
711 tracemalloc_filenames = hashtable_new(0,
712 (_Py_hashtable_hash_func)PyObject_Hash,
713 hashtable_compare_unicode);
714
715 tracemalloc_tracebacks = hashtable_new(0,
716 (_Py_hashtable_hash_func)hashtable_hash_traceback,
717 (_Py_hashtable_compare_func)hashtable_compare_traceback);
718
719 tracemalloc_traces = hashtable_new(sizeof(trace_t),
720 _Py_hashtable_hash_ptr,
721 _Py_hashtable_compare_direct);
722
723 if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL
724 || tracemalloc_traces == NULL)
725 {
726 PyErr_NoMemory();
727 return -1;
728 }
729
730 unknown_filename = PyUnicode_FromString("<unknown>");
731 if (unknown_filename == NULL)
732 return -1;
733 PyUnicode_InternInPlace(&unknown_filename);
734
735 tracemalloc_empty_traceback.nframe = 1;
736 /* borrowed reference */
737 tracemalloc_empty_traceback.frames[0].filename = unknown_filename;
738 tracemalloc_empty_traceback.frames[0].lineno = 0;
739 tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback);
740
741 /* Disable tracing allocations until hooks are installed. Set
742 also the reentrant flag to detect bugs: fail with an assertion error
743 if set_reentrant(1) is called while tracing is disabled. */
744 set_reentrant(1);
745
746 tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED;
747 return 0;
748}
749
750static void
751tracemalloc_deinit(void)
752{
753 if (tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED)
754 return;
755 tracemalloc_config.initialized = TRACEMALLOC_FINALIZED;
756
757 tracemalloc_stop();
758
759 /* destroy hash tables */
760 _Py_hashtable_destroy(tracemalloc_traces);
761 _Py_hashtable_destroy(tracemalloc_tracebacks);
762 _Py_hashtable_destroy(tracemalloc_filenames);
763
764#if defined(WITH_THREAD) && defined(TRACE_RAW_MALLOC)
765 if (tables_lock != NULL) {
766 PyThread_free_lock(tables_lock);
767 tables_lock = NULL;
768 }
769#endif
770
771#ifdef REENTRANT_THREADLOCAL
772 PyThread_delete_key(tracemalloc_reentrant_key);
773#endif
774
775 Py_XDECREF(unknown_filename);
776}
777
778static int
779tracemalloc_start(void)
780{
781 PyMemAllocator alloc;
782
783 if (tracemalloc_init() < 0)
784 return -1;
785
786 if (tracemalloc_config.tracing) {
787 /* hook already installed: do nothing */
788 return 0;
789 }
790
791 if (tracemalloc_atexit_register() < 0)
792 return -1;
793
794#ifdef TRACE_RAW_MALLOC
795 alloc.malloc = tracemalloc_raw_malloc;
796 alloc.realloc = tracemalloc_raw_realloc;
797 alloc.free = tracemalloc_free;
798
799 alloc.ctx = &allocators.raw;
800 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
801 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
802#endif
803
804 alloc.malloc = tracemalloc_malloc_gil;
805 alloc.realloc = tracemalloc_realloc_gil;
806 alloc.free = tracemalloc_free;
807
808 alloc.ctx = &allocators.mem;
809 PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
810 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
811
812 alloc.ctx = &allocators.obj;
813 PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
814 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc);
815
816 /* everything is ready: start tracing Python memory allocations */
817 tracemalloc_config.tracing = 1;
818 set_reentrant(0);
819
820 return 0;
821}
822
823static void
824tracemalloc_stop(void)
825{
826 if (!tracemalloc_config.tracing)
827 return;
828
829 /* stop tracing Python memory allocations */
830 tracemalloc_config.tracing = 0;
831
832 /* set the reentrant flag to detect bugs: fail with an assertion error if
833 set_reentrant(1) is called while tracing is disabled. */
834 set_reentrant(1);
835
836 /* unregister the hook on memory allocators */
837#ifdef TRACE_RAW_MALLOC
838 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
839#endif
840 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
841 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
842
843 /* release memory */
844 tracemalloc_clear_traces();
845}
846
847
848static PyObject*
849lineno_as_obj(int lineno)
850{
851 if (lineno >= 0)
852 return PyLong_FromLong(lineno);
853 else
854 Py_RETURN_NONE;
855}
856
857PyDoc_STRVAR(tracemalloc_is_tracing_doc,
858 "is_tracing()->bool\n"
859 "\n"
860 "True if the tracemalloc module is tracing Python memory allocations,\n"
861 "False otherwise.");
862
863static PyObject*
864py_tracemalloc_is_tracing(PyObject *self)
865{
866 return PyBool_FromLong(tracemalloc_config.tracing);
867}
868
869PyDoc_STRVAR(tracemalloc_clear_traces_doc,
870 "clear_traces()\n"
871 "\n"
872 "Clear traces of memory blocks allocated by Python.");
873
874static PyObject*
875py_tracemalloc_clear_traces(PyObject *self)
876{
877 if (!tracemalloc_config.tracing)
878 Py_RETURN_NONE;
879
880 set_reentrant(1);
881 tracemalloc_clear_traces();
882 set_reentrant(0);
883
884 Py_RETURN_NONE;
885}
886
887static PyObject*
888frame_to_pyobject(frame_t *frame)
889{
890 PyObject *frame_obj, *lineno_obj;
891
892 frame_obj = PyTuple_New(2);
893 if (frame_obj == NULL)
894 return NULL;
895
896 if (frame->filename == NULL)
897 frame->filename = Py_None;
898 Py_INCREF(frame->filename);
899 PyTuple_SET_ITEM(frame_obj, 0, frame->filename);
900
901 assert(frame->lineno >= 0);
902 lineno_obj = lineno_as_obj(frame->lineno);
903 if (lineno_obj == NULL) {
904 Py_DECREF(frame_obj);
905 return NULL;
906 }
907 PyTuple_SET_ITEM(frame_obj, 1, lineno_obj);
908
909 return frame_obj;
910}
911
912static PyObject*
913traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table)
914{
915 int i;
916 PyObject *frames, *frame;
917
918 if (intern_table != NULL) {
919 if (_Py_HASHTABLE_GET(intern_table, traceback, frames)) {
920 Py_INCREF(frames);
921 return frames;
922 }
923 }
924
925 frames = PyTuple_New(traceback->nframe);
926 if (frames == NULL)
927 return NULL;
928
929 for (i=0; i < traceback->nframe; i++) {
930 frame = frame_to_pyobject(&traceback->frames[i]);
931 if (frame == NULL) {
932 Py_DECREF(frames);
933 return NULL;
934 }
935 PyTuple_SET_ITEM(frames, i, frame);
936 }
937
938 if (intern_table != NULL) {
939 if (_Py_HASHTABLE_SET(intern_table, traceback, frames) < 0) {
940 Py_DECREF(frames);
941 PyErr_NoMemory();
942 return NULL;
943 }
944 /* intern_table keeps a new reference to frames */
945 Py_INCREF(frames);
946 }
947 return frames;
948}
949
950static PyObject*
951trace_to_pyobject(trace_t *trace, _Py_hashtable_t *intern_tracebacks)
952{
953 PyObject *trace_obj = NULL;
954 PyObject *size, *traceback;
955
956 trace_obj = PyTuple_New(2);
957 if (trace_obj == NULL)
958 return NULL;
959
960 size = PyLong_FromSize_t(trace->size);
961 if (size == NULL) {
962 Py_DECREF(trace_obj);
963 return NULL;
964 }
965 PyTuple_SET_ITEM(trace_obj, 0, size);
966
967 traceback = traceback_to_pyobject(trace->traceback, intern_tracebacks);
968 if (traceback == NULL) {
969 Py_DECREF(trace_obj);
970 return NULL;
971 }
972 PyTuple_SET_ITEM(trace_obj, 1, traceback);
973
974 return trace_obj;
975}
976
977typedef struct {
978 _Py_hashtable_t *traces;
979 _Py_hashtable_t *tracebacks;
980 PyObject *list;
981} get_traces_t;
982
983static int
984tracemalloc_get_traces_fill(_Py_hashtable_entry_t *entry, void *user_data)
985{
986 get_traces_t *get_traces = user_data;
987 trace_t *trace;
988 PyObject *tracemalloc_obj;
989 int res;
990
991 trace = (trace_t *)_PY_HASHTABLE_ENTRY_DATA(entry);
992
993 tracemalloc_obj = trace_to_pyobject(trace, get_traces->tracebacks);
994 if (tracemalloc_obj == NULL)
995 return 1;
996
997 res = PyList_Append(get_traces->list, tracemalloc_obj);
998 Py_DECREF(tracemalloc_obj);
999 if (res < 0)
1000 return 1;
1001
1002 return 0;
1003}
1004
1005static int
1006tracemalloc_pyobject_decref_cb(_Py_hashtable_entry_t *entry, void *user_data)
1007{
1008 PyObject *obj = (PyObject *)_Py_HASHTABLE_ENTRY_DATA_AS_VOID_P(entry);
1009 Py_DECREF(obj);
1010 return 0;
1011}
1012
1013PyDoc_STRVAR(tracemalloc_get_traces_doc,
1014 "get_traces() -> list\n"
1015 "\n"
1016 "Get traces of all memory blocks allocated by Python.\n"
1017 "Return a list of (size: int, traceback: tuple) tuples.\n"
1018 "traceback is a tuple of (filename: str, lineno: int) tuples.\n"
1019 "\n"
1020 "Return an empty list if the tracemalloc module is disabled.");
1021
1022static PyObject*
1023py_tracemalloc_get_traces(PyObject *self, PyObject *obj)
1024{
1025 get_traces_t get_traces;
1026 int err;
1027
1028 get_traces.traces = NULL;
1029 get_traces.tracebacks = NULL;
1030 get_traces.list = PyList_New(0);
1031 if (get_traces.list == NULL)
1032 goto error;
1033
1034 if (!tracemalloc_config.tracing)
1035 return get_traces.list;
1036
1037 get_traces.tracebacks = hashtable_new(sizeof(PyObject *),
1038 _Py_hashtable_hash_ptr,
1039 _Py_hashtable_compare_direct);
1040 if (get_traces.tracebacks == NULL) {
1041 PyErr_NoMemory();
1042 goto error;
1043 }
1044
1045 TABLES_LOCK();
1046 get_traces.traces = _Py_hashtable_copy(tracemalloc_traces);
1047 TABLES_UNLOCK();
1048
1049 if (get_traces.traces == NULL) {
1050 PyErr_NoMemory();
1051 goto error;
1052 }
1053
1054 set_reentrant(1);
1055 err = _Py_hashtable_foreach(get_traces.traces,
1056 tracemalloc_get_traces_fill, &get_traces);
1057 set_reentrant(0);
1058 if (err)
1059 goto error;
1060
1061 goto finally;
1062
1063error:
1064 Py_CLEAR(get_traces.list);
1065
1066finally:
1067 if (get_traces.tracebacks != NULL) {
1068 _Py_hashtable_foreach(get_traces.tracebacks,
1069 tracemalloc_pyobject_decref_cb, NULL);
1070 _Py_hashtable_destroy(get_traces.tracebacks);
1071 }
1072 if (get_traces.traces != NULL)
1073 _Py_hashtable_destroy(get_traces.traces);
1074
1075 return get_traces.list;
1076}
1077
1078PyDoc_STRVAR(tracemalloc_get_object_traceback_doc,
1079 "get_object_traceback(obj)\n"
1080 "\n"
1081 "Get the traceback where the Python object obj was allocated.\n"
1082 "Return a tuple of (filename: str, lineno: int) tuples.\n"
1083 "\n"
1084 "Return None if the tracemalloc module is disabled or did not\n"
1085 "trace the allocation of the object.");
1086
1087static PyObject*
1088py_tracemalloc_get_object_traceback(PyObject *self, PyObject *obj)
1089{
1090 PyTypeObject *type;
1091 void *ptr;
1092 trace_t trace;
1093 int found;
1094
1095 if (!tracemalloc_config.tracing)
1096 Py_RETURN_NONE;
1097
1098 type = Py_TYPE(obj);
1099 if (PyType_IS_GC(type))
1100 ptr = (void *)((char *)obj - sizeof(PyGC_Head));
1101 else
1102 ptr = (void *)obj;
1103
1104 TABLES_LOCK();
1105 found = _Py_HASHTABLE_GET(tracemalloc_traces, ptr, trace);
1106 TABLES_UNLOCK();
1107
1108 if (!found)
1109 Py_RETURN_NONE;
1110
1111 return traceback_to_pyobject(trace.traceback, NULL);
1112}
1113
1114static PyObject*
1115tracemalloc_atexit(PyObject *self)
1116{
1117#ifdef WITH_THREAD
1118 assert(PyGILState_Check());
1119#endif
1120 tracemalloc_deinit();
1121 Py_RETURN_NONE;
1122}
1123
1124static PyMethodDef atexit_method = {
1125 "_atexit", (PyCFunction)tracemalloc_atexit, METH_NOARGS, NULL};
1126
1127static int
1128tracemalloc_atexit_register(void)
1129{
1130 PyObject *method = NULL, *atexit = NULL, *func = NULL;
1131 PyObject *result;
1132 int ret = -1;
1133
1134 if (tracemalloc_config.atexit_registered)
1135 return 0;
1136 tracemalloc_config.atexit_registered = 1;
1137
1138 /* private functions */
1139 method = PyCFunction_New(&atexit_method, NULL);
1140 if (method == NULL)
1141 goto done;
1142
1143 atexit = PyImport_ImportModule("atexit");
1144 if (atexit == NULL) {
1145 if (!PyErr_Warn(PyExc_ImportWarning,
1146 "atexit module is missing: "
1147 "cannot automatically disable tracemalloc at exit"))
1148 {
1149 PyErr_Clear();
1150 return 0;
1151 }
1152 goto done;
1153 }
1154
1155 func = PyObject_GetAttrString(atexit, "register");
1156 if (func == NULL)
1157 goto done;
1158
1159 result = PyObject_CallFunction(func, "O", method);
1160 if (result == NULL)
1161 goto done;
1162 Py_DECREF(result);
1163
1164 ret = 0;
1165
1166done:
1167 Py_XDECREF(method);
1168 Py_XDECREF(func);
1169 Py_XDECREF(atexit);
1170 return ret;
1171}
1172
1173PyDoc_STRVAR(tracemalloc_start_doc,
Victor Stinner3728d6c2013-11-23 12:37:20 +01001174 "start(nframe: int=1)\n"
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001175 "\n"
Victor Stinner3728d6c2013-11-23 12:37:20 +01001176 "Start tracing Python memory allocations. Set also the maximum number \n"
1177 "of frames stored in the traceback of a trace to nframe.");
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001178
1179static PyObject*
Victor Stinner3728d6c2013-11-23 12:37:20 +01001180py_tracemalloc_start(PyObject *self, PyObject *args)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001181{
Victor Stinner3728d6c2013-11-23 12:37:20 +01001182 Py_ssize_t nframe = 1;
1183
1184 if (!PyArg_ParseTuple(args, "|n:start", &nframe))
1185 return NULL;
1186
1187 if (nframe < 1 || nframe > MAX_NFRAME) {
1188 PyErr_Format(PyExc_ValueError,
1189 "the number of frames must be in range [1; %i]",
1190 MAX_NFRAME);
1191 return NULL;
1192 }
1193 tracemalloc_config.max_nframe = Py_SAFE_DOWNCAST(nframe, Py_ssize_t, int);
1194
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001195 if (tracemalloc_start() < 0)
1196 return NULL;
1197
1198 Py_RETURN_NONE;
1199}
1200
1201PyDoc_STRVAR(tracemalloc_stop_doc,
1202 "stop()\n"
1203 "\n"
1204 "Stop tracing Python memory allocations and clear traces\n"
1205 "of memory blocks allocated by Python.");
1206
1207static PyObject*
1208py_tracemalloc_stop(PyObject *self)
1209{
1210 tracemalloc_stop();
1211 Py_RETURN_NONE;
1212}
1213
1214PyDoc_STRVAR(tracemalloc_get_traceback_limit_doc,
1215 "get_traceback_limit() -> int\n"
1216 "\n"
1217 "Get the maximum number of frames stored in the traceback\n"
1218 "of a trace.\n"
1219 "\n"
1220 "By default, a trace of an allocated memory block only stores\n"
1221 "the most recent frame: the limit is 1.");
1222
1223static PyObject*
1224py_tracemalloc_get_traceback_limit(PyObject *self)
1225{
1226 return PyLong_FromLong(tracemalloc_config.max_nframe);
1227}
1228
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001229PyDoc_STRVAR(tracemalloc_get_tracemalloc_memory_doc,
1230 "get_tracemalloc_memory() -> int\n"
1231 "\n"
1232 "Get the memory usage in bytes of the tracemalloc module\n"
1233 "used internally to trace memory allocations.");
1234
1235static PyObject*
1236tracemalloc_get_tracemalloc_memory(PyObject *self)
1237{
1238 size_t size;
1239 PyObject *size_obj;
1240
1241 size = _Py_hashtable_size(tracemalloc_tracebacks);
1242 size += _Py_hashtable_size(tracemalloc_filenames);
1243
1244 TABLES_LOCK();
1245 size += _Py_hashtable_size(tracemalloc_traces);
1246 TABLES_UNLOCK();
1247
1248 size_obj = PyLong_FromSize_t(size);
1249 return Py_BuildValue("N", size_obj);
1250}
1251
1252PyDoc_STRVAR(tracemalloc_get_traced_memory_doc,
1253 "get_traced_memory() -> int\n"
1254 "\n"
1255 "Get the current size and maximum size of memory blocks traced\n"
1256 "by the tracemalloc module as a tuple: (size: int, max_size: int).");
1257
1258static PyObject*
1259tracemalloc_get_traced_memory(PyObject *self)
1260{
1261 Py_ssize_t size, max_size;
1262 PyObject *size_obj, *max_size_obj;
1263
1264 if (!tracemalloc_config.tracing)
1265 return Py_BuildValue("ii", 0, 0);
1266
1267 TABLES_LOCK();
1268 size = tracemalloc_traced_memory;
1269 max_size = tracemalloc_max_traced_memory;
1270 TABLES_UNLOCK();
1271
1272 size_obj = PyLong_FromSize_t(size);
1273 max_size_obj = PyLong_FromSize_t(max_size);
1274 return Py_BuildValue("NN", size_obj, max_size_obj);
1275}
1276
1277static PyMethodDef module_methods[] = {
1278 {"is_tracing", (PyCFunction)py_tracemalloc_is_tracing,
1279 METH_NOARGS, tracemalloc_is_tracing_doc},
1280 {"clear_traces", (PyCFunction)py_tracemalloc_clear_traces,
1281 METH_NOARGS, tracemalloc_clear_traces_doc},
1282 {"_get_traces", (PyCFunction)py_tracemalloc_get_traces,
1283 METH_NOARGS, tracemalloc_get_traces_doc},
1284 {"_get_object_traceback", (PyCFunction)py_tracemalloc_get_object_traceback,
1285 METH_O, tracemalloc_get_object_traceback_doc},
1286 {"start", (PyCFunction)py_tracemalloc_start,
Victor Stinner3728d6c2013-11-23 12:37:20 +01001287 METH_VARARGS, tracemalloc_start_doc},
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001288 {"stop", (PyCFunction)py_tracemalloc_stop,
1289 METH_NOARGS, tracemalloc_stop_doc},
1290 {"get_traceback_limit", (PyCFunction)py_tracemalloc_get_traceback_limit,
1291 METH_NOARGS, tracemalloc_get_traceback_limit_doc},
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001292 {"get_tracemalloc_memory", (PyCFunction)tracemalloc_get_tracemalloc_memory,
1293 METH_NOARGS, tracemalloc_get_tracemalloc_memory_doc},
1294 {"get_traced_memory", (PyCFunction)tracemalloc_get_traced_memory,
1295 METH_NOARGS, tracemalloc_get_traced_memory_doc},
1296
1297 /* sentinel */
1298 {NULL, NULL}
1299};
1300
1301PyDoc_STRVAR(module_doc,
1302"Debug module to trace memory blocks allocated by Python.");
1303
1304static struct PyModuleDef module_def = {
1305 PyModuleDef_HEAD_INIT,
1306 "_tracemalloc",
1307 module_doc,
1308 0, /* non-negative size to be able to unload the module */
1309 module_methods,
1310 NULL,
1311};
1312
1313PyMODINIT_FUNC
1314PyInit__tracemalloc(void)
1315{
1316 PyObject *m;
1317 m = PyModule_Create(&module_def);
1318 if (m == NULL)
1319 return NULL;
1320
1321 if (tracemalloc_init() < 0)
1322 return NULL;
1323
1324 return m;
1325}
1326
1327static int
1328parse_sys_xoptions(PyObject *value)
1329{
1330 PyObject *valuelong;
1331 long nframe;
1332
1333 if (value == Py_True)
1334 return 1;
1335
1336 assert(PyUnicode_Check(value));
1337 if (PyUnicode_GetLength(value) == 0)
1338 return -1;
1339
1340 valuelong = PyLong_FromUnicodeObject(value, 10);
1341 if (valuelong == NULL)
1342 return -1;
1343
1344 nframe = PyLong_AsLong(valuelong);
1345 Py_DECREF(valuelong);
1346 if (nframe == -1 && PyErr_Occurred())
1347 return -1;
1348
1349 if (nframe < 1 || nframe > MAX_NFRAME)
1350 return -1;
1351
1352 return Py_SAFE_DOWNCAST(nframe, long, int);
1353}
1354
1355int
1356_PyTraceMalloc_Init(void)
1357{
1358 char *p;
1359 int nframe;
1360
1361#ifdef WITH_THREAD
1362 assert(PyGILState_Check());
1363#endif
1364
1365 if ((p = Py_GETENV("PYTHONTRACEMALLOC")) && *p != '\0') {
1366 char *endptr = p;
1367 unsigned long value;
1368
1369 value = strtoul(p, &endptr, 10);
1370 if (*endptr != '\0'
1371 || value < 1
1372 || value > MAX_NFRAME
1373 || (errno == ERANGE && value == ULONG_MAX))
1374 {
1375 Py_FatalError("PYTHONTRACEMALLOC must be an integer "
1376 "in range [1; " STR(MAX_NFRAME) "]");
1377 return -1;
1378 }
1379
1380 nframe = (int)value;
1381 }
1382 else {
1383 PyObject *xoptions, *key, *value;
1384
1385 xoptions = PySys_GetXOptions();
1386 if (xoptions == NULL)
1387 return -1;
1388
1389 key = PyUnicode_FromString("tracemalloc");
1390 if (key == NULL)
1391 return -1;
1392
1393 value = PyDict_GetItemWithError(xoptions, key);
1394 Py_DECREF(key);
1395 if (value == NULL) {
1396 if (PyErr_Occurred())
1397 return -1;
1398
1399 /* -X tracemalloc is not used */
1400 return 0;
1401 }
1402
1403 nframe = parse_sys_xoptions(value);
1404 Py_DECREF(value);
1405 if (nframe < 0) {
1406 Py_FatalError("-X tracemalloc=NFRAME: number of frame must be "
1407 "an integer in range [1; " STR(MAX_NFRAME) "]");
1408 }
1409 }
1410
1411 tracemalloc_config.max_nframe = nframe;
1412 return tracemalloc_start();
1413}
1414