17db96d56Sopenharmony_ci#include "Python.h" 27db96d56Sopenharmony_ci#include "pycore_fileutils.h" // _Py_write_noraise() 37db96d56Sopenharmony_ci#include "pycore_gc.h" // PyGC_Head 47db96d56Sopenharmony_ci#include "pycore_hashtable.h" // _Py_hashtable_t 57db96d56Sopenharmony_ci#include "pycore_pymem.h" // _Py_tracemalloc_config 67db96d56Sopenharmony_ci#include "pycore_runtime.h" // _Py_ID() 77db96d56Sopenharmony_ci#include "pycore_traceback.h" 87db96d56Sopenharmony_ci#include <pycore_frame.h> 97db96d56Sopenharmony_ci 107db96d56Sopenharmony_ci#include <stdlib.h> // malloc() 117db96d56Sopenharmony_ci 127db96d56Sopenharmony_ci#include "clinic/_tracemalloc.c.h" 137db96d56Sopenharmony_ci 147db96d56Sopenharmony_ci/*[clinic input] 157db96d56Sopenharmony_cimodule _tracemalloc 167db96d56Sopenharmony_ci[clinic start generated code]*/ 177db96d56Sopenharmony_ci/*[clinic end generated code: output=da39a3ee5e6b4b0d input=708a98302fc46e5f]*/ 187db96d56Sopenharmony_ci 197db96d56Sopenharmony_ci_Py_DECLARE_STR(anon_unknown, "<unknown>"); 207db96d56Sopenharmony_ci 217db96d56Sopenharmony_ci/* Trace memory blocks allocated by PyMem_RawMalloc() */ 227db96d56Sopenharmony_ci#define TRACE_RAW_MALLOC 237db96d56Sopenharmony_ci 247db96d56Sopenharmony_ci/* Forward declaration */ 257db96d56Sopenharmony_cistatic void tracemalloc_stop(void); 267db96d56Sopenharmony_cistatic void* raw_malloc(size_t size); 277db96d56Sopenharmony_cistatic void raw_free(void *ptr); 287db96d56Sopenharmony_ci 297db96d56Sopenharmony_ci#ifdef Py_DEBUG 307db96d56Sopenharmony_ci# define TRACE_DEBUG 317db96d56Sopenharmony_ci#endif 327db96d56Sopenharmony_ci 337db96d56Sopenharmony_ci#define TO_PTR(key) ((const void *)(uintptr_t)(key)) 347db96d56Sopenharmony_ci#define FROM_PTR(key) ((uintptr_t)(key)) 357db96d56Sopenharmony_ci 367db96d56Sopenharmony_ci/* Protected by the GIL */ 377db96d56Sopenharmony_cistatic struct { 387db96d56Sopenharmony_ci PyMemAllocatorEx mem; 397db96d56Sopenharmony_ci PyMemAllocatorEx raw; 407db96d56Sopenharmony_ci PyMemAllocatorEx obj; 417db96d56Sopenharmony_ci} allocators; 427db96d56Sopenharmony_ci 437db96d56Sopenharmony_ci 447db96d56Sopenharmony_ci#if defined(TRACE_RAW_MALLOC) 457db96d56Sopenharmony_ci/* This lock is needed because tracemalloc_free() is called without 467db96d56Sopenharmony_ci the GIL held from PyMem_RawFree(). It cannot acquire the lock because it 477db96d56Sopenharmony_ci would introduce a deadlock in _PyThreadState_DeleteCurrent(). */ 487db96d56Sopenharmony_cistatic PyThread_type_lock tables_lock; 497db96d56Sopenharmony_ci# define TABLES_LOCK() PyThread_acquire_lock(tables_lock, 1) 507db96d56Sopenharmony_ci# define TABLES_UNLOCK() PyThread_release_lock(tables_lock) 517db96d56Sopenharmony_ci#else 527db96d56Sopenharmony_ci /* variables are protected by the GIL */ 537db96d56Sopenharmony_ci# define TABLES_LOCK() 547db96d56Sopenharmony_ci# define TABLES_UNLOCK() 557db96d56Sopenharmony_ci#endif 567db96d56Sopenharmony_ci 577db96d56Sopenharmony_ci 587db96d56Sopenharmony_ci#define DEFAULT_DOMAIN 0 597db96d56Sopenharmony_ci 607db96d56Sopenharmony_ci/* Pack the frame_t structure to reduce the memory footprint on 64-bit 617db96d56Sopenharmony_ci architectures: 12 bytes instead of 16. */ 627db96d56Sopenharmony_citypedef struct 637db96d56Sopenharmony_ci#ifdef __GNUC__ 647db96d56Sopenharmony_ci__attribute__((packed)) 657db96d56Sopenharmony_ci#elif defined(_MSC_VER) 667db96d56Sopenharmony_ci#pragma pack(push, 4) 677db96d56Sopenharmony_ci#endif 687db96d56Sopenharmony_ci{ 697db96d56Sopenharmony_ci /* filename cannot be NULL: "<unknown>" is used if the Python frame 707db96d56Sopenharmony_ci filename is NULL */ 717db96d56Sopenharmony_ci PyObject *filename; 727db96d56Sopenharmony_ci unsigned int lineno; 737db96d56Sopenharmony_ci} frame_t; 747db96d56Sopenharmony_ci#ifdef _MSC_VER 757db96d56Sopenharmony_ci#pragma pack(pop) 767db96d56Sopenharmony_ci#endif 777db96d56Sopenharmony_ci 787db96d56Sopenharmony_ci 797db96d56Sopenharmony_citypedef struct { 807db96d56Sopenharmony_ci Py_uhash_t hash; 817db96d56Sopenharmony_ci /* Number of frames stored */ 827db96d56Sopenharmony_ci uint16_t nframe; 837db96d56Sopenharmony_ci /* Total number of frames the traceback had */ 847db96d56Sopenharmony_ci uint16_t total_nframe; 857db96d56Sopenharmony_ci frame_t frames[1]; 867db96d56Sopenharmony_ci} traceback_t; 877db96d56Sopenharmony_ci 887db96d56Sopenharmony_ci#define TRACEBACK_SIZE(NFRAME) \ 897db96d56Sopenharmony_ci (sizeof(traceback_t) + sizeof(frame_t) * (NFRAME - 1)) 907db96d56Sopenharmony_ci 917db96d56Sopenharmony_ci/* The maximum number of frames is either: 927db96d56Sopenharmony_ci - The maximum number of frames we can store in `traceback_t.nframe` 937db96d56Sopenharmony_ci - The maximum memory size_t we can allocate */ 947db96d56Sopenharmony_cistatic const unsigned long MAX_NFRAME = Py_MIN(UINT16_MAX, ((SIZE_MAX - sizeof(traceback_t)) / sizeof(frame_t) + 1)); 957db96d56Sopenharmony_ci 967db96d56Sopenharmony_ci 977db96d56Sopenharmony_cistatic traceback_t tracemalloc_empty_traceback; 987db96d56Sopenharmony_ci 997db96d56Sopenharmony_ci/* Trace of a memory block */ 1007db96d56Sopenharmony_citypedef struct { 1017db96d56Sopenharmony_ci /* Size of the memory block in bytes */ 1027db96d56Sopenharmony_ci size_t size; 1037db96d56Sopenharmony_ci 1047db96d56Sopenharmony_ci /* Traceback where the memory block was allocated */ 1057db96d56Sopenharmony_ci traceback_t *traceback; 1067db96d56Sopenharmony_ci} trace_t; 1077db96d56Sopenharmony_ci 1087db96d56Sopenharmony_ci 1097db96d56Sopenharmony_ci/* Size in bytes of currently traced memory. 1107db96d56Sopenharmony_ci Protected by TABLES_LOCK(). */ 1117db96d56Sopenharmony_cistatic size_t tracemalloc_traced_memory = 0; 1127db96d56Sopenharmony_ci 1137db96d56Sopenharmony_ci/* Peak size in bytes of traced memory. 1147db96d56Sopenharmony_ci Protected by TABLES_LOCK(). */ 1157db96d56Sopenharmony_cistatic size_t tracemalloc_peak_traced_memory = 0; 1167db96d56Sopenharmony_ci 1177db96d56Sopenharmony_ci/* Hash table used as a set to intern filenames: 1187db96d56Sopenharmony_ci PyObject* => PyObject*. 1197db96d56Sopenharmony_ci Protected by the GIL */ 1207db96d56Sopenharmony_cistatic _Py_hashtable_t *tracemalloc_filenames = NULL; 1217db96d56Sopenharmony_ci 1227db96d56Sopenharmony_ci/* Buffer to store a new traceback in traceback_new(). 1237db96d56Sopenharmony_ci Protected by the GIL. */ 1247db96d56Sopenharmony_cistatic traceback_t *tracemalloc_traceback = NULL; 1257db96d56Sopenharmony_ci 1267db96d56Sopenharmony_ci/* Hash table used as a set to intern tracebacks: 1277db96d56Sopenharmony_ci traceback_t* => traceback_t* 1287db96d56Sopenharmony_ci Protected by the GIL */ 1297db96d56Sopenharmony_cistatic _Py_hashtable_t *tracemalloc_tracebacks = NULL; 1307db96d56Sopenharmony_ci 1317db96d56Sopenharmony_ci/* pointer (void*) => trace (trace_t*). 1327db96d56Sopenharmony_ci Protected by TABLES_LOCK(). */ 1337db96d56Sopenharmony_cistatic _Py_hashtable_t *tracemalloc_traces = NULL; 1347db96d56Sopenharmony_ci 1357db96d56Sopenharmony_ci/* domain (unsigned int) => traces (_Py_hashtable_t). 1367db96d56Sopenharmony_ci Protected by TABLES_LOCK(). */ 1377db96d56Sopenharmony_cistatic _Py_hashtable_t *tracemalloc_domains = NULL; 1387db96d56Sopenharmony_ci 1397db96d56Sopenharmony_ci 1407db96d56Sopenharmony_ci#ifdef TRACE_DEBUG 1417db96d56Sopenharmony_cistatic void 1427db96d56Sopenharmony_citracemalloc_error(const char *format, ...) 1437db96d56Sopenharmony_ci{ 1447db96d56Sopenharmony_ci va_list ap; 1457db96d56Sopenharmony_ci fprintf(stderr, "tracemalloc: "); 1467db96d56Sopenharmony_ci va_start(ap, format); 1477db96d56Sopenharmony_ci vfprintf(stderr, format, ap); 1487db96d56Sopenharmony_ci va_end(ap); 1497db96d56Sopenharmony_ci fprintf(stderr, "\n"); 1507db96d56Sopenharmony_ci fflush(stderr); 1517db96d56Sopenharmony_ci} 1527db96d56Sopenharmony_ci#endif 1537db96d56Sopenharmony_ci 1547db96d56Sopenharmony_ci 1557db96d56Sopenharmony_ci#if defined(TRACE_RAW_MALLOC) 1567db96d56Sopenharmony_ci#define REENTRANT_THREADLOCAL 1577db96d56Sopenharmony_ci 1587db96d56Sopenharmony_cistatic Py_tss_t tracemalloc_reentrant_key = Py_tss_NEEDS_INIT; 1597db96d56Sopenharmony_ci 1607db96d56Sopenharmony_ci/* Any non-NULL pointer can be used */ 1617db96d56Sopenharmony_ci#define REENTRANT Py_True 1627db96d56Sopenharmony_ci 1637db96d56Sopenharmony_cistatic int 1647db96d56Sopenharmony_ciget_reentrant(void) 1657db96d56Sopenharmony_ci{ 1667db96d56Sopenharmony_ci void *ptr; 1677db96d56Sopenharmony_ci 1687db96d56Sopenharmony_ci assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); 1697db96d56Sopenharmony_ci ptr = PyThread_tss_get(&tracemalloc_reentrant_key); 1707db96d56Sopenharmony_ci if (ptr != NULL) { 1717db96d56Sopenharmony_ci assert(ptr == REENTRANT); 1727db96d56Sopenharmony_ci return 1; 1737db96d56Sopenharmony_ci } 1747db96d56Sopenharmony_ci else 1757db96d56Sopenharmony_ci return 0; 1767db96d56Sopenharmony_ci} 1777db96d56Sopenharmony_ci 1787db96d56Sopenharmony_cistatic void 1797db96d56Sopenharmony_ciset_reentrant(int reentrant) 1807db96d56Sopenharmony_ci{ 1817db96d56Sopenharmony_ci assert(reentrant == 0 || reentrant == 1); 1827db96d56Sopenharmony_ci assert(PyThread_tss_is_created(&tracemalloc_reentrant_key)); 1837db96d56Sopenharmony_ci 1847db96d56Sopenharmony_ci if (reentrant) { 1857db96d56Sopenharmony_ci assert(!get_reentrant()); 1867db96d56Sopenharmony_ci PyThread_tss_set(&tracemalloc_reentrant_key, REENTRANT); 1877db96d56Sopenharmony_ci } 1887db96d56Sopenharmony_ci else { 1897db96d56Sopenharmony_ci assert(get_reentrant()); 1907db96d56Sopenharmony_ci PyThread_tss_set(&tracemalloc_reentrant_key, NULL); 1917db96d56Sopenharmony_ci } 1927db96d56Sopenharmony_ci} 1937db96d56Sopenharmony_ci 1947db96d56Sopenharmony_ci#else 1957db96d56Sopenharmony_ci 1967db96d56Sopenharmony_ci/* TRACE_RAW_MALLOC not defined: variable protected by the GIL */ 1977db96d56Sopenharmony_cistatic int tracemalloc_reentrant = 0; 1987db96d56Sopenharmony_ci 1997db96d56Sopenharmony_cistatic int 2007db96d56Sopenharmony_ciget_reentrant(void) 2017db96d56Sopenharmony_ci{ 2027db96d56Sopenharmony_ci return tracemalloc_reentrant; 2037db96d56Sopenharmony_ci} 2047db96d56Sopenharmony_ci 2057db96d56Sopenharmony_cistatic void 2067db96d56Sopenharmony_ciset_reentrant(int reentrant) 2077db96d56Sopenharmony_ci{ 2087db96d56Sopenharmony_ci assert(reentrant != tracemalloc_reentrant); 2097db96d56Sopenharmony_ci tracemalloc_reentrant = reentrant; 2107db96d56Sopenharmony_ci} 2117db96d56Sopenharmony_ci#endif 2127db96d56Sopenharmony_ci 2137db96d56Sopenharmony_ci 2147db96d56Sopenharmony_cistatic Py_uhash_t 2157db96d56Sopenharmony_cihashtable_hash_pyobject(const void *key) 2167db96d56Sopenharmony_ci{ 2177db96d56Sopenharmony_ci PyObject *obj = (PyObject *)key; 2187db96d56Sopenharmony_ci return PyObject_Hash(obj); 2197db96d56Sopenharmony_ci} 2207db96d56Sopenharmony_ci 2217db96d56Sopenharmony_ci 2227db96d56Sopenharmony_cistatic int 2237db96d56Sopenharmony_cihashtable_compare_unicode(const void *key1, const void *key2) 2247db96d56Sopenharmony_ci{ 2257db96d56Sopenharmony_ci PyObject *obj1 = (PyObject *)key1; 2267db96d56Sopenharmony_ci PyObject *obj2 = (PyObject *)key2; 2277db96d56Sopenharmony_ci if (obj1 != NULL && obj2 != NULL) { 2287db96d56Sopenharmony_ci return (PyUnicode_Compare(obj1, obj2) == 0); 2297db96d56Sopenharmony_ci } 2307db96d56Sopenharmony_ci else { 2317db96d56Sopenharmony_ci return obj1 == obj2; 2327db96d56Sopenharmony_ci } 2337db96d56Sopenharmony_ci} 2347db96d56Sopenharmony_ci 2357db96d56Sopenharmony_ci 2367db96d56Sopenharmony_cistatic Py_uhash_t 2377db96d56Sopenharmony_cihashtable_hash_uint(const void *key_raw) 2387db96d56Sopenharmony_ci{ 2397db96d56Sopenharmony_ci unsigned int key = (unsigned int)FROM_PTR(key_raw); 2407db96d56Sopenharmony_ci return (Py_uhash_t)key; 2417db96d56Sopenharmony_ci} 2427db96d56Sopenharmony_ci 2437db96d56Sopenharmony_ci 2447db96d56Sopenharmony_cistatic _Py_hashtable_t * 2457db96d56Sopenharmony_cihashtable_new(_Py_hashtable_hash_func hash_func, 2467db96d56Sopenharmony_ci _Py_hashtable_compare_func compare_func, 2477db96d56Sopenharmony_ci _Py_hashtable_destroy_func key_destroy_func, 2487db96d56Sopenharmony_ci _Py_hashtable_destroy_func value_destroy_func) 2497db96d56Sopenharmony_ci{ 2507db96d56Sopenharmony_ci _Py_hashtable_allocator_t hashtable_alloc = {malloc, free}; 2517db96d56Sopenharmony_ci return _Py_hashtable_new_full(hash_func, compare_func, 2527db96d56Sopenharmony_ci key_destroy_func, value_destroy_func, 2537db96d56Sopenharmony_ci &hashtable_alloc); 2547db96d56Sopenharmony_ci} 2557db96d56Sopenharmony_ci 2567db96d56Sopenharmony_ci 2577db96d56Sopenharmony_cistatic void* 2587db96d56Sopenharmony_ciraw_malloc(size_t size) 2597db96d56Sopenharmony_ci{ 2607db96d56Sopenharmony_ci return allocators.raw.malloc(allocators.raw.ctx, size); 2617db96d56Sopenharmony_ci} 2627db96d56Sopenharmony_ci 2637db96d56Sopenharmony_cistatic void 2647db96d56Sopenharmony_ciraw_free(void *ptr) 2657db96d56Sopenharmony_ci{ 2667db96d56Sopenharmony_ci allocators.raw.free(allocators.raw.ctx, ptr); 2677db96d56Sopenharmony_ci} 2687db96d56Sopenharmony_ci 2697db96d56Sopenharmony_ci 2707db96d56Sopenharmony_cistatic Py_uhash_t 2717db96d56Sopenharmony_cihashtable_hash_traceback(const void *key) 2727db96d56Sopenharmony_ci{ 2737db96d56Sopenharmony_ci const traceback_t *traceback = (const traceback_t *)key; 2747db96d56Sopenharmony_ci return traceback->hash; 2757db96d56Sopenharmony_ci} 2767db96d56Sopenharmony_ci 2777db96d56Sopenharmony_ci 2787db96d56Sopenharmony_cistatic int 2797db96d56Sopenharmony_cihashtable_compare_traceback(const void *key1, const void *key2) 2807db96d56Sopenharmony_ci{ 2817db96d56Sopenharmony_ci const traceback_t *traceback1 = (const traceback_t *)key1; 2827db96d56Sopenharmony_ci const traceback_t *traceback2 = (const traceback_t *)key2; 2837db96d56Sopenharmony_ci 2847db96d56Sopenharmony_ci if (traceback1->nframe != traceback2->nframe) { 2857db96d56Sopenharmony_ci return 0; 2867db96d56Sopenharmony_ci } 2877db96d56Sopenharmony_ci if (traceback1->total_nframe != traceback2->total_nframe) { 2887db96d56Sopenharmony_ci return 0; 2897db96d56Sopenharmony_ci } 2907db96d56Sopenharmony_ci 2917db96d56Sopenharmony_ci for (int i=0; i < traceback1->nframe; i++) { 2927db96d56Sopenharmony_ci const frame_t *frame1 = &traceback1->frames[i]; 2937db96d56Sopenharmony_ci const frame_t *frame2 = &traceback2->frames[i]; 2947db96d56Sopenharmony_ci 2957db96d56Sopenharmony_ci if (frame1->lineno != frame2->lineno) { 2967db96d56Sopenharmony_ci return 0; 2977db96d56Sopenharmony_ci } 2987db96d56Sopenharmony_ci if (frame1->filename != frame2->filename) { 2997db96d56Sopenharmony_ci assert(PyUnicode_Compare(frame1->filename, frame2->filename) != 0); 3007db96d56Sopenharmony_ci return 0; 3017db96d56Sopenharmony_ci } 3027db96d56Sopenharmony_ci } 3037db96d56Sopenharmony_ci return 1; 3047db96d56Sopenharmony_ci} 3057db96d56Sopenharmony_ci 3067db96d56Sopenharmony_ci 3077db96d56Sopenharmony_cistatic void 3087db96d56Sopenharmony_citracemalloc_get_frame(_PyInterpreterFrame *pyframe, frame_t *frame) 3097db96d56Sopenharmony_ci{ 3107db96d56Sopenharmony_ci frame->filename = &_Py_STR(anon_unknown); 3117db96d56Sopenharmony_ci int lineno = _PyInterpreterFrame_GetLine(pyframe); 3127db96d56Sopenharmony_ci if (lineno < 0) { 3137db96d56Sopenharmony_ci lineno = 0; 3147db96d56Sopenharmony_ci } 3157db96d56Sopenharmony_ci frame->lineno = (unsigned int)lineno; 3167db96d56Sopenharmony_ci 3177db96d56Sopenharmony_ci PyObject *filename = pyframe->f_code->co_filename; 3187db96d56Sopenharmony_ci 3197db96d56Sopenharmony_ci if (filename == NULL) { 3207db96d56Sopenharmony_ci#ifdef TRACE_DEBUG 3217db96d56Sopenharmony_ci tracemalloc_error("failed to get the filename of the code object"); 3227db96d56Sopenharmony_ci#endif 3237db96d56Sopenharmony_ci return; 3247db96d56Sopenharmony_ci } 3257db96d56Sopenharmony_ci 3267db96d56Sopenharmony_ci if (!PyUnicode_Check(filename)) { 3277db96d56Sopenharmony_ci#ifdef TRACE_DEBUG 3287db96d56Sopenharmony_ci tracemalloc_error("filename is not a unicode string"); 3297db96d56Sopenharmony_ci#endif 3307db96d56Sopenharmony_ci return; 3317db96d56Sopenharmony_ci } 3327db96d56Sopenharmony_ci if (!PyUnicode_IS_READY(filename)) { 3337db96d56Sopenharmony_ci /* Don't make a Unicode string ready to avoid reentrant calls 3347db96d56Sopenharmony_ci to tracemalloc_malloc() or tracemalloc_realloc() */ 3357db96d56Sopenharmony_ci#ifdef TRACE_DEBUG 3367db96d56Sopenharmony_ci tracemalloc_error("filename is not a ready unicode string"); 3377db96d56Sopenharmony_ci#endif 3387db96d56Sopenharmony_ci return; 3397db96d56Sopenharmony_ci } 3407db96d56Sopenharmony_ci 3417db96d56Sopenharmony_ci /* intern the filename */ 3427db96d56Sopenharmony_ci _Py_hashtable_entry_t *entry; 3437db96d56Sopenharmony_ci entry = _Py_hashtable_get_entry(tracemalloc_filenames, filename); 3447db96d56Sopenharmony_ci if (entry != NULL) { 3457db96d56Sopenharmony_ci filename = (PyObject *)entry->key; 3467db96d56Sopenharmony_ci } 3477db96d56Sopenharmony_ci else { 3487db96d56Sopenharmony_ci /* tracemalloc_filenames is responsible to keep a reference 3497db96d56Sopenharmony_ci to the filename */ 3507db96d56Sopenharmony_ci Py_INCREF(filename); 3517db96d56Sopenharmony_ci if (_Py_hashtable_set(tracemalloc_filenames, filename, NULL) < 0) { 3527db96d56Sopenharmony_ci Py_DECREF(filename); 3537db96d56Sopenharmony_ci#ifdef TRACE_DEBUG 3547db96d56Sopenharmony_ci tracemalloc_error("failed to intern the filename"); 3557db96d56Sopenharmony_ci#endif 3567db96d56Sopenharmony_ci return; 3577db96d56Sopenharmony_ci } 3587db96d56Sopenharmony_ci } 3597db96d56Sopenharmony_ci 3607db96d56Sopenharmony_ci /* the tracemalloc_filenames table keeps a reference to the filename */ 3617db96d56Sopenharmony_ci frame->filename = filename; 3627db96d56Sopenharmony_ci} 3637db96d56Sopenharmony_ci 3647db96d56Sopenharmony_ci 3657db96d56Sopenharmony_cistatic Py_uhash_t 3667db96d56Sopenharmony_citraceback_hash(traceback_t *traceback) 3677db96d56Sopenharmony_ci{ 3687db96d56Sopenharmony_ci /* code based on tuplehash() of Objects/tupleobject.c */ 3697db96d56Sopenharmony_ci Py_uhash_t x, y; /* Unsigned for defined overflow behavior. */ 3707db96d56Sopenharmony_ci int len = traceback->nframe; 3717db96d56Sopenharmony_ci Py_uhash_t mult = _PyHASH_MULTIPLIER; 3727db96d56Sopenharmony_ci frame_t *frame; 3737db96d56Sopenharmony_ci 3747db96d56Sopenharmony_ci x = 0x345678UL; 3757db96d56Sopenharmony_ci frame = traceback->frames; 3767db96d56Sopenharmony_ci while (--len >= 0) { 3777db96d56Sopenharmony_ci y = (Py_uhash_t)PyObject_Hash(frame->filename); 3787db96d56Sopenharmony_ci y ^= (Py_uhash_t)frame->lineno; 3797db96d56Sopenharmony_ci frame++; 3807db96d56Sopenharmony_ci 3817db96d56Sopenharmony_ci x = (x ^ y) * mult; 3827db96d56Sopenharmony_ci /* the cast might truncate len; that doesn't change hash stability */ 3837db96d56Sopenharmony_ci mult += (Py_uhash_t)(82520UL + len + len); 3847db96d56Sopenharmony_ci } 3857db96d56Sopenharmony_ci x ^= traceback->total_nframe; 3867db96d56Sopenharmony_ci x += 97531UL; 3877db96d56Sopenharmony_ci return x; 3887db96d56Sopenharmony_ci} 3897db96d56Sopenharmony_ci 3907db96d56Sopenharmony_ci 3917db96d56Sopenharmony_cistatic void 3927db96d56Sopenharmony_citraceback_get_frames(traceback_t *traceback) 3937db96d56Sopenharmony_ci{ 3947db96d56Sopenharmony_ci PyThreadState *tstate = PyGILState_GetThisThreadState(); 3957db96d56Sopenharmony_ci if (tstate == NULL) { 3967db96d56Sopenharmony_ci#ifdef TRACE_DEBUG 3977db96d56Sopenharmony_ci tracemalloc_error("failed to get the current thread state"); 3987db96d56Sopenharmony_ci#endif 3997db96d56Sopenharmony_ci return; 4007db96d56Sopenharmony_ci } 4017db96d56Sopenharmony_ci 4027db96d56Sopenharmony_ci _PyInterpreterFrame *pyframe = tstate->cframe->current_frame; 4037db96d56Sopenharmony_ci for (;;) { 4047db96d56Sopenharmony_ci while (pyframe && _PyFrame_IsIncomplete(pyframe)) { 4057db96d56Sopenharmony_ci pyframe = pyframe->previous; 4067db96d56Sopenharmony_ci } 4077db96d56Sopenharmony_ci if (pyframe == NULL) { 4087db96d56Sopenharmony_ci break; 4097db96d56Sopenharmony_ci } 4107db96d56Sopenharmony_ci if (traceback->nframe < _Py_tracemalloc_config.max_nframe) { 4117db96d56Sopenharmony_ci tracemalloc_get_frame(pyframe, &traceback->frames[traceback->nframe]); 4127db96d56Sopenharmony_ci assert(traceback->frames[traceback->nframe].filename != NULL); 4137db96d56Sopenharmony_ci traceback->nframe++; 4147db96d56Sopenharmony_ci } 4157db96d56Sopenharmony_ci if (traceback->total_nframe < UINT16_MAX) { 4167db96d56Sopenharmony_ci traceback->total_nframe++; 4177db96d56Sopenharmony_ci } 4187db96d56Sopenharmony_ci 4197db96d56Sopenharmony_ci pyframe = pyframe->previous; 4207db96d56Sopenharmony_ci } 4217db96d56Sopenharmony_ci} 4227db96d56Sopenharmony_ci 4237db96d56Sopenharmony_ci 4247db96d56Sopenharmony_cistatic traceback_t * 4257db96d56Sopenharmony_citraceback_new(void) 4267db96d56Sopenharmony_ci{ 4277db96d56Sopenharmony_ci traceback_t *traceback; 4287db96d56Sopenharmony_ci _Py_hashtable_entry_t *entry; 4297db96d56Sopenharmony_ci 4307db96d56Sopenharmony_ci assert(PyGILState_Check()); 4317db96d56Sopenharmony_ci 4327db96d56Sopenharmony_ci /* get frames */ 4337db96d56Sopenharmony_ci traceback = tracemalloc_traceback; 4347db96d56Sopenharmony_ci traceback->nframe = 0; 4357db96d56Sopenharmony_ci traceback->total_nframe = 0; 4367db96d56Sopenharmony_ci traceback_get_frames(traceback); 4377db96d56Sopenharmony_ci if (traceback->nframe == 0) 4387db96d56Sopenharmony_ci return &tracemalloc_empty_traceback; 4397db96d56Sopenharmony_ci traceback->hash = traceback_hash(traceback); 4407db96d56Sopenharmony_ci 4417db96d56Sopenharmony_ci /* intern the traceback */ 4427db96d56Sopenharmony_ci entry = _Py_hashtable_get_entry(tracemalloc_tracebacks, traceback); 4437db96d56Sopenharmony_ci if (entry != NULL) { 4447db96d56Sopenharmony_ci traceback = (traceback_t *)entry->key; 4457db96d56Sopenharmony_ci } 4467db96d56Sopenharmony_ci else { 4477db96d56Sopenharmony_ci traceback_t *copy; 4487db96d56Sopenharmony_ci size_t traceback_size; 4497db96d56Sopenharmony_ci 4507db96d56Sopenharmony_ci traceback_size = TRACEBACK_SIZE(traceback->nframe); 4517db96d56Sopenharmony_ci 4527db96d56Sopenharmony_ci copy = raw_malloc(traceback_size); 4537db96d56Sopenharmony_ci if (copy == NULL) { 4547db96d56Sopenharmony_ci#ifdef TRACE_DEBUG 4557db96d56Sopenharmony_ci tracemalloc_error("failed to intern the traceback: malloc failed"); 4567db96d56Sopenharmony_ci#endif 4577db96d56Sopenharmony_ci return NULL; 4587db96d56Sopenharmony_ci } 4597db96d56Sopenharmony_ci memcpy(copy, traceback, traceback_size); 4607db96d56Sopenharmony_ci 4617db96d56Sopenharmony_ci if (_Py_hashtable_set(tracemalloc_tracebacks, copy, NULL) < 0) { 4627db96d56Sopenharmony_ci raw_free(copy); 4637db96d56Sopenharmony_ci#ifdef TRACE_DEBUG 4647db96d56Sopenharmony_ci tracemalloc_error("failed to intern the traceback: putdata failed"); 4657db96d56Sopenharmony_ci#endif 4667db96d56Sopenharmony_ci return NULL; 4677db96d56Sopenharmony_ci } 4687db96d56Sopenharmony_ci traceback = copy; 4697db96d56Sopenharmony_ci } 4707db96d56Sopenharmony_ci return traceback; 4717db96d56Sopenharmony_ci} 4727db96d56Sopenharmony_ci 4737db96d56Sopenharmony_ci 4747db96d56Sopenharmony_cistatic _Py_hashtable_t* 4757db96d56Sopenharmony_citracemalloc_create_traces_table(void) 4767db96d56Sopenharmony_ci{ 4777db96d56Sopenharmony_ci return hashtable_new(_Py_hashtable_hash_ptr, 4787db96d56Sopenharmony_ci _Py_hashtable_compare_direct, 4797db96d56Sopenharmony_ci NULL, raw_free); 4807db96d56Sopenharmony_ci} 4817db96d56Sopenharmony_ci 4827db96d56Sopenharmony_ci 4837db96d56Sopenharmony_cistatic _Py_hashtable_t* 4847db96d56Sopenharmony_citracemalloc_create_domains_table(void) 4857db96d56Sopenharmony_ci{ 4867db96d56Sopenharmony_ci return hashtable_new(hashtable_hash_uint, 4877db96d56Sopenharmony_ci _Py_hashtable_compare_direct, 4887db96d56Sopenharmony_ci NULL, 4897db96d56Sopenharmony_ci (_Py_hashtable_destroy_func)_Py_hashtable_destroy); 4907db96d56Sopenharmony_ci} 4917db96d56Sopenharmony_ci 4927db96d56Sopenharmony_ci 4937db96d56Sopenharmony_cistatic _Py_hashtable_t* 4947db96d56Sopenharmony_citracemalloc_get_traces_table(unsigned int domain) 4957db96d56Sopenharmony_ci{ 4967db96d56Sopenharmony_ci if (domain == DEFAULT_DOMAIN) { 4977db96d56Sopenharmony_ci return tracemalloc_traces; 4987db96d56Sopenharmony_ci } 4997db96d56Sopenharmony_ci else { 5007db96d56Sopenharmony_ci return _Py_hashtable_get(tracemalloc_domains, TO_PTR(domain)); 5017db96d56Sopenharmony_ci } 5027db96d56Sopenharmony_ci} 5037db96d56Sopenharmony_ci 5047db96d56Sopenharmony_ci 5057db96d56Sopenharmony_cistatic void 5067db96d56Sopenharmony_citracemalloc_remove_trace(unsigned int domain, uintptr_t ptr) 5077db96d56Sopenharmony_ci{ 5087db96d56Sopenharmony_ci assert(_Py_tracemalloc_config.tracing); 5097db96d56Sopenharmony_ci 5107db96d56Sopenharmony_ci _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); 5117db96d56Sopenharmony_ci if (!traces) { 5127db96d56Sopenharmony_ci return; 5137db96d56Sopenharmony_ci } 5147db96d56Sopenharmony_ci 5157db96d56Sopenharmony_ci trace_t *trace = _Py_hashtable_steal(traces, TO_PTR(ptr)); 5167db96d56Sopenharmony_ci if (!trace) { 5177db96d56Sopenharmony_ci return; 5187db96d56Sopenharmony_ci } 5197db96d56Sopenharmony_ci assert(tracemalloc_traced_memory >= trace->size); 5207db96d56Sopenharmony_ci tracemalloc_traced_memory -= trace->size; 5217db96d56Sopenharmony_ci raw_free(trace); 5227db96d56Sopenharmony_ci} 5237db96d56Sopenharmony_ci 5247db96d56Sopenharmony_ci#define REMOVE_TRACE(ptr) \ 5257db96d56Sopenharmony_ci tracemalloc_remove_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr)) 5267db96d56Sopenharmony_ci 5277db96d56Sopenharmony_ci 5287db96d56Sopenharmony_cistatic int 5297db96d56Sopenharmony_citracemalloc_add_trace(unsigned int domain, uintptr_t ptr, 5307db96d56Sopenharmony_ci size_t size) 5317db96d56Sopenharmony_ci{ 5327db96d56Sopenharmony_ci assert(_Py_tracemalloc_config.tracing); 5337db96d56Sopenharmony_ci 5347db96d56Sopenharmony_ci traceback_t *traceback = traceback_new(); 5357db96d56Sopenharmony_ci if (traceback == NULL) { 5367db96d56Sopenharmony_ci return -1; 5377db96d56Sopenharmony_ci } 5387db96d56Sopenharmony_ci 5397db96d56Sopenharmony_ci _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); 5407db96d56Sopenharmony_ci if (traces == NULL) { 5417db96d56Sopenharmony_ci traces = tracemalloc_create_traces_table(); 5427db96d56Sopenharmony_ci if (traces == NULL) { 5437db96d56Sopenharmony_ci return -1; 5447db96d56Sopenharmony_ci } 5457db96d56Sopenharmony_ci 5467db96d56Sopenharmony_ci if (_Py_hashtable_set(tracemalloc_domains, TO_PTR(domain), traces) < 0) { 5477db96d56Sopenharmony_ci _Py_hashtable_destroy(traces); 5487db96d56Sopenharmony_ci return -1; 5497db96d56Sopenharmony_ci } 5507db96d56Sopenharmony_ci } 5517db96d56Sopenharmony_ci 5527db96d56Sopenharmony_ci trace_t *trace = _Py_hashtable_get(traces, TO_PTR(ptr)); 5537db96d56Sopenharmony_ci if (trace != NULL) { 5547db96d56Sopenharmony_ci /* the memory block is already tracked */ 5557db96d56Sopenharmony_ci assert(tracemalloc_traced_memory >= trace->size); 5567db96d56Sopenharmony_ci tracemalloc_traced_memory -= trace->size; 5577db96d56Sopenharmony_ci 5587db96d56Sopenharmony_ci trace->size = size; 5597db96d56Sopenharmony_ci trace->traceback = traceback; 5607db96d56Sopenharmony_ci } 5617db96d56Sopenharmony_ci else { 5627db96d56Sopenharmony_ci trace = raw_malloc(sizeof(trace_t)); 5637db96d56Sopenharmony_ci if (trace == NULL) { 5647db96d56Sopenharmony_ci return -1; 5657db96d56Sopenharmony_ci } 5667db96d56Sopenharmony_ci trace->size = size; 5677db96d56Sopenharmony_ci trace->traceback = traceback; 5687db96d56Sopenharmony_ci 5697db96d56Sopenharmony_ci int res = _Py_hashtable_set(traces, TO_PTR(ptr), trace); 5707db96d56Sopenharmony_ci if (res != 0) { 5717db96d56Sopenharmony_ci raw_free(trace); 5727db96d56Sopenharmony_ci return res; 5737db96d56Sopenharmony_ci } 5747db96d56Sopenharmony_ci } 5757db96d56Sopenharmony_ci 5767db96d56Sopenharmony_ci assert(tracemalloc_traced_memory <= SIZE_MAX - size); 5777db96d56Sopenharmony_ci tracemalloc_traced_memory += size; 5787db96d56Sopenharmony_ci if (tracemalloc_traced_memory > tracemalloc_peak_traced_memory) { 5797db96d56Sopenharmony_ci tracemalloc_peak_traced_memory = tracemalloc_traced_memory; 5807db96d56Sopenharmony_ci } 5817db96d56Sopenharmony_ci return 0; 5827db96d56Sopenharmony_ci} 5837db96d56Sopenharmony_ci 5847db96d56Sopenharmony_ci#define ADD_TRACE(ptr, size) \ 5857db96d56Sopenharmony_ci tracemalloc_add_trace(DEFAULT_DOMAIN, (uintptr_t)(ptr), size) 5867db96d56Sopenharmony_ci 5877db96d56Sopenharmony_ci 5887db96d56Sopenharmony_cistatic void* 5897db96d56Sopenharmony_citracemalloc_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) 5907db96d56Sopenharmony_ci{ 5917db96d56Sopenharmony_ci PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 5927db96d56Sopenharmony_ci void *ptr; 5937db96d56Sopenharmony_ci 5947db96d56Sopenharmony_ci assert(elsize == 0 || nelem <= SIZE_MAX / elsize); 5957db96d56Sopenharmony_ci 5967db96d56Sopenharmony_ci if (use_calloc) 5977db96d56Sopenharmony_ci ptr = alloc->calloc(alloc->ctx, nelem, elsize); 5987db96d56Sopenharmony_ci else 5997db96d56Sopenharmony_ci ptr = alloc->malloc(alloc->ctx, nelem * elsize); 6007db96d56Sopenharmony_ci if (ptr == NULL) 6017db96d56Sopenharmony_ci return NULL; 6027db96d56Sopenharmony_ci 6037db96d56Sopenharmony_ci TABLES_LOCK(); 6047db96d56Sopenharmony_ci if (ADD_TRACE(ptr, nelem * elsize) < 0) { 6057db96d56Sopenharmony_ci /* Failed to allocate a trace for the new memory block */ 6067db96d56Sopenharmony_ci TABLES_UNLOCK(); 6077db96d56Sopenharmony_ci alloc->free(alloc->ctx, ptr); 6087db96d56Sopenharmony_ci return NULL; 6097db96d56Sopenharmony_ci } 6107db96d56Sopenharmony_ci TABLES_UNLOCK(); 6117db96d56Sopenharmony_ci return ptr; 6127db96d56Sopenharmony_ci} 6137db96d56Sopenharmony_ci 6147db96d56Sopenharmony_ci 6157db96d56Sopenharmony_cistatic void* 6167db96d56Sopenharmony_citracemalloc_realloc(void *ctx, void *ptr, size_t new_size) 6177db96d56Sopenharmony_ci{ 6187db96d56Sopenharmony_ci PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 6197db96d56Sopenharmony_ci void *ptr2; 6207db96d56Sopenharmony_ci 6217db96d56Sopenharmony_ci ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); 6227db96d56Sopenharmony_ci if (ptr2 == NULL) 6237db96d56Sopenharmony_ci return NULL; 6247db96d56Sopenharmony_ci 6257db96d56Sopenharmony_ci if (ptr != NULL) { 6267db96d56Sopenharmony_ci /* an existing memory block has been resized */ 6277db96d56Sopenharmony_ci 6287db96d56Sopenharmony_ci TABLES_LOCK(); 6297db96d56Sopenharmony_ci 6307db96d56Sopenharmony_ci /* tracemalloc_add_trace() updates the trace if there is already 6317db96d56Sopenharmony_ci a trace at address ptr2 */ 6327db96d56Sopenharmony_ci if (ptr2 != ptr) { 6337db96d56Sopenharmony_ci REMOVE_TRACE(ptr); 6347db96d56Sopenharmony_ci } 6357db96d56Sopenharmony_ci 6367db96d56Sopenharmony_ci if (ADD_TRACE(ptr2, new_size) < 0) { 6377db96d56Sopenharmony_ci /* Memory allocation failed. The error cannot be reported to 6387db96d56Sopenharmony_ci the caller, because realloc() may already have shrunk the 6397db96d56Sopenharmony_ci memory block and so removed bytes. 6407db96d56Sopenharmony_ci 6417db96d56Sopenharmony_ci This case is very unlikely: a hash entry has just been 6427db96d56Sopenharmony_ci released, so the hash table should have at least one free entry. 6437db96d56Sopenharmony_ci 6447db96d56Sopenharmony_ci The GIL and the table lock ensures that only one thread is 6457db96d56Sopenharmony_ci allocating memory. */ 6467db96d56Sopenharmony_ci Py_FatalError("tracemalloc_realloc() failed to allocate a trace"); 6477db96d56Sopenharmony_ci } 6487db96d56Sopenharmony_ci TABLES_UNLOCK(); 6497db96d56Sopenharmony_ci } 6507db96d56Sopenharmony_ci else { 6517db96d56Sopenharmony_ci /* new allocation */ 6527db96d56Sopenharmony_ci 6537db96d56Sopenharmony_ci TABLES_LOCK(); 6547db96d56Sopenharmony_ci if (ADD_TRACE(ptr2, new_size) < 0) { 6557db96d56Sopenharmony_ci /* Failed to allocate a trace for the new memory block */ 6567db96d56Sopenharmony_ci TABLES_UNLOCK(); 6577db96d56Sopenharmony_ci alloc->free(alloc->ctx, ptr2); 6587db96d56Sopenharmony_ci return NULL; 6597db96d56Sopenharmony_ci } 6607db96d56Sopenharmony_ci TABLES_UNLOCK(); 6617db96d56Sopenharmony_ci } 6627db96d56Sopenharmony_ci return ptr2; 6637db96d56Sopenharmony_ci} 6647db96d56Sopenharmony_ci 6657db96d56Sopenharmony_ci 6667db96d56Sopenharmony_cistatic void 6677db96d56Sopenharmony_citracemalloc_free(void *ctx, void *ptr) 6687db96d56Sopenharmony_ci{ 6697db96d56Sopenharmony_ci PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 6707db96d56Sopenharmony_ci 6717db96d56Sopenharmony_ci if (ptr == NULL) 6727db96d56Sopenharmony_ci return; 6737db96d56Sopenharmony_ci 6747db96d56Sopenharmony_ci /* GIL cannot be locked in PyMem_RawFree() because it would introduce 6757db96d56Sopenharmony_ci a deadlock in _PyThreadState_DeleteCurrent(). */ 6767db96d56Sopenharmony_ci 6777db96d56Sopenharmony_ci alloc->free(alloc->ctx, ptr); 6787db96d56Sopenharmony_ci 6797db96d56Sopenharmony_ci TABLES_LOCK(); 6807db96d56Sopenharmony_ci REMOVE_TRACE(ptr); 6817db96d56Sopenharmony_ci TABLES_UNLOCK(); 6827db96d56Sopenharmony_ci} 6837db96d56Sopenharmony_ci 6847db96d56Sopenharmony_ci 6857db96d56Sopenharmony_cistatic void* 6867db96d56Sopenharmony_citracemalloc_alloc_gil(int use_calloc, void *ctx, size_t nelem, size_t elsize) 6877db96d56Sopenharmony_ci{ 6887db96d56Sopenharmony_ci void *ptr; 6897db96d56Sopenharmony_ci 6907db96d56Sopenharmony_ci if (get_reentrant()) { 6917db96d56Sopenharmony_ci PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 6927db96d56Sopenharmony_ci if (use_calloc) 6937db96d56Sopenharmony_ci return alloc->calloc(alloc->ctx, nelem, elsize); 6947db96d56Sopenharmony_ci else 6957db96d56Sopenharmony_ci return alloc->malloc(alloc->ctx, nelem * elsize); 6967db96d56Sopenharmony_ci } 6977db96d56Sopenharmony_ci 6987db96d56Sopenharmony_ci /* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for 6997db96d56Sopenharmony_ci allocations larger than 512 bytes, don't trace the same memory 7007db96d56Sopenharmony_ci allocation twice. */ 7017db96d56Sopenharmony_ci set_reentrant(1); 7027db96d56Sopenharmony_ci 7037db96d56Sopenharmony_ci ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); 7047db96d56Sopenharmony_ci 7057db96d56Sopenharmony_ci set_reentrant(0); 7067db96d56Sopenharmony_ci return ptr; 7077db96d56Sopenharmony_ci} 7087db96d56Sopenharmony_ci 7097db96d56Sopenharmony_ci 7107db96d56Sopenharmony_cistatic void* 7117db96d56Sopenharmony_citracemalloc_malloc_gil(void *ctx, size_t size) 7127db96d56Sopenharmony_ci{ 7137db96d56Sopenharmony_ci return tracemalloc_alloc_gil(0, ctx, 1, size); 7147db96d56Sopenharmony_ci} 7157db96d56Sopenharmony_ci 7167db96d56Sopenharmony_ci 7177db96d56Sopenharmony_cistatic void* 7187db96d56Sopenharmony_citracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize) 7197db96d56Sopenharmony_ci{ 7207db96d56Sopenharmony_ci return tracemalloc_alloc_gil(1, ctx, nelem, elsize); 7217db96d56Sopenharmony_ci} 7227db96d56Sopenharmony_ci 7237db96d56Sopenharmony_ci 7247db96d56Sopenharmony_cistatic void* 7257db96d56Sopenharmony_citracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size) 7267db96d56Sopenharmony_ci{ 7277db96d56Sopenharmony_ci void *ptr2; 7287db96d56Sopenharmony_ci 7297db96d56Sopenharmony_ci if (get_reentrant()) { 7307db96d56Sopenharmony_ci /* Reentrant call to PyMem_Realloc() and PyMem_RawRealloc(). 7317db96d56Sopenharmony_ci Example: PyMem_RawRealloc() is called internally by pymalloc 7327db96d56Sopenharmony_ci (_PyObject_Malloc() and _PyObject_Realloc()) to allocate a new 7337db96d56Sopenharmony_ci arena (new_arena()). */ 7347db96d56Sopenharmony_ci PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 7357db96d56Sopenharmony_ci 7367db96d56Sopenharmony_ci ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); 7377db96d56Sopenharmony_ci if (ptr2 != NULL && ptr != NULL) { 7387db96d56Sopenharmony_ci TABLES_LOCK(); 7397db96d56Sopenharmony_ci REMOVE_TRACE(ptr); 7407db96d56Sopenharmony_ci TABLES_UNLOCK(); 7417db96d56Sopenharmony_ci } 7427db96d56Sopenharmony_ci return ptr2; 7437db96d56Sopenharmony_ci } 7447db96d56Sopenharmony_ci 7457db96d56Sopenharmony_ci /* Ignore reentrant call. PyObjet_Realloc() calls PyMem_Realloc() for 7467db96d56Sopenharmony_ci allocations larger than 512 bytes. Don't trace the same memory 7477db96d56Sopenharmony_ci allocation twice. */ 7487db96d56Sopenharmony_ci set_reentrant(1); 7497db96d56Sopenharmony_ci 7507db96d56Sopenharmony_ci ptr2 = tracemalloc_realloc(ctx, ptr, new_size); 7517db96d56Sopenharmony_ci 7527db96d56Sopenharmony_ci set_reentrant(0); 7537db96d56Sopenharmony_ci return ptr2; 7547db96d56Sopenharmony_ci} 7557db96d56Sopenharmony_ci 7567db96d56Sopenharmony_ci 7577db96d56Sopenharmony_ci#ifdef TRACE_RAW_MALLOC 7587db96d56Sopenharmony_cistatic void* 7597db96d56Sopenharmony_citracemalloc_raw_alloc(int use_calloc, void *ctx, size_t nelem, size_t elsize) 7607db96d56Sopenharmony_ci{ 7617db96d56Sopenharmony_ci PyGILState_STATE gil_state; 7627db96d56Sopenharmony_ci void *ptr; 7637db96d56Sopenharmony_ci 7647db96d56Sopenharmony_ci if (get_reentrant()) { 7657db96d56Sopenharmony_ci PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 7667db96d56Sopenharmony_ci if (use_calloc) 7677db96d56Sopenharmony_ci return alloc->calloc(alloc->ctx, nelem, elsize); 7687db96d56Sopenharmony_ci else 7697db96d56Sopenharmony_ci return alloc->malloc(alloc->ctx, nelem * elsize); 7707db96d56Sopenharmony_ci } 7717db96d56Sopenharmony_ci 7727db96d56Sopenharmony_ci /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() 7737db96d56Sopenharmony_ci indirectly which would call PyGILState_Ensure() if reentrant are not 7747db96d56Sopenharmony_ci disabled. */ 7757db96d56Sopenharmony_ci set_reentrant(1); 7767db96d56Sopenharmony_ci 7777db96d56Sopenharmony_ci gil_state = PyGILState_Ensure(); 7787db96d56Sopenharmony_ci ptr = tracemalloc_alloc(use_calloc, ctx, nelem, elsize); 7797db96d56Sopenharmony_ci PyGILState_Release(gil_state); 7807db96d56Sopenharmony_ci 7817db96d56Sopenharmony_ci set_reentrant(0); 7827db96d56Sopenharmony_ci return ptr; 7837db96d56Sopenharmony_ci} 7847db96d56Sopenharmony_ci 7857db96d56Sopenharmony_ci 7867db96d56Sopenharmony_cistatic void* 7877db96d56Sopenharmony_citracemalloc_raw_malloc(void *ctx, size_t size) 7887db96d56Sopenharmony_ci{ 7897db96d56Sopenharmony_ci return tracemalloc_raw_alloc(0, ctx, 1, size); 7907db96d56Sopenharmony_ci} 7917db96d56Sopenharmony_ci 7927db96d56Sopenharmony_ci 7937db96d56Sopenharmony_cistatic void* 7947db96d56Sopenharmony_citracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize) 7957db96d56Sopenharmony_ci{ 7967db96d56Sopenharmony_ci return tracemalloc_raw_alloc(1, ctx, nelem, elsize); 7977db96d56Sopenharmony_ci} 7987db96d56Sopenharmony_ci 7997db96d56Sopenharmony_ci 8007db96d56Sopenharmony_cistatic void* 8017db96d56Sopenharmony_citracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size) 8027db96d56Sopenharmony_ci{ 8037db96d56Sopenharmony_ci PyGILState_STATE gil_state; 8047db96d56Sopenharmony_ci void *ptr2; 8057db96d56Sopenharmony_ci 8067db96d56Sopenharmony_ci if (get_reentrant()) { 8077db96d56Sopenharmony_ci /* Reentrant call to PyMem_RawRealloc(). */ 8087db96d56Sopenharmony_ci PyMemAllocatorEx *alloc = (PyMemAllocatorEx *)ctx; 8097db96d56Sopenharmony_ci 8107db96d56Sopenharmony_ci ptr2 = alloc->realloc(alloc->ctx, ptr, new_size); 8117db96d56Sopenharmony_ci 8127db96d56Sopenharmony_ci if (ptr2 != NULL && ptr != NULL) { 8137db96d56Sopenharmony_ci TABLES_LOCK(); 8147db96d56Sopenharmony_ci REMOVE_TRACE(ptr); 8157db96d56Sopenharmony_ci TABLES_UNLOCK(); 8167db96d56Sopenharmony_ci } 8177db96d56Sopenharmony_ci return ptr2; 8187db96d56Sopenharmony_ci } 8197db96d56Sopenharmony_ci 8207db96d56Sopenharmony_ci /* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc() 8217db96d56Sopenharmony_ci indirectly which would call PyGILState_Ensure() if reentrant calls are 8227db96d56Sopenharmony_ci not disabled. */ 8237db96d56Sopenharmony_ci set_reentrant(1); 8247db96d56Sopenharmony_ci 8257db96d56Sopenharmony_ci gil_state = PyGILState_Ensure(); 8267db96d56Sopenharmony_ci ptr2 = tracemalloc_realloc(ctx, ptr, new_size); 8277db96d56Sopenharmony_ci PyGILState_Release(gil_state); 8287db96d56Sopenharmony_ci 8297db96d56Sopenharmony_ci set_reentrant(0); 8307db96d56Sopenharmony_ci return ptr2; 8317db96d56Sopenharmony_ci} 8327db96d56Sopenharmony_ci#endif /* TRACE_RAW_MALLOC */ 8337db96d56Sopenharmony_ci 8347db96d56Sopenharmony_ci 8357db96d56Sopenharmony_cistatic void 8367db96d56Sopenharmony_citracemalloc_clear_filename(void *value) 8377db96d56Sopenharmony_ci{ 8387db96d56Sopenharmony_ci PyObject *filename = (PyObject *)value; 8397db96d56Sopenharmony_ci Py_DECREF(filename); 8407db96d56Sopenharmony_ci} 8417db96d56Sopenharmony_ci 8427db96d56Sopenharmony_ci 8437db96d56Sopenharmony_ci/* reentrant flag must be set to call this function and GIL must be held */ 8447db96d56Sopenharmony_cistatic void 8457db96d56Sopenharmony_citracemalloc_clear_traces(void) 8467db96d56Sopenharmony_ci{ 8477db96d56Sopenharmony_ci /* The GIL protects variables against concurrent access */ 8487db96d56Sopenharmony_ci assert(PyGILState_Check()); 8497db96d56Sopenharmony_ci 8507db96d56Sopenharmony_ci TABLES_LOCK(); 8517db96d56Sopenharmony_ci _Py_hashtable_clear(tracemalloc_traces); 8527db96d56Sopenharmony_ci _Py_hashtable_clear(tracemalloc_domains); 8537db96d56Sopenharmony_ci tracemalloc_traced_memory = 0; 8547db96d56Sopenharmony_ci tracemalloc_peak_traced_memory = 0; 8557db96d56Sopenharmony_ci TABLES_UNLOCK(); 8567db96d56Sopenharmony_ci 8577db96d56Sopenharmony_ci _Py_hashtable_clear(tracemalloc_tracebacks); 8587db96d56Sopenharmony_ci 8597db96d56Sopenharmony_ci _Py_hashtable_clear(tracemalloc_filenames); 8607db96d56Sopenharmony_ci} 8617db96d56Sopenharmony_ci 8627db96d56Sopenharmony_ci 8637db96d56Sopenharmony_cistatic int 8647db96d56Sopenharmony_citracemalloc_init(void) 8657db96d56Sopenharmony_ci{ 8667db96d56Sopenharmony_ci if (_Py_tracemalloc_config.initialized == TRACEMALLOC_FINALIZED) { 8677db96d56Sopenharmony_ci PyErr_SetString(PyExc_RuntimeError, 8687db96d56Sopenharmony_ci "the tracemalloc module has been unloaded"); 8697db96d56Sopenharmony_ci return -1; 8707db96d56Sopenharmony_ci } 8717db96d56Sopenharmony_ci 8727db96d56Sopenharmony_ci if (_Py_tracemalloc_config.initialized == TRACEMALLOC_INITIALIZED) 8737db96d56Sopenharmony_ci return 0; 8747db96d56Sopenharmony_ci 8757db96d56Sopenharmony_ci PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); 8767db96d56Sopenharmony_ci 8777db96d56Sopenharmony_ci#ifdef REENTRANT_THREADLOCAL 8787db96d56Sopenharmony_ci if (PyThread_tss_create(&tracemalloc_reentrant_key) != 0) { 8797db96d56Sopenharmony_ci#ifdef MS_WINDOWS 8807db96d56Sopenharmony_ci PyErr_SetFromWindowsErr(0); 8817db96d56Sopenharmony_ci#else 8827db96d56Sopenharmony_ci PyErr_SetFromErrno(PyExc_OSError); 8837db96d56Sopenharmony_ci#endif 8847db96d56Sopenharmony_ci return -1; 8857db96d56Sopenharmony_ci } 8867db96d56Sopenharmony_ci#endif 8877db96d56Sopenharmony_ci 8887db96d56Sopenharmony_ci#if defined(TRACE_RAW_MALLOC) 8897db96d56Sopenharmony_ci if (tables_lock == NULL) { 8907db96d56Sopenharmony_ci tables_lock = PyThread_allocate_lock(); 8917db96d56Sopenharmony_ci if (tables_lock == NULL) { 8927db96d56Sopenharmony_ci PyErr_SetString(PyExc_RuntimeError, "cannot allocate lock"); 8937db96d56Sopenharmony_ci return -1; 8947db96d56Sopenharmony_ci } 8957db96d56Sopenharmony_ci } 8967db96d56Sopenharmony_ci#endif 8977db96d56Sopenharmony_ci 8987db96d56Sopenharmony_ci tracemalloc_filenames = hashtable_new(hashtable_hash_pyobject, 8997db96d56Sopenharmony_ci hashtable_compare_unicode, 9007db96d56Sopenharmony_ci tracemalloc_clear_filename, NULL); 9017db96d56Sopenharmony_ci 9027db96d56Sopenharmony_ci tracemalloc_tracebacks = hashtable_new(hashtable_hash_traceback, 9037db96d56Sopenharmony_ci hashtable_compare_traceback, 9047db96d56Sopenharmony_ci NULL, raw_free); 9057db96d56Sopenharmony_ci 9067db96d56Sopenharmony_ci tracemalloc_traces = tracemalloc_create_traces_table(); 9077db96d56Sopenharmony_ci tracemalloc_domains = tracemalloc_create_domains_table(); 9087db96d56Sopenharmony_ci 9097db96d56Sopenharmony_ci if (tracemalloc_filenames == NULL || tracemalloc_tracebacks == NULL 9107db96d56Sopenharmony_ci || tracemalloc_traces == NULL || tracemalloc_domains == NULL) { 9117db96d56Sopenharmony_ci PyErr_NoMemory(); 9127db96d56Sopenharmony_ci return -1; 9137db96d56Sopenharmony_ci } 9147db96d56Sopenharmony_ci 9157db96d56Sopenharmony_ci tracemalloc_empty_traceback.nframe = 1; 9167db96d56Sopenharmony_ci tracemalloc_empty_traceback.total_nframe = 1; 9177db96d56Sopenharmony_ci /* borrowed reference */ 9187db96d56Sopenharmony_ci tracemalloc_empty_traceback.frames[0].filename = &_Py_STR(anon_unknown); 9197db96d56Sopenharmony_ci tracemalloc_empty_traceback.frames[0].lineno = 0; 9207db96d56Sopenharmony_ci tracemalloc_empty_traceback.hash = traceback_hash(&tracemalloc_empty_traceback); 9217db96d56Sopenharmony_ci 9227db96d56Sopenharmony_ci _Py_tracemalloc_config.initialized = TRACEMALLOC_INITIALIZED; 9237db96d56Sopenharmony_ci return 0; 9247db96d56Sopenharmony_ci} 9257db96d56Sopenharmony_ci 9267db96d56Sopenharmony_ci 9277db96d56Sopenharmony_cistatic void 9287db96d56Sopenharmony_citracemalloc_deinit(void) 9297db96d56Sopenharmony_ci{ 9307db96d56Sopenharmony_ci if (_Py_tracemalloc_config.initialized != TRACEMALLOC_INITIALIZED) 9317db96d56Sopenharmony_ci return; 9327db96d56Sopenharmony_ci _Py_tracemalloc_config.initialized = TRACEMALLOC_FINALIZED; 9337db96d56Sopenharmony_ci 9347db96d56Sopenharmony_ci tracemalloc_stop(); 9357db96d56Sopenharmony_ci 9367db96d56Sopenharmony_ci /* destroy hash tables */ 9377db96d56Sopenharmony_ci _Py_hashtable_destroy(tracemalloc_domains); 9387db96d56Sopenharmony_ci _Py_hashtable_destroy(tracemalloc_traces); 9397db96d56Sopenharmony_ci _Py_hashtable_destroy(tracemalloc_tracebacks); 9407db96d56Sopenharmony_ci _Py_hashtable_destroy(tracemalloc_filenames); 9417db96d56Sopenharmony_ci 9427db96d56Sopenharmony_ci#if defined(TRACE_RAW_MALLOC) 9437db96d56Sopenharmony_ci if (tables_lock != NULL) { 9447db96d56Sopenharmony_ci PyThread_free_lock(tables_lock); 9457db96d56Sopenharmony_ci tables_lock = NULL; 9467db96d56Sopenharmony_ci } 9477db96d56Sopenharmony_ci#endif 9487db96d56Sopenharmony_ci 9497db96d56Sopenharmony_ci#ifdef REENTRANT_THREADLOCAL 9507db96d56Sopenharmony_ci PyThread_tss_delete(&tracemalloc_reentrant_key); 9517db96d56Sopenharmony_ci#endif 9527db96d56Sopenharmony_ci} 9537db96d56Sopenharmony_ci 9547db96d56Sopenharmony_ci 9557db96d56Sopenharmony_cistatic int 9567db96d56Sopenharmony_citracemalloc_start(int max_nframe) 9577db96d56Sopenharmony_ci{ 9587db96d56Sopenharmony_ci PyMemAllocatorEx alloc; 9597db96d56Sopenharmony_ci size_t size; 9607db96d56Sopenharmony_ci 9617db96d56Sopenharmony_ci if (max_nframe < 1 || (unsigned long) max_nframe > MAX_NFRAME) { 9627db96d56Sopenharmony_ci PyErr_Format(PyExc_ValueError, 9637db96d56Sopenharmony_ci "the number of frames must be in range [1; %lu]", 9647db96d56Sopenharmony_ci MAX_NFRAME); 9657db96d56Sopenharmony_ci return -1; 9667db96d56Sopenharmony_ci } 9677db96d56Sopenharmony_ci 9687db96d56Sopenharmony_ci if (tracemalloc_init() < 0) { 9697db96d56Sopenharmony_ci return -1; 9707db96d56Sopenharmony_ci } 9717db96d56Sopenharmony_ci 9727db96d56Sopenharmony_ci if (_Py_tracemalloc_config.tracing) { 9737db96d56Sopenharmony_ci /* hook already installed: do nothing */ 9747db96d56Sopenharmony_ci return 0; 9757db96d56Sopenharmony_ci } 9767db96d56Sopenharmony_ci 9777db96d56Sopenharmony_ci _Py_tracemalloc_config.max_nframe = max_nframe; 9787db96d56Sopenharmony_ci 9797db96d56Sopenharmony_ci /* allocate a buffer to store a new traceback */ 9807db96d56Sopenharmony_ci size = TRACEBACK_SIZE(max_nframe); 9817db96d56Sopenharmony_ci assert(tracemalloc_traceback == NULL); 9827db96d56Sopenharmony_ci tracemalloc_traceback = raw_malloc(size); 9837db96d56Sopenharmony_ci if (tracemalloc_traceback == NULL) { 9847db96d56Sopenharmony_ci PyErr_NoMemory(); 9857db96d56Sopenharmony_ci return -1; 9867db96d56Sopenharmony_ci } 9877db96d56Sopenharmony_ci 9887db96d56Sopenharmony_ci#ifdef TRACE_RAW_MALLOC 9897db96d56Sopenharmony_ci alloc.malloc = tracemalloc_raw_malloc; 9907db96d56Sopenharmony_ci alloc.calloc = tracemalloc_raw_calloc; 9917db96d56Sopenharmony_ci alloc.realloc = tracemalloc_raw_realloc; 9927db96d56Sopenharmony_ci alloc.free = tracemalloc_free; 9937db96d56Sopenharmony_ci 9947db96d56Sopenharmony_ci alloc.ctx = &allocators.raw; 9957db96d56Sopenharmony_ci PyMem_GetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); 9967db96d56Sopenharmony_ci PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &alloc); 9977db96d56Sopenharmony_ci#endif 9987db96d56Sopenharmony_ci 9997db96d56Sopenharmony_ci alloc.malloc = tracemalloc_malloc_gil; 10007db96d56Sopenharmony_ci alloc.calloc = tracemalloc_calloc_gil; 10017db96d56Sopenharmony_ci alloc.realloc = tracemalloc_realloc_gil; 10027db96d56Sopenharmony_ci alloc.free = tracemalloc_free; 10037db96d56Sopenharmony_ci 10047db96d56Sopenharmony_ci alloc.ctx = &allocators.mem; 10057db96d56Sopenharmony_ci PyMem_GetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); 10067db96d56Sopenharmony_ci PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &alloc); 10077db96d56Sopenharmony_ci 10087db96d56Sopenharmony_ci alloc.ctx = &allocators.obj; 10097db96d56Sopenharmony_ci PyMem_GetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); 10107db96d56Sopenharmony_ci PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &alloc); 10117db96d56Sopenharmony_ci 10127db96d56Sopenharmony_ci /* everything is ready: start tracing Python memory allocations */ 10137db96d56Sopenharmony_ci _Py_tracemalloc_config.tracing = 1; 10147db96d56Sopenharmony_ci 10157db96d56Sopenharmony_ci return 0; 10167db96d56Sopenharmony_ci} 10177db96d56Sopenharmony_ci 10187db96d56Sopenharmony_ci 10197db96d56Sopenharmony_cistatic void 10207db96d56Sopenharmony_citracemalloc_stop(void) 10217db96d56Sopenharmony_ci{ 10227db96d56Sopenharmony_ci if (!_Py_tracemalloc_config.tracing) 10237db96d56Sopenharmony_ci return; 10247db96d56Sopenharmony_ci 10257db96d56Sopenharmony_ci /* stop tracing Python memory allocations */ 10267db96d56Sopenharmony_ci _Py_tracemalloc_config.tracing = 0; 10277db96d56Sopenharmony_ci 10287db96d56Sopenharmony_ci /* unregister the hook on memory allocators */ 10297db96d56Sopenharmony_ci#ifdef TRACE_RAW_MALLOC 10307db96d56Sopenharmony_ci PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw); 10317db96d56Sopenharmony_ci#endif 10327db96d56Sopenharmony_ci PyMem_SetAllocator(PYMEM_DOMAIN_MEM, &allocators.mem); 10337db96d56Sopenharmony_ci PyMem_SetAllocator(PYMEM_DOMAIN_OBJ, &allocators.obj); 10347db96d56Sopenharmony_ci 10357db96d56Sopenharmony_ci tracemalloc_clear_traces(); 10367db96d56Sopenharmony_ci 10377db96d56Sopenharmony_ci /* release memory */ 10387db96d56Sopenharmony_ci raw_free(tracemalloc_traceback); 10397db96d56Sopenharmony_ci tracemalloc_traceback = NULL; 10407db96d56Sopenharmony_ci} 10417db96d56Sopenharmony_ci 10427db96d56Sopenharmony_ci 10437db96d56Sopenharmony_ci 10447db96d56Sopenharmony_ci/*[clinic input] 10457db96d56Sopenharmony_ci_tracemalloc.is_tracing 10467db96d56Sopenharmony_ci 10477db96d56Sopenharmony_ciReturn True if the tracemalloc module is tracing Python memory allocations. 10487db96d56Sopenharmony_ci[clinic start generated code]*/ 10497db96d56Sopenharmony_ci 10507db96d56Sopenharmony_cistatic PyObject * 10517db96d56Sopenharmony_ci_tracemalloc_is_tracing_impl(PyObject *module) 10527db96d56Sopenharmony_ci/*[clinic end generated code: output=2d763b42601cd3ef input=af104b0a00192f63]*/ 10537db96d56Sopenharmony_ci{ 10547db96d56Sopenharmony_ci return PyBool_FromLong(_Py_tracemalloc_config.tracing); 10557db96d56Sopenharmony_ci} 10567db96d56Sopenharmony_ci 10577db96d56Sopenharmony_ci 10587db96d56Sopenharmony_ci/*[clinic input] 10597db96d56Sopenharmony_ci_tracemalloc.clear_traces 10607db96d56Sopenharmony_ci 10617db96d56Sopenharmony_ciClear traces of memory blocks allocated by Python. 10627db96d56Sopenharmony_ci[clinic start generated code]*/ 10637db96d56Sopenharmony_ci 10647db96d56Sopenharmony_cistatic PyObject * 10657db96d56Sopenharmony_ci_tracemalloc_clear_traces_impl(PyObject *module) 10667db96d56Sopenharmony_ci/*[clinic end generated code: output=a86080ee41b84197 input=0dab5b6c785183a5]*/ 10677db96d56Sopenharmony_ci{ 10687db96d56Sopenharmony_ci if (!_Py_tracemalloc_config.tracing) 10697db96d56Sopenharmony_ci Py_RETURN_NONE; 10707db96d56Sopenharmony_ci 10717db96d56Sopenharmony_ci set_reentrant(1); 10727db96d56Sopenharmony_ci tracemalloc_clear_traces(); 10737db96d56Sopenharmony_ci set_reentrant(0); 10747db96d56Sopenharmony_ci 10757db96d56Sopenharmony_ci Py_RETURN_NONE; 10767db96d56Sopenharmony_ci} 10777db96d56Sopenharmony_ci 10787db96d56Sopenharmony_ci 10797db96d56Sopenharmony_cistatic PyObject* 10807db96d56Sopenharmony_ciframe_to_pyobject(frame_t *frame) 10817db96d56Sopenharmony_ci{ 10827db96d56Sopenharmony_ci PyObject *frame_obj, *lineno_obj; 10837db96d56Sopenharmony_ci 10847db96d56Sopenharmony_ci frame_obj = PyTuple_New(2); 10857db96d56Sopenharmony_ci if (frame_obj == NULL) 10867db96d56Sopenharmony_ci return NULL; 10877db96d56Sopenharmony_ci 10887db96d56Sopenharmony_ci Py_INCREF(frame->filename); 10897db96d56Sopenharmony_ci PyTuple_SET_ITEM(frame_obj, 0, frame->filename); 10907db96d56Sopenharmony_ci 10917db96d56Sopenharmony_ci lineno_obj = PyLong_FromUnsignedLong(frame->lineno); 10927db96d56Sopenharmony_ci if (lineno_obj == NULL) { 10937db96d56Sopenharmony_ci Py_DECREF(frame_obj); 10947db96d56Sopenharmony_ci return NULL; 10957db96d56Sopenharmony_ci } 10967db96d56Sopenharmony_ci PyTuple_SET_ITEM(frame_obj, 1, lineno_obj); 10977db96d56Sopenharmony_ci 10987db96d56Sopenharmony_ci return frame_obj; 10997db96d56Sopenharmony_ci} 11007db96d56Sopenharmony_ci 11017db96d56Sopenharmony_ci 11027db96d56Sopenharmony_cistatic PyObject* 11037db96d56Sopenharmony_citraceback_to_pyobject(traceback_t *traceback, _Py_hashtable_t *intern_table) 11047db96d56Sopenharmony_ci{ 11057db96d56Sopenharmony_ci PyObject *frames; 11067db96d56Sopenharmony_ci 11077db96d56Sopenharmony_ci if (intern_table != NULL) { 11087db96d56Sopenharmony_ci frames = _Py_hashtable_get(intern_table, (const void *)traceback); 11097db96d56Sopenharmony_ci if (frames) { 11107db96d56Sopenharmony_ci Py_INCREF(frames); 11117db96d56Sopenharmony_ci return frames; 11127db96d56Sopenharmony_ci } 11137db96d56Sopenharmony_ci } 11147db96d56Sopenharmony_ci 11157db96d56Sopenharmony_ci frames = PyTuple_New(traceback->nframe); 11167db96d56Sopenharmony_ci if (frames == NULL) 11177db96d56Sopenharmony_ci return NULL; 11187db96d56Sopenharmony_ci 11197db96d56Sopenharmony_ci for (int i=0; i < traceback->nframe; i++) { 11207db96d56Sopenharmony_ci PyObject *frame = frame_to_pyobject(&traceback->frames[i]); 11217db96d56Sopenharmony_ci if (frame == NULL) { 11227db96d56Sopenharmony_ci Py_DECREF(frames); 11237db96d56Sopenharmony_ci return NULL; 11247db96d56Sopenharmony_ci } 11257db96d56Sopenharmony_ci PyTuple_SET_ITEM(frames, i, frame); 11267db96d56Sopenharmony_ci } 11277db96d56Sopenharmony_ci 11287db96d56Sopenharmony_ci if (intern_table != NULL) { 11297db96d56Sopenharmony_ci if (_Py_hashtable_set(intern_table, traceback, frames) < 0) { 11307db96d56Sopenharmony_ci Py_DECREF(frames); 11317db96d56Sopenharmony_ci PyErr_NoMemory(); 11327db96d56Sopenharmony_ci return NULL; 11337db96d56Sopenharmony_ci } 11347db96d56Sopenharmony_ci /* intern_table keeps a new reference to frames */ 11357db96d56Sopenharmony_ci Py_INCREF(frames); 11367db96d56Sopenharmony_ci } 11377db96d56Sopenharmony_ci return frames; 11387db96d56Sopenharmony_ci} 11397db96d56Sopenharmony_ci 11407db96d56Sopenharmony_ci 11417db96d56Sopenharmony_cistatic PyObject* 11427db96d56Sopenharmony_citrace_to_pyobject(unsigned int domain, const trace_t *trace, 11437db96d56Sopenharmony_ci _Py_hashtable_t *intern_tracebacks) 11447db96d56Sopenharmony_ci{ 11457db96d56Sopenharmony_ci PyObject *trace_obj = NULL; 11467db96d56Sopenharmony_ci PyObject *obj; 11477db96d56Sopenharmony_ci 11487db96d56Sopenharmony_ci trace_obj = PyTuple_New(4); 11497db96d56Sopenharmony_ci if (trace_obj == NULL) 11507db96d56Sopenharmony_ci return NULL; 11517db96d56Sopenharmony_ci 11527db96d56Sopenharmony_ci obj = PyLong_FromSize_t(domain); 11537db96d56Sopenharmony_ci if (obj == NULL) { 11547db96d56Sopenharmony_ci Py_DECREF(trace_obj); 11557db96d56Sopenharmony_ci return NULL; 11567db96d56Sopenharmony_ci } 11577db96d56Sopenharmony_ci PyTuple_SET_ITEM(trace_obj, 0, obj); 11587db96d56Sopenharmony_ci 11597db96d56Sopenharmony_ci obj = PyLong_FromSize_t(trace->size); 11607db96d56Sopenharmony_ci if (obj == NULL) { 11617db96d56Sopenharmony_ci Py_DECREF(trace_obj); 11627db96d56Sopenharmony_ci return NULL; 11637db96d56Sopenharmony_ci } 11647db96d56Sopenharmony_ci PyTuple_SET_ITEM(trace_obj, 1, obj); 11657db96d56Sopenharmony_ci 11667db96d56Sopenharmony_ci obj = traceback_to_pyobject(trace->traceback, intern_tracebacks); 11677db96d56Sopenharmony_ci if (obj == NULL) { 11687db96d56Sopenharmony_ci Py_DECREF(trace_obj); 11697db96d56Sopenharmony_ci return NULL; 11707db96d56Sopenharmony_ci } 11717db96d56Sopenharmony_ci PyTuple_SET_ITEM(trace_obj, 2, obj); 11727db96d56Sopenharmony_ci 11737db96d56Sopenharmony_ci obj = PyLong_FromUnsignedLong(trace->traceback->total_nframe); 11747db96d56Sopenharmony_ci if (obj == NULL) { 11757db96d56Sopenharmony_ci Py_DECREF(trace_obj); 11767db96d56Sopenharmony_ci return NULL; 11777db96d56Sopenharmony_ci } 11787db96d56Sopenharmony_ci PyTuple_SET_ITEM(trace_obj, 3, obj); 11797db96d56Sopenharmony_ci 11807db96d56Sopenharmony_ci return trace_obj; 11817db96d56Sopenharmony_ci} 11827db96d56Sopenharmony_ci 11837db96d56Sopenharmony_ci 11847db96d56Sopenharmony_citypedef struct { 11857db96d56Sopenharmony_ci _Py_hashtable_t *traces; 11867db96d56Sopenharmony_ci _Py_hashtable_t *domains; 11877db96d56Sopenharmony_ci _Py_hashtable_t *tracebacks; 11887db96d56Sopenharmony_ci PyObject *list; 11897db96d56Sopenharmony_ci unsigned int domain; 11907db96d56Sopenharmony_ci} get_traces_t; 11917db96d56Sopenharmony_ci 11927db96d56Sopenharmony_ci 11937db96d56Sopenharmony_cistatic int 11947db96d56Sopenharmony_citracemalloc_copy_trace(_Py_hashtable_t *traces, 11957db96d56Sopenharmony_ci const void *key, const void *value, 11967db96d56Sopenharmony_ci void *user_data) 11977db96d56Sopenharmony_ci{ 11987db96d56Sopenharmony_ci _Py_hashtable_t *traces2 = (_Py_hashtable_t *)user_data; 11997db96d56Sopenharmony_ci 12007db96d56Sopenharmony_ci trace_t *trace = (trace_t *)value; 12017db96d56Sopenharmony_ci 12027db96d56Sopenharmony_ci trace_t *trace2 = raw_malloc(sizeof(trace_t)); 12037db96d56Sopenharmony_ci if (trace2 == NULL) { 12047db96d56Sopenharmony_ci return -1; 12057db96d56Sopenharmony_ci } 12067db96d56Sopenharmony_ci *trace2 = *trace; 12077db96d56Sopenharmony_ci if (_Py_hashtable_set(traces2, key, trace2) < 0) { 12087db96d56Sopenharmony_ci raw_free(trace2); 12097db96d56Sopenharmony_ci return -1; 12107db96d56Sopenharmony_ci } 12117db96d56Sopenharmony_ci return 0; 12127db96d56Sopenharmony_ci} 12137db96d56Sopenharmony_ci 12147db96d56Sopenharmony_ci 12157db96d56Sopenharmony_cistatic _Py_hashtable_t* 12167db96d56Sopenharmony_citracemalloc_copy_traces(_Py_hashtable_t *traces) 12177db96d56Sopenharmony_ci{ 12187db96d56Sopenharmony_ci _Py_hashtable_t *traces2 = tracemalloc_create_traces_table(); 12197db96d56Sopenharmony_ci if (traces2 == NULL) { 12207db96d56Sopenharmony_ci return NULL; 12217db96d56Sopenharmony_ci } 12227db96d56Sopenharmony_ci 12237db96d56Sopenharmony_ci int err = _Py_hashtable_foreach(traces, 12247db96d56Sopenharmony_ci tracemalloc_copy_trace, 12257db96d56Sopenharmony_ci traces2); 12267db96d56Sopenharmony_ci if (err) { 12277db96d56Sopenharmony_ci _Py_hashtable_destroy(traces2); 12287db96d56Sopenharmony_ci return NULL; 12297db96d56Sopenharmony_ci } 12307db96d56Sopenharmony_ci return traces2; 12317db96d56Sopenharmony_ci} 12327db96d56Sopenharmony_ci 12337db96d56Sopenharmony_ci 12347db96d56Sopenharmony_cistatic int 12357db96d56Sopenharmony_citracemalloc_copy_domain(_Py_hashtable_t *domains, 12367db96d56Sopenharmony_ci const void *key, const void *value, 12377db96d56Sopenharmony_ci void *user_data) 12387db96d56Sopenharmony_ci{ 12397db96d56Sopenharmony_ci _Py_hashtable_t *domains2 = (_Py_hashtable_t *)user_data; 12407db96d56Sopenharmony_ci 12417db96d56Sopenharmony_ci unsigned int domain = (unsigned int)FROM_PTR(key); 12427db96d56Sopenharmony_ci _Py_hashtable_t *traces = (_Py_hashtable_t *)value; 12437db96d56Sopenharmony_ci 12447db96d56Sopenharmony_ci _Py_hashtable_t *traces2 = tracemalloc_copy_traces(traces); 12457db96d56Sopenharmony_ci if (traces2 == NULL) { 12467db96d56Sopenharmony_ci return -1; 12477db96d56Sopenharmony_ci } 12487db96d56Sopenharmony_ci if (_Py_hashtable_set(domains2, TO_PTR(domain), traces2) < 0) { 12497db96d56Sopenharmony_ci _Py_hashtable_destroy(traces2); 12507db96d56Sopenharmony_ci return -1; 12517db96d56Sopenharmony_ci } 12527db96d56Sopenharmony_ci return 0; 12537db96d56Sopenharmony_ci} 12547db96d56Sopenharmony_ci 12557db96d56Sopenharmony_ci 12567db96d56Sopenharmony_cistatic _Py_hashtable_t* 12577db96d56Sopenharmony_citracemalloc_copy_domains(_Py_hashtable_t *domains) 12587db96d56Sopenharmony_ci{ 12597db96d56Sopenharmony_ci _Py_hashtable_t *domains2 = tracemalloc_create_domains_table(); 12607db96d56Sopenharmony_ci if (domains2 == NULL) { 12617db96d56Sopenharmony_ci return NULL; 12627db96d56Sopenharmony_ci } 12637db96d56Sopenharmony_ci 12647db96d56Sopenharmony_ci int err = _Py_hashtable_foreach(domains, 12657db96d56Sopenharmony_ci tracemalloc_copy_domain, 12667db96d56Sopenharmony_ci domains2); 12677db96d56Sopenharmony_ci if (err) { 12687db96d56Sopenharmony_ci _Py_hashtable_destroy(domains2); 12697db96d56Sopenharmony_ci return NULL; 12707db96d56Sopenharmony_ci } 12717db96d56Sopenharmony_ci return domains2; 12727db96d56Sopenharmony_ci} 12737db96d56Sopenharmony_ci 12747db96d56Sopenharmony_ci 12757db96d56Sopenharmony_cistatic int 12767db96d56Sopenharmony_citracemalloc_get_traces_fill(_Py_hashtable_t *traces, 12777db96d56Sopenharmony_ci const void *key, const void *value, 12787db96d56Sopenharmony_ci void *user_data) 12797db96d56Sopenharmony_ci{ 12807db96d56Sopenharmony_ci get_traces_t *get_traces = user_data; 12817db96d56Sopenharmony_ci 12827db96d56Sopenharmony_ci const trace_t *trace = (const trace_t *)value; 12837db96d56Sopenharmony_ci 12847db96d56Sopenharmony_ci PyObject *tuple = trace_to_pyobject(get_traces->domain, trace, 12857db96d56Sopenharmony_ci get_traces->tracebacks); 12867db96d56Sopenharmony_ci if (tuple == NULL) { 12877db96d56Sopenharmony_ci return 1; 12887db96d56Sopenharmony_ci } 12897db96d56Sopenharmony_ci 12907db96d56Sopenharmony_ci int res = PyList_Append(get_traces->list, tuple); 12917db96d56Sopenharmony_ci Py_DECREF(tuple); 12927db96d56Sopenharmony_ci if (res < 0) { 12937db96d56Sopenharmony_ci return 1; 12947db96d56Sopenharmony_ci } 12957db96d56Sopenharmony_ci 12967db96d56Sopenharmony_ci return 0; 12977db96d56Sopenharmony_ci} 12987db96d56Sopenharmony_ci 12997db96d56Sopenharmony_ci 13007db96d56Sopenharmony_cistatic int 13017db96d56Sopenharmony_citracemalloc_get_traces_domain(_Py_hashtable_t *domains, 13027db96d56Sopenharmony_ci const void *key, const void *value, 13037db96d56Sopenharmony_ci void *user_data) 13047db96d56Sopenharmony_ci{ 13057db96d56Sopenharmony_ci get_traces_t *get_traces = user_data; 13067db96d56Sopenharmony_ci 13077db96d56Sopenharmony_ci unsigned int domain = (unsigned int)FROM_PTR(key); 13087db96d56Sopenharmony_ci _Py_hashtable_t *traces = (_Py_hashtable_t *)value; 13097db96d56Sopenharmony_ci 13107db96d56Sopenharmony_ci get_traces->domain = domain; 13117db96d56Sopenharmony_ci return _Py_hashtable_foreach(traces, 13127db96d56Sopenharmony_ci tracemalloc_get_traces_fill, 13137db96d56Sopenharmony_ci get_traces); 13147db96d56Sopenharmony_ci} 13157db96d56Sopenharmony_ci 13167db96d56Sopenharmony_ci 13177db96d56Sopenharmony_cistatic void 13187db96d56Sopenharmony_citracemalloc_pyobject_decref(void *value) 13197db96d56Sopenharmony_ci{ 13207db96d56Sopenharmony_ci PyObject *obj = (PyObject *)value; 13217db96d56Sopenharmony_ci Py_DECREF(obj); 13227db96d56Sopenharmony_ci} 13237db96d56Sopenharmony_ci 13247db96d56Sopenharmony_ci 13257db96d56Sopenharmony_ci 13267db96d56Sopenharmony_ci/*[clinic input] 13277db96d56Sopenharmony_ci_tracemalloc._get_traces 13287db96d56Sopenharmony_ci 13297db96d56Sopenharmony_ciGet traces of all memory blocks allocated by Python. 13307db96d56Sopenharmony_ci 13317db96d56Sopenharmony_ciReturn a list of (size: int, traceback: tuple) tuples. 13327db96d56Sopenharmony_citraceback is a tuple of (filename: str, lineno: int) tuples. 13337db96d56Sopenharmony_ci 13347db96d56Sopenharmony_ciReturn an empty list if the tracemalloc module is disabled. 13357db96d56Sopenharmony_ci[clinic start generated code]*/ 13367db96d56Sopenharmony_ci 13377db96d56Sopenharmony_cistatic PyObject * 13387db96d56Sopenharmony_ci_tracemalloc__get_traces_impl(PyObject *module) 13397db96d56Sopenharmony_ci/*[clinic end generated code: output=e9929876ced4b5cc input=6c7d2230b24255aa]*/ 13407db96d56Sopenharmony_ci{ 13417db96d56Sopenharmony_ci get_traces_t get_traces; 13427db96d56Sopenharmony_ci get_traces.domain = DEFAULT_DOMAIN; 13437db96d56Sopenharmony_ci get_traces.traces = NULL; 13447db96d56Sopenharmony_ci get_traces.domains = NULL; 13457db96d56Sopenharmony_ci get_traces.tracebacks = NULL; 13467db96d56Sopenharmony_ci get_traces.list = PyList_New(0); 13477db96d56Sopenharmony_ci if (get_traces.list == NULL) 13487db96d56Sopenharmony_ci goto error; 13497db96d56Sopenharmony_ci 13507db96d56Sopenharmony_ci if (!_Py_tracemalloc_config.tracing) 13517db96d56Sopenharmony_ci return get_traces.list; 13527db96d56Sopenharmony_ci 13537db96d56Sopenharmony_ci /* the traceback hash table is used temporarily to intern traceback tuple 13547db96d56Sopenharmony_ci of (filename, lineno) tuples */ 13557db96d56Sopenharmony_ci get_traces.tracebacks = hashtable_new(_Py_hashtable_hash_ptr, 13567db96d56Sopenharmony_ci _Py_hashtable_compare_direct, 13577db96d56Sopenharmony_ci NULL, tracemalloc_pyobject_decref); 13587db96d56Sopenharmony_ci if (get_traces.tracebacks == NULL) { 13597db96d56Sopenharmony_ci goto no_memory; 13607db96d56Sopenharmony_ci } 13617db96d56Sopenharmony_ci 13627db96d56Sopenharmony_ci // Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable 13637db96d56Sopenharmony_ci // temporarily tracemalloc which would impact other threads and so would 13647db96d56Sopenharmony_ci // miss allocations while get_traces() is called. 13657db96d56Sopenharmony_ci TABLES_LOCK(); 13667db96d56Sopenharmony_ci get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces); 13677db96d56Sopenharmony_ci TABLES_UNLOCK(); 13687db96d56Sopenharmony_ci 13697db96d56Sopenharmony_ci if (get_traces.traces == NULL) { 13707db96d56Sopenharmony_ci goto no_memory; 13717db96d56Sopenharmony_ci } 13727db96d56Sopenharmony_ci 13737db96d56Sopenharmony_ci TABLES_LOCK(); 13747db96d56Sopenharmony_ci get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains); 13757db96d56Sopenharmony_ci TABLES_UNLOCK(); 13767db96d56Sopenharmony_ci 13777db96d56Sopenharmony_ci if (get_traces.domains == NULL) { 13787db96d56Sopenharmony_ci goto no_memory; 13797db96d56Sopenharmony_ci } 13807db96d56Sopenharmony_ci 13817db96d56Sopenharmony_ci // Convert traces to a list of tuples 13827db96d56Sopenharmony_ci set_reentrant(1); 13837db96d56Sopenharmony_ci int err = _Py_hashtable_foreach(get_traces.traces, 13847db96d56Sopenharmony_ci tracemalloc_get_traces_fill, 13857db96d56Sopenharmony_ci &get_traces); 13867db96d56Sopenharmony_ci if (!err) { 13877db96d56Sopenharmony_ci err = _Py_hashtable_foreach(get_traces.domains, 13887db96d56Sopenharmony_ci tracemalloc_get_traces_domain, 13897db96d56Sopenharmony_ci &get_traces); 13907db96d56Sopenharmony_ci } 13917db96d56Sopenharmony_ci set_reentrant(0); 13927db96d56Sopenharmony_ci if (err) { 13937db96d56Sopenharmony_ci goto error; 13947db96d56Sopenharmony_ci } 13957db96d56Sopenharmony_ci 13967db96d56Sopenharmony_ci goto finally; 13977db96d56Sopenharmony_ci 13987db96d56Sopenharmony_cino_memory: 13997db96d56Sopenharmony_ci PyErr_NoMemory(); 14007db96d56Sopenharmony_ci 14017db96d56Sopenharmony_cierror: 14027db96d56Sopenharmony_ci Py_CLEAR(get_traces.list); 14037db96d56Sopenharmony_ci 14047db96d56Sopenharmony_cifinally: 14057db96d56Sopenharmony_ci if (get_traces.tracebacks != NULL) { 14067db96d56Sopenharmony_ci _Py_hashtable_destroy(get_traces.tracebacks); 14077db96d56Sopenharmony_ci } 14087db96d56Sopenharmony_ci if (get_traces.traces != NULL) { 14097db96d56Sopenharmony_ci _Py_hashtable_destroy(get_traces.traces); 14107db96d56Sopenharmony_ci } 14117db96d56Sopenharmony_ci if (get_traces.domains != NULL) { 14127db96d56Sopenharmony_ci _Py_hashtable_destroy(get_traces.domains); 14137db96d56Sopenharmony_ci } 14147db96d56Sopenharmony_ci 14157db96d56Sopenharmony_ci return get_traces.list; 14167db96d56Sopenharmony_ci} 14177db96d56Sopenharmony_ci 14187db96d56Sopenharmony_ci 14197db96d56Sopenharmony_cistatic traceback_t* 14207db96d56Sopenharmony_citracemalloc_get_traceback(unsigned int domain, uintptr_t ptr) 14217db96d56Sopenharmony_ci{ 14227db96d56Sopenharmony_ci 14237db96d56Sopenharmony_ci if (!_Py_tracemalloc_config.tracing) 14247db96d56Sopenharmony_ci return NULL; 14257db96d56Sopenharmony_ci 14267db96d56Sopenharmony_ci trace_t *trace; 14277db96d56Sopenharmony_ci TABLES_LOCK(); 14287db96d56Sopenharmony_ci _Py_hashtable_t *traces = tracemalloc_get_traces_table(domain); 14297db96d56Sopenharmony_ci if (traces) { 14307db96d56Sopenharmony_ci trace = _Py_hashtable_get(traces, TO_PTR(ptr)); 14317db96d56Sopenharmony_ci } 14327db96d56Sopenharmony_ci else { 14337db96d56Sopenharmony_ci trace = NULL; 14347db96d56Sopenharmony_ci } 14357db96d56Sopenharmony_ci TABLES_UNLOCK(); 14367db96d56Sopenharmony_ci 14377db96d56Sopenharmony_ci if (!trace) { 14387db96d56Sopenharmony_ci return NULL; 14397db96d56Sopenharmony_ci } 14407db96d56Sopenharmony_ci 14417db96d56Sopenharmony_ci return trace->traceback; 14427db96d56Sopenharmony_ci} 14437db96d56Sopenharmony_ci 14447db96d56Sopenharmony_ci 14457db96d56Sopenharmony_ci 14467db96d56Sopenharmony_ci/*[clinic input] 14477db96d56Sopenharmony_ci_tracemalloc._get_object_traceback 14487db96d56Sopenharmony_ci 14497db96d56Sopenharmony_ci obj: object 14507db96d56Sopenharmony_ci / 14517db96d56Sopenharmony_ci 14527db96d56Sopenharmony_ciGet the traceback where the Python object obj was allocated. 14537db96d56Sopenharmony_ci 14547db96d56Sopenharmony_ciReturn a tuple of (filename: str, lineno: int) tuples. 14557db96d56Sopenharmony_ciReturn None if the tracemalloc module is disabled or did not 14567db96d56Sopenharmony_citrace the allocation of the object. 14577db96d56Sopenharmony_ci[clinic start generated code]*/ 14587db96d56Sopenharmony_ci 14597db96d56Sopenharmony_cistatic PyObject * 14607db96d56Sopenharmony_ci_tracemalloc__get_object_traceback(PyObject *module, PyObject *obj) 14617db96d56Sopenharmony_ci/*[clinic end generated code: output=41ee0553a658b0aa input=29495f1b21c53212]*/ 14627db96d56Sopenharmony_ci{ 14637db96d56Sopenharmony_ci PyTypeObject *type; 14647db96d56Sopenharmony_ci void *ptr; 14657db96d56Sopenharmony_ci traceback_t *traceback; 14667db96d56Sopenharmony_ci 14677db96d56Sopenharmony_ci type = Py_TYPE(obj); 14687db96d56Sopenharmony_ci if (PyType_IS_GC(type)) { 14697db96d56Sopenharmony_ci ptr = (void *)((char *)obj - sizeof(PyGC_Head)); 14707db96d56Sopenharmony_ci } 14717db96d56Sopenharmony_ci else { 14727db96d56Sopenharmony_ci ptr = (void *)obj; 14737db96d56Sopenharmony_ci } 14747db96d56Sopenharmony_ci 14757db96d56Sopenharmony_ci traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr); 14767db96d56Sopenharmony_ci if (traceback == NULL) 14777db96d56Sopenharmony_ci Py_RETURN_NONE; 14787db96d56Sopenharmony_ci 14797db96d56Sopenharmony_ci return traceback_to_pyobject(traceback, NULL); 14807db96d56Sopenharmony_ci} 14817db96d56Sopenharmony_ci 14827db96d56Sopenharmony_ci 14837db96d56Sopenharmony_ci#define PUTS(fd, str) _Py_write_noraise(fd, str, (int)strlen(str)) 14847db96d56Sopenharmony_ci 14857db96d56Sopenharmony_cistatic void 14867db96d56Sopenharmony_ci_PyMem_DumpFrame(int fd, frame_t * frame) 14877db96d56Sopenharmony_ci{ 14887db96d56Sopenharmony_ci PUTS(fd, " File \""); 14897db96d56Sopenharmony_ci _Py_DumpASCII(fd, frame->filename); 14907db96d56Sopenharmony_ci PUTS(fd, "\", line "); 14917db96d56Sopenharmony_ci _Py_DumpDecimal(fd, frame->lineno); 14927db96d56Sopenharmony_ci PUTS(fd, "\n"); 14937db96d56Sopenharmony_ci} 14947db96d56Sopenharmony_ci 14957db96d56Sopenharmony_ci/* Dump the traceback where a memory block was allocated into file descriptor 14967db96d56Sopenharmony_ci fd. The function may block on TABLES_LOCK() but it is unlikely. */ 14977db96d56Sopenharmony_civoid 14987db96d56Sopenharmony_ci_PyMem_DumpTraceback(int fd, const void *ptr) 14997db96d56Sopenharmony_ci{ 15007db96d56Sopenharmony_ci traceback_t *traceback; 15017db96d56Sopenharmony_ci int i; 15027db96d56Sopenharmony_ci 15037db96d56Sopenharmony_ci if (!_Py_tracemalloc_config.tracing) { 15047db96d56Sopenharmony_ci PUTS(fd, "Enable tracemalloc to get the memory block " 15057db96d56Sopenharmony_ci "allocation traceback\n\n"); 15067db96d56Sopenharmony_ci return; 15077db96d56Sopenharmony_ci } 15087db96d56Sopenharmony_ci 15097db96d56Sopenharmony_ci traceback = tracemalloc_get_traceback(DEFAULT_DOMAIN, (uintptr_t)ptr); 15107db96d56Sopenharmony_ci if (traceback == NULL) 15117db96d56Sopenharmony_ci return; 15127db96d56Sopenharmony_ci 15137db96d56Sopenharmony_ci PUTS(fd, "Memory block allocated at (most recent call first):\n"); 15147db96d56Sopenharmony_ci for (i=0; i < traceback->nframe; i++) { 15157db96d56Sopenharmony_ci _PyMem_DumpFrame(fd, &traceback->frames[i]); 15167db96d56Sopenharmony_ci } 15177db96d56Sopenharmony_ci PUTS(fd, "\n"); 15187db96d56Sopenharmony_ci} 15197db96d56Sopenharmony_ci 15207db96d56Sopenharmony_ci#undef PUTS 15217db96d56Sopenharmony_ci 15227db96d56Sopenharmony_ci 15237db96d56Sopenharmony_ci 15247db96d56Sopenharmony_ci/*[clinic input] 15257db96d56Sopenharmony_ci_tracemalloc.start 15267db96d56Sopenharmony_ci 15277db96d56Sopenharmony_ci nframe: int = 1 15287db96d56Sopenharmony_ci / 15297db96d56Sopenharmony_ci 15307db96d56Sopenharmony_ciStart tracing Python memory allocations. 15317db96d56Sopenharmony_ci 15327db96d56Sopenharmony_ciAlso set the maximum number of frames stored in the traceback of a 15337db96d56Sopenharmony_citrace to nframe. 15347db96d56Sopenharmony_ci[clinic start generated code]*/ 15357db96d56Sopenharmony_ci 15367db96d56Sopenharmony_cistatic PyObject * 15377db96d56Sopenharmony_ci_tracemalloc_start_impl(PyObject *module, int nframe) 15387db96d56Sopenharmony_ci/*[clinic end generated code: output=caae05c23c159d3c input=40d849b5b29d1933]*/ 15397db96d56Sopenharmony_ci{ 15407db96d56Sopenharmony_ci if (tracemalloc_start(nframe) < 0) { 15417db96d56Sopenharmony_ci return NULL; 15427db96d56Sopenharmony_ci } 15437db96d56Sopenharmony_ci Py_RETURN_NONE; 15447db96d56Sopenharmony_ci} 15457db96d56Sopenharmony_ci 15467db96d56Sopenharmony_ci 15477db96d56Sopenharmony_ci/*[clinic input] 15487db96d56Sopenharmony_ci_tracemalloc.stop 15497db96d56Sopenharmony_ci 15507db96d56Sopenharmony_ciStop tracing Python memory allocations. 15517db96d56Sopenharmony_ci 15527db96d56Sopenharmony_ciAlso clear traces of memory blocks allocated by Python. 15537db96d56Sopenharmony_ci[clinic start generated code]*/ 15547db96d56Sopenharmony_ci 15557db96d56Sopenharmony_cistatic PyObject * 15567db96d56Sopenharmony_ci_tracemalloc_stop_impl(PyObject *module) 15577db96d56Sopenharmony_ci/*[clinic end generated code: output=c3c42ae03e3955cd input=7478f075e51dae18]*/ 15587db96d56Sopenharmony_ci{ 15597db96d56Sopenharmony_ci tracemalloc_stop(); 15607db96d56Sopenharmony_ci Py_RETURN_NONE; 15617db96d56Sopenharmony_ci} 15627db96d56Sopenharmony_ci 15637db96d56Sopenharmony_ci 15647db96d56Sopenharmony_ci/*[clinic input] 15657db96d56Sopenharmony_ci_tracemalloc.get_traceback_limit 15667db96d56Sopenharmony_ci 15677db96d56Sopenharmony_ciGet the maximum number of frames stored in the traceback of a trace. 15687db96d56Sopenharmony_ci 15697db96d56Sopenharmony_ciBy default, a trace of an allocated memory block only stores 15707db96d56Sopenharmony_cithe most recent frame: the limit is 1. 15717db96d56Sopenharmony_ci[clinic start generated code]*/ 15727db96d56Sopenharmony_ci 15737db96d56Sopenharmony_cistatic PyObject * 15747db96d56Sopenharmony_ci_tracemalloc_get_traceback_limit_impl(PyObject *module) 15757db96d56Sopenharmony_ci/*[clinic end generated code: output=d556d9306ba95567 input=da3cd977fc68ae3b]*/ 15767db96d56Sopenharmony_ci{ 15777db96d56Sopenharmony_ci return PyLong_FromLong(_Py_tracemalloc_config.max_nframe); 15787db96d56Sopenharmony_ci} 15797db96d56Sopenharmony_ci 15807db96d56Sopenharmony_ci 15817db96d56Sopenharmony_cistatic int 15827db96d56Sopenharmony_citracemalloc_get_tracemalloc_memory_cb(_Py_hashtable_t *domains, 15837db96d56Sopenharmony_ci const void *key, const void *value, 15847db96d56Sopenharmony_ci void *user_data) 15857db96d56Sopenharmony_ci{ 15867db96d56Sopenharmony_ci const _Py_hashtable_t *traces = value; 15877db96d56Sopenharmony_ci size_t *size = (size_t*)user_data; 15887db96d56Sopenharmony_ci *size += _Py_hashtable_size(traces); 15897db96d56Sopenharmony_ci return 0; 15907db96d56Sopenharmony_ci} 15917db96d56Sopenharmony_ci 15927db96d56Sopenharmony_ci 15937db96d56Sopenharmony_ci/*[clinic input] 15947db96d56Sopenharmony_ci_tracemalloc.get_tracemalloc_memory 15957db96d56Sopenharmony_ci 15967db96d56Sopenharmony_ciGet the memory usage in bytes of the tracemalloc module. 15977db96d56Sopenharmony_ci 15987db96d56Sopenharmony_ciThis memory is used internally to trace memory allocations. 15997db96d56Sopenharmony_ci[clinic start generated code]*/ 16007db96d56Sopenharmony_ci 16017db96d56Sopenharmony_cistatic PyObject * 16027db96d56Sopenharmony_ci_tracemalloc_get_tracemalloc_memory_impl(PyObject *module) 16037db96d56Sopenharmony_ci/*[clinic end generated code: output=e3f14e280a55f5aa input=5d919c0f4d5132ad]*/ 16047db96d56Sopenharmony_ci{ 16057db96d56Sopenharmony_ci size_t size; 16067db96d56Sopenharmony_ci 16077db96d56Sopenharmony_ci size = _Py_hashtable_size(tracemalloc_tracebacks); 16087db96d56Sopenharmony_ci size += _Py_hashtable_size(tracemalloc_filenames); 16097db96d56Sopenharmony_ci 16107db96d56Sopenharmony_ci TABLES_LOCK(); 16117db96d56Sopenharmony_ci size += _Py_hashtable_size(tracemalloc_traces); 16127db96d56Sopenharmony_ci _Py_hashtable_foreach(tracemalloc_domains, 16137db96d56Sopenharmony_ci tracemalloc_get_tracemalloc_memory_cb, &size); 16147db96d56Sopenharmony_ci TABLES_UNLOCK(); 16157db96d56Sopenharmony_ci 16167db96d56Sopenharmony_ci return PyLong_FromSize_t(size); 16177db96d56Sopenharmony_ci} 16187db96d56Sopenharmony_ci 16197db96d56Sopenharmony_ci 16207db96d56Sopenharmony_ci 16217db96d56Sopenharmony_ci/*[clinic input] 16227db96d56Sopenharmony_ci_tracemalloc.get_traced_memory 16237db96d56Sopenharmony_ci 16247db96d56Sopenharmony_ciGet the current size and peak size of memory blocks traced by tracemalloc. 16257db96d56Sopenharmony_ci 16267db96d56Sopenharmony_ciReturns a tuple: (current: int, peak: int). 16277db96d56Sopenharmony_ci[clinic start generated code]*/ 16287db96d56Sopenharmony_ci 16297db96d56Sopenharmony_cistatic PyObject * 16307db96d56Sopenharmony_ci_tracemalloc_get_traced_memory_impl(PyObject *module) 16317db96d56Sopenharmony_ci/*[clinic end generated code: output=5b167189adb9e782 input=61ddb5478400ff66]*/ 16327db96d56Sopenharmony_ci{ 16337db96d56Sopenharmony_ci Py_ssize_t size, peak_size; 16347db96d56Sopenharmony_ci 16357db96d56Sopenharmony_ci if (!_Py_tracemalloc_config.tracing) 16367db96d56Sopenharmony_ci return Py_BuildValue("ii", 0, 0); 16377db96d56Sopenharmony_ci 16387db96d56Sopenharmony_ci TABLES_LOCK(); 16397db96d56Sopenharmony_ci size = tracemalloc_traced_memory; 16407db96d56Sopenharmony_ci peak_size = tracemalloc_peak_traced_memory; 16417db96d56Sopenharmony_ci TABLES_UNLOCK(); 16427db96d56Sopenharmony_ci 16437db96d56Sopenharmony_ci return Py_BuildValue("nn", size, peak_size); 16447db96d56Sopenharmony_ci} 16457db96d56Sopenharmony_ci 16467db96d56Sopenharmony_ci/*[clinic input] 16477db96d56Sopenharmony_ci_tracemalloc.reset_peak 16487db96d56Sopenharmony_ci 16497db96d56Sopenharmony_ciSet the peak size of memory blocks traced by tracemalloc to the current size. 16507db96d56Sopenharmony_ci 16517db96d56Sopenharmony_ciDo nothing if the tracemalloc module is not tracing memory allocations. 16527db96d56Sopenharmony_ci 16537db96d56Sopenharmony_ci[clinic start generated code]*/ 16547db96d56Sopenharmony_ci 16557db96d56Sopenharmony_cistatic PyObject * 16567db96d56Sopenharmony_ci_tracemalloc_reset_peak_impl(PyObject *module) 16577db96d56Sopenharmony_ci/*[clinic end generated code: output=140c2870f691dbb2 input=18afd0635066e9ce]*/ 16587db96d56Sopenharmony_ci{ 16597db96d56Sopenharmony_ci if (!_Py_tracemalloc_config.tracing) { 16607db96d56Sopenharmony_ci Py_RETURN_NONE; 16617db96d56Sopenharmony_ci } 16627db96d56Sopenharmony_ci 16637db96d56Sopenharmony_ci TABLES_LOCK(); 16647db96d56Sopenharmony_ci tracemalloc_peak_traced_memory = tracemalloc_traced_memory; 16657db96d56Sopenharmony_ci TABLES_UNLOCK(); 16667db96d56Sopenharmony_ci 16677db96d56Sopenharmony_ci Py_RETURN_NONE; 16687db96d56Sopenharmony_ci} 16697db96d56Sopenharmony_ci 16707db96d56Sopenharmony_ci 16717db96d56Sopenharmony_cistatic PyMethodDef module_methods[] = { 16727db96d56Sopenharmony_ci _TRACEMALLOC_IS_TRACING_METHODDEF 16737db96d56Sopenharmony_ci _TRACEMALLOC_CLEAR_TRACES_METHODDEF 16747db96d56Sopenharmony_ci _TRACEMALLOC__GET_TRACES_METHODDEF 16757db96d56Sopenharmony_ci _TRACEMALLOC__GET_OBJECT_TRACEBACK_METHODDEF 16767db96d56Sopenharmony_ci _TRACEMALLOC_START_METHODDEF 16777db96d56Sopenharmony_ci _TRACEMALLOC_STOP_METHODDEF 16787db96d56Sopenharmony_ci _TRACEMALLOC_GET_TRACEBACK_LIMIT_METHODDEF 16797db96d56Sopenharmony_ci _TRACEMALLOC_GET_TRACEMALLOC_MEMORY_METHODDEF 16807db96d56Sopenharmony_ci _TRACEMALLOC_GET_TRACED_MEMORY_METHODDEF 16817db96d56Sopenharmony_ci _TRACEMALLOC_RESET_PEAK_METHODDEF 16827db96d56Sopenharmony_ci /* sentinel */ 16837db96d56Sopenharmony_ci {NULL, NULL} 16847db96d56Sopenharmony_ci}; 16857db96d56Sopenharmony_ci 16867db96d56Sopenharmony_ciPyDoc_STRVAR(module_doc, 16877db96d56Sopenharmony_ci"Debug module to trace memory blocks allocated by Python."); 16887db96d56Sopenharmony_ci 16897db96d56Sopenharmony_cistatic struct PyModuleDef module_def = { 16907db96d56Sopenharmony_ci PyModuleDef_HEAD_INIT, 16917db96d56Sopenharmony_ci "_tracemalloc", 16927db96d56Sopenharmony_ci module_doc, 16937db96d56Sopenharmony_ci 0, /* non-negative size to be able to unload the module */ 16947db96d56Sopenharmony_ci module_methods, 16957db96d56Sopenharmony_ci NULL, 16967db96d56Sopenharmony_ci}; 16977db96d56Sopenharmony_ci 16987db96d56Sopenharmony_ciPyMODINIT_FUNC 16997db96d56Sopenharmony_ciPyInit__tracemalloc(void) 17007db96d56Sopenharmony_ci{ 17017db96d56Sopenharmony_ci PyObject *m; 17027db96d56Sopenharmony_ci m = PyModule_Create(&module_def); 17037db96d56Sopenharmony_ci if (m == NULL) 17047db96d56Sopenharmony_ci return NULL; 17057db96d56Sopenharmony_ci 17067db96d56Sopenharmony_ci if (tracemalloc_init() < 0) { 17077db96d56Sopenharmony_ci Py_DECREF(m); 17087db96d56Sopenharmony_ci return NULL; 17097db96d56Sopenharmony_ci } 17107db96d56Sopenharmony_ci 17117db96d56Sopenharmony_ci return m; 17127db96d56Sopenharmony_ci} 17137db96d56Sopenharmony_ci 17147db96d56Sopenharmony_ci 17157db96d56Sopenharmony_ciint 17167db96d56Sopenharmony_ci_PyTraceMalloc_Init(int nframe) 17177db96d56Sopenharmony_ci{ 17187db96d56Sopenharmony_ci assert(PyGILState_Check()); 17197db96d56Sopenharmony_ci if (nframe == 0) { 17207db96d56Sopenharmony_ci return 0; 17217db96d56Sopenharmony_ci } 17227db96d56Sopenharmony_ci return tracemalloc_start(nframe); 17237db96d56Sopenharmony_ci} 17247db96d56Sopenharmony_ci 17257db96d56Sopenharmony_ci 17267db96d56Sopenharmony_civoid 17277db96d56Sopenharmony_ci_PyTraceMalloc_Fini(void) 17287db96d56Sopenharmony_ci{ 17297db96d56Sopenharmony_ci assert(PyGILState_Check()); 17307db96d56Sopenharmony_ci tracemalloc_deinit(); 17317db96d56Sopenharmony_ci} 17327db96d56Sopenharmony_ci 17337db96d56Sopenharmony_ciint 17347db96d56Sopenharmony_ciPyTraceMalloc_Track(unsigned int domain, uintptr_t ptr, 17357db96d56Sopenharmony_ci size_t size) 17367db96d56Sopenharmony_ci{ 17377db96d56Sopenharmony_ci int res; 17387db96d56Sopenharmony_ci PyGILState_STATE gil_state; 17397db96d56Sopenharmony_ci 17407db96d56Sopenharmony_ci if (!_Py_tracemalloc_config.tracing) { 17417db96d56Sopenharmony_ci /* tracemalloc is not tracing: do nothing */ 17427db96d56Sopenharmony_ci return -2; 17437db96d56Sopenharmony_ci } 17447db96d56Sopenharmony_ci 17457db96d56Sopenharmony_ci gil_state = PyGILState_Ensure(); 17467db96d56Sopenharmony_ci 17477db96d56Sopenharmony_ci TABLES_LOCK(); 17487db96d56Sopenharmony_ci res = tracemalloc_add_trace(domain, ptr, size); 17497db96d56Sopenharmony_ci TABLES_UNLOCK(); 17507db96d56Sopenharmony_ci 17517db96d56Sopenharmony_ci PyGILState_Release(gil_state); 17527db96d56Sopenharmony_ci return res; 17537db96d56Sopenharmony_ci} 17547db96d56Sopenharmony_ci 17557db96d56Sopenharmony_ci 17567db96d56Sopenharmony_ciint 17577db96d56Sopenharmony_ciPyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr) 17587db96d56Sopenharmony_ci{ 17597db96d56Sopenharmony_ci if (!_Py_tracemalloc_config.tracing) { 17607db96d56Sopenharmony_ci /* tracemalloc is not tracing: do nothing */ 17617db96d56Sopenharmony_ci return -2; 17627db96d56Sopenharmony_ci } 17637db96d56Sopenharmony_ci 17647db96d56Sopenharmony_ci TABLES_LOCK(); 17657db96d56Sopenharmony_ci tracemalloc_remove_trace(domain, ptr); 17667db96d56Sopenharmony_ci TABLES_UNLOCK(); 17677db96d56Sopenharmony_ci 17687db96d56Sopenharmony_ci return 0; 17697db96d56Sopenharmony_ci} 17707db96d56Sopenharmony_ci 17717db96d56Sopenharmony_ci 17727db96d56Sopenharmony_ci/* If the object memory block is already traced, update its trace 17737db96d56Sopenharmony_ci with the current Python traceback. 17747db96d56Sopenharmony_ci 17757db96d56Sopenharmony_ci Do nothing if tracemalloc is not tracing memory allocations 17767db96d56Sopenharmony_ci or if the object memory block is not already traced. */ 17777db96d56Sopenharmony_ciint 17787db96d56Sopenharmony_ci_PyTraceMalloc_NewReference(PyObject *op) 17797db96d56Sopenharmony_ci{ 17807db96d56Sopenharmony_ci assert(PyGILState_Check()); 17817db96d56Sopenharmony_ci 17827db96d56Sopenharmony_ci if (!_Py_tracemalloc_config.tracing) { 17837db96d56Sopenharmony_ci /* tracemalloc is not tracing: do nothing */ 17847db96d56Sopenharmony_ci return -1; 17857db96d56Sopenharmony_ci } 17867db96d56Sopenharmony_ci 17877db96d56Sopenharmony_ci uintptr_t ptr; 17887db96d56Sopenharmony_ci PyTypeObject *type = Py_TYPE(op); 17897db96d56Sopenharmony_ci if (PyType_IS_GC(type)) { 17907db96d56Sopenharmony_ci ptr = (uintptr_t)((char *)op - sizeof(PyGC_Head)); 17917db96d56Sopenharmony_ci } 17927db96d56Sopenharmony_ci else { 17937db96d56Sopenharmony_ci ptr = (uintptr_t)op; 17947db96d56Sopenharmony_ci } 17957db96d56Sopenharmony_ci 17967db96d56Sopenharmony_ci int res = -1; 17977db96d56Sopenharmony_ci 17987db96d56Sopenharmony_ci TABLES_LOCK(); 17997db96d56Sopenharmony_ci trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr)); 18007db96d56Sopenharmony_ci if (trace != NULL) { 18017db96d56Sopenharmony_ci /* update the traceback of the memory block */ 18027db96d56Sopenharmony_ci traceback_t *traceback = traceback_new(); 18037db96d56Sopenharmony_ci if (traceback != NULL) { 18047db96d56Sopenharmony_ci trace->traceback = traceback; 18057db96d56Sopenharmony_ci res = 0; 18067db96d56Sopenharmony_ci } 18077db96d56Sopenharmony_ci } 18087db96d56Sopenharmony_ci /* else: cannot track the object, its memory block size is unknown */ 18097db96d56Sopenharmony_ci TABLES_UNLOCK(); 18107db96d56Sopenharmony_ci 18117db96d56Sopenharmony_ci return res; 18127db96d56Sopenharmony_ci} 18137db96d56Sopenharmony_ci 18147db96d56Sopenharmony_ci 18157db96d56Sopenharmony_ciPyObject* 18167db96d56Sopenharmony_ci_PyTraceMalloc_GetTraceback(unsigned int domain, uintptr_t ptr) 18177db96d56Sopenharmony_ci{ 18187db96d56Sopenharmony_ci traceback_t *traceback; 18197db96d56Sopenharmony_ci 18207db96d56Sopenharmony_ci traceback = tracemalloc_get_traceback(domain, ptr); 18217db96d56Sopenharmony_ci if (traceback == NULL) 18227db96d56Sopenharmony_ci Py_RETURN_NONE; 18237db96d56Sopenharmony_ci 18247db96d56Sopenharmony_ci return traceback_to_pyobject(traceback, NULL); 18257db96d56Sopenharmony_ci} 1826