Skip to content

Commit abf7f0c

Browse files
committed
_tracemalloc: use compact key for traces
Issue #26588: Optimize memory footprint of _tracemalloc before non-zero domain is used. Start with compact key (Py_uintptr_t) and also switch to pointer_t key when the first memory block with a non-zero domain is tracked.
1 parent ac29b28 commit abf7f0c

File tree

1 file changed

+61
-1
lines changed

1 file changed

+61
-1
lines changed

Modules/_tracemalloc.c

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ static struct {
4343
/* use domain in trace key?
4444
Variable protected by the GIL. */
4545
int use_domain;
46-
} tracemalloc_config = {TRACEMALLOC_NOT_INITIALIZED, 0, 1, 1};
46+
} tracemalloc_config = {TRACEMALLOC_NOT_INITIALIZED, 0, 1, 0};
4747

4848
#if defined(TRACE_RAW_MALLOC) && defined(WITH_THREAD)
4949
/* This lock is needed because tracemalloc_free() is called without
@@ -519,6 +519,58 @@ traceback_new(void)
519519
}
520520

521521

522+
static int
523+
tracemalloc_use_domain_cb(_Py_hashtable_t *old_traces,
524+
_Py_hashtable_entry_t *entry, void *user_data)
525+
{
526+
Py_uintptr_t ptr;
527+
pointer_t key;
528+
_Py_hashtable_t *new_traces = (_Py_hashtable_t *)user_data;
529+
const void *pdata = _Py_HASHTABLE_ENTRY_PDATA(old_traces, entry);
530+
531+
_Py_HASHTABLE_ENTRY_READ_KEY(old_traces, entry, ptr);
532+
key.ptr = ptr;
533+
key.domain = DEFAULT_DOMAIN;
534+
535+
return _Py_hashtable_set(new_traces,
536+
sizeof(key), &key,
537+
old_traces->data_size, pdata);
538+
}
539+
540+
541+
/* Convert tracemalloc_traces from compact key (Py_uintptr_t) to pointer_t key.
542+
* Return 0 on success, -1 on error. */
543+
static int
544+
tracemalloc_use_domain(void)
545+
{
546+
_Py_hashtable_t *new_traces = NULL;
547+
548+
assert(!tracemalloc_config.use_domain);
549+
550+
new_traces = hashtable_new(sizeof(pointer_t),
551+
sizeof(trace_t),
552+
hashtable_hash_pointer_t,
553+
hashtable_compare_pointer_t);
554+
if (new_traces == NULL) {
555+
return -1;
556+
}
557+
558+
if (_Py_hashtable_foreach(tracemalloc_traces, tracemalloc_use_domain_cb,
559+
new_traces) < 0)
560+
{
561+
_Py_hashtable_destroy(new_traces);
562+
return -1;
563+
}
564+
565+
_Py_hashtable_destroy(tracemalloc_traces);
566+
tracemalloc_traces = new_traces;
567+
568+
tracemalloc_config.use_domain = 1;
569+
570+
return 0;
571+
}
572+
573+
522574
static void
523575
tracemalloc_remove_trace(_PyTraceMalloc_domain_t domain, Py_uintptr_t ptr)
524576
{
@@ -563,6 +615,14 @@ tracemalloc_add_trace(_PyTraceMalloc_domain_t domain, Py_uintptr_t ptr,
563615
return -1;
564616
}
565617

618+
if (!tracemalloc_config.use_domain && domain != DEFAULT_DOMAIN) {
619+
/* first trace using a non-zero domain whereas traces use compact
620+
(Py_uintptr_t) keys: switch to pointer_t keys. */
621+
if (tracemalloc_use_domain() < 0) {
622+
return -1;
623+
}
624+
}
625+
566626
if (tracemalloc_config.use_domain) {
567627
entry = _Py_HASHTABLE_GET_ENTRY(tracemalloc_traces, key);
568628
}

0 commit comments

Comments
 (0)