Skip to content

Commit e6ac054

Browse files
vstinnercmaloney
andcommitted
Move the function to _winapi
Co-Authored-by: Cody Maloney <cmaloney@users.noreply.github.com>
1 parent aff7bed commit e6ac054

4 files changed

Lines changed: 113 additions & 45 deletions

File tree

Lib/test/libregrtest/utils.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
import textwrap
1515
from collections.abc import Callable
1616
try:
17-
from _testcapi import get_process_memory_usage as _get_process_memory_usage
17+
import _winapi
1818
except ImportError:
19-
_get_process_memory_usage = None
19+
_winapi = None
2020

2121
from test import support
2222
from test.support import os_helper
@@ -758,13 +758,7 @@ def display_title(title):
758758
print(flush=True)
759759

760760

761-
def get_process_memory_usage(pid: int) -> int | None:
762-
"""
763-
Get process memory usage in bytes.
764-
"""
765-
if _get_process_memory_usage is not None:
766-
return _get_process_memory_usage(pid)
767-
761+
def _get_process_memory_usage_linux(pid: int) -> int | None:
768762
# Linux implementation: read the private memory in bytes from
769763
# /proc/pid/smaps.
770764
try:
@@ -784,3 +778,25 @@ def get_process_memory_usage(pid: int) -> int | None:
784778
return total
785779
except ProcessLookupError:
786780
return None
781+
782+
783+
def _get_process_memory_usage_windows(pid: int) -> int | None:
784+
handle = _winapi.OpenProcess(_winapi.PROCESS_QUERY_LIMITED_INFORMATION,
785+
False, pid)
786+
try:
787+
mem_info = _winapi.GetProcessMemoryInfo(handle)
788+
finally:
789+
_winapi.CloseHandle(handle)
790+
return mem_info['WorkingSetSize']
791+
792+
793+
if _winapi is not None:
794+
get_process_memory_usage = _get_process_memory_usage_windows
795+
elif sys.platform == 'linux':
796+
get_process_memory_usage = _get_process_memory_usage_linux
797+
else:
798+
def get_process_memory_usage(pid: int) -> int | None:
799+
"""
800+
Get process memory usage in bytes.
801+
"""
802+
return None

Modules/_testcapi/mem.c

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
#include "parts.h"
22

3-
#ifdef MS_WINDOWS
4-
# include <windows.h>
5-
# include <psapi.h> // GetProcessMemoryInfo()
6-
#endif
73
#include <stddef.h>
84

95

@@ -688,34 +684,6 @@ tracemalloc_track_race(PyObject *self, PyObject *args)
688684
}
689685

690686

691-
#ifdef MS_WINDOWS
692-
// Get process memory usage in bytes.
693-
static PyObject *
694-
get_process_memory_usage(PyObject *self, PyObject *args)
695-
{
696-
int pid;
697-
if (!PyArg_ParseTuple(args, "i", &pid)) {
698-
return NULL;
699-
}
700-
701-
// Get WorkingSetSize from GetProcessMemoryInfo()
702-
HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)pid);
703-
if (handle == NULL) {
704-
return PyErr_SetFromWindowsErr(0);
705-
}
706-
707-
PROCESS_MEMORY_COUNTERS pmc;
708-
if (!GetProcessMemoryInfo(handle, &pmc, sizeof(pmc))) {
709-
CloseHandle(handle);
710-
return PyErr_SetFromWindowsErr(0);
711-
}
712-
CloseHandle(handle);
713-
714-
return PyLong_FromSize_t(pmc.WorkingSetSize);
715-
}
716-
#endif
717-
718-
719687
static PyMethodDef test_methods[] = {
720688
{"pymem_api_misuse", pymem_api_misuse, METH_NOARGS},
721689
{"pymem_buffer_overflow", pymem_buffer_overflow, METH_NOARGS},
@@ -730,9 +698,6 @@ static PyMethodDef test_methods[] = {
730698
{"test_pymem_setrawallocators", test_pymem_setrawallocators, METH_NOARGS},
731699
{"test_pyobject_new", test_pyobject_new, METH_NOARGS},
732700
{"test_pyobject_setallocators", test_pyobject_setallocators, METH_NOARGS},
733-
#ifdef MS_WINDOWS
734-
{"get_process_memory_usage", get_process_memory_usage, METH_VARARGS},
735-
#endif
736701

737702
// Tracemalloc tests
738703
{"tracemalloc_track", tracemalloc_track, METH_VARARGS},

Modules/_winapi.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@
4949
#include <crtdbg.h>
5050
#include "winreparse.h"
5151

52+
// PSAPI_VERSION=2 redirects GetProcessMemoryInfo() to
53+
// K32GetProcessMemoryInfo() in kernel32.dll, so we don't need to link
54+
// psapi.lib. See:
55+
// https://learn.microsoft.com/windows/win32/api/psapi/nf-psapi-getprocessmemoryinfo
56+
#define PSAPI_VERSION 2
57+
#include <psapi.h> // GetProcessMemoryInfo()
58+
5259
#if defined(MS_WIN32) && !defined(MS_WIN64)
5360
#define HANDLE_TO_PYNUM(handle) \
5461
PyLong_FromUnsignedLong((unsigned long) handle)
@@ -3080,6 +3087,57 @@ _winapi_ReportEvent_impl(PyObject *module, HANDLE handle,
30803087
}
30813088

30823089

3090+
3091+
/*[clinic input]
3092+
_winapi.GetProcessMemoryInfo
3093+
handle: HANDLE
3094+
/
3095+
3096+
Return the memory usage of the given process handle.
3097+
[clinic start generated code]*/
3098+
3099+
static PyObject *
3100+
_winapi_GetProcessMemoryInfo_impl(PyObject *module, HANDLE handle)
3101+
/*[clinic end generated code: output=00a5d09732e84120 input=cfa669907cfbcecb]*/
3102+
{
3103+
PROCESS_MEMORY_COUNTERS pmc;
3104+
if (!GetProcessMemoryInfo(handle, &pmc, sizeof(pmc))) {
3105+
return PyErr_SetFromWindowsErr(0);
3106+
}
3107+
3108+
PyObject *result = PyDict_New();
3109+
if (result == NULL) {
3110+
return NULL;
3111+
}
3112+
3113+
#define ADD(ATTR) \
3114+
do { \
3115+
PyObject *obj = PyLong_FromSize_t(pmc.ATTR); \
3116+
if (obj == NULL) { \
3117+
Py_DECREF(result); \
3118+
return NULL; \
3119+
} \
3120+
if (PyDict_SetItemString(result, #ATTR, obj) < 0) { \
3121+
Py_DECREF(obj); \
3122+
return NULL; \
3123+
} \
3124+
Py_DECREF(obj); \
3125+
} while (0)
3126+
3127+
ADD(PageFaultCount);
3128+
ADD(PeakWorkingSetSize);
3129+
ADD(WorkingSetSize);
3130+
ADD(QuotaPeakPagedPoolUsage);
3131+
ADD(QuotaPagedPoolUsage);
3132+
ADD(QuotaPeakNonPagedPoolUsage);
3133+
ADD(QuotaNonPagedPoolUsage);
3134+
ADD(PagefileUsage);
3135+
ADD(PeakPagefileUsage);
3136+
3137+
return result;
3138+
}
3139+
3140+
30833141
static PyMethodDef winapi_functions[] = {
30843142
_WINAPI_CLOSEHANDLE_METHODDEF
30853143
_WINAPI_CONNECTNAMEDPIPE_METHODDEF
@@ -3130,6 +3188,7 @@ static PyMethodDef winapi_functions[] = {
31303188
_WINAPI__MIMETYPES_READ_WINDOWS_REGISTRY_METHODDEF
31313189
_WINAPI_NEEDCURRENTDIRECTORYFOREXEPATH_METHODDEF
31323190
_WINAPI_COPYFILE2_METHODDEF
3191+
_WINAPI_GETPROCESSMEMORYINFO_METHODDEF
31333192
{NULL, NULL}
31343193
};
31353194

@@ -3226,6 +3285,7 @@ static int winapi_exec(PyObject *m)
32263285
WINAPI_CONSTANT(F_DWORD, PROCESS_ALL_ACCESS);
32273286
WINAPI_CONSTANT(F_DWORD, SYNCHRONIZE);
32283287
WINAPI_CONSTANT(F_DWORD, PROCESS_DUP_HANDLE);
3288+
WINAPI_CONSTANT(F_DWORD, PROCESS_QUERY_LIMITED_INFORMATION);
32293289
WINAPI_CONSTANT(F_DWORD, SEC_COMMIT);
32303290
WINAPI_CONSTANT(F_DWORD, SEC_IMAGE);
32313291
WINAPI_CONSTANT(F_DWORD, SEC_LARGE_PAGES);

Modules/clinic/_winapi.c.h

Lines changed: 28 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)