diff --git a/Include/Python.h b/Include/Python.h index 183d07cc539b4a..07f6c202a7f126 100644 --- a/Include/Python.h +++ b/Include/Python.h @@ -103,7 +103,7 @@ #include "pystrcmp.h" #include "fileutils.h" #include "cpython/pyfpe.h" -#include "tracemalloc.h" +#include "cpython/tracemalloc.h" #include "cpython/optimizer.h" #endif /* !Py_PYTHON_H */ diff --git a/Include/cpython/tracemalloc.h b/Include/cpython/tracemalloc.h new file mode 100644 index 00000000000000..61a16ea9a9f3eb --- /dev/null +++ b/Include/cpython/tracemalloc.h @@ -0,0 +1,26 @@ +#ifndef Py_LIMITED_API +#ifndef Py_TRACEMALLOC_H +#define Py_TRACEMALLOC_H + +/* Track an allocated memory block in the tracemalloc module. + Return 0 on success, return -1 on error (failed to allocate memory to store + the trace). + + Return -2 if tracemalloc is disabled. + + If memory block is already tracked, update the existing trace. */ +PyAPI_FUNC(int) PyTraceMalloc_Track( + unsigned int domain, + uintptr_t ptr, + size_t size); + +/* Untrack an allocated memory block in the tracemalloc module. + Do nothing if the block was not tracked. + + Return -2 if tracemalloc is disabled, otherwise return 0. */ +PyAPI_FUNC(int) PyTraceMalloc_Untrack( + unsigned int domain, + uintptr_t ptr); + +#endif // !Py_TRACEMALLOC_H +#endif // !Py_LIMITED_API diff --git a/Include/internal/pycore_tracemalloc.h b/Include/internal/pycore_tracemalloc.h index d086adc61c319b..cfc4d1fe43999e 100644 --- a/Include/internal/pycore_tracemalloc.h +++ b/Include/internal/pycore_tracemalloc.h @@ -117,6 +117,51 @@ struct _tracemalloc_runtime_state { } +/* Get the traceback where a memory block was allocated. + + Return a tuple of (filename: str, lineno: int) tuples. + + Return None if the tracemalloc module is disabled or if the memory block + is not tracked by tracemalloc. + + Raise an exception and return NULL on error. */ +PyAPI_FUNC(PyObject*) _PyTraceMalloc_GetTraceback( + unsigned int domain, + uintptr_t ptr); + +/* Return non-zero if tracemalloc is tracing */ +extern int _PyTraceMalloc_IsTracing(void); + +/* Clear the tracemalloc traces */ +extern void _PyTraceMalloc_ClearTraces(void); + +/* Clear the tracemalloc traces */ +extern PyObject* _PyTraceMalloc_GetTraces(void); + +/* Clear tracemalloc traceback for an object */ +extern PyObject* _PyTraceMalloc_GetObjectTraceback(PyObject *obj); + +/* Initialize tracemalloc */ +extern int _PyTraceMalloc_Init(void); + +/* Start tracemalloc */ +extern int _PyTraceMalloc_Start(int max_nframe); + +/* Stop tracemalloc */ +extern void _PyTraceMalloc_Stop(void); + +/* Get the tracemalloc traceback limit */ +extern int _PyTraceMalloc_GetTracebackLimit(void); + +/* Get the memory usage of tracemalloc in bytes */ +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); + +/* Set the peak size of traced memory blocks to the current size */ +extern void _PyTraceMalloc_ResetPeak(void); + #ifdef __cplusplus } #endif diff --git a/Include/tracemalloc.h b/Include/tracemalloc.h deleted file mode 100644 index 580027a8e365e5..00000000000000 --- a/Include/tracemalloc.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef Py_TRACEMALLOC_H -#define Py_TRACEMALLOC_H - -#ifndef Py_LIMITED_API -/* Track an allocated memory block in the tracemalloc module. - Return 0 on success, return -1 on error (failed to allocate memory to store - the trace). - - Return -2 if tracemalloc is disabled. - - If memory block is already tracked, update the existing trace. */ -PyAPI_FUNC(int) PyTraceMalloc_Track( - unsigned int domain, - uintptr_t ptr, - size_t size); - -/* Untrack an allocated memory block in the tracemalloc module. - Do nothing if the block was not tracked. - - Return -2 if tracemalloc is disabled, otherwise return 0. */ -PyAPI_FUNC(int) PyTraceMalloc_Untrack( - unsigned int domain, - uintptr_t ptr); - -/* Get the traceback where a memory block was allocated. - - Return a tuple of (filename: str, lineno: int) tuples. - - Return None if the tracemalloc module is disabled or if the memory block - is not tracked by tracemalloc. - - Raise an exception and return NULL on error. */ -PyAPI_FUNC(PyObject*) _PyTraceMalloc_GetTraceback( - unsigned int domain, - uintptr_t ptr); - -/* Return non-zero if tracemalloc is tracing */ -PyAPI_FUNC(int) _PyTraceMalloc_IsTracing(void); - -/* Clear the tracemalloc traces */ -PyAPI_FUNC(void) _PyTraceMalloc_ClearTraces(void); - -/* Clear the tracemalloc traces */ -PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetTraces(void); - -/* Clear tracemalloc traceback for an object */ -PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetObjectTraceback(PyObject *obj); - -/* Initialize tracemalloc */ -PyAPI_FUNC(int) _PyTraceMalloc_Init(void); - -/* Start tracemalloc */ -PyAPI_FUNC(int) _PyTraceMalloc_Start(int max_nframe); - -/* Stop tracemalloc */ -PyAPI_FUNC(void) _PyTraceMalloc_Stop(void); - -/* Get the tracemalloc traceback limit */ -PyAPI_FUNC(int) _PyTraceMalloc_GetTracebackLimit(void); - -/* Get the memory usage of tracemalloc in bytes */ -PyAPI_FUNC(size_t) _PyTraceMalloc_GetMemory(void); - -/* Get the current size and peak size of traced memory blocks as a 2-tuple */ -PyAPI_FUNC(PyObject *) _PyTraceMalloc_GetTracedMemory(void); - -/* Set the peak size of traced memory blocks to the current size */ -PyAPI_FUNC(void) _PyTraceMalloc_ResetPeak(void); - -#endif - -#endif /* !Py_TRACEMALLOC_H */ diff --git a/Lib/test/test_tracemalloc.py b/Lib/test/test_tracemalloc.py index 94bcee302fe730..4af4ca3b977236 100644 --- a/Lib/test/test_tracemalloc.py +++ b/Lib/test/test_tracemalloc.py @@ -11,8 +11,10 @@ try: import _testcapi + import _testinternalcapi except ImportError: _testcapi = None + _testinternalcapi = None EMPTY_STRING_SIZE = sys.getsizeof(b'') @@ -1008,7 +1010,7 @@ def tearDown(self): tracemalloc.stop() def get_traceback(self): - frames = _testcapi.tracemalloc_get_traceback(self.domain, self.ptr) + frames = _testinternalcapi._PyTraceMalloc_GetTraceback(self.domain, self.ptr) if frames is not None: return tracemalloc.Traceback(frames) else: diff --git a/Makefile.pre.in b/Makefile.pre.in index 54d0516ad4423b..e788e590dcbb43 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1658,7 +1658,6 @@ PYTHON_HEADERS= \ $(srcdir)/Include/structseq.h \ $(srcdir)/Include/sysmodule.h \ $(srcdir)/Include/traceback.h \ - $(srcdir)/Include/tracemalloc.h \ $(srcdir)/Include/tupleobject.h \ $(srcdir)/Include/unicodeobject.h \ $(srcdir)/Include/warnings.h \ @@ -1713,6 +1712,7 @@ PYTHON_HEADERS= \ $(srcdir)/Include/cpython/setobject.h \ $(srcdir)/Include/cpython/sysmodule.h \ $(srcdir)/Include/cpython/traceback.h \ + $(srcdir)/Include/cpython/tracemalloc.h \ $(srcdir)/Include/cpython/tupleobject.h \ $(srcdir)/Include/cpython/unicodeobject.h \ $(srcdir)/Include/cpython/warnings.h \ diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c index af32e9668dda2d..16bda66af554af 100644 --- a/Modules/_testcapi/mem.c +++ b/Modules/_testcapi/mem.c @@ -655,23 +655,6 @@ tracemalloc_untrack(PyObject *self, PyObject *args) Py_RETURN_NONE; } -static PyObject * -tracemalloc_get_traceback(PyObject *self, PyObject *args) -{ - unsigned int domain; - PyObject *ptr_obj; - - if (!PyArg_ParseTuple(args, "IO", &domain, &ptr_obj)) { - return NULL; - } - void *ptr = PyLong_AsVoidPtr(ptr_obj); - if (PyErr_Occurred()) { - return NULL; - } - - return _PyTraceMalloc_GetTraceback(domain, (uintptr_t)ptr); -} - static PyMethodDef test_methods[] = { {"check_pyobject_forbidden_bytes_is_freed", check_pyobject_forbidden_bytes_is_freed, METH_NOARGS}, @@ -697,7 +680,6 @@ static PyMethodDef test_methods[] = { // Tracemalloc tests {"tracemalloc_track", tracemalloc_track, METH_VARARGS}, {"tracemalloc_untrack", tracemalloc_untrack, METH_VARARGS}, - {"tracemalloc_get_traceback", tracemalloc_get_traceback, METH_VARARGS}, {NULL}, }; diff --git a/Modules/_testinternalcapi.c b/Modules/_testinternalcapi.c index c598d7edef8ae2..f6ae389ea05679 100644 --- a/Modules/_testinternalcapi.c +++ b/Modules/_testinternalcapi.c @@ -1216,6 +1216,24 @@ test_pytime_object_to_timespec(PyObject *self, PyObject *args) } +static PyObject * +tracemalloc_get_traceback(PyObject *self, PyObject *args) +{ + unsigned int domain; + PyObject *ptr_obj; + + if (!PyArg_ParseTuple(args, "IO", &domain, &ptr_obj)) { + return NULL; + } + void *ptr = PyLong_AsVoidPtr(ptr_obj); + if (PyErr_Occurred()) { + return NULL; + } + + return _PyTraceMalloc_GetTraceback(domain, (uintptr_t)ptr); +} + + static PyMethodDef module_functions[] = { {"get_configs", get_configs, METH_NOARGS}, {"get_recursion_depth", get_recursion_depth, METH_NOARGS}, @@ -1250,7 +1268,6 @@ static PyMethodDef module_functions[] = { {"get_uop_optimizer", get_uop_optimizer, METH_NOARGS, NULL}, {"pending_threadfunc", _PyCFunction_CAST(pending_threadfunc), METH_VARARGS | METH_KEYWORDS}, -// {"pending_fd_identify", pending_fd_identify, METH_VARARGS, NULL}, {"pending_identify", pending_identify, METH_VARARGS, NULL}, {"_PyTime_AsMicroseconds", test_PyTime_AsMicroseconds, METH_VARARGS}, {"_PyTime_AsMilliseconds", test_PyTime_AsMilliseconds, METH_VARARGS}, @@ -1266,6 +1283,7 @@ static PyMethodDef module_functions[] = { {"_PyTime_ObjectToTime_t", test_pytime_object_to_time_t, METH_VARARGS}, {"_PyTime_ObjectToTimespec", test_pytime_object_to_timespec, METH_VARARGS}, {"_PyTime_ObjectToTimeval", test_pytime_object_to_timeval, METH_VARARGS}, + {"_PyTraceMalloc_GetTraceback", tracemalloc_get_traceback, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj index 58abd871376a06..436381c3ea5db4 100644 --- a/PCbuild/pythoncore.vcxproj +++ b/PCbuild/pythoncore.vcxproj @@ -179,6 +179,7 @@ + @@ -320,7 +321,6 @@ - diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters index 4d7b5ccf9a8a9e..4d9acf4893872d 100644 --- a/PCbuild/pythoncore.vcxproj.filters +++ b/PCbuild/pythoncore.vcxproj.filters @@ -219,9 +219,6 @@ Include - - Include - Include @@ -453,6 +450,9 @@ Include\cpython + + Include + Include\cpython