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