Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork32.4k
Description
(See#100227.)
Currently the tracemalloc module has some state in_PyRuntimeState
, including objects, which is shared by all interpreters. Interpreters should be isolated from each other, for a variety of reasons (including the possibility of a per-interpreter GIL). Isolating the module will involve moving some of the state toPyInterpreterState
(and, under per-interpreter GIL, guarding other state with a global lock).
Analysis:
(expand)
Allocators
The module installs a custom allocator (using the PEP 445 API
(docs).
(expand)
the allocator functions:
domain | func | wraps | wraps (reentrant) | actually wraps |
---|---|---|---|---|
- | tracemalloc_alloc() | <originalmalloc() orcalloc() > | <--- | |
- | tracemalloc_realloc() | <originalrealloc() orfree() > | <--- | |
- | tracemalloc_raw_alloc() | tracemalloc_alloc() * | <originalmalloc() orcalloc() > | |
- | tracemalloc_alloc_gil() | tracemalloc_alloc() | <originalmalloc() orcalloc() > | |
raw | ||||
tracemalloc_raw_malloc() | tracemalloc_alloc() | <originalmalloc() > | tracemalloc_raw_alloc() | |
tracemalloc_raw_calloc() | tracemalloc_alloc() | <originalcalloc() > | tracemalloc_raw_alloc() | |
tracemalloc_raw_realloc() | tracemalloc_realloc() * | <originalrealloc() > | ||
tracemalloc_free() | <originalfree() > | <--- | ||
mem | ||||
obj | ||||
tracemalloc_malloc_gil() | tracemalloc_alloc_gil() | <--- | ||
tracemalloc_calloc_gil() | tracemalloc_alloc_gil() | <--- | ||
tracemalloc_realloc_gil() | tracemalloc_realloc() | <originalrealloc() > | ||
tracemalloc_free() | <originalfree() > | <--- |
* Note thattracemalloc_raw_alloc()
wraps thetracemalloc_alloc()
call
withPyGILState_Ensure()
/PyGILState_Release()
.
Likewise fortracemalloc_raw_realloc()
where it callstracemalloc_realloc()
.
In no other case does an allocator function use the GILState API for any calls.
State
Fields
(expand)
https://github.com/python/cpython/blob/main/Include/internal/pycore_tracemalloc.h#L57-L107
https://github.com/python/cpython/blob/main/Include/internal/pycore_runtime.h#L147
raw
cpython/Include/internal/pycore_tracemalloc.h
Lines 43 to 55 in0675b8f
struct | |
#ifdef__GNUC__ | |
__attribute__((packed)) | |
#endif | |
tracemalloc_frame { | |
/* filename cannot be NULL: "<unknown>" is used if the Python frame | |
filename is NULL */ | |
PyObject*filename; | |
unsignedintlineno; | |
}; | |
#ifdef_MSC_VER | |
#pragma pack(pop) | |
#endif |
cpython/Include/internal/pycore_tracemalloc.h
Lines 57 to 64 in0675b8f
structtracemalloc_traceback { | |
Py_uhash_thash; | |
/* Number of frames stored */ | |
uint16_tnframe; | |
/* Total number of frames the traceback had */ | |
uint16_ttotal_nframe; | |
structtracemalloc_frameframes[1]; | |
}; |
cpython/Include/internal/pycore_tracemalloc.h
Lines 57 to 107 in0675b8f
structtracemalloc_traceback { | |
Py_uhash_thash; | |
/* Number of frames stored */ | |
uint16_tnframe; | |
/* Total number of frames the traceback had */ | |
uint16_ttotal_nframe; | |
structtracemalloc_frameframes[1]; | |
}; | |
struct_tracemalloc_runtime_state { | |
struct_PyTraceMalloc_Configconfig; | |
/* Protected by the GIL */ | |
struct { | |
PyMemAllocatorExmem; | |
PyMemAllocatorExraw; | |
PyMemAllocatorExobj; | |
}allocators; | |
#if defined(TRACE_RAW_MALLOC) | |
PyThread_type_locktables_lock; | |
#endif | |
/* Size in bytes of currently traced memory. | |
Protected by TABLES_LOCK(). */ | |
size_ttraced_memory; | |
/* Peak size in bytes of traced memory. | |
Protected by TABLES_LOCK(). */ | |
size_tpeak_traced_memory; | |
/* Hash table used as a set to intern filenames: | |
PyObject* => PyObject*. | |
Protected by the GIL */ | |
_Py_hashtable_t*filenames; | |
/* Buffer to store a new traceback in traceback_new(). | |
Protected by the GIL. */ | |
structtracemalloc_traceback*traceback; | |
/* Hash table used as a set to intern tracebacks: | |
traceback_t* => traceback_t* | |
Protected by the GIL */ | |
_Py_hashtable_t*tracebacks; | |
/* pointer (void*) => trace (trace_t*). | |
Protected by TABLES_LOCK(). */ | |
_Py_hashtable_t*traces; | |
/* domain (unsigned int) => traces (_Py_hashtable_t). | |
Protected by TABLES_LOCK(). */ | |
_Py_hashtable_t*domains; | |
structtracemalloc_tracebackempty_traceback; | |
Py_tss_treentrant_key; | |
}; |
cpython/Modules/_tracemalloc.c
Lines 54 to 55 in0675b8f
typedefstructtracemalloc_frameframe_t; | |
typedefstructtracemalloc_tracebacktraceback_t; |
cpython/Modules/_tracemalloc.c
Lines 69 to 76 in0675b8f
/* Trace of a memory block */ | |
typedefstruct { | |
/* Size of the memory block in bytes */ | |
size_tsize; | |
/* Traceback where the memory block was allocated */ | |
traceback_t*traceback; | |
}trace_t; |
name | type | protected by | #ifdef | notes |
---|---|---|---|---|
config | struct _PyTraceMalloc_Config | |||
.initialized | enum {} | GIL | ||
.tracing | bool | GIL | ||
.max_nframe | int | GIL | ||
allocators | see PEP 445 (docs) | |||
.mem | PyMemAllocatorEx | GIL | ||
.raw | PyMemAllocatorEx | GIL | ||
.obj | PyMemAllocatorEx | GIL | ||
tables_lock | PyThread_type_lock | GIL | TRACE_RAW_MALLOC | |
traced_memory | size_t | tables_lock | ||
peak_traced_memory | size_t | tables_lock | ||
filenames | _Py_hashtable_t * | GIL | interned; effectively aset of objects | |
traceback | struct tracemalloc_traceback * | GIL | a temporary buffer | |
tracebacks | _Py_hashtable_t * | GIL | interned; effectively aset oftraceback_t | |
traces | _Py_hashtable_t * | tables_lock | void-ptr ->trace_t | |
domains | _Py_hashtable_t * | tables_lock | domain ->_Py_hashtable_t * (per-domaintraces ) | |
empty_traceback | struct tracemalloc_traceback | ??? | ||
reentrant_key | Py_tss_t | ??? |
notes:
- each frame in
struct tracemalloc_traceback
holds a filename object traceback_t
is a typedef forstruct tracemalloc_traceback
frame_t
is a typedef forstruct tracemalloc_frame
hold objects:
filenames
traceback
(filename in each frame)tracebacks
(filename in each frame of each traceback)traces
(filename in each frame of each traceback)domains
(filename in each frame of each traceback in each domain)
Usage
(expand)
simple:
name | context | get | set |
---|---|---|---|
config | |||
.initialized | lifecycle | tracemalloc_init() tracemalloc_deinit() | tracemalloc_init() tracemalloc_deinit() |
.tracing | module | _tracemalloc_is_tracing_impl() _tracemalloc__get_traces_impl() _tracemalloc_clear_traces_impl() _tracemalloc_get_traceback_limit_impl() _tracemalloc_get_traced_memory_impl() _tracemalloc_reset_peak_impl() | |
C-API | PyTraceMalloc_Track() PyTraceMalloc_Untrack() _PyTraceMalloc_NewReference() _PyMem_DumpTraceback() | ||
lifecycle | tracemalloc_start() tracemalloc_stop() | tracemalloc_start() tracemalloc_stop() | |
internal | tracemalloc_get_traceback() | ||
.max_nframe | module | _tracemalloc_get_traceback_limit_impl() | |
lifecycle | tracemalloc_start() | ||
internal | traceback_get_frames() | ||
allocators | |||
.mem | lifecycle | tracemalloc_start() +tracemalloc_stop() | |
.raw | lifecycle | tracemalloc_init() +tracemalloc_start() +tracemalloc_stop() | |
internal | raw_malloc() raw_free() | ||
.obj | lifecycle | tracemalloc_start() +tracemalloc_stop() | |
tables_lock | module | _tracemalloc__get_traces_impl() +_tracemalloc_get_tracemalloc_memory_impl() +_tracemalloc_get_traced_memory_impl() +_tracemalloc_reset_peak_impl() + | |
C-API | PyTraceMalloc_Track() +PyTraceMalloc_Untrack() +_PyTraceMalloc_NewReference() + | ||
lifecycle | tracemalloc_init() tracemalloc_deinit() | tracemalloc_init() *tracemalloc_deinit() * | |
allocator | tracemalloc_alloc() +tracemalloc_realloc() +tracemalloc_free() +tracemalloc_realloc_gil() +tracemalloc_raw_realloc() + | ||
internal | tracemalloc_get_traceback() +tracemalloc_clear_traces() + | ||
traced_memory | module | _tracemalloc_get_traced_memory_impl() _tracemalloc_reset_peak_impl() | |
internal | tracemalloc_add_trace() | tracemalloc_add_trace() tracemalloc_remove_trace() tracemalloc_clear_traces() | |
peak_traced_memory | module | _tracemalloc_get_traced_memory_impl() | _tracemalloc_reset_peak_impl() |
internal | tracemalloc_add_trace() | tracemalloc_add_trace() tracemalloc_clear_traces() | |
filenames | module | _tracemalloc_get_tracemalloc_memory_impl() | |
lifecycle | tracemalloc_init() * | ||
internal | tracemalloc_get_frame() tracemalloc_clear_traces() + | ||
traceback | lifecycle | tracemalloc_stop() | tracemalloc_start() *tracemalloc_stop() * |
internal | traceback_new() + | ||
tracebacks | module | _tracemalloc_get_tracemalloc_memory_impl() | |
lifecycle | tracemalloc_init() *tracemalloc_deinit() + | ||
internal | traceback_new() +tracemalloc_clear_traces() + | ||
traces | module | _tracemalloc__get_traces_impl() _tracemalloc_get_tracemalloc_memory_impl() | |
C-API | _PyTraceMalloc_NewReference() | ||
lifecycle | tracemalloc_deinit() + | tracemalloc_init() * | |
internal | tracemalloc_get_traces_table() tracemalloc_add_trace() (indirect)tracemalloc_remove_trace() (indirect)tracemalloc_get_traceback() (indirect)tracemalloc_clear_traces() + | ||
domains | module | _tracemalloc__get_traces_impl() _tracemalloc_get_tracemalloc_memory_impl() | |
lifecycle | tracemalloc_deinit() + | tracemalloc_init() * | |
internal | tracemalloc_get_traces_table() tracemalloc_remove_trace() (indirect)tracemalloc_get_traceback() (indirect)tracemalloc_clear_traces() +tracemalloc_add_trace() + | ||
empty_traceback | lifecycle | tracemalloc_init() + | |
internal | traceback_new() | ||
reentrant_key | lifecycle | tracemalloc_init() +tracemalloc_deinit() + | |
allocator | tracemalloc_alloc_gil() (indirect) +tracemalloc_realloc_gil() (indirect) +tracemalloc_raw_alloc() (indirect) +tracemalloc_raw_realloc() (indirect) + | ||
internal | get_reentrant() set_reentrant() + |
* the function allocates/deallocates the value (see below)
+ the function mutates the value (see below)
simple (extraneous):
name | context | allocate/deallocate | get (assert-only) |
---|---|---|---|
config.tracing | internal | tracemalloc_add_trace() tracemalloc_remove_trace() | |
tables_lock | lifecycle | tracemalloc_init() tracemalloc_deinit() | |
traced_memory | internal | tracemalloc_remove_trace() | |
filenames | lifecycle | tracemalloc_init() | |
traceback | lifecycle | tracemalloc_start() tracemalloc_stop() | tracemalloc_start() |
tracebacks | lifecycle | tracemalloc_init() | |
traces | lifecycle | tracemalloc_init() | |
domains | lifecycle | tracemalloc_init() |
mutation of complex fields:
name | context | initialize | finalize | clear | modify |
---|---|---|---|---|---|
allocators.mem | lifecycle | tracemalloc_start() | |||
allocators.raw | lifecycle | tracemalloc_init() tracemalloc_start() | |||
allocators.obj | lifecycle | tracemalloc_start() | |||
tables_lock | module | _tracemalloc__get_traces_impl() _tracemalloc_get_tracemalloc_memory_impl() _tracemalloc_get_traced_memory_impl() _tracemalloc_reset_peak_impl() | |||
C-API | PyTraceMalloc_Track() PyTraceMalloc_Untrack() _PyTraceMalloc_NewReference() | ||||
allocator | tracemalloc_alloc() | tracemalloc_alloc() tracemalloc_realloc() tracemalloc_free() tracemalloc_realloc_gil() tracemalloc_raw_realloc() | |||
internal | tracemalloc_clear_traces() tracemalloc_get_traceback() | ||||
filenames | internal | tracemalloc_clear_traces() | tracemalloc_get_frame() tracemalloc_clear_traces() | ||
lifecycle | tracemalloc_deinit() | ||||
traceback | internal | traceback_new() | |||
tracebacks | lifecycle | tracemalloc_deinit() | |||
internal | tracemalloc_clear_traces() | traceback_new() | |||
traces | lifecycle | tracemalloc_deinit() | |||
internal | tracemalloc_clear_traces() | ||||
domains | lifecycle | tracemalloc_deinit() | |||
internal | tracemalloc_clear_traces() | tracemalloc_add_trace() | |||
reentrant_key | lifecycle | tracemalloc_init() | tracemalloc_deinit() | ||
internal | set_reentrant() |
indirection:
name | context | direct | indirect |
---|---|---|---|
allocators.raw | lifecycle | tracemalloc_start() tracemalloc_copy_trace() | raw_malloc() |
tracemalloc_stop() | raw_free() | ||
internal | traceback_new() tracemalloc_add_trace() tracemalloc_copy_trace() | raw_malloc() | |
traceback_new() tracemalloc_add_trace() tracemalloc_remove_trace() | raw_free() | ||
traces | internal | tracemalloc_add_trace() tracemalloc_remove_trace() tracemalloc_get_traceback() | tracemalloc_get_traces_table() |
domains | internal | tracemalloc_add_trace() tracemalloc_remove_trace() tracemalloc_get_traceback() | tracemalloc_get_traces_table() |
reentrant_key | allocator | tracemalloc_alloc_gil() tracemalloc_realloc_gil() tracemalloc_raw_alloc() tracemalloc_raw_realloc() | get_reentrant() |
tracemalloc_alloc_gil() tracemalloc_realloc_gil() tracemalloc_raw_alloc() tracemalloc_raw_realloc() | set_reentrant() |
Linked PRs
Metadata
Metadata
Assignees
Labels
Projects
Status