Skip to content

Commit aad122a

Browse files
committed
Use atomics for the _PyRuntime.tracemalloc.config.tracing so we can bail
early in `PyTraceMalloc_Track` and `PyTraceMalloc_Untrack` if tracemalloc isn't enabled. This avoids a significant scaling issue when tracemalloc isn't enabled, in extension modules that properly use the PyTraceMalloc_Track API (like numpy).
1 parent 6e625f8 commit aad122a

File tree

2 files changed

+16
-6
lines changed

2 files changed

+16
-6
lines changed

Include/internal/pycore_tracemalloc.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ struct _PyTraceMalloc_Config {
2020
TRACEMALLOC_FINALIZED
2121
} initialized;
2222

23-
/* Is tracemalloc tracing memory allocations?
24-
Variable protected by the TABLES_LOCK(). */
23+
/* Is tracemalloc tracing memory allocations? (Atomic.) */
2524
int tracing;
2625

2726
/* limit of the number of frames in a traceback, 1 by default.

Python/tracemalloc.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -850,7 +850,7 @@ _PyTraceMalloc_Start(int max_nframe)
850850

851851
/* everything is ready: start tracing Python memory allocations */
852852
TABLES_LOCK();
853-
tracemalloc_config.tracing = 1;
853+
_Py_atomic_store_int_release(&tracemalloc_config.tracing, 1);
854854
TABLES_UNLOCK();
855855

856856
return 0;
@@ -867,7 +867,7 @@ _PyTraceMalloc_Stop(void)
867867
}
868868

869869
/* stop tracing Python memory allocations */
870-
tracemalloc_config.tracing = 0;
870+
_Py_atomic_store_int_release(&tracemalloc_config.tracing, 0);
871871

872872
/* unregister the hook on memory allocators */
873873
PyMem_SetAllocator(PYMEM_DOMAIN_RAW, &allocators.raw);
@@ -1207,6 +1207,12 @@ int
12071207
PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr,
12081208
size_t size)
12091209
{
1210+
if (!_Py_atomic_load_int_relaxed(&tracemalloc_config.tracing)) {
1211+
// Exit early without attempting to lock if it doesn't look like
1212+
// we're tracing.
1213+
return -2;
1214+
}
1215+
12101216
PyGILState_STATE gil_state = PyGILState_Ensure();
12111217
TABLES_LOCK();
12121218

@@ -1215,7 +1221,7 @@ PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr,
12151221
result = tracemalloc_add_trace_unlocked(domain, ptr, size);
12161222
}
12171223
else {
1218-
/* tracemalloc is not tracing: do nothing */
1224+
/* tracemalloc was disabled before we locked tables; do nothing. */
12191225
result = -2;
12201226
}
12211227

@@ -1228,6 +1234,11 @@ PyTraceMalloc_Track(unsigned int domain, uintptr_t ptr,
12281234
int
12291235
PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)
12301236
{
1237+
if (!_Py_atomic_load_int_relaxed(&tracemalloc_config.tracing)) {
1238+
// Exit early without attempting to lock if it doesn't look like
1239+
// we're tracing.
1240+
return -2;
1241+
}
12311242
TABLES_LOCK();
12321243

12331244
int result;
@@ -1236,7 +1247,7 @@ PyTraceMalloc_Untrack(unsigned int domain, uintptr_t ptr)
12361247
result = 0;
12371248
}
12381249
else {
1239-
/* tracemalloc is not tracing: do nothing */
1250+
/* tracemalloc was disabled before we locked tables; do nothing. */
12401251
result = -2;
12411252
}
12421253

0 commit comments

Comments
 (0)