1 #include "Python.h" 2 #include "hashtable.h" 3 #include "frameobject.h" 4 #include "pythread.h" 5 #include "osdefs.h" 6 7 #include "clinic/_tracemalloc.c.h" 8 /*[clinic input] 9 module _tracemalloc 10 [clinic start generated code]*/ 11 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=708a98302fc46e5f]*/ 12 13 /* Trace memory blocks allocated by PyMem_RawMalloc() */ 14 #define TRACE_RAW_MALLOC 15 16 /* Forward declaration */ 17 static void tracemalloc_stop(void); 18 static void* raw_malloc(size_t size); 19 static void raw_free(void *ptr); 20 21 #ifdef Py_DEBUG 22 # define TRACE_DEBUG 23 #endif 24 25 /* Protected by the GIL */ 26 static struct { 27 PyMemAllocatorEx mem; 28 PyMemAllocatorEx raw; 29 PyMemAllocatorEx obj; 30 } allocators; 31 32 static struct { 33 /* Module initialized? 34 Variable protected by the GIL */ 35 enum { 36 TRACEMALLOC_NOT_INITIALIZED, 37 TRACEMALLOC_INITIALIZED, 38 TRACEMALLOC_FINALIZED 39 } initialized; 40 41 /* Is tracemalloc tracing memory allocations? 42 Variable protected by the GIL */ 43 int tracing; 44 45 /* limit of the number of frames in a traceback, 1 by default. 46 Variable protected by the GIL. */ 47 int max_nframe; 48 49 /* use domain in trace key? 50 Variable protected by the GIL. */ 51 int use_domain; 52 } tracemalloc_config = {TRACEMALLOC_NOT_INITIALIZED, 0, 1, 0}; 53 54 #if defined(TRACE_RAW_MALLOC) 55 /* This lock is needed because tracemalloc_free() is called without 56 the GIL held from PyMem_RawFree(). It cannot acquire the lock because it 57 would introduce a deadlock in PyThreadState_DeleteCurrent(). */ 58 static PyThread_type_lock tables_lock; 59 # define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1) 60 # define TABLES_UNLOCK() PyThread_release_lock(tables_lock) 61 #else 62 /* variables are protected by the GIL */ 63 # define TABLES_LOCK() 64 # define TABLES_UNLOCK() 65 #endif 66 67 68 #define DEFAULT_DOMAIN 0 69 70 /* Pack the frame_t structure to reduce the memory footprint. */ 71 typedef struct 72 #ifdef __GNUC__ 73 __attribute__((packed)) 74 #endif 75 { 76 uintptr_t ptr; 77 unsigned int domain; 78 } pointer_t; 79 80 /* Pack the frame_t structure to reduce the memory footprint on 64-bit 81 architectures: 12 bytes instead of 16. */ 82 typedef struct 83 #ifdef __GNUC__ 84 __attribute__((packed)) 85 #elif defined(_MSC_VER) 86 #pragma pack(push, 4) 87 #endif 88 { 89 /* filename cannot be NULL: "<unknown>" is used if the Python frame 90 filename is NULL */ 91 PyObject *filename; 92 unsigned int lineno; 93 } frame_t; 94 #ifdef _MSC_VER 95 #pragma pack(pop) 96 #endif 97 98 99 typedef struct { 100 Py_uhash_t hash; 101 int nframe; 102 frame_t frames[1]; 103 } traceback_t; 104 105 #define TRACEBACK_SIZE(NFRAME) \ 106 (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1)) 107 108 #define MAX_NFRAME \ 109 ((INT_MAX - (int)sizeof(traceback_t)) / (int)sizeof(frame_t) + 1) 110 111 112 static PyObject *unknown_filename = NULL; 113 static traceback_t tracemalloc_empty_traceback; 114 115 /* Trace of a memory block */ 116 typedef struct { 117 /* Size of the memory block in bytes */ 118 size_t size; 119 120 /* Traceback where the memory block was allocated */ 121 traceback_t *traceback; 122 } trace_t; 123 124 125 /* Size in bytes of currently traced memory. 126 Protected by TABLES_LOCK(). */ 127 static size_t tracemalloc_traced_memory = 0; 128 129 /* Peak size in bytes of traced memory. 130 Protected by TABLES_LOCK(). */ 131 static size_t tracemalloc_peak_traced_memory = 0; 132 133 /* Hash table used as a set to intern filenames: 134 PyObject* => PyObject*. 135 Protected by the GIL */ 136 static _Py_hashtable_t *tracemalloc_filenames = NULL; 137 138 /* Buffer to store a new traceback in traceback_new(). 139 Protected by the GIL. */ 140 static traceback_t *tracemalloc_traceback = NULL; 141 142 /* Hash table used as a set to intern tracebacks: 143 traceback_t* => traceback_t* 144 Protected by the GIL */ 145 static _Py_hashtable_t *tracemalloc_tracebacks = NULL; 146 147 /* pointer (void*) => trace (trace_t). 148 Protected by TABLES_LOCK(). */ 149 static _Py_hashtable_t *tracemalloc_traces = NULL; 150 151 152 #ifdef TRACE_DEBUG 153 static void 154 tracemalloc_error(const char *format, ...) 155 { 156 va_list ap; 157 fprintf(stderr, "tracemalloc: "); 158 va_start(ap, format); 159 vfprintf(stderr, format, ap); 160 va_end(ap); 161 fprintf(stderr, "\n"); 162 fflush(stderr); 163 } 164 #endif 165 166 167 #if defined(TRACE_RAW_MALLOC) 168 #define REENTRANT_THREADLOCAL 169 170 static Py_tss_t tracemalloc_reentrant_key = Py_tss_NEEDS_INIT; 171 172 /* Any non-NULL pointer can be used */ 173 #define REENTRANT Py_True 174 175 static int 176 get_reentrant(void) 177 { 178 void *ptr; 179 180 assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); 181 ptr = PyThread_tss_get(&tracemalloc_reentrant_key); 182 if (ptr != NULL) { 183 assert(ptr == REENTRANT); 184 return 1; 185 } 186 else 187 return 0; 188 } 189 190 static void 191 set_reentrant(int reentrant) 192 { 193 assert(reentrant == 0 || reentrant == 1); 194 assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); 195 196 if (reentrant) { 197 assert(!get_reentrant()); 198 PyThread_tss_set(&tracemalloc_reentrant_key, REENTRANT); 199 } 200 else { 201 assert(get_reentrant()); 202 PyThread_tss_set(&tracemalloc_reentrant_key, NULL); 203 } 204 } 205 206 #else 207 208 /* TRACE_RAW_MALLOC not defined: variable protected by the GIL */ 209 static int tracemalloc_reentrant = 0; 210 211 static int 212 get_reentrant(void) 213 { 214 return tracemalloc_reentrant; 215 } 216 217 static void 218 set_reentrant(int reentrant) 219 { 220 assert(reentrant != tracemalloc_reentrant); 221 tracemalloc_reentrant = reentrant; 222 } 223 #endif 224 225 226 static Py_uhash_t 227 hashtable_hash_pyobject(_Py_hashtable_t *ht, const void *pkey) 228 { 229 PyObject *obj; 230 231 _Py_HASHTABLE_READ_KEY(ht, pkey, obj); 232 return PyObject_Hash(obj); 233 } 234 235 236 static int 237 hashtable_compare_unicode(_Py_hashtable_t *ht, const void *pkey, 238 const _Py_hashtable_entry_t *entry) 239 { 240 PyObject *key1, *key2; 241 242 _Py_HASHTABLE_READ_KEY(ht, pkey, key1); 243 _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, key2); 244 245 if (key1 != NULL && key2 != NULL) 246 return (PyUnicode_Compare(key1, key2) == 0); 247 else 248 return key1 == key2; 249 } 250 251 252 static Py_uhash_t 253 hashtable_hash_pointer_t(_Py_hashtable_t *ht, const void *pkey) 254 { 255 pointer_t ptr; 256 Py_uhash_t hash; 257 258 _Py_HASHTABLE_READ_KEY(ht, pkey, ptr); 259 260 hash = (Py_uhash_t)_Py_HashPointer((void*)ptr.ptr); 261 hash ^= ptr.domain; 262 return hash; 263 } 264 265 266 static int 267 hashtable_compare_pointer_t(_Py_hashtable_t *ht, const void *pkey, 268 const _Py_hashtable_entry_t *entry) 269 { 270 pointer_t ptr1, ptr2; 271 272 _Py_HASHTABLE_READ_KEY(ht, pkey, ptr1); 273 _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, ptr2); 274 275 /* compare pointer before domain, because pointer is more likely to be 276 different */ 277 return (ptr1.ptr == ptr2.ptr && ptr1.domain == ptr2.domain); 278 279 } 280 281 282 static _Py_hashtable_t * 283 hashtable_new(size_t key_size, size_t data_size, 284 _Py_hashtable_hash_func hash_func, 285 _Py_hashtable_compare_func compare_func) 286 { 287 _Py_hashtable_allocator_t hashtable_alloc = {malloc, free}; 288 return _Py_hashtable_new_full(key_size, data_size, 0, 289 hash_func, compare_func, 290 &hashtable_alloc); 291 } 292 293 294 static void* 295 raw_malloc(size_t size) 296 { 297 return allocators.raw.malloc(allocators.raw.ctx, size); 298 } 299 300 static void 301 raw_free(void *ptr) 302 { 303 allocators.raw.free(allocators.raw.ctx, ptr); 304 } 305 306 307 static Py_uhash_t 308 hashtable_hash_traceback(_Py_hashtable_t *ht, const void *pkey) 309 { 310 traceback_t *traceback; 311 312 _Py_HASHTABLE_READ_KEY(ht, pkey, traceback); 313 return traceback->hash; 314 } 315 316 317 static int 318 hashtable_compare_traceback(_Py_hashtable_t *ht, const void *pkey, 319 const _Py_hashtable_entry_t *entry) 320 { 321 traceback_t *traceback1, *traceback2; 322 const frame_t *frame1, *frame2; 323 int i; 324 325 _Py_HASHTABLE_READ_KEY(ht, pkey, traceback1); 326 _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, traceback2); 327 328 if (traceback1->nframe != traceback2->nframe) 329 return 0; 330 331 for (i=0; i < traceback1->nframe; i++) { 332 frame1 = &traceback1->frames[i]; 333 frame2 = &traceback2->frames[i]; 334 335 if (frame1->lineno != frame2->lineno) 336 return 0; 337 338 if (frame1->filename != frame2->filename) { 339 assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0); 340 return 0; 341 } 342 } 343 return 1; 344 } 345 346 347 static void 348 tracemalloc_get_frame(PyFrameObject *pyframe, frame_t *frame) 349 { 350 PyCodeObject *code; 351 PyObject *filename; 352 _Py_hashtable_entry_t *entry; 353 int lineno; 354 355 frame->filename = unknown_filename; 356 lineno = PyFrame_GetLineNumber(pyframe); 357 if (lineno < 0) 358 lineno = 0; 359 frame->lineno = (unsigned int)lineno; 360 361 code = pyframe->f_code; 362 if (code == NULL) { 363 #ifdef TRACE_DEBUG 364 tracemalloc_error("failed to get the code object of the frame"); 365 #endif 366 return; 367 } 368 369 if (code->co_filename == NULL) { 370 #ifdef TRACE_DEBUG 371 tracemalloc_error("failed to get the filename of the code object"); 372 #endif 373 return; 374 } 375 376 filename = code->co_filename; 377 assert(filename != NULL); 378 if (filename == NULL) 379 return; 380 381 if (!PyUnicode_Check(filename)) { 382 #ifdef TRACE_DEBUG 383 tracemalloc_error("filename is not a unicode string"); 384 #endif 385 return; 386 } 387 if (!PyUnicode_IS_READY(filename)) { 388 /* Don't make a Unicode string ready to avoid reentrant calls 389 to tracemalloc_malloc() or tracemalloc_realloc() */ 390 #ifdef TRACE_DEBUG 391 tracemalloc_error("filename is not a ready unicode string"); 392 #endif 393 return; 394 } 395 396 /* intern the filename */ 397 entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_filenames, filename); 398 if (entry != NULL) { 399 _Py_HASHTABLE_ENTRY_READ_KEY(tracemalloc_filenames, entry, filename); 400 } 401 else { 402 /* tracemalloc_filenames is responsible to keep a reference 403 to the filename */ 404 Py_INCREF(filename); 405 if (_Py_HASHTABLE_SET_NODATA(tracemalloc_filenames, filename) < 0) { 406 Py_DECREF(filename); 407 #ifdef TRACE_DEBUG 408 tracemalloc_error("failed to intern the filename"); 409 #endif 410 return; 411 } 412 } 413 414 /* the tracemalloc_filenames table keeps a reference to the filename */ 415 frame->filename = filename; 416 } 417 418 419 static Py_uhash_t 420 traceback_hash(traceback_t *traceback) 421 { 422 /* code based on tuplehash() of Objects/tupleobject.c */ 423 Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */ 424 int len = traceback->nframe; 425 Py_uhash_t mult = _PyHASH_MULTIPLIER; 426 frame_t *frame; 427 428 x = 0x345678UL; 429 frame = traceback->frames; 430 while (--len >= 0) { 431 y = (Py_uhash_t)PyObject_Hash(frame->filename); 432 y ^= (Py_uhash_t)frame->lineno; 433 frame++; 434 435 x = (x ^ y) * mult; 436 /* the cast might truncate len; that doesn't change hash stability */ 437 mult += (Py_uhash_t)(82520UL + len + len); 438 } 439 x += 97531UL; 440 return x; 441 } 442 443 444 static void 445 traceback_get_frames(traceback_t *traceback) 446 { 447 PyThreadState *tstate; 448 PyFrameObject *pyframe; 449 450 tstate = PyGILState_GetThisThreadState(); 451 if (tstate == NULL) { 452 #ifdef TRACE_DEBUG 453 tracemalloc_error("failed to get the current thread state"); 454 #endif 455 return; 456 } 457 458 for (pyframe = tstate->frame; pyframe != NULL; pyframe = pyframe->f_back) { 459 tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]); 460 assert(traceback->frames[traceback->nframe].filename != NULL); 461 traceback->nframe++; 462 if (traceback->nframe == tracemalloc_config.max_nframe) 463 break; 464 } 465 } 466 467 468 static traceback_t * 469 traceback_new(void) 470 { 471 traceback_t *traceback; 472 _Py_hashtable_entry_t *entry; 473 474 assert(PyGILState_Check()); 475 476 /* get frames */ 477 traceback = tracemalloc_traceback; 478 traceback->nframe = 0; 479 traceback_get_frames(traceback); 480 if (traceback->nframe == 0) 481 return &tracemalloc_empty_traceback; 482 traceback->hash = traceback_hash(traceback); 483 484 /* intern the traceback */ 485 entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_tracebacks, traceback); 486 if (entry != NULL) { 487 _Py_HASHTABLE_ENTRY_READ_KEY(tracemalloc_tracebacks, entry, traceback); 488 } 489 else { 490 traceback_t *copy; 491 size_t traceback_size; 492 493 traceback_size = TRACEBACK_SIZE(traceback->nframe); 494 495 copy = raw_malloc(traceback_size); 496 if (copy == NULL) { 497 #ifdef TRACE_DEBUG 498 tracemalloc_error("failed to intern the traceback: malloc failed"); 499 #endif 500 return NULL; 501 } 502 memcpy(copy, traceback, traceback_size); 503 504 if (_Py_HASHTABLE_SET_NODATA(tracemalloc_tracebacks, copy) < 0) { 505 raw_free(copy); 506 #ifdef TRACE_DEBUG 507 tracemalloc_error("failed to intern the traceback: putdata failed"); 508 #endif 509 return NULL; 510 } 511 traceback = copy; 512 } 513 return traceback; 514 } 515 516 517 static int 518 tracemalloc_use_domain_cb(_Py_hashtable_t *old_traces, 519 _Py_hashtable_entry_t *entry, void *user_data) 520 { 521 uintptr_t ptr; 522 pointer_t key; 523 _Py_hashtable_t *new_traces = (_Py_hashtable_t *)user_data; 524 const void *pdata = _Py_HASHTABLE_ENTRY_PDATA(old_traces, entry); 525 526 _Py_HASHTABLE_ENTRY_READ_KEY(old_traces, entry, ptr); 527 key.ptr = ptr; 528 key.domain = DEFAULT_DOMAIN; 529 530 return _Py_hashtable_set(new_traces, 531 sizeof(key), &key, 532 old_traces->data_size, pdata); 533 } 534 535 536 /* Convert tracemalloc_traces from compact key (uintptr_t) to pointer_t key. 537 * Return 0 on success, -1 on error. */ 538 static int 539 tracemalloc_use_domain(void) 540 { 541 _Py_hashtable_t *new_traces = NULL; 542 543 assert(!tracemalloc_config.use_domain); 544 545 new_traces = hashtable_new(sizeof(pointer_t), 546 sizeof(trace_t), 547 hashtable_hash_pointer_t, 548 hashtable_compare_pointer_t); 549 if (new_traces == NULL) { 550 return -1; 551 } 552 553 if (_Py_hashtable_foreach(tracemalloc_traces, tracemalloc_use_domain_cb, 554 new_traces) < 0) 555 { 556 _Py_hashtable_destroy(new_traces); 557 return -1; 558 } 559 560 _Py_hashtable_destroy(tracemalloc_traces); 561 tracemalloc_traces = new_traces; 562 563 tracemalloc_config.use_domain = 1; 564 565 return 0; 566 } 567 568 569 static void 570 tracemalloc_remove_trace(unsigned int domain, uintptr_t ptr) 571 { 572 trace_t trace; 573 int removed; 574 575 assert(tracemalloc_config.tracing); 576 577 if (tracemalloc_config.use_domain) { 578 pointer_t key = {ptr, domain}; 579 removed = _Py_HASHTABLE_POP(tracemalloc_traces, key, trace); 580 } 581 else { 582 removed = _Py_HASHTABLE_POP(tracemalloc_traces, ptr, trace); 583 } 584 if (!removed) { 585 return; 586 } 587 588 assert(tracemalloc_traced_memory >= trace.size); 589 tracemalloc_traced_memory -= trace.size; 590 } 591 592 #define REMOVE_TRACE(ptr) \ 593 tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr)) 594 595 596 static int 597 tracemalloc_add_trace(unsigned int domain, uintptr_t ptr, 598 size_t size) 599 { 600 pointer_t key = {ptr, domain}; 601 traceback_t *traceback; 602 trace_t trace; 603 _Py_hashtable_entry_t* entry; 604 int res; 605 606 assert(tracemalloc_config.tracing); 607 608 traceback = traceback_new(); 609 if (traceback == NULL) { 610 return -1; 611 } 612 613 if (!tracemalloc_config.use_domain && domain != DEFAULT_DOMAIN) { 614 /* first trace using a non-zero domain whereas traces use compact 615 (uintptr_t) keys: switch to pointer_t keys. */ 616 if (tracemalloc_use_domain() < 0) { 617 return -1; 618 } 619 } 620 621 if (tracemalloc_config.use_domain) { 622 entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_traces, key); 623 } 624 else { 625 entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_traces, ptr); 626 } 627 628 if (entry != NULL) { 629 /* the memory block is already tracked */ 630 _Py_HASHTABLE_ENTRY_READ_DATA(tracemalloc_traces, entry, trace); 631 assert(tracemalloc_traced_memory >= trace.size); 632 tracemalloc_traced_memory -= trace.size; 633 634 trace.size = size; 635 trace.traceback = traceback; 636 _Py_HASHTABLE_ENTRY_WRITE_DATA(tracemalloc_traces, entry, trace); 637 } 638 else { 639 trace.size = size; 640 trace.traceback = traceback; 641 642 if (tracemalloc_config.use_domain) { 643 res = _Py_HASHTABLE_SET(tracemalloc_traces, key, trace); 644 } 645 else { 646 res = _Py_HASHTABLE_SET(tracemalloc_traces, ptr, trace); 647 } 648 if (res != 0) { 649 return res; 650 } 651 } 652 653 assert(tracemalloc_traced_memory <= SIZE_MAX - size); 654 tracemalloc_traced_memory += size; 655 if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory) 656 tracemalloc_peak_traced_memory = tracemalloc_traced_memory; 657 return 0; 658 } 659 660 #define ADD_TRACE(ptr, size) \ 661 tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size) 662 663 664 static void* 665 tracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) 666 { 667 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 668 void *ptr; 669 670 assert(elsize == 0 || nelem <= SIZE_MAX / elsize); 671 672 if (use_calloc) 673 ptr = alloc->calloc(alloc->ctx, nelem, elsize); 674 else 675 ptr = alloc->malloc(alloc->ctx, nelem * elsize); 676 if (ptr == NULL) 677 return NULL; 678 679 TABLES_LOCK(); 680 if (ADD_TRACE(ptr, nelem * elsize) < 0) { 681 /* Failed to allocate a trace for the new memory block */ 682 TABLES_UNLOCK(); 683 alloc->free(alloc->ctx, ptr); 684 return NULL; 685 } 686 TABLES_UNLOCK(); 687 return ptr; 688 } 689 690 691 static void* 692 tracemalloc_realloc(void *ctx, void *ptr, size_t new_size) 693 { 694 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 695 void *ptr2; 696 697 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); 698 if (ptr2 == NULL) 699 return NULL; 700 701 if (ptr != NULL) { 702 /* an existing memory block has been resized */ 703 704 TABLES_LOCK(); 705 706 /* tracemalloc_add_trace() updates the trace if there is already 707 a trace at address (domain, ptr2) */ 708 if (ptr2 != ptr) { 709 REMOVE_TRACE(ptr); 710 } 711 712 if (ADD_TRACE(ptr2, new_size) < 0) { 713 /* Memory allocation failed. The error cannot be reported to 714 the caller, because realloc() may already have shrunk the 715 memory block and so removed bytes. 716 717 This case is very unlikely: a hash entry has just been 718 released, so the hash table should have at least one free entry. 719 720 The GIL and the table lock ensures that only one thread is 721 allocating memory. */ 722 Py_UNREACHABLE(); 723 } 724 TABLES_UNLOCK(); 725 } 726 else { 727 /* new allocation */ 728 729 TABLES_LOCK(); 730 if (ADD_TRACE(ptr2, new_size) < 0) { 731 /* Failed to allocate a trace for the new memory block */ 732 TABLES_UNLOCK(); 733 alloc->free(alloc->ctx, ptr2); 734 return NULL; 735 } 736 TABLES_UNLOCK(); 737 } 738 return ptr2; 739 } 740 741 742 static void 743 tracemalloc_free(void *ctx, void *ptr) 744 { 745 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 746 747 if (ptr == NULL) 748 return; 749 750 /* GIL cannot be locked in PyMem_RawFree() because it would introduce 751 a deadlock in PyThreadState_DeleteCurrent(). */ 752 753 alloc->free(alloc->ctx, ptr); 754 755 TABLES_LOCK(); 756 REMOVE_TRACE(ptr); 757 TABLES_UNLOCK(); 758 } 759 760 761 static void* 762 tracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize) 763 { 764 void *ptr; 765 766 if (get_reentrant()) { 767 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 768 if (use_calloc) 769 return alloc->calloc(alloc->ctx, nelem, elsize); 770 else 771 return alloc->malloc(alloc->ctx, nelem * elsize); 772 } 773 774 /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for 775 allocations larger than 512 bytes, don't trace the same memory 776 allocation twice. */ 777 set_reentrant(1); 778 779 ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); 780 781 set_reentrant(0); 782 return ptr; 783 } 784 785 786 static void* 787 tracemalloc_malloc_gil(void *ctx, size_t size) 788 { 789 return tracemalloc_alloc_gil(0, ctx, 1, size); 790 } 791 792 793 static void* 794 tracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize) 795 { 796 return tracemalloc_alloc_gil(1, ctx, nelem, elsize); 797 } 798 799 800 static void* 801 tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size) 802 { 803 void *ptr2; 804 805 if (get_reentrant()) { 806 /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc(). 807 Example: PyMem_RawRealloc() is called internally by pymalloc 808 (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new 809 arena (new_arena()). */ 810 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 811 812 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); 813 if (ptr2 != NULL && ptr != NULL) { 814 TABLES_LOCK(); 815 REMOVE_TRACE(ptr); 816 TABLES_UNLOCK(); 817 } 818 return ptr2; 819 } 820 821 /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for 822 allocations larger than 512 bytes. Don't trace the same memory 823 allocation twice. */ 824 set_reentrant(1); 825 826 ptr2 = tracemalloc_realloc(ctx, ptr, new_size); 827 828 set_reentrant(0); 829 return ptr2; 830 } 831 832 833 #ifdef TRACE_RAW_MALLOC 834 static void* 835 tracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) 836 { 837 PyGILState_STATE gil_state; 838 void *ptr; 839 840 if (get_reentrant()) { 841 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 842 if (use_calloc) 843 return alloc->calloc(alloc->ctx, nelem, elsize); 844 else 845 return alloc->malloc(alloc->ctx, nelem * elsize); 846 } 847 848 /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() 849 indirectly which would call PyGILState_Ensure() if reentrant are not 850 disabled. */ 851 set_reentrant(1); 852 853 gil_state = PyGILState_Ensure(); 854 ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); 855 PyGILState_Release(gil_state); 856 857 set_reentrant(0); 858 return ptr; 859 } 860 861 862 static void* 863 tracemalloc_raw_malloc(void *ctx, size_t size) 864 { 865 return tracemalloc_raw_alloc(0, ctx, 1, size); 866 } 867 868 869 static void* 870 tracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize) 871 { 872 return tracemalloc_raw_alloc(1, ctx, nelem, elsize); 873 } 874 875 876 static void* 877 tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size) 878 { 879 PyGILState_STATE gil_state; 880 void *ptr2; 881 882 if (get_reentrant()) { 883 /* Reentrant call to PyMem_RawRealloc(). */ 884 PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 885 886 ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); 887 888 if (ptr2 != NULL && ptr != NULL) { 889 TABLES_LOCK(); 890 REMOVE_TRACE(ptr); 891 TABLES_UNLOCK(); 892 } 893 return ptr2; 894 } 895 896 /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() 897 indirectly which would call PyGILState_Ensure() if reentrant calls are 898 not disabled. */ 899 set_reentrant(1); 900 901 gil_state = PyGILState_Ensure(); 902 ptr2 = tracemalloc_realloc(ctx, ptr, new_size); 903 PyGILState_Release(gil_state); 904 905 set_reentrant(0); 906 return ptr2; 907 } 908 #endif /* TRACE_RAW_MALLOC */ 909 910 911 static int 912 tracemalloc_clear_filename(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry, 913 void *user_data) 914 { 915 PyObject *filename; 916 917 _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, filename); 918 Py_DECREF(filename); 919 return 0; 920 } 921 922 923 static int 924 traceback_free_traceback(_Py_hashtable_t *ht, _Py_hashtable_entry_t *entry, 925 void *user_data) 926 { 927 traceback_t *traceback; 928 929 _Py_HASHTABLE_ENTRY_READ_KEY(ht, entry, traceback); 930 raw_free(traceback); 931 return 0; 932 } 933 934 935 /* reentrant flag must be set to call this function and GIL must be held */ 936 static void 937 tracemalloc_clear_traces(void) 938 { 939 /* The GIL protects variables againt concurrent access */ 940 assert(PyGILState_Check()); 941 942 TABLES_LOCK(); 943 _Py_hashtable_clear(tracemalloc_traces); 944 tracemalloc_traced_memory = 0; 945 tracemalloc_peak_traced_memory = 0; 946 TABLES_UNLOCK(); 947 948 _Py_hashtable_foreach(tracemalloc_tracebacks, traceback_free_traceback, NULL); 949 _Py_hashtable_clear(tracemalloc_tracebacks); 950 951 _Py_hashtable_foreach(tracemalloc_filenames, tracemalloc_clear_filename, NULL); 952 _Py_hashtable_clear(tracemalloc_filenames); 953 } 954 955 956 static int 957 tracemalloc_init(void) 958 { 959 if (tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) { 960 PyErr_SetString(PyExc_RuntimeError, 961 "the tracemalloc module has been unloaded"); 962 return -1; 963 } 964 965 if (tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED) 966 return 0; 967 968 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); 969 970 #ifdef REENTRANT_THREADLOCAL 971 if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) { 972 #ifdef MS_WINDOWS 973 PyErr_SetFromWindowsErr(0); 974 #else 975 PyErr_SetFromErrno(PyExc_OSError); 976 #endif 977 return -1; 978 } 979 #endif 980 981 #if defined(TRACE_RAW_MALLOC) 982 if (tables_lock == NULL) { 983 tables_lock = PyThread_allocate_lock(); 984 if (tables_lock == NULL) { 985 PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock"); 986 return -1; 987 } 988 } 989 #endif 990 991 tracemalloc_filenames = hashtable_new(sizeof(PyObject *), 0, 992 hashtable_hash_pyobject, 993 hashtable_compare_unicode); 994 995 tracemalloc_tracebacks = hashtable_new(sizeof(traceback_t *), 0, 996 hashtable_hash_traceback, 997 hashtable_compare_traceback); 998 999 if (tracemalloc_config.use_domain) { 1000 tracemalloc_traces = hashtable_new(sizeof(pointer_t), 1001 sizeof(trace_t), 1002 hashtable_hash_pointer_t, 1003 hashtable_compare_pointer_t); 1004 } 1005 else { 1006 tracemalloc_traces = hashtable_new(sizeof(uintptr_t), 1007 sizeof(trace_t), 1008 _Py_hashtable_hash_ptr, 1009 _Py_hashtable_compare_direct); 1010 } 1011 1012 if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL 1013 || tracemalloc_traces == NULL) { 1014 PyErr_NoMemory(); 1015 return -1; 1016 } 1017 1018 unknown_filename = PyUnicode_FromString("<unknown>"); 1019 if (unknown_filename == NULL) 1020 return -1; 1021 PyUnicode_InternInPlace(&unknown_filename); 1022 1023 tracemalloc_empty_traceback.nframe = 1; 1024 /* borrowed reference */ 1025 tracemalloc_empty_traceback.frames[0].filename = unknown_filename; 1026 tracemalloc_empty_traceback.frames[0].lineno = 0; 1027 tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback); 1028 1029 tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED; 1030 return 0; 1031 } 1032 1033 1034 static void 1035 tracemalloc_deinit(void) 1036 { 1037 if (tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED) 1038 return; 1039 tracemalloc_config.initialized = TRACEMALLOC_FINALIZED; 1040 1041 tracemalloc_stop(); 1042 1043 /* destroy hash tables */ 1044 _Py_hashtable_destroy(tracemalloc_tracebacks); 1045 _Py_hashtable_destroy(tracemalloc_filenames); 1046 _Py_hashtable_destroy(tracemalloc_traces); 1047 1048 #if defined(TRACE_RAW_MALLOC) 1049 if (tables_lock != NULL) { 1050 PyThread_free_lock(tables_lock); 1051 tables_lock = NULL; 1052 } 1053 #endif 1054 1055 #ifdef REENTRANT_THREADLOCAL 1056 PyThread_tss_delete(&tracemalloc_reentrant_key); 1057 #endif 1058 1059 Py_XDECREF(unknown_filename); 1060 } 1061 1062 1063 static int 1064 tracemalloc_start(int max_nframe) 1065 { 1066 PyMemAllocatorEx alloc; 1067 size_t size; 1068 1069 if (max_nframe < 1 || max_nframe > MAX_NFRAME) { 1070 PyErr_Format(PyExc_ValueError, 1071 "the number of frames must be in range [1; %i]", 1072 (int)MAX_NFRAME); 1073 return -1; 1074 } 1075 1076 if (tracemalloc_init() < 0) { 1077 return -1; 1078 } 1079 1080 if (tracemalloc_config.tracing) { 1081 /* hook already installed: do nothing */ 1082 return 0; 1083 } 1084 1085 assert(1 <= max_nframe && max_nframe <= MAX_NFRAME); 1086 tracemalloc_config.max_nframe = max_nframe; 1087 1088 /* allocate a buffer to store a new traceback */ 1089 size = TRACEBACK_SIZE(max_nframe); 1090 assert(tracemalloc_traceback == NULL); 1091 tracemalloc_traceback = raw_malloc(size); 1092 if (tracemalloc_traceback == NULL) { 1093 PyErr_NoMemory(); 1094 return -1; 1095 } 1096 1097 #ifdef TRACE_RAW_MALLOC 1098 alloc.malloc = tracemalloc_raw_malloc; 1099 alloc.calloc = tracemalloc_raw_calloc; 1100 alloc.realloc = tracemalloc_raw_realloc; 1101 alloc.free = tracemalloc_free; 1102 1103 alloc.ctx = &allocators.raw; 1104 PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); 1105 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); 1106 #endif 1107 1108 alloc.malloc = tracemalloc_malloc_gil; 1109 alloc.calloc = tracemalloc_calloc_gil; 1110 alloc.realloc = tracemalloc_realloc_gil; 1111 alloc.free = tracemalloc_free; 1112 1113 alloc.ctx = &allocators.mem; 1114 PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); 1115 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); 1116 1117 alloc.ctx = &allocators.obj; 1118 PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); 1119 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); 1120 1121 /* everything is ready: start tracing Python memory allocations */ 1122 tracemalloc_config.tracing = 1; 1123 1124 return 0; 1125 } 1126 1127 1128 static void 1129 tracemalloc_stop(void) 1130 { 1131 if (!tracemalloc_config.tracing) 1132 return; 1133 1134 /* stop tracing Python memory allocations */ 1135 tracemalloc_config.tracing = 0; 1136 1137 /* unregister the hook on memory allocators */ 1138 #ifdef TRACE_RAW_MALLOC 1139 PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); 1140 #endif 1141 PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); 1142 PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); 1143 1144 tracemalloc_clear_traces(); 1145 1146 /* release memory */ 1147 raw_free(tracemalloc_traceback); 1148 tracemalloc_traceback = NULL; 1149 } 1150 1151 1152 1153 /*[clinic input] 1154 _tracemalloc.is_tracing 1155 1156 Return True if the tracemalloc module is tracing Python memory allocations. 1157 [clinic start generated code]*/ 1158 1159 static PyObject * 1160 _tracemalloc_is_tracing_impl(PyObject *module) 1161 /*[clinic end generated code: output=2d763b42601cd3ef input=af104b0a00192f63]*/ 1162 { 1163 return PyBool_FromLong(tracemalloc_config.tracing); 1164 } 1165 1166 1167 /*[clinic input] 1168 _tracemalloc.clear_traces 1169 1170 Clear traces of memory blocks allocated by Python. 1171 [clinic start generated code]*/ 1172 1173 static PyObject * 1174 _tracemalloc_clear_traces_impl(PyObject *module) 1175 /*[clinic end generated code: output=a86080ee41b84197 input=0dab5b6c785183a5]*/ 1176 { 1177 if (!tracemalloc_config.tracing) 1178 Py_RETURN_NONE; 1179 1180 set_reentrant(1); 1181 tracemalloc_clear_traces(); 1182 set_reentrant(0); 1183 1184 Py_RETURN_NONE; 1185 } 1186 1187 1188 static PyObject* 1189 frame_to_pyobject(frame_t *frame) 1190 { 1191 PyObject *frame_obj, *lineno_obj; 1192 1193 frame_obj = PyTuple_New(2); 1194 if (frame_obj == NULL) 1195 return NULL; 1196 1197 Py_INCREF(frame->filename); 1198 PyTuple_SET_ITEM(frame_obj, 0, frame->filename); 1199 1200 lineno_obj = PyLong_FromUnsignedLong(frame->lineno); 1201 if (lineno_obj == NULL) { 1202 Py_DECREF(frame_obj); 1203 return NULL; 1204 } 1205 PyTuple_SET_ITEM(frame_obj, 1, lineno_obj); 1206 1207 return frame_obj; 1208 } 1209 1210 1211 static PyObject* 1212 traceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table) 1213 { 1214 int i; 1215 PyObject *frames, *frame; 1216 1217 if (intern_table != NULL) { 1218 if (_Py_HASHTABLE_GET(intern_table, traceback, frames)) { 1219 Py_INCREF(frames); 1220 return frames; 1221 } 1222 } 1223 1224 frames = PyTuple_New(traceback->nframe); 1225 if (frames == NULL) 1226 return NULL; 1227 1228 for (i=0; i < traceback->nframe; i++) { 1229 frame = frame_to_pyobject(&traceback->frames[i]); 1230 if (frame == NULL) { 1231 Py_DECREF(frames); 1232 return NULL; 1233 } 1234 PyTuple_SET_ITEM(frames, i, frame); 1235 } 1236 1237 if (intern_table != NULL) { 1238 if (_Py_HASHTABLE_SET(intern_table, traceback, frames) < 0) { 1239 Py_DECREF(frames); 1240 PyErr_NoMemory(); 1241 return NULL; 1242 } 1243 /* intern_table keeps a new reference to frames */ 1244 Py_INCREF(frames); 1245 } 1246 return frames; 1247 } 1248 1249 1250 static PyObject* 1251 trace_to_pyobject(unsigned int domain, trace_t *trace, 1252 _Py_hashtable_t *intern_tracebacks) 1253 { 1254 PyObject *trace_obj = NULL; 1255 PyObject *obj; 1256 1257 trace_obj = PyTuple_New(3); 1258 if (trace_obj == NULL) 1259 return NULL; 1260 1261 obj = PyLong_FromSize_t(domain); 1262 if (obj == NULL) { 1263 Py_DECREF(trace_obj); 1264 return NULL; 1265 } 1266 PyTuple_SET_ITEM(trace_obj, 0, obj); 1267 1268 obj = PyLong_FromSize_t(trace->size); 1269 if (obj == NULL) { 1270 Py_DECREF(trace_obj); 1271 return NULL; 1272 } 1273 PyTuple_SET_ITEM(trace_obj, 1, obj); 1274 1275 obj = traceback_to_pyobject(trace->traceback, intern_tracebacks); 1276 if (obj == NULL) { 1277 Py_DECREF(trace_obj); 1278 return NULL; 1279 } 1280 PyTuple_SET_ITEM(trace_obj, 2, obj); 1281 1282 return trace_obj; 1283 } 1284 1285 1286 typedef struct { 1287 _Py_hashtable_t *traces; 1288 _Py_hashtable_t *tracebacks; 1289 PyObject *list; 1290 } get_traces_t; 1291 1292 static int 1293 tracemalloc_get_traces_fill(_Py_hashtable_t *traces, _Py_hashtable_entry_t *entry, 1294 void *user_data) 1295 { 1296 get_traces_t *get_traces = user_data; 1297 unsigned int domain; 1298 trace_t trace; 1299 PyObject *tracemalloc_obj; 1300 int res; 1301 1302 if (tracemalloc_config.use_domain) { 1303 pointer_t key; 1304 _Py_HASHTABLE_ENTRY_READ_KEY(traces, entry, key); 1305 domain = key.domain; 1306 } 1307 else { 1308 domain = DEFAULT_DOMAIN; 1309 } 1310 _Py_HASHTABLE_ENTRY_READ_DATA(traces, entry, trace); 1311 1312 tracemalloc_obj = trace_to_pyobject(domain, &trace, get_traces->tracebacks); 1313 if (tracemalloc_obj == NULL) 1314 return 1; 1315 1316 res = PyList_Append(get_traces->list, tracemalloc_obj); 1317 Py_DECREF(tracemalloc_obj); 1318 if (res < 0) 1319 return 1; 1320 1321 return 0; 1322 } 1323 1324 1325 static int 1326 tracemalloc_pyobject_decref_cb(_Py_hashtable_t *tracebacks, 1327 _Py_hashtable_entry_t *entry, 1328 void *user_data) 1329 { 1330 PyObject *obj; 1331 _Py_HASHTABLE_ENTRY_READ_DATA(tracebacks, entry, obj); 1332 Py_DECREF(obj); 1333 return 0; 1334 } 1335 1336 1337 1338 /*[clinic input] 1339 _tracemalloc._get_traces 1340 1341 Get traces of all memory blocks allocated by Python. 1342 1343 Return a list of (size: int, traceback: tuple) tuples. 1344 traceback is a tuple of (filename: str, lineno: int) tuples. 1345 1346 Return an empty list if the tracemalloc module is disabled. 1347 [clinic start generated code]*/ 1348 1349 static PyObject * 1350 _tracemalloc__get_traces_impl(PyObject *module) 1351 /*[clinic end generated code: output=e9929876ced4b5cc input=6c7d2230b24255aa]*/ 1352 { 1353 get_traces_t get_traces; 1354 int err; 1355 1356 get_traces.traces = NULL; 1357 get_traces.tracebacks = NULL; 1358 get_traces.list = PyList_New(0); 1359 if (get_traces.list == NULL) 1360 goto error; 1361 1362 if (!tracemalloc_config.tracing) 1363 return get_traces.list; 1364 1365 /* the traceback hash table is used temporarily to intern traceback tuple 1366 of (filename, lineno) tuples */ 1367 get_traces.tracebacks = hashtable_new(sizeof(traceback_t *), 1368 sizeof(PyObject *), 1369 _Py_hashtable_hash_ptr, 1370 _Py_hashtable_compare_direct); 1371 if (get_traces.tracebacks == NULL) { 1372 PyErr_NoMemory(); 1373 goto error; 1374 } 1375 1376 TABLES_LOCK(); 1377 get_traces.traces = _Py_hashtable_copy(tracemalloc_traces); 1378 TABLES_UNLOCK(); 1379 1380 if (get_traces.traces == NULL) { 1381 PyErr_NoMemory(); 1382 goto error; 1383 } 1384 1385 set_reentrant(1); 1386 err = _Py_hashtable_foreach(get_traces.traces, 1387 tracemalloc_get_traces_fill, &get_traces); 1388 set_reentrant(0); 1389 if (err) 1390 goto error; 1391 1392 goto finally; 1393 1394 error: 1395 Py_CLEAR(get_traces.list); 1396 1397 finally: 1398 if (get_traces.tracebacks != NULL) { 1399 _Py_hashtable_foreach(get_traces.tracebacks, 1400 tracemalloc_pyobject_decref_cb, NULL); 1401 _Py_hashtable_destroy(get_traces.tracebacks); 1402 } 1403 if (get_traces.traces != NULL) { 1404 _Py_hashtable_destroy(get_traces.traces); 1405 } 1406 1407 return get_traces.list; 1408 } 1409 1410 1411 static traceback_t* 1412 tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr) 1413 { 1414 trace_t trace; 1415 int found; 1416 1417 if (!tracemalloc_config.tracing) 1418 return NULL; 1419 1420 TABLES_LOCK(); 1421 if (tracemalloc_config.use_domain) { 1422 pointer_t key = {ptr, domain}; 1423 found = _Py_HASHTABLE_GET(tracemalloc_traces, key, trace); 1424 } 1425 else { 1426 found = _Py_HASHTABLE_GET(tracemalloc_traces, ptr, trace); 1427 } 1428 TABLES_UNLOCK(); 1429 1430 if (!found) 1431 return NULL; 1432 1433 return trace.traceback; 1434 } 1435 1436 1437 1438 /*[clinic input] 1439 _tracemalloc._get_object_traceback 1440 1441 obj: object 1442 / 1443 1444 Get the traceback where the Python object obj was allocated. 1445 1446 Return a tuple of (filename: str, lineno: int) tuples. 1447 Return None if the tracemalloc module is disabled or did not 1448 trace the allocation of the object. 1449 [clinic start generated code]*/ 1450 1451 static PyObject * 1452 _tracemalloc__get_object_traceback(PyObject *module, PyObject *obj) 1453 /*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/ 1454 { 1455 PyTypeObject *type; 1456 void *ptr; 1457 traceback_t *traceback; 1458 1459 type = Py_TYPE(obj); 1460 if (PyType_IS_GC(type)) 1461 ptr = (void *)((char *)obj - sizeof(PyGC_Head)); 1462 else 1463 ptr = (void *)obj; 1464 1465 traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr); 1466 if (traceback == NULL) 1467 Py_RETURN_NONE; 1468 1469 return traceback_to_pyobject(traceback, NULL); 1470 } 1471 1472 1473 #define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str)) 1474 1475 static void 1476 _PyMem_DumpFrame(int fd, frame_t * frame) 1477 { 1478 PUTS(fd, " File \""); 1479 _Py_DumpASCII(fd, frame->filename); 1480 PUTS(fd, "\", line "); 1481 _Py_DumpDecimal(fd, frame->lineno); 1482 PUTS(fd, "\n"); 1483 } 1484 1485 /* Dump the traceback where a memory block was allocated into file descriptor 1486 fd. The function may block on TABLES_LOCK() but it is unlikely. */ 1487 void 1488 _PyMem_DumpTraceback(int fd, const void *ptr) 1489 { 1490 traceback_t *traceback; 1491 int i; 1492 1493 if (!tracemalloc_config.tracing) { 1494 PUTS(fd, "Enable tracemalloc to get the memory block " 1495 "allocation traceback\n\n"); 1496 return; 1497 } 1498 1499 traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr); 1500 if (traceback == NULL) 1501 return; 1502 1503 PUTS(fd, "Memory block allocated at (most recent call first):\n"); 1504 for (i=0; i < traceback->nframe; i++) { 1505 _PyMem_DumpFrame(fd, &traceback->frames[i]); 1506 } 1507 PUTS(fd, "\n"); 1508 } 1509 1510 #undef PUTS 1511 1512 1513 1514 /*[clinic input] 1515 _tracemalloc.start 1516 1517 nframe: int = 1 1518 / 1519 1520 Start tracing Python memory allocations. 1521 1522 Also set the maximum number of frames stored in the traceback of a 1523 trace to nframe. 1524 [clinic start generated code]*/ 1525 1526 static PyObject * 1527 _tracemalloc_start_impl(PyObject *module, int nframe) 1528 /*[clinic end generated code: output=caae05c23c159d3c input=40d849b5b29d1933]*/ 1529 { 1530 if (tracemalloc_start(nframe) < 0) { 1531 return NULL; 1532 } 1533 Py_RETURN_NONE; 1534 } 1535 1536 1537 /*[clinic input] 1538 _tracemalloc.stop 1539 1540 Stop tracing Python memory allocations. 1541 1542 Also clear traces of memory blocks allocated by Python. 1543 [clinic start generated code]*/ 1544 1545 static PyObject * 1546 _tracemalloc_stop_impl(PyObject *module) 1547 /*[clinic end generated code: output=c3c42ae03e3955cd input=7478f075e51dae18]*/ 1548 { 1549 tracemalloc_stop(); 1550 Py_RETURN_NONE; 1551 } 1552 1553 1554 /*[clinic input] 1555 _tracemalloc.get_traceback_limit 1556 1557 Get the maximum number of frames stored in the traceback of a trace. 1558 1559 By default, a trace of an allocated memory block only stores 1560 the most recent frame: the limit is 1. 1561 [clinic start generated code]*/ 1562 1563 static PyObject * 1564 _tracemalloc_get_traceback_limit_impl(PyObject *module) 1565 /*[clinic end generated code: output=d556d9306ba95567 input=da3cd977fc68ae3b]*/ 1566 { 1567 return PyLong_FromLong(tracemalloc_config.max_nframe); 1568 } 1569 1570 1571 1572 /*[clinic input] 1573 _tracemalloc.get_tracemalloc_memory 1574 1575 Get the memory usage in bytes of the tracemalloc module. 1576 1577 This memory is used internally to trace memory allocations. 1578 [clinic start generated code]*/ 1579 1580 static PyObject * 1581 _tracemalloc_get_tracemalloc_memory_impl(PyObject *module) 1582 /*[clinic end generated code: output=e3f14e280a55f5aa input=5d919c0f4d5132ad]*/ 1583 { 1584 size_t size; 1585 1586 size = _Py_hashtable_size(tracemalloc_tracebacks); 1587 size += _Py_hashtable_size(tracemalloc_filenames); 1588 1589 TABLES_LOCK(); 1590 size += _Py_hashtable_size(tracemalloc_traces); 1591 TABLES_UNLOCK(); 1592 1593 return PyLong_FromSize_t(size); 1594 } 1595 1596 1597 1598 /*[clinic input] 1599 _tracemalloc.get_traced_memory 1600 1601 Get the current size and peak size of memory blocks traced by tracemalloc. 1602 1603 Returns a tuple: (current: int, peak: int). 1604 [clinic start generated code]*/ 1605 1606 static PyObject * 1607 _tracemalloc_get_traced_memory_impl(PyObject *module) 1608 /*[clinic end generated code: output=5b167189adb9e782 input=61ddb5478400ff66]*/ 1609 { 1610 Py_ssize_t size, peak_size; 1611 1612 if (!tracemalloc_config.tracing) 1613 return Py_BuildValue("ii", 0, 0); 1614 1615 TABLES_LOCK(); 1616 size = tracemalloc_traced_memory; 1617 peak_size = tracemalloc_peak_traced_memory; 1618 TABLES_UNLOCK(); 1619 1620 return Py_BuildValue("nn", size, peak_size); 1621 } 1622 1623 1624 static PyMethodDef module_methods[] = { 1625 _TRACEMALLOC_IS_TRACING_METHODDEF 1626 _TRACEMALLOC_CLEAR_TRACES_METHODDEF 1627 _TRACEMALLOC__GET_TRACES_METHODDEF 1628 _TRACEMALLOC__GET_OBJECT_TRACEBACK_METHODDEF 1629 _TRACEMALLOC_START_METHODDEF 1630 _TRACEMALLOC_STOP_METHODDEF 1631 _TRACEMALLOC_GET_TRACEBACK_LIMIT_METHODDEF 1632 _TRACEMALLOC_GET_TRACEMALLOC_MEMORY_METHODDEF 1633 _TRACEMALLOC_GET_TRACED_MEMORY_METHODDEF 1634 /* sentinel */ 1635 {NULL, NULL} 1636 }; 1637 1638 PyDoc_STRVAR(module_doc, 1639 "Debug module to trace memory blocks allocated by Python."); 1640 1641 static struct PyModuleDef module_def = { 1642 PyModuleDef_HEAD_INIT, 1643 "_tracemalloc", 1644 module_doc, 1645 0, /* non-negative size to be able to unload the module */ 1646 module_methods, 1647 NULL, 1648 }; 1649 1650 PyMODINIT_FUNC 1651 PyInit__tracemalloc(void) 1652 { 1653 PyObject *m; 1654 m = PyModule_Create(&module_def); 1655 if (m == NULL) 1656 return NULL; 1657 1658 if (tracemalloc_init() < 0) 1659 return NULL; 1660 1661 return m; 1662 } 1663 1664 1665 int 1666 _PyTraceMalloc_Init(int nframe) 1667 { 1668 assert(PyGILState_Check()); 1669 if (nframe == 0) { 1670 return 0; 1671 } 1672 return tracemalloc_start(nframe); 1673 } 1674 1675 1676 void 1677 _PyTraceMalloc_Fini(void) 1678 { 1679 assert(PyGILState_Check()); 1680 tracemalloc_deinit(); 1681 } 1682 1683 int 1684 PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, 1685 size_t size) 1686 { 1687 int res; 1688 PyGILState_STATE gil_state; 1689 1690 if (!tracemalloc_config.tracing) { 1691 /* tracemalloc is not tracing: do nothing */ 1692 return -2; 1693 } 1694 1695 gil_state = PyGILState_Ensure(); 1696 1697 TABLES_LOCK(); 1698 res = tracemalloc_add_trace(domain, ptr, size); 1699 TABLES_UNLOCK(); 1700 1701 PyGILState_Release(gil_state); 1702 return res; 1703 } 1704 1705 1706 int 1707 PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr) 1708 { 1709 if (!tracemalloc_config.tracing) { 1710 /* tracemalloc is not tracing: do nothing */ 1711 return -2; 1712 } 1713 1714 TABLES_LOCK(); 1715 tracemalloc_remove_trace(domain, ptr); 1716 TABLES_UNLOCK(); 1717 1718 return 0; 1719 } 1720 1721 1722 PyObject* 1723 _PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr) 1724 { 1725 traceback_t *traceback; 1726 1727 traceback = tracemalloc_get_traceback(domain, ptr); 1728 if (traceback == NULL) 1729 Py_RETURN_NONE; 1730 1731 return traceback_to_pyobject(traceback, NULL); 1732 } 1733