From 73275613e02ebff3d09cd8161290e17b1b5b43c5 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Mon, 25 May 2026 22:03:39 +0900 Subject: [PATCH 1/4] gh-150114: Log the memory usage in regrtest on macOS --- Lib/test/libregrtest/utils.py | 15 ++++++++++++++- Modules/_testcapi/mem.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/Lib/test/libregrtest/utils.py b/Lib/test/libregrtest/utils.py index 21b84f7555b7713..63e67447f611433 100644 --- a/Lib/test/libregrtest/utils.py +++ b/Lib/test/libregrtest/utils.py @@ -19,6 +19,10 @@ import _winapi except ImportError: _winapi = None +try: + from _testcapi import get_process_memory_usage as _get_process_memory_usage +except ImportError: + _get_process_memory_usage = None from test import support from test.support import os_helper @@ -793,7 +797,16 @@ def _get_process_memory_usage_windows(pid: int) -> int | None: return mem_info['WorkingSetSize'] -if _winapi is not None: +if _get_process_memory_usage is not None: + _testcapi_get_process_memory_usage = _get_process_memory_usage + + def get_process_memory_usage(pid: int) -> int | None: + # Worker may exit before we query its memory. + try: + return _testcapi_get_process_memory_usage(pid) + except ProcessLookupError: + return None +elif _winapi is not None: get_process_memory_usage = _get_process_memory_usage_windows elif sys.platform == 'linux': get_process_memory_usage = _get_process_memory_usage_linux diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c index b4896f984510bd6..1a2f943332910bc 100644 --- a/Modules/_testcapi/mem.c +++ b/Modules/_testcapi/mem.c @@ -2,6 +2,12 @@ #include +#ifdef __APPLE__ +# include // errno, ESRCH +# include // proc_pidinfo(), PROC_PIDTASKINFO +# include // struct proc_taskinfo +#endif + typedef struct { PyMemAllocatorEx alloc; @@ -684,6 +690,32 @@ tracemalloc_track_race(PyObject *self, PyObject *args) } +#ifdef __APPLE__ +// Return RSS via proc_pidinfo(PROC_PIDTASKINFO).pti_resident_size. +static PyObject* +get_process_memory_usage(PyObject *self, PyObject *args) +{ + int pid; + if (!PyArg_ParseTuple(args, "i", &pid)) { + return NULL; + } + + struct proc_taskinfo pti; + int ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)); + if (ret <= 0) { + if (errno == 0) { + // proc_pidinfo() can return 0 without setting errno when the + // process does not exist. + errno = ESRCH; + } + return PyErr_SetFromErrno(PyExc_OSError); + } + + return PyLong_FromUnsignedLongLong(pti.pti_resident_size); +} +#endif + + static PyMethodDef test_methods[] = { {"pymem_api_misuse", pymem_api_misuse, METH_NOARGS}, {"pymem_buffer_overflow", pymem_buffer_overflow, METH_NOARGS}, @@ -698,6 +730,9 @@ static PyMethodDef test_methods[] = { {"test_pymem_setrawallocators", test_pymem_setrawallocators, METH_NOARGS}, {"test_pyobject_new", test_pyobject_new, METH_NOARGS}, {"test_pyobject_setallocators", test_pyobject_setallocators, METH_NOARGS}, +#ifdef __APPLE__ + {"get_process_memory_usage", get_process_memory_usage, METH_VARARGS}, +#endif // Tracemalloc tests {"tracemalloc_track", tracemalloc_track, METH_VARARGS}, From 03abe46cc22da0407ba8cd3600d1a6c65d7bbdf7 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Mon, 25 May 2026 22:11:05 +0900 Subject: [PATCH 2/4] fix for iOS --- Modules/_testcapi/mem.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c index 1a2f943332910bc..28048178d00e5a3 100644 --- a/Modules/_testcapi/mem.c +++ b/Modules/_testcapi/mem.c @@ -2,10 +2,17 @@ #include -#ifdef __APPLE__ -# include // errno, ESRCH -# include // proc_pidinfo(), PROC_PIDTASKINFO -# include // struct proc_taskinfo +#if defined(__APPLE__) +# include + // Older macOS SDKs do not define TARGET_OS_OSX +# if !defined(TARGET_OS_OSX) +# define TARGET_OS_OSX 1 +# endif +# if TARGET_OS_OSX +# include // errno, ESRCH +# include // proc_pidinfo(), PROC_PIDTASKINFO +# include // struct proc_taskinfo +# endif #endif @@ -690,7 +697,7 @@ tracemalloc_track_race(PyObject *self, PyObject *args) } -#ifdef __APPLE__ +#if TARGET_OS_OSX // Return RSS via proc_pidinfo(PROC_PIDTASKINFO).pti_resident_size. static PyObject* get_process_memory_usage(PyObject *self, PyObject *args) @@ -730,7 +737,7 @@ static PyMethodDef test_methods[] = { {"test_pymem_setrawallocators", test_pymem_setrawallocators, METH_NOARGS}, {"test_pyobject_new", test_pyobject_new, METH_NOARGS}, {"test_pyobject_setallocators", test_pyobject_setallocators, METH_NOARGS}, -#ifdef __APPLE__ +#if TARGET_OS_OSX {"get_process_memory_usage", get_process_memory_usage, METH_VARARGS}, #endif From f31e2838384f692a5e7e153e2a7c460b4b5b0df3 Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Mon, 25 May 2026 23:12:58 +0900 Subject: [PATCH 3/4] Address code review --- Modules/_testcapi/mem.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c index 1c812c5f4a4fcba..7104c17201e1077 100644 --- a/Modules/_testcapi/mem.c +++ b/Modules/_testcapi/mem.c @@ -706,8 +706,8 @@ tracemalloc_track_race(PyObject *self, PyObject *args) } -#if TARGET_OS_OSX -// Return RSS via proc_pidinfo(PROC_PIDTASKINFO).pti_resident_size. +#if TARGET_OS_OSX || defined(__FreeBSD__) +// Return RSS only. Per-process swap usage isn't readily available static PyObject* get_process_memory_usage(PyObject *self, PyObject *args) { @@ -715,7 +715,8 @@ get_process_memory_usage(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "i", &pid)) { return NULL; } - +#if TARGET_OS_OSX + // macOS: proc_pidinfo(PROC_PIDTASKINFO).pti_resident_size struct proc_taskinfo pti; int ret = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &pti, sizeof(pti)); if (ret <= 0) { @@ -728,20 +729,8 @@ get_process_memory_usage(PyObject *self, PyObject *args) } return PyLong_FromUnsignedLongLong(pti.pti_resident_size); -} -#endif - - -#ifdef __FreeBSD__ -// Return RSS only. Per-process swap usage isn't readily available -static PyObject* -get_process_memory_usage(PyObject *self, PyObject *args) -{ - int pid; - if (!PyArg_ParseTuple(args, "i", &pid)) { - return NULL; - } - +#else + // FreeBSD: kvm_getprocs(KERN_PROC_PID) and ki_rssize * page_size long page_size = sysconf(_SC_PAGESIZE); if (page_size <= 0) { return PyErr_SetFromErrno(PyExc_OSError); @@ -779,6 +768,7 @@ get_process_memory_usage(PyObject *self, PyObject *args) error: kvm_close(kd); return NULL; +#endif } #endif From 526034a7ebd8ab53cbe526de4797882de14b5d4c Mon Sep 17 00:00:00 2001 From: Donghee Na Date: Mon, 25 May 2026 23:27:51 +0900 Subject: [PATCH 4/4] Address code review --- Modules/_testcapi/mem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/_testcapi/mem.c b/Modules/_testcapi/mem.c index 7104c17201e1077..7909476ac11aa6b 100644 --- a/Modules/_testcapi/mem.c +++ b/Modules/_testcapi/mem.c @@ -715,6 +715,7 @@ get_process_memory_usage(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, "i", &pid)) { return NULL; } + #if TARGET_OS_OSX // macOS: proc_pidinfo(PROC_PIDTASKINFO).pti_resident_size struct proc_taskinfo pti;