From 3db607f8016c8d05f087085dc730ed4b1aeb35f7 Mon Sep 17 00:00:00 2001 From: Tomasz Pytel Date: Fri, 28 Feb 2025 12:09:49 -0500 Subject: [PATCH 1/5] gh-130695: add count create/destroy refs to tracemalloc --- Doc/library/tracemalloc.rst | 9 +++++++- Include/internal/pycore_tracemalloc.h | 9 ++++++++ Lib/test/test_tracemalloc.py | 32 +++++++++++++++++++++++++++ Modules/_tracemalloc.c | 18 +++++++++++++++ Modules/clinic/_tracemalloc.c.h | 22 +++++++++++++++++- Python/tracemalloc.c | 29 ++++++++++++++++++++++++ 6 files changed, 117 insertions(+), 2 deletions(-) diff --git a/Doc/library/tracemalloc.rst b/Doc/library/tracemalloc.rst index 2370d927292eb0..8bc3eda88a016d 100644 --- a/Doc/library/tracemalloc.rst +++ b/Doc/library/tracemalloc.rst @@ -299,7 +299,8 @@ Functions .. function:: clear_traces() - Clear traces of memory blocks allocated by Python. + Clear traces of memory blocks allocated and counts of created and destroyed + memory blocks by Python. See also :func:`stop`. @@ -330,6 +331,12 @@ Functions :mod:`tracemalloc` module as a tuple: ``(current: int, peak: int)``. +.. function:: get_traced_refs() + + Get the current count of created and destroyed memory blocks. + :mod:`tracemalloc` module as a tuple: ``(created: int, destroyed: int)``. + + .. function:: reset_peak() Set the peak size of memory blocks traced by the :mod:`tracemalloc` module diff --git a/Include/internal/pycore_tracemalloc.h b/Include/internal/pycore_tracemalloc.h index 572e8025876319..ba1064a6e6617e 100644 --- a/Include/internal/pycore_tracemalloc.h +++ b/Include/internal/pycore_tracemalloc.h @@ -94,6 +94,12 @@ struct _tracemalloc_runtime_state { /* domain (unsigned int) => traces (_Py_hashtable_t). Protected by TABLES_LOCK(). */ _Py_hashtable_t *domains; + /* Number of references created. + Protected by TABLES_LOCK(). */ + size_t refs_created; + /* Number of references destroyed. + Protected by TABLES_LOCK() and sometimes modified atomically. */ + size_t refs_destroyed; struct tracemalloc_traceback empty_traceback; @@ -155,6 +161,9 @@ extern size_t _PyTraceMalloc_GetMemory(void); /* Get the current size and peak size of traced memory blocks as a 2-tuple */ extern PyObject* _PyTraceMalloc_GetTracedMemory(void); +/* Get the current number of references created and destroyed as a 2-tuple */ +extern PyObject* _PyTraceMalloc_GetTracedRefs(void); + /* Set the peak size of traced memory blocks to the current size */ extern void _PyTraceMalloc_ResetPeak(void); diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py index 0220a83d24b428..359682238e3e75 100644 --- a/Lib/test/test_tracemalloc.py +++ b/Lib/test/test_tracemalloc.py @@ -4,6 +4,7 @@ import textwrap import tracemalloc import unittest +import warnings from unittest.mock import patch from test.support.script_helper import (assert_python_ok, assert_python_failure, interpreter_requires_environment) @@ -1141,6 +1142,37 @@ def __del__(self, untrack=_testcapi.tracemalloc_untrack): """) assert_python_ok("-c", code) + def test_trace_refs(self): + def f(): + l = [] + del l + + def g(): + l = [], [] + del l + + tracemalloc.start() + + try: + tracemalloc.clear_traces() + f() + refs = tracemalloc.get_traced_refs() + if refs == (1, 0): + warnings.warn("ceval Py_DECREF doesn't emit PyRefTracer_DESTROY in this build") + else: + self.assertEqual(refs, (1, 1)) + + tracemalloc.clear_traces() + g() + refs = tracemalloc.get_traced_refs() + if refs == (3, 2): + warnings.warn("ceval Py_DECREF doesn't emit PyRefTracer_DESTROY in this build") + else: + self.assertEqual(refs, (3, 3)) + + finally: + tracemalloc.stop() + if __name__ == "__main__": unittest.main() diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index be71fc9fc9c341..876c2e5fe5a8c7 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -167,6 +167,23 @@ _tracemalloc_get_traced_memory_impl(PyObject *module) return _PyTraceMalloc_GetTracedMemory(); } + +/*[clinic input] +_tracemalloc.get_traced_refs + +Get the current count of created and destroyed refs. + +Returns a tuple: (created: int, destroyed: int). +[clinic start generated code]*/ + +static PyObject * +_tracemalloc_get_traced_refs_impl(PyObject *module) +/*[clinic end generated code: output=81d36fdeb3ffc362 input=d0652f2592733b0e]*/ +{ + return _PyTraceMalloc_GetTracedRefs(); +} + + /*[clinic input] _tracemalloc.reset_peak @@ -195,6 +212,7 @@ static PyMethodDef module_methods[] = { _TRACEMALLOC_GET_TRACEBACK_LIMIT_METHODDEF _TRACEMALLOC_GET_TRACEMALLOC_MEMORY_METHODDEF _TRACEMALLOC_GET_TRACED_MEMORY_METHODDEF + _TRACEMALLOC_GET_TRACED_REFS_METHODDEF _TRACEMALLOC_RESET_PEAK_METHODDEF /* sentinel */ {NULL, NULL} diff --git a/Modules/clinic/_tracemalloc.c.h b/Modules/clinic/_tracemalloc.c.h index 1d100247423991..ac408cf6c51e38 100644 --- a/Modules/clinic/_tracemalloc.c.h +++ b/Modules/clinic/_tracemalloc.c.h @@ -195,6 +195,26 @@ _tracemalloc_get_traced_memory(PyObject *module, PyObject *Py_UNUSED(ignored)) return _tracemalloc_get_traced_memory_impl(module); } +PyDoc_STRVAR(_tracemalloc_get_traced_refs__doc__, +"get_traced_refs($module, /)\n" +"--\n" +"\n" +"Get the current count of created and destroyed refs.\n" +"\n" +"Returns a tuple: (created: int, destroyed: int)."); + +#define _TRACEMALLOC_GET_TRACED_REFS_METHODDEF \ + {"get_traced_refs", (PyCFunction)_tracemalloc_get_traced_refs, METH_NOARGS, _tracemalloc_get_traced_refs__doc__}, + +static PyObject * +_tracemalloc_get_traced_refs_impl(PyObject *module); + +static PyObject * +_tracemalloc_get_traced_refs(PyObject *module, PyObject *Py_UNUSED(ignored)) +{ + return _tracemalloc_get_traced_refs_impl(module); +} + PyDoc_STRVAR(_tracemalloc_reset_peak__doc__, "reset_peak($module, /)\n" "--\n" @@ -214,4 +234,4 @@ _tracemalloc_reset_peak(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _tracemalloc_reset_peak_impl(module); } -/*[clinic end generated code: output=9d4d884b156c2ddb input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7efbb9b4f08daab3 input=a9049054013a1b77]*/ diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c index d69b0ebd585a7f..bd22c25c023aa8 100644 --- a/Python/tracemalloc.c +++ b/Python/tracemalloc.c @@ -76,6 +76,8 @@ typedef struct { #define tracemalloc_tracebacks _PyRuntime.tracemalloc.tracebacks #define tracemalloc_traces _PyRuntime.tracemalloc.traces #define tracemalloc_domains _PyRuntime.tracemalloc.domains +#define tracemalloc_refs_created _PyRuntime.tracemalloc.refs_created +#define tracemalloc_refs_destroyed _PyRuntime.tracemalloc.refs_destroyed #ifdef TRACE_DEBUG @@ -1258,6 +1260,10 @@ _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, void* Py_UNUSED(ignore)) { if (event != PyRefTracer_CREATE) { + /* we don't want bother here with the lock for performance reasons */ + if (_Py_atomic_load_int32_relaxed(&tracemalloc_config.tracing)) { + _Py_atomic_add_ssize((Py_ssize_t *)&tracemalloc_refs_destroyed, 1); + } return 0; } if (get_reentrant()) { @@ -1271,6 +1277,8 @@ _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, goto done; } + tracemalloc_refs_created += 1; + PyTypeObject *type = Py_TYPE(op); const size_t presize = _PyType_PreHeaderSize(type); uintptr_t ptr = (uintptr_t)((char *)op - presize); @@ -1326,6 +1334,8 @@ _PyTraceMalloc_ClearTraces(void) TABLES_LOCK(); if (tracemalloc_config.tracing) { tracemalloc_clear_traces_unlocked(); + tracemalloc_refs_created = 0; + tracemalloc_refs_destroyed = 0; } TABLES_UNLOCK(); } @@ -1464,6 +1474,25 @@ _PyTraceMalloc_GetTracedMemory(void) return Py_BuildValue("nn", traced, peak); } + +PyObject * +_PyTraceMalloc_GetTracedRefs(void) +{ + TABLES_LOCK(); + Py_ssize_t created, destroyed; + if (tracemalloc_config.tracing) { + created = tracemalloc_refs_created; + destroyed = tracemalloc_refs_destroyed; + } + else { + created = 0; + destroyed = 0; + } + TABLES_UNLOCK(); + + return Py_BuildValue("nn", created, destroyed); +} + void _PyTraceMalloc_ResetPeak(void) { From cfdaaeebb0430e2c892ea2e240164e515c6a470e Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 17:13:37 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-02-28-17-13-36.gh-issue-130695.WuCmBj.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-02-28-17-13-36.gh-issue-130695.WuCmBj.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-02-28-17-13-36.gh-issue-130695.WuCmBj.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-28-17-13-36.gh-issue-130695.WuCmBj.rst new file mode 100644 index 00000000000000..94ae45c6b25c40 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-02-28-17-13-36.gh-issue-130695.WuCmBj.rst @@ -0,0 +1 @@ +Add tracking of number of deallocations to :mod:`tracemalloc`. From 0bb3261a70a064dce51561a3c51d572cb69c2da9 Mon Sep 17 00:00:00 2001 From: Tomasz Pytel Date: Fri, 28 Feb 2025 14:23:30 -0500 Subject: [PATCH 3/5] requested changes --- Doc/library/tracemalloc.rst | 6 +++--- Include/internal/pycore_tracemalloc.h | 10 +++++----- Lib/test/test_tracemalloc.py | 4 ++-- Modules/_tracemalloc.c | 10 +++++----- Modules/clinic/_tracemalloc.c.h | 16 +++++++-------- Python/tracemalloc.c | 28 +++++++++++++-------------- 6 files changed, 37 insertions(+), 37 deletions(-) diff --git a/Doc/library/tracemalloc.rst b/Doc/library/tracemalloc.rst index 8bc3eda88a016d..455d723c847bcf 100644 --- a/Doc/library/tracemalloc.rst +++ b/Doc/library/tracemalloc.rst @@ -331,10 +331,10 @@ Functions :mod:`tracemalloc` module as a tuple: ``(current: int, peak: int)``. -.. function:: get_traced_refs() +.. function:: get_traced_allocs() - Get the current count of created and destroyed memory blocks. - :mod:`tracemalloc` module as a tuple: ``(created: int, destroyed: int)``. + Get the current unit counts of allocated and deallocated memory blocks. + :mod:`tracemalloc` module as a tuple: ``(allocs: int, deallocs: int)``. .. function:: reset_peak() diff --git a/Include/internal/pycore_tracemalloc.h b/Include/internal/pycore_tracemalloc.h index ba1064a6e6617e..df7bfad80c8a29 100644 --- a/Include/internal/pycore_tracemalloc.h +++ b/Include/internal/pycore_tracemalloc.h @@ -94,12 +94,12 @@ struct _tracemalloc_runtime_state { /* domain (unsigned int) => traces (_Py_hashtable_t). Protected by TABLES_LOCK(). */ _Py_hashtable_t *domains; - /* Number of references created. + /* Number of allocations. Protected by TABLES_LOCK(). */ - size_t refs_created; - /* Number of references destroyed. + Py_ssize_t allocations; + /* Number of deallocations. Protected by TABLES_LOCK() and sometimes modified atomically. */ - size_t refs_destroyed; + Py_ssize_t deallocations; struct tracemalloc_traceback empty_traceback; @@ -162,7 +162,7 @@ extern size_t _PyTraceMalloc_GetMemory(void); extern PyObject* _PyTraceMalloc_GetTracedMemory(void); /* Get the current number of references created and destroyed as a 2-tuple */ -extern PyObject* _PyTraceMalloc_GetTracedRefs(void); +extern PyObject* _PyTraceMalloc_GetTracedAllocs(void); /* Set the peak size of traced memory blocks to the current size */ extern void _PyTraceMalloc_ResetPeak(void); diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py index 359682238e3e75..2ec650f71dce94 100644 --- a/Lib/test/test_tracemalloc.py +++ b/Lib/test/test_tracemalloc.py @@ -1156,7 +1156,7 @@ def g(): try: tracemalloc.clear_traces() f() - refs = tracemalloc.get_traced_refs() + refs = tracemalloc.get_traced_allocs() if refs == (1, 0): warnings.warn("ceval Py_DECREF doesn't emit PyRefTracer_DESTROY in this build") else: @@ -1164,7 +1164,7 @@ def g(): tracemalloc.clear_traces() g() - refs = tracemalloc.get_traced_refs() + refs = tracemalloc.get_traced_allocs() if refs == (3, 2): warnings.warn("ceval Py_DECREF doesn't emit PyRefTracer_DESTROY in this build") else: diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index 876c2e5fe5a8c7..b8ff7ab626cc25 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -169,7 +169,7 @@ _tracemalloc_get_traced_memory_impl(PyObject *module) /*[clinic input] -_tracemalloc.get_traced_refs +_tracemalloc.get_traced_allocs Get the current count of created and destroyed refs. @@ -177,10 +177,10 @@ Returns a tuple: (created: int, destroyed: int). [clinic start generated code]*/ static PyObject * -_tracemalloc_get_traced_refs_impl(PyObject *module) -/*[clinic end generated code: output=81d36fdeb3ffc362 input=d0652f2592733b0e]*/ +_tracemalloc_get_traced_allocs_impl(PyObject *module) +/*[clinic end generated code: output=cb84cbd781fab85f input=336f38d37a5830ef]*/ { - return _PyTraceMalloc_GetTracedRefs(); + return _PyTraceMalloc_GetTracedAllocs(); } @@ -212,7 +212,7 @@ static PyMethodDef module_methods[] = { _TRACEMALLOC_GET_TRACEBACK_LIMIT_METHODDEF _TRACEMALLOC_GET_TRACEMALLOC_MEMORY_METHODDEF _TRACEMALLOC_GET_TRACED_MEMORY_METHODDEF - _TRACEMALLOC_GET_TRACED_REFS_METHODDEF + _TRACEMALLOC_GET_TRACED_ALLOCS_METHODDEF _TRACEMALLOC_RESET_PEAK_METHODDEF /* sentinel */ {NULL, NULL} diff --git a/Modules/clinic/_tracemalloc.c.h b/Modules/clinic/_tracemalloc.c.h index ac408cf6c51e38..2434781d0936f0 100644 --- a/Modules/clinic/_tracemalloc.c.h +++ b/Modules/clinic/_tracemalloc.c.h @@ -195,24 +195,24 @@ _tracemalloc_get_traced_memory(PyObject *module, PyObject *Py_UNUSED(ignored)) return _tracemalloc_get_traced_memory_impl(module); } -PyDoc_STRVAR(_tracemalloc_get_traced_refs__doc__, -"get_traced_refs($module, /)\n" +PyDoc_STRVAR(_tracemalloc_get_traced_allocs__doc__, +"get_traced_allocs($module, /)\n" "--\n" "\n" "Get the current count of created and destroyed refs.\n" "\n" "Returns a tuple: (created: int, destroyed: int)."); -#define _TRACEMALLOC_GET_TRACED_REFS_METHODDEF \ - {"get_traced_refs", (PyCFunction)_tracemalloc_get_traced_refs, METH_NOARGS, _tracemalloc_get_traced_refs__doc__}, +#define _TRACEMALLOC_GET_TRACED_ALLOCS_METHODDEF \ + {"get_traced_allocs", (PyCFunction)_tracemalloc_get_traced_allocs, METH_NOARGS, _tracemalloc_get_traced_allocs__doc__}, static PyObject * -_tracemalloc_get_traced_refs_impl(PyObject *module); +_tracemalloc_get_traced_allocs_impl(PyObject *module); static PyObject * -_tracemalloc_get_traced_refs(PyObject *module, PyObject *Py_UNUSED(ignored)) +_tracemalloc_get_traced_allocs(PyObject *module, PyObject *Py_UNUSED(ignored)) { - return _tracemalloc_get_traced_refs_impl(module); + return _tracemalloc_get_traced_allocs_impl(module); } PyDoc_STRVAR(_tracemalloc_reset_peak__doc__, @@ -234,4 +234,4 @@ _tracemalloc_reset_peak(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _tracemalloc_reset_peak_impl(module); } -/*[clinic end generated code: output=7efbb9b4f08daab3 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=9cb364916c67f0be input=a9049054013a1b77]*/ diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c index bd22c25c023aa8..6a70d5b99830d3 100644 --- a/Python/tracemalloc.c +++ b/Python/tracemalloc.c @@ -76,8 +76,8 @@ typedef struct { #define tracemalloc_tracebacks _PyRuntime.tracemalloc.tracebacks #define tracemalloc_traces _PyRuntime.tracemalloc.traces #define tracemalloc_domains _PyRuntime.tracemalloc.domains -#define tracemalloc_refs_created _PyRuntime.tracemalloc.refs_created -#define tracemalloc_refs_destroyed _PyRuntime.tracemalloc.refs_destroyed +#define tracemalloc_allocations _PyRuntime.tracemalloc.allocations +#define tracemalloc_deallocations _PyRuntime.tracemalloc.deallocations #ifdef TRACE_DEBUG @@ -1261,8 +1261,8 @@ _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, { if (event != PyRefTracer_CREATE) { /* we don't want bother here with the lock for performance reasons */ - if (_Py_atomic_load_int32_relaxed(&tracemalloc_config.tracing)) { - _Py_atomic_add_ssize((Py_ssize_t *)&tracemalloc_refs_destroyed, 1); + if (_Py_atomic_load_int_relaxed(&tracemalloc_config.tracing)) { + _Py_atomic_add_ssize(&tracemalloc_deallocations, 1); } return 0; } @@ -1277,7 +1277,7 @@ _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, goto done; } - tracemalloc_refs_created += 1; + tracemalloc_allocations += 1; PyTypeObject *type = Py_TYPE(op); const size_t presize = _PyType_PreHeaderSize(type); @@ -1334,8 +1334,8 @@ _PyTraceMalloc_ClearTraces(void) TABLES_LOCK(); if (tracemalloc_config.tracing) { tracemalloc_clear_traces_unlocked(); - tracemalloc_refs_created = 0; - tracemalloc_refs_destroyed = 0; + tracemalloc_allocations = 0; + tracemalloc_deallocations = 0; } TABLES_UNLOCK(); } @@ -1476,21 +1476,21 @@ _PyTraceMalloc_GetTracedMemory(void) PyObject * -_PyTraceMalloc_GetTracedRefs(void) +_PyTraceMalloc_GetTracedAllocs(void) { TABLES_LOCK(); - Py_ssize_t created, destroyed; + Py_ssize_t allocations, deallocations; if (tracemalloc_config.tracing) { - created = tracemalloc_refs_created; - destroyed = tracemalloc_refs_destroyed; + allocations = tracemalloc_allocations; + deallocations = tracemalloc_deallocations; } else { - created = 0; - destroyed = 0; + allocations = 0; + deallocations = 0; } TABLES_UNLOCK(); - return Py_BuildValue("nn", created, destroyed); + return Py_BuildValue("nn", allocations, deallocations); } void From 4f7d8a84ac115f7a2948d405a2a704c3aa8e9aad Mon Sep 17 00:00:00 2001 From: Tomasz Pytel Date: Mon, 3 Mar 2025 17:47:56 -0500 Subject: [PATCH 4/5] revert to refs_created/_destroyed, other tweaks --- Doc/library/tracemalloc.rst | 8 +- Include/internal/pycore_tracemalloc.h | 10 +-- Lib/test/test_tracemalloc.py | 4 +- Modules/_tracemalloc.c | 10 +-- Modules/clinic/_tracemalloc.c.h | 16 ++-- Python/tracemalloc.c | 105 +++++++++++++------------- 6 files changed, 77 insertions(+), 76 deletions(-) diff --git a/Doc/library/tracemalloc.rst b/Doc/library/tracemalloc.rst index 455d723c847bcf..ee75cd1e10a003 100644 --- a/Doc/library/tracemalloc.rst +++ b/Doc/library/tracemalloc.rst @@ -331,10 +331,12 @@ Functions :mod:`tracemalloc` module as a tuple: ``(current: int, peak: int)``. -.. function:: get_traced_allocs() +.. function:: get_traced_refs() - Get the current unit counts of allocated and deallocated memory blocks. - :mod:`tracemalloc` module as a tuple: ``(allocs: int, deallocs: int)``. + Get the current count of created and destroyed traced references. + :mod:`tracemalloc` module as a tuple: ``(created: int, destroyed: int)``. + + .. versionadded:: next .. function:: reset_peak() diff --git a/Include/internal/pycore_tracemalloc.h b/Include/internal/pycore_tracemalloc.h index df7bfad80c8a29..71912ab238a08e 100644 --- a/Include/internal/pycore_tracemalloc.h +++ b/Include/internal/pycore_tracemalloc.h @@ -94,12 +94,12 @@ struct _tracemalloc_runtime_state { /* domain (unsigned int) => traces (_Py_hashtable_t). Protected by TABLES_LOCK(). */ _Py_hashtable_t *domains; - /* Number of allocations. + /* Number of references created. Protected by TABLES_LOCK(). */ - Py_ssize_t allocations; - /* Number of deallocations. + Py_ssize_t refs_created; + /* Number of references destroyed. Protected by TABLES_LOCK() and sometimes modified atomically. */ - Py_ssize_t deallocations; + Py_ssize_t refs_destroyed; struct tracemalloc_traceback empty_traceback; @@ -162,7 +162,7 @@ extern size_t _PyTraceMalloc_GetMemory(void); extern PyObject* _PyTraceMalloc_GetTracedMemory(void); /* Get the current number of references created and destroyed as a 2-tuple */ -extern PyObject* _PyTraceMalloc_GetTracedAllocs(void); +extern PyObject* _PyTraceMalloc_GetTracedRefs(void); /* Set the peak size of traced memory blocks to the current size */ extern void _PyTraceMalloc_ResetPeak(void); diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py index 2ec650f71dce94..359682238e3e75 100644 --- a/Lib/test/test_tracemalloc.py +++ b/Lib/test/test_tracemalloc.py @@ -1156,7 +1156,7 @@ def g(): try: tracemalloc.clear_traces() f() - refs = tracemalloc.get_traced_allocs() + refs = tracemalloc.get_traced_refs() if refs == (1, 0): warnings.warn("ceval Py_DECREF doesn't emit PyRefTracer_DESTROY in this build") else: @@ -1164,7 +1164,7 @@ def g(): tracemalloc.clear_traces() g() - refs = tracemalloc.get_traced_allocs() + refs = tracemalloc.get_traced_refs() if refs == (3, 2): warnings.warn("ceval Py_DECREF doesn't emit PyRefTracer_DESTROY in this build") else: diff --git a/Modules/_tracemalloc.c b/Modules/_tracemalloc.c index b8ff7ab626cc25..876c2e5fe5a8c7 100644 --- a/Modules/_tracemalloc.c +++ b/Modules/_tracemalloc.c @@ -169,7 +169,7 @@ _tracemalloc_get_traced_memory_impl(PyObject *module) /*[clinic input] -_tracemalloc.get_traced_allocs +_tracemalloc.get_traced_refs Get the current count of created and destroyed refs. @@ -177,10 +177,10 @@ Returns a tuple: (created: int, destroyed: int). [clinic start generated code]*/ static PyObject * -_tracemalloc_get_traced_allocs_impl(PyObject *module) -/*[clinic end generated code: output=cb84cbd781fab85f input=336f38d37a5830ef]*/ +_tracemalloc_get_traced_refs_impl(PyObject *module) +/*[clinic end generated code: output=81d36fdeb3ffc362 input=d0652f2592733b0e]*/ { - return _PyTraceMalloc_GetTracedAllocs(); + return _PyTraceMalloc_GetTracedRefs(); } @@ -212,7 +212,7 @@ static PyMethodDef module_methods[] = { _TRACEMALLOC_GET_TRACEBACK_LIMIT_METHODDEF _TRACEMALLOC_GET_TRACEMALLOC_MEMORY_METHODDEF _TRACEMALLOC_GET_TRACED_MEMORY_METHODDEF - _TRACEMALLOC_GET_TRACED_ALLOCS_METHODDEF + _TRACEMALLOC_GET_TRACED_REFS_METHODDEF _TRACEMALLOC_RESET_PEAK_METHODDEF /* sentinel */ {NULL, NULL} diff --git a/Modules/clinic/_tracemalloc.c.h b/Modules/clinic/_tracemalloc.c.h index 2434781d0936f0..ac408cf6c51e38 100644 --- a/Modules/clinic/_tracemalloc.c.h +++ b/Modules/clinic/_tracemalloc.c.h @@ -195,24 +195,24 @@ _tracemalloc_get_traced_memory(PyObject *module, PyObject *Py_UNUSED(ignored)) return _tracemalloc_get_traced_memory_impl(module); } -PyDoc_STRVAR(_tracemalloc_get_traced_allocs__doc__, -"get_traced_allocs($module, /)\n" +PyDoc_STRVAR(_tracemalloc_get_traced_refs__doc__, +"get_traced_refs($module, /)\n" "--\n" "\n" "Get the current count of created and destroyed refs.\n" "\n" "Returns a tuple: (created: int, destroyed: int)."); -#define _TRACEMALLOC_GET_TRACED_ALLOCS_METHODDEF \ - {"get_traced_allocs", (PyCFunction)_tracemalloc_get_traced_allocs, METH_NOARGS, _tracemalloc_get_traced_allocs__doc__}, +#define _TRACEMALLOC_GET_TRACED_REFS_METHODDEF \ + {"get_traced_refs", (PyCFunction)_tracemalloc_get_traced_refs, METH_NOARGS, _tracemalloc_get_traced_refs__doc__}, static PyObject * -_tracemalloc_get_traced_allocs_impl(PyObject *module); +_tracemalloc_get_traced_refs_impl(PyObject *module); static PyObject * -_tracemalloc_get_traced_allocs(PyObject *module, PyObject *Py_UNUSED(ignored)) +_tracemalloc_get_traced_refs(PyObject *module, PyObject *Py_UNUSED(ignored)) { - return _tracemalloc_get_traced_allocs_impl(module); + return _tracemalloc_get_traced_refs_impl(module); } PyDoc_STRVAR(_tracemalloc_reset_peak__doc__, @@ -234,4 +234,4 @@ _tracemalloc_reset_peak(PyObject *module, PyObject *Py_UNUSED(ignored)) { return _tracemalloc_reset_peak_impl(module); } -/*[clinic end generated code: output=9cb364916c67f0be input=a9049054013a1b77]*/ +/*[clinic end generated code: output=7efbb9b4f08daab3 input=a9049054013a1b77]*/ diff --git a/Python/tracemalloc.c b/Python/tracemalloc.c index 6a70d5b99830d3..90636d7f1e19a8 100644 --- a/Python/tracemalloc.c +++ b/Python/tracemalloc.c @@ -76,8 +76,8 @@ typedef struct { #define tracemalloc_tracebacks _PyRuntime.tracemalloc.tracebacks #define tracemalloc_traces _PyRuntime.tracemalloc.traces #define tracemalloc_domains _PyRuntime.tracemalloc.domains -#define tracemalloc_allocations _PyRuntime.tracemalloc.allocations -#define tracemalloc_deallocations _PyRuntime.tracemalloc.deallocations +#define tracemalloc_refs_created _PyRuntime.tracemalloc.refs_created +#define tracemalloc_refs_destroyed _PyRuntime.tracemalloc.refs_destroyed #ifdef TRACE_DEBUG @@ -1255,48 +1255,47 @@ _PyTraceMalloc_Fini(void) Do nothing if tracemalloc is not tracing memory allocations or if the object memory block is not already traced. */ -static int -_PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, - void* Py_UNUSED(ignore)) -{ - if (event != PyRefTracer_CREATE) { - /* we don't want bother here with the lock for performance reasons */ - if (_Py_atomic_load_int_relaxed(&tracemalloc_config.tracing)) { - _Py_atomic_add_ssize(&tracemalloc_deallocations, 1); - } - return 0; - } - if (get_reentrant()) { - return 0; - } - - _Py_AssertHoldsTstate(); - TABLES_LOCK(); - - if (!tracemalloc_config.tracing) { - goto done; - } - - tracemalloc_allocations += 1; - - PyTypeObject *type = Py_TYPE(op); - const size_t presize = _PyType_PreHeaderSize(type); - uintptr_t ptr = (uintptr_t)((char *)op - presize); - - trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr)); - if (trace != NULL) { - /* update the traceback of the memory block */ - traceback_t *traceback = traceback_new(); - if (traceback != NULL) { - trace->traceback = traceback; - } - } - /* else: cannot track the object, its memory block size is unknown */ - -done: - TABLES_UNLOCK(); - return 0; -} + static int + _PyTraceMalloc_TraceRef(PyObject *op, PyRefTracerEvent event, + void* Py_UNUSED(ignore)) + { + if (get_reentrant()) { + return 0; + } + + _Py_AssertHoldsTstate(); + TABLES_LOCK(); + + if (!tracemalloc_config.tracing) { + goto done; + } + + if (event == PyRefTracer_CREATE) { + tracemalloc_refs_created += 1; + } + else { + tracemalloc_refs_destroyed += 1; + goto done; + } + + PyTypeObject *type = Py_TYPE(op); + const size_t presize = _PyType_PreHeaderSize(type); + uintptr_t ptr = (uintptr_t)((char *)op - presize); + + trace_t *trace = _Py_hashtable_get(tracemalloc_traces, TO_PTR(ptr)); + if (trace != NULL) { + /* update the traceback of the memory block */ + traceback_t *traceback = traceback_new(); + if (traceback != NULL) { + trace->traceback = traceback; + } + } + /* else: cannot track the object, its memory block size is unknown */ + + done: + TABLES_UNLOCK(); + return 0; + } PyObject* @@ -1334,8 +1333,8 @@ _PyTraceMalloc_ClearTraces(void) TABLES_LOCK(); if (tracemalloc_config.tracing) { tracemalloc_clear_traces_unlocked(); - tracemalloc_allocations = 0; - tracemalloc_deallocations = 0; + tracemalloc_refs_created = 0; + tracemalloc_refs_destroyed = 0; } TABLES_UNLOCK(); } @@ -1476,21 +1475,21 @@ _PyTraceMalloc_GetTracedMemory(void) PyObject * -_PyTraceMalloc_GetTracedAllocs(void) +_PyTraceMalloc_GetTracedRefs(void) { TABLES_LOCK(); - Py_ssize_t allocations, deallocations; + Py_ssize_t created, destroyed; if (tracemalloc_config.tracing) { - allocations = tracemalloc_allocations; - deallocations = tracemalloc_deallocations; + created = tracemalloc_refs_created; + destroyed = tracemalloc_refs_destroyed; } else { - allocations = 0; - deallocations = 0; + created = 0; + destroyed = 0; } TABLES_UNLOCK(); - return Py_BuildValue("nn", allocations, deallocations); + return Py_BuildValue("nn", created, destroyed); } void From 7432709792704d149ee51127c10af07e18db9dc3 Mon Sep 17 00:00:00 2001 From: Tomasz Pytel Date: Mon, 3 Mar 2025 18:38:25 -0500 Subject: [PATCH 5/5] comment fix --- Include/internal/pycore_tracemalloc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_tracemalloc.h b/Include/internal/pycore_tracemalloc.h index 71912ab238a08e..b3fe287d48e176 100644 --- a/Include/internal/pycore_tracemalloc.h +++ b/Include/internal/pycore_tracemalloc.h @@ -98,7 +98,7 @@ struct _tracemalloc_runtime_state { Protected by TABLES_LOCK(). */ Py_ssize_t refs_created; /* Number of references destroyed. - Protected by TABLES_LOCK() and sometimes modified atomically. */ + Protected by TABLES_LOCK(). */ Py_ssize_t refs_destroyed; struct tracemalloc_traceback empty_traceback;