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