summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-05-13 01:52:11 (GMT)
committerGitHub <noreply@github.com>2020-05-13 01:52:11 (GMT)
commitd95bd4214c2babe851b02562d973d60c02e639b7 (patch)
tree75f9961793fecd850e1b4455bb8a6383add6b9bf /Modules
parent2d0a3d682f699cce8db6e30981d41d9125318726 (diff)
downloadcpython-d95bd4214c2babe851b02562d973d60c02e639b7.zip
cpython-d95bd4214c2babe851b02562d973d60c02e639b7.tar.gz
cpython-d95bd4214c2babe851b02562d973d60c02e639b7.tar.bz2
bpo-40609: _tracemalloc allocates traces (GH-20064)
Rewrite _tracemalloc to store "trace_t*" rather than directly "trace_t" in traces hash tables. Traces are now allocated on the heap memory, outside the hash table. Add tracemalloc_copy_traces() and tracemalloc_copy_domains() helper functions. Remove _Py_hashtable_copy() function since there is no API to copy a key or a value. Remove also _Py_hashtable_delete() function which was commented.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_tracemalloc.c160
1 files changed, 117 insertions, 43 deletions
diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c
index 618bf47..a42349a 100644
--- a/Modules/_tracemalloc.c
+++ b/Modules/_tracemalloc.c
@@ -122,7 +122,7 @@ static traceback_t *tracemalloc_traceback = NULL;
Protected by the GIL */
static _Py_hashtable_t *tracemalloc_tracebacks = NULL;
-/* pointer (void*) => trace (trace_t).
+/* pointer (void*) => trace (trace_t*).
Protected by TABLES_LOCK(). */
static _Py_hashtable_t *tracemalloc_traces = NULL;
@@ -467,13 +467,23 @@ traceback_new(void)
}
+static void
+tracemalloc_destroy_trace_cb(_Py_hashtable_t *traces,
+ _Py_hashtable_entry_t *entry)
+{
+ trace_t *trace;
+ _Py_HASHTABLE_ENTRY_READ_DATA(traces, entry, trace);
+ raw_free(trace);
+}
+
+
static _Py_hashtable_t*
tracemalloc_create_traces_table(void)
{
- return hashtable_new(sizeof(trace_t),
+ return hashtable_new(sizeof(trace_t*),
_Py_hashtable_hash_ptr,
_Py_hashtable_compare_direct,
- NULL);
+ tracemalloc_destroy_trace_cb);
}
@@ -528,12 +538,13 @@ tracemalloc_remove_trace(unsigned int domain, uintptr_t ptr)
return;
}
- trace_t trace;
+ trace_t *trace;
if (!_Py_HASHTABLE_POP(traces, TO_PTR(ptr), trace)) {
return;
}
- assert(tracemalloc_traced_memory >= trace.size);
- tracemalloc_traced_memory -= trace.size;
+ assert(tracemalloc_traced_memory >= trace->size);
+ tracemalloc_traced_memory -= trace->size;
+ raw_free(trace);
}
#define REMOVE_TRACE(ptr) \
@@ -565,23 +576,27 @@ tracemalloc_add_trace(unsigned int domain, uintptr_t ptr,
}
_Py_hashtable_entry_t* entry = _Py_HASHTABLE_GET_ENTRY(traces, ptr);
- trace_t trace;
if (entry != NULL) {
/* the memory block is already tracked */
+ trace_t *trace;
_Py_HASHTABLE_ENTRY_READ_DATA(traces, entry, trace);
- assert(tracemalloc_traced_memory >= trace.size);
- tracemalloc_traced_memory -= trace.size;
+ assert(tracemalloc_traced_memory >= trace->size);
+ tracemalloc_traced_memory -= trace->size;
- trace.size = size;
- trace.traceback = traceback;
- _Py_HASHTABLE_ENTRY_WRITE_DATA(traces, entry, trace);
+ trace->size = size;
+ trace->traceback = traceback;
}
else {
- trace.size = size;
- trace.traceback = traceback;
+ trace_t *trace = raw_malloc(sizeof(trace_t));
+ if (trace == NULL) {
+ return -1;
+ }
+ trace->size = size;
+ trace->traceback = traceback;
int res = _Py_HASHTABLE_SET(traces, TO_PTR(ptr), trace);
if (res != 0) {
+ raw_free(trace);
return res;
}
}
@@ -1225,19 +1240,62 @@ typedef struct {
unsigned int domain;
} get_traces_t;
+
static int
-tracemalloc_get_traces_copy_domain(_Py_hashtable_t *domains,
- _Py_hashtable_entry_t *entry,
- void *user_data)
+tracemalloc_copy_trace(_Py_hashtable_t *traces,
+ _Py_hashtable_entry_t *entry,
+ void *traces2_raw)
{
- get_traces_t *get_traces = user_data;
+ _Py_hashtable_t *traces2 = (_Py_hashtable_t *)traces2_raw;
+
+ trace_t *trace;
+ _Py_HASHTABLE_ENTRY_READ_DATA(traces, entry, trace);
+
+ trace_t *trace2 = raw_malloc(sizeof(trace_t));
+ if (traces2 == NULL) {
+ return -1;
+ }
+ *trace2 = *trace;
+ if (_Py_HASHTABLE_SET(traces2, entry->key, trace2) < 0) {
+ raw_free(trace2);
+ return -1;
+ }
+ return 0;
+}
+
+
+static _Py_hashtable_t*
+tracemalloc_copy_traces(_Py_hashtable_t *traces)
+{
+ _Py_hashtable_t *traces2 = tracemalloc_create_traces_table();
+ if (traces2 == NULL) {
+ return NULL;
+ }
+
+ int err = _Py_hashtable_foreach(traces,
+ tracemalloc_copy_trace,
+ traces2);
+ if (err) {
+ _Py_hashtable_destroy(traces2);
+ return NULL;
+ }
+ return traces2;
+}
+
+
+static int
+tracemalloc_copy_domain(_Py_hashtable_t *domains,
+ _Py_hashtable_entry_t *entry,
+ void *domains2_raw)
+{
+ _Py_hashtable_t *domains2 = (_Py_hashtable_t *)domains2_raw;
unsigned int domain = (unsigned int)FROM_PTR(entry->key);
_Py_hashtable_t *traces;
_Py_HASHTABLE_ENTRY_READ_DATA(domains, entry, traces);
- _Py_hashtable_t *traces2 = _Py_hashtable_copy(traces);
- if (_Py_HASHTABLE_SET(get_traces->domains, TO_PTR(domain), traces2) < 0) {
+ _Py_hashtable_t *traces2 = tracemalloc_copy_traces(traces);
+ if (_Py_HASHTABLE_SET(domains2, TO_PTR(domain), traces2) < 0) {
_Py_hashtable_destroy(traces2);
return -1;
}
@@ -1245,18 +1303,37 @@ tracemalloc_get_traces_copy_domain(_Py_hashtable_t *domains,
}
+static _Py_hashtable_t*
+tracemalloc_copy_domains(_Py_hashtable_t *domains)
+{
+ _Py_hashtable_t *domains2 = tracemalloc_create_domains_table();
+ if (domains2 == NULL) {
+ return NULL;
+ }
+
+ int err = _Py_hashtable_foreach(domains,
+ tracemalloc_copy_domain,
+ domains2);
+ if (err) {
+ _Py_hashtable_destroy(domains2);
+ return NULL;
+ }
+ return domains2;
+}
+
+
static int
tracemalloc_get_traces_fill(_Py_hashtable_t *traces, _Py_hashtable_entry_t *entry,
void *user_data)
{
get_traces_t *get_traces = user_data;
- trace_t trace;
+ trace_t *trace;
PyObject *tracemalloc_obj;
int res;
_Py_HASHTABLE_ENTRY_READ_DATA(traces, entry, trace);
- tracemalloc_obj = trace_to_pyobject(get_traces->domain, &trace, get_traces->tracebacks);
+ tracemalloc_obj = trace_to_pyobject(get_traces->domain, trace, get_traces->tracebacks);
if (tracemalloc_obj == NULL)
return 1;
@@ -1335,37 +1412,34 @@ _tracemalloc__get_traces_impl(PyObject *module)
goto no_memory;
}
- get_traces.domains = tracemalloc_create_domains_table();
- if (get_traces.domains == NULL) {
- goto no_memory;
- }
-
- int err;
-
// Copy all traces so tracemalloc_get_traces_fill() doesn't have to disable
// temporarily tracemalloc which would impact other threads and so would
// miss allocations while get_traces() is called.
TABLES_LOCK();
- get_traces.traces = _Py_hashtable_copy(tracemalloc_traces);
- err = _Py_hashtable_foreach(tracemalloc_domains,
- tracemalloc_get_traces_copy_domain,
- &get_traces);
+ get_traces.traces = tracemalloc_copy_traces(tracemalloc_traces);
TABLES_UNLOCK();
if (get_traces.traces == NULL) {
goto no_memory;
}
- if (err) {
+
+ TABLES_LOCK();
+ get_traces.domains = tracemalloc_copy_domains(tracemalloc_domains);
+ TABLES_UNLOCK();
+
+ if (get_traces.domains == NULL) {
goto no_memory;
}
// Convert traces to a list of tuples
set_reentrant(1);
- err = _Py_hashtable_foreach(get_traces.traces,
- tracemalloc_get_traces_fill, &get_traces);
+ int err = _Py_hashtable_foreach(get_traces.traces,
+ tracemalloc_get_traces_fill,
+ &get_traces);
if (!err) {
err = _Py_hashtable_foreach(get_traces.domains,
- tracemalloc_get_traces_domain, &get_traces);
+ tracemalloc_get_traces_domain,
+ &get_traces);
}
set_reentrant(0);
if (err) {
@@ -1398,7 +1472,7 @@ finally:
static traceback_t*
tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr)
{
- trace_t trace;
+ trace_t *trace;
int found;
if (!_Py_tracemalloc_config.tracing)
@@ -1414,10 +1488,11 @@ tracemalloc_get_traceback(unsigned int domain, uintptr_t ptr)
}
TABLES_UNLOCK();
- if (!found)
+ if (!found) {
return NULL;
+ }
- return trace.traceback;
+ return trace->traceback;
}
@@ -1758,10 +1833,9 @@ _PyTraceMalloc_NewReference(PyObject *op)
/* update the traceback of the memory block */
traceback_t *traceback = traceback_new();
if (traceback != NULL) {
- trace_t trace;
+ trace_t *trace;
_Py_HASHTABLE_ENTRY_READ_DATA(tracemalloc_traces, entry, trace);
- trace.traceback = traceback;
- _Py_HASHTABLE_ENTRY_WRITE_DATA(tracemalloc_traces, entry, trace);
+ trace->traceback = traceback;
res = 0;
}
}