blob: 9dd4b19bccd43158e110cad7a2ce23110bdcd75f [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
439static void
440tracemalloc_log_alloc(void *ptr, size_t size)
441{
442 traceback_t *traceback;
443 trace_t trace;
444
445#ifdef WITH_THREAD
446 assert(PyGILState_Check());
447#endif
448
449 traceback = traceback_new();
450 if (traceback == NULL)
451 return;
452
453 trace.size = size;
454 trace.traceback = traceback;
455
456 TABLES_LOCK();
457 assert(tracemalloc_traced_memory <= PY_SIZE_MAX - size);
458 tracemalloc_traced_memory += size;
459 if (tracemalloc_traced_memory > tracemalloc_max_traced_memory)
460 tracemalloc_max_traced_memory = tracemalloc_traced_memory;
461
462 _Py_HASHTABLE_SET(tracemalloc_traces, ptr, trace);
463 TABLES_UNLOCK();
464}
465
466static void
467tracemalloc_log_free(void *ptr)
468{
469 trace_t trace;
470
471 TABLES_LOCK();
472 if (_Py_hashtable_pop(tracemalloc_traces, ptr, &trace, sizeof(trace))) {
473 assert(tracemalloc_traced_memory >= trace.size);
474 tracemalloc_traced_memory -= trace.size;
475 }
476 TABLES_UNLOCK();
477}
478
479static void*
480tracemalloc_malloc(void *ctx, size_t size, int gil_held)
481{
482 PyMemAllocator *alloc = (PyMemAllocator *)ctx;
483#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
484 PyGILState_STATE gil_state;
485#endif
486 void *ptr;
487
488 if (get_reentrant()) {
489 return alloc->malloc(alloc->ctx, size);
490 }
491
492 /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc()
493 for allocations larger than 512 bytes. PyGILState_Ensure() may call
494 PyMem_RawMalloc() indirectly which would call PyGILState_Ensure() if
495 reentrant are not disabled. */
496 set_reentrant(1);
497#ifdef WITH_THREAD
498#ifdef TRACE_RAW_MALLOC
499 if (!gil_held)
500 gil_state = PyGILState_Ensure();
501#else
502 assert(gil_held);
503#endif
504#endif
505 ptr = alloc->malloc(alloc->ctx, size);
506 set_reentrant(0);
507
508 if (ptr != NULL)
509 tracemalloc_log_alloc(ptr, size);
510
511#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
512 if (!gil_held)
513 PyGILState_Release(gil_state);
514#endif
515
516 return ptr;
517}
518
519static void*
520tracemalloc_realloc(void *ctx, void *ptr, size_t new_size, int gil_held)
521{
522 PyMemAllocator *alloc = (PyMemAllocator *)ctx;
523#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
524 PyGILState_STATE gil_state;
525#endif
526 void *ptr2;
527
528 if (get_reentrant()) {
529 /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc().
530 Example: PyMem_RawRealloc() is called internally by pymalloc
531 (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new
532 arena (new_arena()). */
533 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
534
535 if (ptr2 != NULL && ptr != NULL)
536 tracemalloc_log_free(ptr);
537
538 return ptr2;
539 }
540
541 /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for
542 allocations larger than 512 bytes. PyGILState_Ensure() may call
543 PyMem_RawMalloc() indirectly which would call PyGILState_Ensure() if
544 reentrant are not disabled. */
545 set_reentrant(1);
546#ifdef WITH_THREAD
547#ifdef TRACE_RAW_MALLOC
548 if (!gil_held)
549 gil_state = PyGILState_Ensure();
550#else
551 assert(gil_held);
552#endif
553#endif
554 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size);
555 set_reentrant(0);
556
557 if (ptr2 != NULL) {
558 if (ptr != NULL)
559 tracemalloc_log_free(ptr);
560
561 tracemalloc_log_alloc(ptr2, new_size);
562 }
563
564#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
565 if (!gil_held)
566 PyGILState_Release(gil_state);
567#endif
568
569 return ptr2;
570}
571
572static void
573tracemalloc_free(void *ctx, void *ptr)
574{
575 PyMemAllocator *alloc = (PyMemAllocator *)ctx;
576
577 if (ptr == NULL)
578 return;
579
580 /* GIL cannot be locked in PyMem_RawFree() because it would introduce
581 a deadlock in PyThreadState_DeleteCurrent(). */
582
583 alloc->free(alloc->ctx, ptr);
584 tracemalloc_log_free(ptr);
585}
586
587static void*
588tracemalloc_malloc_gil(void *ctx, size_t size)
589{
590 return tracemalloc_malloc(ctx, size, 1);
591}
592
593static void*
594tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
595{
596 return tracemalloc_realloc(ctx, ptr, new_size, 1);
597}
598
599#ifdef TRACE_RAW_MALLOC
600static void*
601tracemalloc_raw_malloc(void *ctx, size_t size)
602{
603 return tracemalloc_malloc(ctx, size, 0);
604}
605
606static void*
607tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
608{
609 return tracemalloc_realloc(ctx, ptr, new_size, 0);
610}
611#endif
612
613static int
614tracemalloc_clear_filename(_Py_hashtable_entry_t *entry, void *user_data)
615{
616 PyObject *filename = (PyObject *)entry->key;
617 Py_DECREF(filename);
618 return 0;
619}
620
621static int
622traceback_free_traceback(_Py_hashtable_entry_t *entry, void *user_data)
623{
624 traceback_t *traceback = (traceback_t *)entry->key;
625 raw_free(traceback);
626 return 0;
627}
628
629/* reentrant flag must be set to call this function and GIL must be held */
630static void
631tracemalloc_clear_traces(void)
632{
633#ifdef WITH_THREAD
634 /* The GIL protects variables againt concurrent access */
635 assert(PyGILState_Check());
636#endif
637
638 /* Disable also reentrant calls to tracemalloc_malloc() to not add a new
639 trace while we are clearing traces */
640 assert(get_reentrant());
641
642 TABLES_LOCK();
643 _Py_hashtable_clear(tracemalloc_traces);
644 tracemalloc_traced_memory = 0;
645 tracemalloc_max_traced_memory = 0;
646 TABLES_UNLOCK();
647
648 _Py_hashtable_foreach(tracemalloc_tracebacks, traceback_free_traceback, NULL);
649 _Py_hashtable_clear(tracemalloc_tracebacks);
650
651 _Py_hashtable_foreach(tracemalloc_filenames, tracemalloc_clear_filename, NULL);
652 _Py_hashtable_clear(tracemalloc_filenames);
653}
654
655static int
656tracemalloc_init(void)
657{
658 if (tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) {
659 PyErr_SetString(PyExc_RuntimeError,
660 "the tracemalloc module has been unloaded");
661 return -1;
662 }
663
664 if (tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED)
665 return 0;
666
667 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
668
669#ifdef REENTRANT_THREADLOCAL
670 tracemalloc_reentrant_key = PyThread_create_key();
671 if (tracemalloc_reentrant_key == -1) {
672#ifdef MS_WINDOWS
673 PyErr_SetFromWindowsErr(0);
674#else
675 PyErr_SetFromErrno(PyExc_OSError);
676#endif
677 return -1;
678 }
679#endif
680
681#if defined(WITH_THREAD) && defined(TRACE_RAW_MALLOC)
682 if (tables_lock == NULL) {
683 tables_lock = PyThread_allocate_lock();
684 if (tables_lock == NULL) {
685 PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock");
686 return -1;
687 }
688 }
689#endif
690
691 tracemalloc_filenames = hashtable_new(0,
692 (_Py_hashtable_hash_func)PyObject_Hash,
693 hashtable_compare_unicode);
694
695 tracemalloc_tracebacks = hashtable_new(0,
696 (_Py_hashtable_hash_func)hashtable_hash_traceback,
697 (_Py_hashtable_compare_func)hashtable_compare_traceback);
698
699 tracemalloc_traces = hashtable_new(sizeof(trace_t),
700 _Py_hashtable_hash_ptr,
701 _Py_hashtable_compare_direct);
702
703 if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL
704 || tracemalloc_traces == NULL)
705 {
706 PyErr_NoMemory();
707 return -1;
708 }
709
710 unknown_filename = PyUnicode_FromString("<unknown>");
711 if (unknown_filename == NULL)
712 return -1;
713 PyUnicode_InternInPlace(&unknown_filename);
714
715 tracemalloc_empty_traceback.nframe = 1;
716 /* borrowed reference */
717 tracemalloc_empty_traceback.frames[0].filename = unknown_filename;
718 tracemalloc_empty_traceback.frames[0].lineno = 0;
719 tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback);
720
721 /* Disable tracing allocations until hooks are installed. Set
722 also the reentrant flag to detect bugs: fail with an assertion error
723 if set_reentrant(1) is called while tracing is disabled. */
724 set_reentrant(1);
725
726 tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED;
727 return 0;
728}
729
730static void
731tracemalloc_deinit(void)
732{
733 if (tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED)
734 return;
735 tracemalloc_config.initialized = TRACEMALLOC_FINALIZED;
736
737 tracemalloc_stop();
738
739 /* destroy hash tables */
740 _Py_hashtable_destroy(tracemalloc_traces);
741 _Py_hashtable_destroy(tracemalloc_tracebacks);
742 _Py_hashtable_destroy(tracemalloc_filenames);
743
744#if defined(WITH_THREAD) && defined(TRACE_RAW_MALLOC)
745 if (tables_lock != NULL) {
746 PyThread_free_lock(tables_lock);
747 tables_lock = NULL;
748 }
749#endif
750
751#ifdef REENTRANT_THREADLOCAL
752 PyThread_delete_key(tracemalloc_reentrant_key);
753#endif
754
755 Py_XDECREF(unknown_filename);
756}
757
758static int
759tracemalloc_start(void)
760{
761 PyMemAllocator alloc;
762
763 if (tracemalloc_init() < 0)
764 return -1;
765
766 if (tracemalloc_config.tracing) {
767 /* hook already installed: do nothing */
768 return 0;
769 }
770
771 if (tracemalloc_atexit_register() < 0)
772 return -1;
773
774#ifdef TRACE_RAW_MALLOC
775 alloc.malloc = tracemalloc_raw_malloc;
776 alloc.realloc = tracemalloc_raw_realloc;
777 alloc.free = tracemalloc_free;
778
779 alloc.ctx = &allocators.raw;
780 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
781 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc);
782#endif
783
784 alloc.malloc = tracemalloc_malloc_gil;
785 alloc.realloc = tracemalloc_realloc_gil;
786 alloc.free = tracemalloc_free;
787
788 alloc.ctx = &allocators.mem;
789 PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
790 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc);
791
792 alloc.ctx = &allocators.obj;
793 PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
794 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc);
795
796 /* everything is ready: start tracing Python memory allocations */
797 tracemalloc_config.tracing = 1;
798 set_reentrant(0);
799
800 return 0;
801}
802
803static void
804tracemalloc_stop(void)
805{
806 if (!tracemalloc_config.tracing)
807 return;
808
809 /* stop tracing Python memory allocations */
810 tracemalloc_config.tracing = 0;
811
812 /* set the reentrant flag to detect bugs: fail with an assertion error if
813 set_reentrant(1) is called while tracing is disabled. */
814 set_reentrant(1);
815
816 /* unregister the hook on memory allocators */
817#ifdef TRACE_RAW_MALLOC
818 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
819#endif
820 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem);
821 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj);
822
823 /* release memory */
824 tracemalloc_clear_traces();
825}
826
827
828static PyObject*
829lineno_as_obj(int lineno)
830{
831 if (lineno >= 0)
832 return PyLong_FromLong(lineno);
833 else
834 Py_RETURN_NONE;
835}
836
837PyDoc_STRVAR(tracemalloc_is_tracing_doc,
838 "is_tracing()->bool\n"
839 "\n"
840 "True if the tracemalloc module is tracing Python memory allocations,\n"
841 "False otherwise.");
842
843static PyObject*
844py_tracemalloc_is_tracing(PyObject *self)
845{
846 return PyBool_FromLong(tracemalloc_config.tracing);
847}
848
849PyDoc_STRVAR(tracemalloc_clear_traces_doc,
850 "clear_traces()\n"
851 "\n"
852 "Clear traces of memory blocks allocated by Python.");
853
854static PyObject*
855py_tracemalloc_clear_traces(PyObject *self)
856{
857 if (!tracemalloc_config.tracing)
858 Py_RETURN_NONE;
859
860 set_reentrant(1);
861 tracemalloc_clear_traces();
862 set_reentrant(0);
863
864 Py_RETURN_NONE;
865}
866
867static PyObject*
868frame_to_pyobject(frame_t *frame)
869{
870 PyObject *frame_obj, *lineno_obj;
871
872 frame_obj = PyTuple_New(2);
873 if (frame_obj == NULL)
874 return NULL;
875
876 if (frame->filename == NULL)
877 frame->filename = Py_None;
878 Py_INCREF(frame->filename);
879 PyTuple_SET_ITEM(frame_obj, 0, frame->filename);
880
881 assert(frame->lineno >= 0);
882 lineno_obj = lineno_as_obj(frame->lineno);
883 if (lineno_obj == NULL) {
884 Py_DECREF(frame_obj);
885 return NULL;
886 }
887 PyTuple_SET_ITEM(frame_obj, 1, lineno_obj);
888
889 return frame_obj;
890}
891
892static PyObject*
893traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table)
894{
895 int i;
896 PyObject *frames, *frame;
897
898 if (intern_table != NULL) {
899 if (_Py_HASHTABLE_GET(intern_table, traceback, frames)) {
900 Py_INCREF(frames);
901 return frames;
902 }
903 }
904
905 frames = PyTuple_New(traceback->nframe);
906 if (frames == NULL)
907 return NULL;
908
909 for (i=0; i < traceback->nframe; i++) {
910 frame = frame_to_pyobject(&traceback->frames[i]);
911 if (frame == NULL) {
912 Py_DECREF(frames);
913 return NULL;
914 }
915 PyTuple_SET_ITEM(frames, i, frame);
916 }
917
918 if (intern_table != NULL) {
919 if (_Py_HASHTABLE_SET(intern_table, traceback, frames) < 0) {
920 Py_DECREF(frames);
921 PyErr_NoMemory();
922 return NULL;
923 }
924 /* intern_table keeps a new reference to frames */
925 Py_INCREF(frames);
926 }
927 return frames;
928}
929
930static PyObject*
931trace_to_pyobject(trace_t *trace, _Py_hashtable_t *intern_tracebacks)
932{
933 PyObject *trace_obj = NULL;
934 PyObject *size, *traceback;
935
936 trace_obj = PyTuple_New(2);
937 if (trace_obj == NULL)
938 return NULL;
939
940 size = PyLong_FromSize_t(trace->size);
941 if (size == NULL) {
942 Py_DECREF(trace_obj);
943 return NULL;
944 }
945 PyTuple_SET_ITEM(trace_obj, 0, size);
946
947 traceback = traceback_to_pyobject(trace->traceback, intern_tracebacks);
948 if (traceback == NULL) {
949 Py_DECREF(trace_obj);
950 return NULL;
951 }
952 PyTuple_SET_ITEM(trace_obj, 1, traceback);
953
954 return trace_obj;
955}
956
957typedef struct {
958 _Py_hashtable_t *traces;
959 _Py_hashtable_t *tracebacks;
960 PyObject *list;
961} get_traces_t;
962
963static int
964tracemalloc_get_traces_fill(_Py_hashtable_entry_t *entry, void *user_data)
965{
966 get_traces_t *get_traces = user_data;
967 trace_t *trace;
968 PyObject *tracemalloc_obj;
969 int res;
970
971 trace = (trace_t *)_PY_HASHTABLE_ENTRY_DATA(entry);
972
973 tracemalloc_obj = trace_to_pyobject(trace, get_traces->tracebacks);
974 if (tracemalloc_obj == NULL)
975 return 1;
976
977 res = PyList_Append(get_traces->list, tracemalloc_obj);
978 Py_DECREF(tracemalloc_obj);
979 if (res < 0)
980 return 1;
981
982 return 0;
983}
984
985static int
986tracemalloc_pyobject_decref_cb(_Py_hashtable_entry_t *entry, void *user_data)
987{
988 PyObject *obj = (PyObject *)_Py_HASHTABLE_ENTRY_DATA_AS_VOID_P(entry);
989 Py_DECREF(obj);
990 return 0;
991}
992
993PyDoc_STRVAR(tracemalloc_get_traces_doc,
994 "get_traces() -> list\n"
995 "\n"
996 "Get traces of all memory blocks allocated by Python.\n"
997 "Return a list of (size: int, traceback: tuple) tuples.\n"
998 "traceback is a tuple of (filename: str, lineno: int) tuples.\n"
999 "\n"
1000 "Return an empty list if the tracemalloc module is disabled.");
1001
1002static PyObject*
1003py_tracemalloc_get_traces(PyObject *self, PyObject *obj)
1004{
1005 get_traces_t get_traces;
1006 int err;
1007
1008 get_traces.traces = NULL;
1009 get_traces.tracebacks = NULL;
1010 get_traces.list = PyList_New(0);
1011 if (get_traces.list == NULL)
1012 goto error;
1013
1014 if (!tracemalloc_config.tracing)
1015 return get_traces.list;
1016
1017 get_traces.tracebacks = hashtable_new(sizeof(PyObject *),
1018 _Py_hashtable_hash_ptr,
1019 _Py_hashtable_compare_direct);
1020 if (get_traces.tracebacks == NULL) {
1021 PyErr_NoMemory();
1022 goto error;
1023 }
1024
1025 TABLES_LOCK();
1026 get_traces.traces = _Py_hashtable_copy(tracemalloc_traces);
1027 TABLES_UNLOCK();
1028
1029 if (get_traces.traces == NULL) {
1030 PyErr_NoMemory();
1031 goto error;
1032 }
1033
1034 set_reentrant(1);
1035 err = _Py_hashtable_foreach(get_traces.traces,
1036 tracemalloc_get_traces_fill, &get_traces);
1037 set_reentrant(0);
1038 if (err)
1039 goto error;
1040
1041 goto finally;
1042
1043error:
1044 Py_CLEAR(get_traces.list);
1045
1046finally:
1047 if (get_traces.tracebacks != NULL) {
1048 _Py_hashtable_foreach(get_traces.tracebacks,
1049 tracemalloc_pyobject_decref_cb, NULL);
1050 _Py_hashtable_destroy(get_traces.tracebacks);
1051 }
1052 if (get_traces.traces != NULL)
1053 _Py_hashtable_destroy(get_traces.traces);
1054
1055 return get_traces.list;
1056}
1057
1058PyDoc_STRVAR(tracemalloc_get_object_traceback_doc,
1059 "get_object_traceback(obj)\n"
1060 "\n"
1061 "Get the traceback where the Python object obj was allocated.\n"
1062 "Return a tuple of (filename: str, lineno: int) tuples.\n"
1063 "\n"
1064 "Return None if the tracemalloc module is disabled or did not\n"
1065 "trace the allocation of the object.");
1066
1067static PyObject*
1068py_tracemalloc_get_object_traceback(PyObject *self, PyObject *obj)
1069{
1070 PyTypeObject *type;
1071 void *ptr;
1072 trace_t trace;
1073 int found;
1074
1075 if (!tracemalloc_config.tracing)
1076 Py_RETURN_NONE;
1077
1078 type = Py_TYPE(obj);
1079 if (PyType_IS_GC(type))
1080 ptr = (void *)((char *)obj - sizeof(PyGC_Head));
1081 else
1082 ptr = (void *)obj;
1083
1084 TABLES_LOCK();
1085 found = _Py_HASHTABLE_GET(tracemalloc_traces, ptr, trace);
1086 TABLES_UNLOCK();
1087
1088 if (!found)
1089 Py_RETURN_NONE;
1090
1091 return traceback_to_pyobject(trace.traceback, NULL);
1092}
1093
1094static PyObject*
1095tracemalloc_atexit(PyObject *self)
1096{
1097#ifdef WITH_THREAD
1098 assert(PyGILState_Check());
1099#endif
1100 tracemalloc_deinit();
1101 Py_RETURN_NONE;
1102}
1103
1104static PyMethodDef atexit_method = {
1105 "_atexit", (PyCFunction)tracemalloc_atexit, METH_NOARGS, NULL};
1106
1107static int
1108tracemalloc_atexit_register(void)
1109{
1110 PyObject *method = NULL, *atexit = NULL, *func = NULL;
1111 PyObject *result;
1112 int ret = -1;
1113
1114 if (tracemalloc_config.atexit_registered)
1115 return 0;
1116 tracemalloc_config.atexit_registered = 1;
1117
1118 /* private functions */
1119 method = PyCFunction_New(&atexit_method, NULL);
1120 if (method == NULL)
1121 goto done;
1122
1123 atexit = PyImport_ImportModule("atexit");
1124 if (atexit == NULL) {
1125 if (!PyErr_Warn(PyExc_ImportWarning,
1126 "atexit module is missing: "
1127 "cannot automatically disable tracemalloc at exit"))
1128 {
1129 PyErr_Clear();
1130 return 0;
1131 }
1132 goto done;
1133 }
1134
1135 func = PyObject_GetAttrString(atexit, "register");
1136 if (func == NULL)
1137 goto done;
1138
1139 result = PyObject_CallFunction(func, "O", method);
1140 if (result == NULL)
1141 goto done;
1142 Py_DECREF(result);
1143
1144 ret = 0;
1145
1146done:
1147 Py_XDECREF(method);
1148 Py_XDECREF(func);
1149 Py_XDECREF(atexit);
1150 return ret;
1151}
1152
1153PyDoc_STRVAR(tracemalloc_start_doc,
Victor Stinner3728d6c2013-11-23 12:37:20 +01001154 "start(nframe: int=1)\n"
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001155 "\n"
Victor Stinner3728d6c2013-11-23 12:37:20 +01001156 "Start tracing Python memory allocations. Set also the maximum number \n"
1157 "of frames stored in the traceback of a trace to nframe.");
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001158
1159static PyObject*
Victor Stinner3728d6c2013-11-23 12:37:20 +01001160py_tracemalloc_start(PyObject *self, PyObject *args)
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001161{
Victor Stinner3728d6c2013-11-23 12:37:20 +01001162 Py_ssize_t nframe = 1;
1163
1164 if (!PyArg_ParseTuple(args, "|n:start", &nframe))
1165 return NULL;
1166
1167 if (nframe < 1 || nframe > MAX_NFRAME) {
1168 PyErr_Format(PyExc_ValueError,
1169 "the number of frames must be in range [1; %i]",
1170 MAX_NFRAME);
1171 return NULL;
1172 }
1173 tracemalloc_config.max_nframe = Py_SAFE_DOWNCAST(nframe, Py_ssize_t, int);
1174
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001175 if (tracemalloc_start() < 0)
1176 return NULL;
1177
1178 Py_RETURN_NONE;
1179}
1180
1181PyDoc_STRVAR(tracemalloc_stop_doc,
1182 "stop()\n"
1183 "\n"
1184 "Stop tracing Python memory allocations and clear traces\n"
1185 "of memory blocks allocated by Python.");
1186
1187static PyObject*
1188py_tracemalloc_stop(PyObject *self)
1189{
1190 tracemalloc_stop();
1191 Py_RETURN_NONE;
1192}
1193
1194PyDoc_STRVAR(tracemalloc_get_traceback_limit_doc,
1195 "get_traceback_limit() -> int\n"
1196 "\n"
1197 "Get the maximum number of frames stored in the traceback\n"
1198 "of a trace.\n"
1199 "\n"
1200 "By default, a trace of an allocated memory block only stores\n"
1201 "the most recent frame: the limit is 1.");
1202
1203static PyObject*
1204py_tracemalloc_get_traceback_limit(PyObject *self)
1205{
1206 return PyLong_FromLong(tracemalloc_config.max_nframe);
1207}
1208
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001209PyDoc_STRVAR(tracemalloc_get_tracemalloc_memory_doc,
1210 "get_tracemalloc_memory() -> int\n"
1211 "\n"
1212 "Get the memory usage in bytes of the tracemalloc module\n"
1213 "used internally to trace memory allocations.");
1214
1215static PyObject*
1216tracemalloc_get_tracemalloc_memory(PyObject *self)
1217{
1218 size_t size;
1219 PyObject *size_obj;
1220
1221 size = _Py_hashtable_size(tracemalloc_tracebacks);
1222 size += _Py_hashtable_size(tracemalloc_filenames);
1223
1224 TABLES_LOCK();
1225 size += _Py_hashtable_size(tracemalloc_traces);
1226 TABLES_UNLOCK();
1227
1228 size_obj = PyLong_FromSize_t(size);
1229 return Py_BuildValue("N", size_obj);
1230}
1231
1232PyDoc_STRVAR(tracemalloc_get_traced_memory_doc,
1233 "get_traced_memory() -> int\n"
1234 "\n"
1235 "Get the current size and maximum size of memory blocks traced\n"
1236 "by the tracemalloc module as a tuple: (size: int, max_size: int).");
1237
1238static PyObject*
1239tracemalloc_get_traced_memory(PyObject *self)
1240{
1241 Py_ssize_t size, max_size;
1242 PyObject *size_obj, *max_size_obj;
1243
1244 if (!tracemalloc_config.tracing)
1245 return Py_BuildValue("ii", 0, 0);
1246
1247 TABLES_LOCK();
1248 size = tracemalloc_traced_memory;
1249 max_size = tracemalloc_max_traced_memory;
1250 TABLES_UNLOCK();
1251
1252 size_obj = PyLong_FromSize_t(size);
1253 max_size_obj = PyLong_FromSize_t(max_size);
1254 return Py_BuildValue("NN", size_obj, max_size_obj);
1255}
1256
1257static PyMethodDef module_methods[] = {
1258 {"is_tracing", (PyCFunction)py_tracemalloc_is_tracing,
1259 METH_NOARGS, tracemalloc_is_tracing_doc},
1260 {"clear_traces", (PyCFunction)py_tracemalloc_clear_traces,
1261 METH_NOARGS, tracemalloc_clear_traces_doc},
1262 {"_get_traces", (PyCFunction)py_tracemalloc_get_traces,
1263 METH_NOARGS, tracemalloc_get_traces_doc},
1264 {"_get_object_traceback", (PyCFunction)py_tracemalloc_get_object_traceback,
1265 METH_O, tracemalloc_get_object_traceback_doc},
1266 {"start", (PyCFunction)py_tracemalloc_start,
Victor Stinner3728d6c2013-11-23 12:37:20 +01001267 METH_VARARGS, tracemalloc_start_doc},
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001268 {"stop", (PyCFunction)py_tracemalloc_stop,
1269 METH_NOARGS, tracemalloc_stop_doc},
1270 {"get_traceback_limit", (PyCFunction)py_tracemalloc_get_traceback_limit,
1271 METH_NOARGS, tracemalloc_get_traceback_limit_doc},
Victor Stinnered3b0bc2013-11-23 12:27:24 +01001272 {"get_tracemalloc_memory", (PyCFunction)tracemalloc_get_tracemalloc_memory,
1273 METH_NOARGS, tracemalloc_get_tracemalloc_memory_doc},
1274 {"get_traced_memory", (PyCFunction)tracemalloc_get_traced_memory,
1275 METH_NOARGS, tracemalloc_get_traced_memory_doc},
1276
1277 /* sentinel */
1278 {NULL, NULL}
1279};
1280
1281PyDoc_STRVAR(module_doc,
1282"Debug module to trace memory blocks allocated by Python.");
1283
1284static struct PyModuleDef module_def = {
1285 PyModuleDef_HEAD_INIT,
1286 "_tracemalloc",
1287 module_doc,
1288 0, /* non-negative size to be able to unload the module */
1289 module_methods,
1290 NULL,
1291};
1292
1293PyMODINIT_FUNC
1294PyInit__tracemalloc(void)
1295{
1296 PyObject *m;
1297 m = PyModule_Create(&module_def);
1298 if (m == NULL)
1299 return NULL;
1300
1301 if (tracemalloc_init() < 0)
1302 return NULL;
1303
1304 return m;
1305}
1306
1307static int
1308parse_sys_xoptions(PyObject *value)
1309{
1310 PyObject *valuelong;
1311 long nframe;
1312
1313 if (value == Py_True)
1314 return 1;
1315
1316 assert(PyUnicode_Check(value));
1317 if (PyUnicode_GetLength(value) == 0)
1318 return -1;
1319
1320 valuelong = PyLong_FromUnicodeObject(value, 10);
1321 if (valuelong == NULL)
1322 return -1;
1323
1324 nframe = PyLong_AsLong(valuelong);
1325 Py_DECREF(valuelong);
1326 if (nframe == -1 && PyErr_Occurred())
1327 return -1;
1328
1329 if (nframe < 1 || nframe > MAX_NFRAME)
1330 return -1;
1331
1332 return Py_SAFE_DOWNCAST(nframe, long, int);
1333}
1334
1335int
1336_PyTraceMalloc_Init(void)
1337{
1338 char *p;
1339 int nframe;
1340
1341#ifdef WITH_THREAD
1342 assert(PyGILState_Check());
1343#endif
1344
1345 if ((p = Py_GETENV("PYTHONTRACEMALLOC")) && *p != '\0') {
1346 char *endptr = p;
1347 unsigned long value;
1348
1349 value = strtoul(p, &endptr, 10);
1350 if (*endptr != '\0'
1351 || value < 1
1352 || value > MAX_NFRAME
1353 || (errno == ERANGE && value == ULONG_MAX))
1354 {
1355 Py_FatalError("PYTHONTRACEMALLOC must be an integer "
1356 "in range [1; " STR(MAX_NFRAME) "]");
1357 return -1;
1358 }
1359
1360 nframe = (int)value;
1361 }
1362 else {
1363 PyObject *xoptions, *key, *value;
1364
1365 xoptions = PySys_GetXOptions();
1366 if (xoptions == NULL)
1367 return -1;
1368
1369 key = PyUnicode_FromString("tracemalloc");
1370 if (key == NULL)
1371 return -1;
1372
1373 value = PyDict_GetItemWithError(xoptions, key);
1374 Py_DECREF(key);
1375 if (value == NULL) {
1376 if (PyErr_Occurred())
1377 return -1;
1378
1379 /* -X tracemalloc is not used */
1380 return 0;
1381 }
1382
1383 nframe = parse_sys_xoptions(value);
1384 Py_DECREF(value);
1385 if (nframe < 0) {
1386 Py_FatalError("-X tracemalloc=NFRAME: number of frame must be "
1387 "an integer in range [1; " STR(MAX_NFRAME) "]");
1388 }
1389 }
1390
1391 tracemalloc_config.max_nframe = nframe;
1392 return tracemalloc_start();
1393}
1394